Mercurial > hg > webaudioevaluationtool
changeset 3108:1ae8c03dd6a6
Merge branch 'master' into vnext
# Conflicts:
# test_create.html
# test_create/test_core.js
author | Nicholas Jillings <nicholas.jillings@mail.bcu.ac.uk> |
---|---|
date | Tue, 10 Apr 2018 10:22:34 +0100 |
parents | 171706465aa9 (diff) f99b888f57e9 (current diff) |
children | 63086deafdf4 9ac4f490a1d8 |
files | js/core.js python/survey_parser.py test_create.html test_create/test_core.js |
diffstat | 38 files changed, 1759 insertions(+), 1208 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.brackets.json Tue Apr 10 10:22:34 2018 +0100 @@ -0,0 +1,12 @@ +{ + "brackets-minifier.on-save-project": false, + "brackets-minifier.js-project-minify": true, + "brackets-minifier.css-project-minify": true, + "brackets-minifier.js-custom-path": "", + "brackets-minifier.css-custom-path": "", + "brackets-minifier.project-exclude": "", + "brackets-minifier.concat-js-filename": "", + "brackets-minifier.concat-css-filename": "", + "brackets-minifier.uglifyjs-options": "{}", + "brackets-minifier.cleancss-options": "{}" +} \ No newline at end of file
--- a/.gitignore Tue Apr 10 10:18:25 2018 +0100 +++ b/.gitignore Tue Apr 10 10:22:34 2018 +0100 @@ -11,3 +11,6 @@ *.DS_STORE *.swp *.swo +saves/ratings/* +saves/timelines/* +saves/timelines_movement/*
--- a/css/core.css Tue Apr 10 10:18:25 2018 +0100 +++ b/css/core.css Tue Apr 10 10:22:34 2018 +0100 @@ -199,6 +199,7 @@ div.master-volume-holder-inline { width: 100%; padding: 5px; + float: left; } div.master-volume-holder-float { position: absolute; @@ -239,7 +240,7 @@ height: auto; } div.calibration-slider { - width: 50px; + width: 44px; margin: 2px; text-align: center; align-content: center; @@ -252,7 +253,15 @@ /* WebKit */ width: 8px; padding: 0 5px; - height: 290px; + height: 200px; +} +button.calibration-button { + height: 25px; + border-radius: 5px; + border: #444; + border-width: 1px; + border-style: solid; + background-color: white; } /* Comment Boxes */
--- a/index.html Tue Apr 10 10:18:25 2018 +0100 +++ b/index.html Tue Apr 10 10:22:34 2018 +0100 @@ -24,7 +24,7 @@ <body> <div id='topLevelBody'> - <h1><a target="_blank" href="https://github.com/BrechtDeMan/WebAudioEvaluationTool">Web Audio Evaluation Toolbox (v1.2.2)</a></h1> + <h1><a target="_blank" href="https://github.com/BrechtDeMan/WebAudioEvaluationTool">Web Audio Evaluation Toolbox (v1.2.3)</a></h1> <h2>Start menu </h2> <ul> <li><a href="test.html?url=tests/examples/APE_example.xml" target="_blank">APE interface test example</a></li> @@ -51,7 +51,7 @@ <button id="popup-previous" class="popupButton">Back</button> </div> <div class="testHalt" style="visibility: hidden"></div> - <div id="footer"><a target="_blank" href="https://github.com/BrechtDeMan/WebAudioEvaluationTool">Web Audio Evaluation Toolbox (v1.2.2)</a></div> + <div id="footer"><a target="_blank" href="https://github.com/BrechtDeMan/WebAudioEvaluationTool">Web Audio Evaluation Toolbox (v1.2.3)</a></div> </body> </html>
--- a/interfaces/AB.css Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/AB.css Tue Apr 10 10:22:34 2018 +0100 @@ -24,6 +24,10 @@ height: 40px; font-size: 1.2em; } +div#submit-holder { + width: 100%; + text-align: center; +} div.interface-buttons { height: 40px; }
--- a/interfaces/AB.js Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/AB.js Tue Apr 10 10:22:34 2018 +0100 @@ -75,13 +75,14 @@ var boxes = document.createElement('div'); boxes.id = "box-holders"; + var submitHolder = document.createElement("div"); + submitHolder.id = "submit-holder"; var submit = document.createElement('button'); submit.id = "submit"; submit.onclick = buttonSubmitClick; submit.className = "big-button"; - submit.textContent = "submit"; - submit.style.position = "relative"; - submit.style.left = (window.innerWidth - 250) / 2 + 'px'; + submit.textContent = "Submit"; + submitHolder.appendChild(submit); feedbackHolder.appendChild(boxes); @@ -95,7 +96,7 @@ testContent.appendChild(interfaceButtons); testContent.appendChild(outsideRef); testContent.appendChild(feedbackHolder); - testContent.appendChild(submit); + testContent.appendChild(submitHolder); testContent.appendChild(comments); interfaceContext.insertPoint.appendChild(testContent); @@ -395,10 +396,13 @@ function buttonSubmitClick() { var checks = testState.currentStateMap.interfaces[0].options, canContinue = true; - + if (interfaceContext.checkFragmentMinPlays() === false) { - return; -} + return; + } + if (interfaceContext.checkCommentQuestions() === false) { + return; + } for (var i = 0; i < checks.length; i++) { if (checks[i].type == 'check') {
--- a/interfaces/ABX.css Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/ABX.css Tue Apr 10 10:22:34 2018 +0100 @@ -20,9 +20,12 @@ height: 40px; font-size: 1.2em; } +div#submit-holder { + width: 100%; + text-align: center; +} div#box-holders { width: 100%; - text-align: center; } div#playback-holder { float: none;
--- a/interfaces/ABX.js Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/ABX.js Tue Apr 10 10:22:34 2018 +0100 @@ -77,15 +77,15 @@ var boxes = document.createElement('div'); boxes.align = "center"; boxes.id = "box-holders"; - boxes.style.float = "left"; + var submitHolder = document.createElement("div"); + submitHolder.id = "submit-holder"; var submit = document.createElement('button'); submit.id = "submit"; submit.onclick = buttonSubmitClick; submit.className = "big-button"; submit.textContent = "submit"; - submit.style.position = "relative"; - submit.style.left = (window.innerWidth - 250) / 2 + 'px'; + submitHolder.appendChild(submit); feedbackHolder.appendChild(boxes); @@ -98,7 +98,7 @@ testContent.appendChild(pagetitle); testContent.appendChild(interfaceButtons); testContent.appendChild(feedbackHolder); - testContent.appendChild(submit); + testContent.appendChild(submitHolder); testContent.appendChild(comments); interfaceContext.insertPoint.appendChild(testContent); @@ -424,9 +424,6 @@ boxW = numObj * 312; diff = window.innerWidth - boxW; } - document.getElementById('box-holders').style.marginLeft = diff / 2 + 'px'; - document.getElementById('box-holders').style.marginRight = diff / 2 + 'px'; - document.getElementById('box-holders').style.width = boxW + 'px'; } function buttonSubmitClick() { @@ -436,6 +433,9 @@ if (interfaceContext.checkFragmentMinPlays() === false) { return; } + if (interfaceContext.checkCommentQuestions() === false) { + return; + } for (var i = 0; i < checks.length; i++) { var checkState = true;
--- a/interfaces/ape.css Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/ape.css Tue Apr 10 10:22:34 2018 +0100 @@ -26,7 +26,6 @@ } div.slider { /* Specify any structure for the slider holder interface */ - background-color: #eee; height: 150px; margin: 5px 50px; -moz-user-select: -moz-none; @@ -61,6 +60,12 @@ -webkit-user-select: none; border: 1px solid black; } +canvas.tick-canvas { + z-index: -1; + position: absolute; + height: 150px; + background-color: #eee; +} div#outside-reference-holder { display: flex; align-content: center;
--- a/interfaces/ape.js Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/ape.js Tue Apr 10 10:22:34 2018 +0100 @@ -4,7 +4,7 @@ */ /*globals window,interfaceContext, document, audioEngineContext, console, $, Interface, testState, storage, specification */ -/*globals metricTracker */ +/*globals metricTracker, module, randomiseOrder */ // Once this is loaded and parsed, begin execution loadInterface(); @@ -21,136 +21,15 @@ testContent.id = 'testContent'; // Bindings for interfaceContext - interfaceContext.checkAllPlayed = function () { - var hasBeenPlayed = audioEngineContext.checkAllPlayed(); - if (hasBeenPlayed.length > 0) // if a fragment has not been played yet - { - var str = ""; - if (hasBeenPlayed.length > 1) { - for (var i = 0; i < hasBeenPlayed.length; i++) { - var ao_id = audioEngineContext.audioObjects[hasBeenPlayed[i]].interfaceDOM.getPresentedId(); - str = str + ao_id; // start from 1 - if (i < hasBeenPlayed.length - 2) { - str += ", "; - } else if (i == hasBeenPlayed.length - 2) { - str += " or "; - } - } - str = 'You have not played fragments ' + str + ' yet. Please listen, rate and comment all samples before submitting.'; - } else { - str = 'You have not played fragment ' + (audioEngineContext.audioObjects[hasBeenPlayed[0]].interfaceDOM.getPresentedId()) + ' yet. Please listen, rate and comment all samples before submitting.'; - } - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - return false; - } - return true; - }; interfaceContext.checkAllMoved = function () { - var state = true; - var str = 'You have not moved the following sliders. '; - for (var i = 0; i < this.interfaceSliders.length; i++) { - var interfaceTID = []; - for (var j = 0; j < this.interfaceSliders[i].metrics.length; j++) { - var ao_id = this.interfaceSliders[i].sliders[j].getAttribute("trackIndex"); - if (this.interfaceSliders[i].metrics[j].wasMoved === false && audioEngineContext.audioObjects[ao_id].interfaceDOM.canMove()) { - state = false; - interfaceTID.push(j); - } - } - if (interfaceTID.length !== 0) { - var interfaceName = this.interfaceSliders[i].interfaceObject.title; - if (interfaceName === undefined) { - str += 'On axis ' + String(i + 1) + ' you must move '; - } else { - str += 'On axis "' + interfaceName + '" you must move '; - } - if (interfaceTID.length == 1) { - str += 'slider ' + (audioEngineContext.audioObjects[interfaceTID[0]].interfaceDOM.getPresentedId()) + '. '; // start from 1 - } else { - str += 'sliders '; - for (var k = 0; k < interfaceTID.length - 1; k++) { - str += (audioEngineContext.audioObjects[interfaceTID[k]].interfaceDOM.getPresentedId()) + ', '; // start from 1 - } - str += (audioEngineContext.audioObjects[interfaceTID[interfaceTID.length - 1]].interfaceDOM.getPresentedId()) + '. '; - } - } - } - if (state !== true) { - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - console.log(str); - } - return state; + return module.checkAllMoved(); }; interfaceContext.checkScaleRange = function () { - var audioObjs = audioEngineContext.audioObjects; - var audioHolder = testState.stateMap[testState.stateIndex]; - var interfaceObject = this.interfaceSliders[0].interfaceObject; - var state = true; - var str = ''; - this.interfaceSliders.forEach(function (sliderHolder, i) { - var scales = (function () { - var scaleRange = interfaceObject.options.find(function (a) { - return a.name == "scalerange"; - }); - return { - min: scaleRange.min, - max: scaleRange.max - }; - })(); - var range = sliderHolder.sliders.reduce(function (a, b) { - var v = convSliderPosToRate(b) * 100.0; - return { - min: Math.min(a.min, v), - max: Math.max(a.max, v) - }; - }, { - min: 100, - max: 0 - }); - if (range.min >= scales.min || range.max <= scales.max) { - state = false; - str += 'On axis "' + sliderHolder.interfaceObject.title + '" you have not used the full width of the scale. '; - } - }); - if (state !== true) { - this.storeErrorNode(str); - interfaceContext.lightbox.post("Message", str); - console.log(str); - } - return state; + return module.checkScaleRange(); }; - Interface.prototype.objectSelected = null; - Interface.prototype.objectMoved = false; - Interface.prototype.selectObject = function (object) { - if (this.objectSelected === null) { - this.objectSelected = object; - this.objectMoved = false; - } - }; - Interface.prototype.moveObject = function () { - if (this.objectMoved === false) { - this.objectMoved = true; - } - }; - Interface.prototype.releaseObject = function () { - this.objectSelected = null; - this.objectMoved = false; - }; - Interface.prototype.getSelectedObject = function () { - return this.objectSelected; - }; - Interface.prototype.hasSelectedObjectMoved = function () { - return this.objectMoved; - }; - - // Bindings for slider interfaces - Interface.prototype.interfaceSliders = []; - // Bindings for audioObjects // Create the top div for the Title element @@ -220,12 +99,13 @@ interfaceContext.insertPoint.appendChild(testContent); // Load the full interface + window.module = new ape(); testState.initialise(); testState.advanceState(); - } function loadTest(audioHolderObject) { + module.clear(); var width = window.innerWidth; var height = window.innerHeight; var id = audioHolderObject.id; @@ -246,15 +126,10 @@ document.getElementById("test-title").textContent = audioHolderObject.title; } - // Delete outside reference document.getElementById("outside-reference-holder").innerHTML = ""; var interfaceObj = interfaceContext.getCombinedInterfaces(audioHolderObject); - interfaceObj.forEach(function (interfaceObjectInstance) { - // Create the div box to center align - interfaceContext.interfaceSliders.push(new interfaceSliderHolder(interfaceObjectInstance, audioHolderObject)); - }); interfaceObj.forEach(function (interface) { interface.options.forEach(function (option) { if (option.type == "show") { @@ -298,113 +173,7 @@ var loopPlayback = audioHolderObject.loop; - var currentTestHolder = document.createElement('audioHolder'); - currentTestHolder.id = audioHolderObject.id; - currentTestHolder.repeatCount = audioHolderObject.repeatCount; - - // Find all the audioElements from the audioHolder - $(audioHolderObject.audioElements).each(function (index, element) { - // Find URL of track - // In this jQuery loop, variable 'this' holds the current audioElement. - var audioObject = audioEngineContext.newTrack(element); - // Check if an outside reference - if (element.type == 'outside-reference') { - // Construct outside reference; - var orNode = new outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder")); - audioObject.bindInterface(orNode); - } else { - // Create a slider per track - var sliderNode = new sliderObject(audioObject, interfaceObj, index); - audioObject.bindInterface(sliderNode); - interfaceContext.commentBoxes.createCommentBox(audioObject); - } - }); - - // Initialse the interfaceSlider object metrics - - $('.track-slider').mousedown(function (event) { - interfaceContext.selectObject($(this)[0]); - }); - $('.track-slider').on('touchstart', null, function (event) { - interfaceContext.selectObject($(this)[0]); - }); - - $('.track-slider').mousemove(function (event) { - event.preventDefault(); - }); - - $('.slider').mousemove(function (event) { - event.preventDefault(); - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var move = event.clientX - 6; - var w = $(event.currentTarget).width(); - move = Math.max(50, move); - move = Math.min(w + 50, move); - $(obj).css("left", move + "px"); - interfaceContext.moveObject(); - }); - - $('.slider').on('touchmove', null, function (event) { - event.preventDefault(); - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var move = event.originalEvent.targetTouches[0].clientX - 6; - var w = $(event.currentTarget).width(); - move = Math.max(50, move); - move = Math.min(w + 50, move); - $(obj).css("left", move + "px"); - interfaceContext.moveObject(); - }); - - $(document).mouseup(function (event) { - event.preventDefault(); - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var interfaceID = obj.parentElement.getAttribute("interfaceid"); - var trackID = obj.getAttribute("trackindex"); - var id; - if (interfaceContext.hasSelectedObjectMoved() === true) { - var l = $(obj).css("left"); - id = obj.getAttribute('trackIndex'); - var time = audioEngineContext.timer.getTestTime(); - var rate = convSliderPosToRate(obj); - audioEngineContext.audioObjects[id].metric.moved(time, rate); - interfaceContext.interfaceSliders[interfaceID].metrics[trackID].moved(time, rate); - console.log("slider " + id + " moved to " + rate + ' (' + time + ')'); - obj.setAttribute("slider-value", convSliderPosToRate(obj)); - } else { - id = Number(obj.attributes.trackIndex.value); - //audioEngineContext.metric.sliderPlayed(id); - audioEngineContext.play(id); - } - interfaceContext.releaseObject(); - }); - - $('.slider').on('touchend', null, function (event) { - var obj = interfaceContext.getSelectedObject(); - if (obj === null) { - return; - } - var interfaceID = obj.parentElement.getAttribute("interfaceid"); - var trackID = obj.getAttribute("trackindex"); - if (interfaceContext.hasSelectedObjectMoved() === true) { - var l = $(obj).css("left"); - var id = obj.getAttribute('trackIndex'); - var time = audioEngineContext.timer.getTestTime(); - var rate = convSliderPosToRate(obj); - audioEngineContext.audioObjects[id].metric.moved(time, rate); - interfaceContext.interfaceSliders[interfaceID].metrics[trackID].moved(time, rate); - console.log("slider " + id + " moved to " + rate + ' (' + time + ')'); - } - interfaceContext.releaseObject(); - }); + module.initialisePage(audioHolderObject); var interfaceList = audioHolderObject.interfaces.concat(specification.interfaces); for (var k = 0; k < interfaceList.length; k++) { @@ -445,238 +214,561 @@ }); //testWaitIndicator(); + module.resize(); } -function interfaceSliderHolder(interfaceObject, page) { - this.sliders = []; - this.metrics = []; - this.id = document.getElementsByClassName("sliderCanvasDiv").length; - this.name = interfaceObject.name; - this.interfaceObject = interfaceObject; - this.sliderDOM = document.createElement('div'); - this.sliderDOM.className = 'sliderCanvasDiv'; - this.sliderDOM.id = 'sliderCanvasHolder-' + this.id; - this.imageHolder = (function () { - var imageController = {}; - imageController.root = document.createElement("div"); - imageController.root.className = "imageController"; - imageController.img = document.createElement("img"); - imageController.root.appendChild(imageController.img); - imageController.setImage = function (src) { - imageController.img.src = ""; - if (typeof src !== "string" || src.length === undefined) { +function ape() { + var axis = []; + var DOMRoot = document.getElementById("slider-holder"); + var AOIs = []; + var page; + + function audioObjectInterface(audioObject, parent) { + // The audioObject communicates with this object + var playing = false; + var sliders = []; + this.enable = function () { + sliders.forEach(function (s) { + s.enable(); + }); + }; + + this.updateLoading = function (p) { + sliders.forEach(function (s) { + s.updateLoading(p); + }); + }; + + this.startPlayback = function () { + playing = true; + sliders.forEach(function (s) { + s.playing(); + }); + }; + + this.stopPlayback = function () { + playing = false; + sliders.forEach(function (s) { + s.stopped(); + }); + }; + + this.getValue = function () { + return sliders[0].value; + }; + + this.getPresentedId = function () { + return sliders[0].label; + }; + + this.canMove = function () { + return true; + }; + + this.exportXMLDOM = function (audioObject) { + var elements = []; + sliders.forEach(function (s) { + elements.push(s.exportXMLDOM()); + }); + return elements; + }; + + this.error = function () { + sliders.forEach(function (s) { + s.error(); + }); + }; + + this.addSlider = function (s) { + sliders.push(s); + }; + + this.clicked = function (event) { + if (!playing) { + audioEngineContext.play(audioObject.id); + } else { + audioEngineContext.stop(); + } + playing = !playing; + }; + + this.pageXMLSave = function (store) { + var inject = audioObject.storeDOM.getElementsByTagName("metric")[0]; + sliders.forEach(function (s) { + s.pageXMLSave(inject); + }); + }; + + } + + function axisObject(interfaceObject, parent) { + + function sliderInterface(AOI, axisInterface) { + var trackObj = document.createElement('div'); + var labelHolder = document.createElement("span"); + var label = ""; + var metric = new metricTracker(this); + var value = Math.random(); + trackObj.align = "center"; + trackObj.className = 'track-slider track-slider-disabled'; + trackObj.appendChild(labelHolder); + axisInterface.sliderRail.appendChild(trackObj); + metric.initialise(this.value); + this.setLabel = function (s) { + label = s; + }; + this.resize = function (event) { + var width = $(axisInterface.sliderRail).width(); + var w = Number(value * width); + trackObj.style.left = String(w) + "px"; + }; + this.playing = function () { + trackObj.classList.add("track-slider-playing"); + }; + this.stopped = function () { + trackObj.classList.remove("track-slider-playing"); + }; + this.enable = function () { + trackObj.addEventListener("mousedown", this); + trackObj.addEventListener("mouseup", this); + trackObj.classList.remove("track-slider-disabled"); + labelHolder.textContent = label; + }; + this.updateLoading = function (progress) { + labelHolder.textContent = progress + "%"; + }; + this.exportXMLDOM = function () { + var node = storage.document.createElement('value'); + node.setAttribute("interface-name", axisInterface.name); + node.textContent = this.value; + return node; + }; + this.error = function () { + trackObj.classList.add("error-colour"); + trackObj.removeEventListener("mousedown"); + trackObj.removeEventListener("mouseup"); + }; + var timing; + this.handleEvent = function (e) { + // This is only for the mousedown / touchdown + if (e.preventDefault) { + e.preventDefault(); + } + if (e.type == "mousedown") { + axisInterface.mousedown(this); + } else if (e.type == "mouseup" || e.type == "touchend" || e.type == "touchcancel") { + axisInterface.mouseup(this); + metric.moved(audioEngineContext.timer.getTestTime(), this.value); + console.log("Slider " + label + " on axis " + axisInterface.name + " moved to " + this.value); + } + }; + this.clicked = function (e) { + AOI.clicked(); + }; + this.pageXMLSave = function (inject) { + var nodes = metric.exportXMLDOM(inject); + nodes.forEach(function (elem) { + var name = elem.getAttribute("name"); + if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved") { + elem.setAttribute("interface-name", axisInterface.name); + } else { + inject.removeChild(elem); + } + }); + }; + this.hasMoved = function () { + return metric.wasMoved; + }; + Object.defineProperties(this, { + "DOM": { + "value": trackObj + }, + "value": { + "get": function () { + return value; + }, + "set": function (v) { + if (v >= 0 && v <= 1) { + value = v; + } + this.resize(); + return value; + } + }, + "label": { + "get": function () { + return label; + }, + "set": function () {} + }, + "metric": { + "value": metric + } + }); + } + + function drawTick(position) { + var context = tickCanvas.getContext("2d"), + w = tickCanvas.width, + h = tickCanvas.height; + context.beginPath(); + context.setLineDash([1, 2]); + context.moveTo(position * w, 0); + context.lineTo(position * w, h); + context.closePath(); + context.stroke(); + } + + function clearTicks() { + var c = tickCanvas.getContext("2d"), + w = tickCanvas.width, + h = tickCanvas.height; + c.clearRect(0, 0, w, h); + } + + function createScaleMarkers(interfaceObject, root, w) { + var ticks = interfaceObject.options.findIndex(function (a) { + return (a.type == "show" && a.name == "ticks"); + }); + ticks = (ticks >= 0); + clearTicks(); + interfaceObject.scales.forEach(function (scaleObj) { + var position = Number(scaleObj.position) * 0.01; + var pixelPosition = (position * w) + 50; + var scaleDOM = document.createElement('span'); + scaleDOM.className = "ape-marker-text"; + scaleDOM.textContent = scaleObj.text; + scaleDOM.setAttribute('value', position); + root.appendChild(scaleDOM); + scaleDOM.style.left = Math.floor((pixelPosition - ($(scaleDOM).width() / 2))) + 'px'; + if (ticks) { + drawTick(position); + } + }, this); + } + var sliders = []; + var UI = { + selected: undefined, + startTime: undefined + }; + this.name = interfaceObject.name; + var DOMRoot = document.createElement("div"); + parent.getDOMRoot().appendChild(DOMRoot); + DOMRoot.className = "sliderCanvasDiv"; + DOMRoot.id = "sliderCanvasHolder-" + this.name; + + var axisTitle = document.createElement("div"); + axisTitle.className = "pageTitle"; + axisTitle.align = "center"; + var titleSpan = document.createElement('span'); + titleSpan.id = "pageTitle-" + this.name; + if (interfaceObject.title !== undefined && typeof interfaceObject.title == "string") { + titleSpan.textContent = interfaceObject.title; + } else { + titleSpan.textContent = "Axis " + String(this.id + 1); + } + axisTitle.appendChild(titleSpan); + DOMRoot.appendChild(axisTitle); + + var imageHolder = (function () { + var imageController = {}; + imageController.root = document.createElement("div"); + imageController.root.className = "imageController"; + imageController.img = document.createElement("img"); + imageController.root.appendChild(imageController.img); + imageController.setImage = function (src) { + imageController.img.src = ""; + if (typeof src !== "string" || src.length === undefined) { + return; + } + imageController.img.src = src; + }; + return imageController; + })(); + if (interfaceObject.image !== undefined || page.audioElements.some(function (a) { + return a.image !== undefined; + })) { + DOMRoot.appendChild(imageHolder.root); + imageHolder.setImage(interfaceObject.image); + } + + // Now create the slider box to hold the fragment sliders + var sliderRail = document.createElement("div"); + sliderRail.id = "sliderrail-" + this.name; + sliderRail.className = "slider"; + sliderRail.align = "left"; + DOMRoot.appendChild(sliderRail); + + // Canvas for the markers + var tickCanvas = document.createElement("canvas"); + tickCanvas.id = "ticks-" + this.name; + tickCanvas.className = "tick-canvas"; + tickCanvas.height = 150; + tickCanvas.width = $(sliderRail).width() - 100; + tickCanvas.style.width = ($(sliderRail).width() - 100) + "px"; + sliderRail.appendChild(tickCanvas); + + // Create the div to hold any scale objects + var scale = document.createElement("div"); + scale.className = "sliderScale"; + scale.id = "slider-scale-holder-" + this.name; + scale.slign = "left"; + DOMRoot.appendChild(scale); + createScaleMarkers(interfaceObject, scale, $(sliderRail).width()); + + this.resize = function (event) { + var w = $(sliderRail).width(); + var marginsize = 50; + sliders.forEach(function (s) { + s.resize(); + }); + scale.innerHTML = ""; + tickCanvas.width = $(sliderRail).width(); + tickCanvas.style.width = tickCanvas.width + "px"; + createScaleMarkers(interfaceObject, scale, $(sliderRail).width()); + }; + this.playing = function (id) { + var node = audioEngineContext.audioObjects.find(function (a) { + return a.id == id; + }); + if (node === undefined) { + this.imageHolder.setImage(interfaceObject.image || ""); return; } - imageController.img.src = src; + var imgurl = node.specification.image || interfaceObject.image || ""; + this.imageHolder.setImage(imgurl); }; - return imageController; - })(); + this.stopped = function () { + var imgurl = interfaceObject.image || ""; + this.imageHolder.setImage(imgurl); + }; + this.addSlider = function (aoi) { + var node = new sliderInterface(aoi, this); + sliders.push(node); + return node; + }; + this.mousedown = function (sliderUI) { + UI.selected = sliderUI; + UI.startTime = new Date(); + }; + this.mouseup = function (event) { + var delta = new Date() - UI.startTime; + if (delta < 200) { + UI.selected.clicked(); + } else if (event.type == "touchend" || event.type == "touchcancel") { + UI.selected.handleEvent(event); + } + UI.selected = undefined; + UI.startTime = undefined; + }; + this.handleEvent = function (event) { + // TODO: Functionalise and scope + function getTargetSlider(target) { + return sliders.find(function (a) { + return a.DOM == target; + }); + } + var time = audioEngineContext.timer.getTestTime(); + var move, w; + if (event.preventDefault) { + event.preventDefault(); + } + if (event.type == "touchstart") { + var selected = getTargetSlider(event.target); + if (typeof selected != "object") { + return; + } + UI.startTime = new Date(); + UI.selected = selected; + } + if (UI.selected === undefined) { + return; + } + if (event.type == "mousemove") { + move = event.clientX - 6; + w = $(sliderRail).width(); + move = Math.max(50, move); + move = Math.min(w, move); + UI.selected.value = (move / w); + } else if (event.type == "touchmove") { + if (UI.selected == getTargetSlider(event.target)) { + if (event.targetTouches) { + move = event.targetTouches[0].clientX - 6; + } else if (event.originalEvent.targetTouches) { + move = event.originalEvent.targetTouches[0].clientX - 6; + } else { + return; + } + w = $(event.currentTarget).width(); + move = Math.max(50, move); + move = Math.min(w, move); + UI.selected.value = (move / w); + } + } else if (event.type == "touchend" || event.type == "touchcancel") { + if (UI.selected == getTargetSlider(event.target)) { + this.mouseup(event); + } + } + }; + this.checkAllMoved = function () { + var notMoved = sliders.filter(function (s) { + return !s.hasMoved(); + }); + if (notMoved.length !== 0) { + var ls = []; + notMoved.forEach(function (s) { + ls.push(s.label); + }); + var str = "On axis \"" + interfaceObject.title + "\", "; + if (ls.length == 1) { + str += "slider " + ls[0]; + } else { + str += "sliders " + [ls.slice(0, ls.length - 1).join(", ")].concat(ls[ls.length - 1]).join(" and "); + } + str += "."; + return str; + } else { + return ""; + } + }; + this.checkScaleRange = function () { + var scaleRange = interfaceObject.options.find(function (a) { + return a.name == "scalerange"; + }); + if (scaleRange === undefined) { + return ""; + } + var scales = { + min: scaleRange.min, + max: scaleRange.max + }; + var maxSlider = sliders.reduce(function (a, b) { + return Math.max(a, b.value); + }, 0); + var minSlider = sliders.reduce(function (a, b) { + return Math.min(a, b.value); + }, 100); + if (minSlider >= scales.min || maxSlider <= scales.max) { + return "On axis \"" + interfaceObject.title + "\", you have not used the required width of the scales"; + } + return ""; + }; + sliderRail.addEventListener("mousemove", this); + sliderRail.addEventListener("touchstart", this); + sliderRail.addEventListener("touchmove", this); + sliderRail.addEventListener("touchend", this); + sliderRail.addEventListener("touchcancel", this); + Object.defineProperties(this, { + "sliderRail": { + "value": sliderRail + } + }); + } + this.getDOMRoot = function () { + return DOMRoot; + }; + this.getPage = function () { + return page; + }; + this.clear = function () { + page = undefined; + axis = []; + AOIs = []; + DOMRoot.innerHTML = ""; + }; + this.initialisePage = function (page_init) { + this.clear(); + page = page_init; + var randomiseAxisOrder; + if (page.randomiseAxisOrder !== undefined) { + randomiseAxisOrder = page.randomiseAxisOrder; + } else { + randomiseAxisOrder = page.parent.randomiseAxisOrder; + } + var commentBoxes = false; + // Create each of the interface axis + if (randomiseAxisOrder) { + page.interfaces = randomiseOrder(page.interfaces); + } + var interfaceObj = interfaceContext.getCombinedInterfaces(page); + interfaceObj.forEach(function (i) { + var node = new axisObject(i, this); + axis.push(node); + i.options.forEach(function (o) { + if (o.type == "show" && o.name == "comments") { + commentBoxes = true; + } + }); + }, this); - var pagetitle = document.createElement('div'); - pagetitle.className = "pageTitle"; - pagetitle.align = "center"; - var titleSpan = document.createElement('span'); - titleSpan.id = "pageTitle-" + this.id; - if (interfaceObject.title !== undefined && typeof interfaceObject.title == "string") { - titleSpan.textContent = interfaceObject.title; - } else { - titleSpan.textContent = "Axis " + String(this.id + 1); - } - pagetitle.appendChild(titleSpan); - this.sliderDOM.appendChild(pagetitle); - - if (interfaceObject.image !== undefined || page.audioElements.some(function (a) { - return a.image !== undefined; - })) { - this.sliderDOM.appendChild(this.imageHolder.root); - this.imageHolder.setImage(interfaceObject.image); - } - // Create the slider box to hold the slider elements - this.canvas = document.createElement('div'); - if (this.name !== undefined) - this.canvas.id = 'slider-' + this.name; - else - this.canvas.id = 'slider-' + this.id; - this.canvas.setAttribute("interfaceid", this.id); - this.canvas.className = 'slider'; - this.canvas.align = "left"; - this.canvas.addEventListener('dragover', function (event) { - event.preventDefault(); - event.dataTransfer.effectAllowed = 'none'; - event.dataTransfer.dropEffect = 'copy'; - return false; - }, false); - this.sliderDOM.appendChild(this.canvas); - - // Create the div to hold any scale objects - this.scale = document.createElement('div'); - this.scale.className = 'sliderScale'; - this.scale.id = 'sliderScaleHolder-' + this.id; - this.scale.align = 'left'; - this.sliderDOM.appendChild(this.scale); - var positionScale = this.canvas.style.width.substr(0, this.canvas.style.width.length - 2); - var offset = 50; - var dest = document.getElementById("slider-holder").appendChild(this.sliderDOM); - interfaceObject.scales.forEach(function (scaleObj) { - var position = Number(scaleObj.position) * 0.01; - var pixelPosition = (position * $(this.canvas).width()) + offset; - var scaleDOM = document.createElement('span'); - scaleDOM.className = "ape-marker-text"; - scaleDOM.textContent = scaleObj.text; - scaleDOM.setAttribute('value', position); - this.scale.appendChild(scaleDOM); - scaleDOM.style.left = Math.floor((pixelPosition - ($(scaleDOM).width() / 2))) + 'px'; - }, this); - - this.createSliderObject = function (audioObject, label) { - var trackObj = document.createElement('div'); - trackObj.align = "center"; - trackObj.className = 'track-slider track-slider-disabled track-slider-' + audioObject.id; - trackObj.id = 'track-slider-' + this.id + '-' + audioObject.id; - trackObj.setAttribute('trackIndex', audioObject.id); - if (this.name !== undefined) { - trackObj.setAttribute('interface-name', this.name); - } else { - trackObj.setAttribute('interface-name', this.id); + // Create the audioObject interface objects for each aO. + page.audioElements.forEach(function (element, index) { + var audioObject = audioEngineContext.newTrack(element); + if (element.type == 'outside-reference') { + // Construct outside reference; + var orNode = new outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder")); + audioObject.bindInterface(orNode); + } else { + var aoi = new audioObjectInterface(audioObject, this); + AOIs.push(aoi); + var label = interfaceContext.getLabel(page.label, index, page.labelStart); + axis.forEach(function (a) { + var node = a.addSlider(aoi); + node.setLabel(label); + aoi.addSlider(node); + }); + audioObject.bindInterface(aoi); + if (commentBoxes) { + interfaceContext.commentBoxes.createCommentBox(audioObject); + } + } + }); + }; + this.checkAllMoved = function () { + var str = "You have not moved the following sliders. "; + var cont = true; + axis.forEach(function (a) { + var msg = a.checkAllMoved(); + if (msg.length > 0) { + cont = false; + str += msg; + } + }); + if (!cont) { + interfaceContext.lightbox.post("Error", str); + interfaceContext.storeErrorNode(str); + console.log(str); } - var offset = 50; - // Distribute it randomnly - var w = window.innerWidth - (offset + 8) * 2; - w = Math.random() * w; - w = Math.floor(w + (offset + 8)); - trackObj.style.left = w + 'px'; - this.canvas.appendChild(trackObj); - this.sliders.push(trackObj); - this.metrics.push(new metricTracker(this)); - var labelHolder = document.createElement("span"); - labelHolder.textContent = label; - trackObj.appendChild(labelHolder); - var rate = convSliderPosToRate(trackObj); - this.metrics[this.metrics.length - 1].initialise(rate); - trackObj.setAttribute("slider-value", rate); - return trackObj; + return cont; }; - - this.resize = function (event) { - var sliderDiv = this.canvas; - var sliderScaleDiv = this.scale; - var width = $(sliderDiv).width(); - var marginsize = 50; - // Move sliders into new position - this.sliders.forEach(function (slider, index) { - var pix = Number(slider.getAttribute("slider-value")) * width; - slider.style.left = (pix + marginsize) + 'px'; + this.checkScaleRange = function () { + var str = ""; + var cont = true; + axis.forEach(function (a) { + var msg = a.checkScaleRange(); + if (msg.length > 0) { + cont = false; + str += msg; + } }); - - // Move scale labels - for (var index = 0; index < this.scale.children.length; index++) { - var scaleObj = this.scale.children[index]; - var position = Number(scaleObj.attributes.value.value); - var pixelPosition = (position * width) + marginsize; - scaleObj.style.left = Math.floor((pixelPosition - ($(scaleObj).width() / 2))) + 'px'; + if (!cont) { + interfaceContext.lightbox.post("Error", str); + interfaceContext.storeErrorNode(str); + console.log(str); } + return cont; }; - - this.playing = function (id) { - var node = audioEngineContext.audioObjects.find(function (a) { - return a.id == id; - }); - if (node === undefined) { - this.imageHolder.setImage(interfaceObject.image || ""); - return; - } - var imgurl = node.specification.image || interfaceObject.image || ""; - this.imageHolder.setImage(imgurl); - }; -} - -function sliderObject(audioObject, interfaceObjects, index) { - // Create a new slider object; - this.parent = audioObject; - this.trackSliderObjects = []; - this.label = interfaceContext.getLabel(audioObject.specification.parent.label, index, audioObject.specification.parent.labelStart); - this.playing = false; - for (var i = 0; i < interfaceContext.interfaceSliders.length; i++) { - var trackObj = interfaceContext.interfaceSliders[i].createSliderObject(audioObject, this.label); - this.trackSliderObjects.push(trackObj); - } - - // Onclick, switch playback to that track - - this.enable = function () { - if (this.parent.state == 1) { - $(this.trackSliderObjects).each(function (i, trackObj) { - $(trackObj).removeClass('track-slider-disabled'); + this.pageXMLSave = function (store, pageSpecification) { + if (axis.length > 1) { + AOIs.forEach(function (ao) { + ao.pageXMLSave(store); }); } }; - this.updateLoading = function (progress) { - if (progress != 100) { - progress = String(progress); - progress = progress.split('.')[0]; - this.trackSliderObjects[0].children[0].textContent = progress + '%'; - } else { - this.trackSliderObjects[0].children[0].textContent = this.label; - } - }; - this.startPlayback = function () { - $('.track-slider').removeClass('track-slider-playing'); - var name = ".track-slider-" + this.parent.id; - $(name).addClass('track-slider-playing'); - interfaceContext.commentBoxes.highlightById(audioObject.id); - $('.outside-reference').removeClass('track-slider-playing'); - this.playing = true; - - if (this.parent.specification.parent.playOne || specification.playOne) { - $('.track-slider').addClass('track-slider-disabled'); - $('.outside-reference').addClass('track-slider-disabled'); - } - interfaceContext.interfaceSliders.forEach(function (ts) { - ts.playing(this.parent.id); - }, this); - }; - this.stopPlayback = function () { - if (this.playing) { - this.playing = false; - var name = ".track-slider-" + this.parent.id; - $(name).removeClass('track-slider-playing'); - $('.track-slider').removeClass('track-slider-disabled'); - $('.outside-reference').removeClass('track-slider-disabled'); - var box = interfaceContext.commentBoxes.boxes.find(function (a) { - return a.id === audioObject.id; - }); - if (box) { - box.highlight(false); - } - } - }; - this.exportXMLDOM = function (audioObject) { - // Called by the audioObject holding this element. Must be present - var obj = []; - $(this.trackSliderObjects).each(function (i, trackObj) { - var node = storage.document.createElement('value'); - if (trackObj.getAttribute("interface-name") !== "null") { - node.setAttribute("interface-name", trackObj.getAttribute("interface-name")); - } - node.textContent = convSliderPosToRate(trackObj); - obj.push(node); + this.resize = function (event) { + axis.forEach(function (a) { + a.resize(event); }); - - return obj; - }; - this.getValue = function () { - return convSliderPosToRate(this.trackSliderObjects[0]); - }; - this.getPresentedId = function () { - return this.label; - }; - this.canMove = function () { - return true; - }; - this.error = function () { - // audioObject has an error!! - this.playback.textContent = "Error"; - $(this.playback).addClass("error-colour"); }; } @@ -753,6 +845,9 @@ if (interfaceContext.checkFragmentMinPlays() === false) { return; } + if (interfaceContext.checkCommentQuestions() === false) { + return; + } for (var i = 0; i < checks.length; i++) { var checkState = true; @@ -820,9 +915,7 @@ // MANDATORY FUNCTION // Resize the slider objects - for (var i = 0; i < interfaceContext.interfaceSliders.length; i++) { - interfaceContext.interfaceSliders[i].resize(event); - } + window.module.resize(event); } function pageXMLSave(store, pageSpecification) { @@ -833,32 +926,5 @@ // pageSpecification is the current page node configuration // To create new XML nodes, use storage.document.createElement(); - if (interfaceContext.interfaceSliders.length == 1) { - // If there is only one axis, there only needs to be one metric return - return; - } - var audioelements = store.getElementsByTagName("audioelement"); - for (var i = 0; i < audioelements.length; i++) { - // Have to append the metric specific nodes - if (pageSpecification.outsideReference === undefined || pageSpecification.outsideReference.id != audioelements[i].id) { - var inject = audioelements[i].getElementsByTagName("metric"); - if (inject.length === 0) { - inject = storage.document.createElement("metric"); - } else { - inject = inject[0]; - } - for (var k = 0; k < interfaceContext.interfaceSliders.length; k++) { - var mrnodes = interfaceContext.interfaceSliders[k].metrics[i].exportXMLDOM(inject); - for (var j = 0; j < mrnodes.length; j++) { - var name = mrnodes[j].getAttribute("name"); - if (name == "elementTracker" || name == "elementTrackerFull" || name == "elementInitialPosition" || name == "elementFlagMoved") { - if (interfaceContext.interfaceSliders[k].name !== null) { - mrnodes[j].setAttribute("interface-name", interfaceContext.interfaceSliders[k].name); - } - mrnodes[j].setAttribute("interface-id", k); - } - } - } - } - } + module.pageXMLSave(store, pageSpecification); }
--- a/interfaces/discrete.css Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/discrete.css Tue Apr 10 10:22:34 2018 +0100 @@ -20,79 +20,47 @@ min-width: 20px; background-color: #ddd } -div#slider-holder { - height: inherit; - position: absolute; - left: 0px; - z-index: 3; - margin-top: 25px; +div#slider-box { + width: 75%; + height: auto; + margin: auto; + padding-bottom: 20px; } -div#scale-holder { - position: absolute; - left: 0px; - z-index: 2; +div#slider-grid { + display: grid; + grid-template-columns: 1fr; + grid-row-gap: 10px; } div#scale-text-holder { - position: relative; - float: left; + display: grid; + grid-template-rows: 1fr; + min-height: 25px; + text-align: center; +} +div.discrete-row { + display: grid; + grid-template-rows: 1fr; + padding: 10px; + border: 1px solid black; + height: 50px; + line-height: 50px; +} +button.discrete-button { + width: 100px; +} +div.discrete-label { + width: 100px; + text-align: center; } div.scale-text { - position: absolute; - font-size: 1.2em; -} -canvas#scale-canvas { - position: relative; - float: left; -} -div.track-slider { - float: left; - height: 30px; - border: solid; - border-width: 1px; - border-color: black; - padding: 2px; - margin-left: 94px; - margin-bottom: 30px; -} -div.track-slider-range { - float: left; - height: 100%; - margin: 0px 50px; position: relative; } -div.track-slider-title { - float: left; - padding-top: 5px; - width: 100px; +div.scale-text > span { + position: absolute; + bottom: 0; + width: 100%; + left: 0; } -button.track-slider-button { - float: left; - width: 100px; - height: 30px; +div.discrete-row-playing { + background-color: rgba(255, 201, 201, 0.5); } -input.track-radio { - position: absolute; - margin: 9px 0px; -} -div#outside-reference-holder { - display: flex; - align-content: center; - justify-content: center; - margin-bottom: 5px; -} -button.outside-reference { - position: inherit; - margin: 0px 5px; -} -div.track-slider-playing { - background-color: #FFDDDD; -} -div#page-count { - float: left; - margin: 0px 5px; -} -div#master-volume-holder { - position: absolute; - top: 10px; - left: 120px; -}
--- a/interfaces/discrete.js Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/discrete.js Tue Apr 10 10:22:34 2018 +0100 @@ -1,4 +1,8 @@ -/* globals interfaceContext, document, window, $, specification, audioEngineContext, console, window, testState, storage */ +/** + * WAET Blank Template + * Use this to start building your custom interface + */ +/*globals window, interfaceContext, testState, Interface, audioEngineContext, console, document, specification, $, storage*/ // Once this is loaded and parsed, begin execution loadInterface(); @@ -56,44 +60,41 @@ console.log('Stopped at ' + time); // DEBUG/SAFETY } }; - - // Create outside reference holder - var outsideRef = document.createElement("div"); - outsideRef.id = "outside-reference-holder"; - // Create Submit (save) button var submit = document.createElement("button"); submit.innerHTML = 'Next'; submit.onclick = buttonSubmitClick; submit.id = 'submit-button'; submit.style.float = 'left'; + + // Create the sort button + var sort = document.createElement("button"); + sort.id = "sort-fragments"; + sort.textContent = "Sort"; + sort.style.display = "inline-block"; + sort.style.visibility = "hidden"; + sort.onclick = buttonSortFragmentClick; + // Append the interface buttons into the interfaceButtons object. interfaceButtons.appendChild(playback); interfaceButtons.appendChild(submit); + interfaceButtons.appendChild(sort); - // Create a slider box - var sliderBox = document.createElement('div'); - sliderBox.style.width = "100%"; - sliderBox.style.height = window.innerHeight - 200 + 12 + 'px'; - sliderBox.style.marginBottom = '10px'; - sliderBox.id = 'slider'; - var scaleHolder = document.createElement('div'); - scaleHolder.id = "scale-holder"; - scaleHolder.style.marginLeft = "107px"; - sliderBox.appendChild(scaleHolder); + + // Create outside reference holder + var outsideRef = document.createElement("div"); + outsideRef.id = "outside-reference-holder"; + + // Create a holder for the slider rows + var sliderBox = document.createElement("div"); + sliderBox.id = 'slider-box'; + var sliderGrid = document.createElement("div"); + sliderGrid.id = "slider-grid"; + sliderBox.appendChild(sliderGrid); var scaleText = document.createElement('div'); scaleText.id = "scale-text-holder"; - scaleText.style.height = "25px"; - scaleText.style.width = "100%"; - scaleHolder.appendChild(scaleText); - var scaleCanvas = document.createElement('canvas'); - scaleCanvas.id = "scale-canvas"; - scaleCanvas.style.marginLeft = "150px"; - scaleHolder.appendChild(scaleCanvas); - var sliderObjectHolder = document.createElement('div'); - sliderObjectHolder.id = 'slider-holder'; - sliderObjectHolder.align = "center"; - sliderBox.appendChild(sliderObjectHolder); + sliderGrid.appendChild(scaleText); + // Global parent for the comment boxes on the page var feedbackHolder = document.createElement('div'); @@ -118,11 +119,16 @@ function loadTest(page) { // Called each time a new test page is to be build. The page specification node is the only item passed in - var id = page.id; var feedbackHolder = document.getElementById('feedbackHolder'); + var sliderBox = document.getElementById('slider-box'); + var sliderGrid = document.getElementById("slider-grid"); + var scaleTextHolder = document.getElementById("scale-text-holder"); + var interfaceObj = interfaceContext.getCombinedInterfaces(page); + var commentBoxPrefix = "Comment on track"; + var loopPlayback = page.loop; feedbackHolder.innerHTML = ""; - var interfaceObj = interfaceContext.getCombinedInterfaces(page); + if (interfaceObj.length > 1) { console.log("WARNING - This interface only supports one <interface> node per page. Using first interface node"); } @@ -132,7 +138,7 @@ if (typeof page.title == "string" && page.title.length > 0) { document.getElementById("test-title").textContent = page.title; } - + // Set the axis title if (interfaceObj.title !== null) { document.getElementById("pageTitle").textContent = interfaceObj.title; } @@ -147,15 +153,67 @@ // Delete outside reference document.getElementById("outside-reference-holder").innerHTML = ""; - var sliderBox = document.getElementById('slider-holder'); - sliderBox.innerHTML = ""; - - var commentBoxPrefix = "Comment on track"; + // Get the comment box prefix if (interfaceObj.commentBoxPrefix !== undefined) { commentBoxPrefix = interfaceObj.commentBoxPrefix; } - var loopPlayback = page.loop; + // Populate the comment questions + $(page.commentQuestions).each(function (index, element) { + var node = interfaceContext.createCommentQuestion(element); + feedbackHolder.appendChild(node.holder); + }); + + // Configure the grid + var numRows = page.audioElements.filter(function (a) { + return (a.type !== "outside-reference"); + }).length; + var numColumns = page.interfaces[0].scales.length; + sliderGrid.style.gridTemplateRows = "50px repeat(" + numRows + ", 72px)"; + scaleTextHolder.style.gridTemplateColumns = "100px repeat(" + numColumns + ", 1fr) 100px"; + page.interfaces[0].scales.sort(function (a, b) { + if (a.position > b.position) { + return 1; + } else if (a.position < b.position) { + return -1; + } + return 0; + }).forEach(function (a, i) { + var h = document.createElement("div"); + var text = document.createElement("span"); + h.className = "scale-text"; + h.style.gridColumn = String(i + 2) + "/" + String(i + 3); + text.textContent = a.text; + h.appendChild(text); + scaleTextHolder.appendChild(h); + }); + + // Find all the audioElements from the audioHolder + var index = 0; + var labelType = page.label; + if (labelType == "default") { + labelType = "number"; + } + $(page.audioElements).each(function (pageIndex, element) { + // Find URL of track + // In this jQuery loop, variable 'this' holds the current audioElement. + + var audioObject = audioEngineContext.newTrack(element); + if (element.type == 'outside-reference') { + // Construct outside reference; + var orNode = new interfaceContext.outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder")); + audioObject.bindInterface(orNode); + } else { + // Create a slider per track + var label = interfaceContext.getLabel(labelType, index, page.labelStart); + var sliderObj = new discreteObject(audioObject, label); + sliderGrid.appendChild(sliderObj.DOMRoot); + audioObject.bindInterface(sliderObj); + interfaceContext.commentBoxes.createCommentBox(audioObject); + index += 1; + } + + }); interfaceObj.options.forEach(function (option) { if (option.type == "show") { switch (option.name) { @@ -187,204 +245,109 @@ case "comments": interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; + case "fragmentSort": + var button = document.getElementById('sort-fragments'); + button.style.visibility = "visible"; + break; } } }); - - // Find all the audioElements from the audioHolder - var index = 0; - var interfaceScales = page.interfaces[0].scales; - var labelType = page.label; - if (labelType == "default") { - labelType = "number"; - } - $(page.audioElements).each(function (pageIndex, element) { - // Find URL of track - // In this jQuery loop, variable 'this' holds the current audioElement. - - var audioObject = audioEngineContext.newTrack(element); - if (element.type == 'outside-reference') { - // Construct outside reference; - var orNode = new interfaceContext.outsideReferenceDOM(audioObject, index, document.getElementById("outside-reference-holder")); - audioObject.bindInterface(orNode); - } else { - // Create a slider per track - var label = interfaceContext.getLabel(labelType, index, page.labelStart); - var sliderObj = new discreteObject(audioObject, label, interfaceScales); - sliderBox.appendChild(sliderObj.holder); - audioObject.bindInterface(sliderObj); - interfaceContext.commentBoxes.createCommentBox(audioObject); - index += 1; - } - - }); - - $(page.commentQuestions).each(function (index, element) { - var node = interfaceContext.createCommentQuestion(element); - feedbackHolder.appendChild(node.holder); - }); - // Auto-align resizeWindow(null); } -function discreteObject(audioObject, label, interfaceScales) { +function discreteObject(audioObject, label) { // An example node, you can make this however you want for each audioElement. // However, every audioObject (audioEngineContext.audioObject) MUST have an interface object with the following // You attach them by calling audioObject.bindInterface( ) - if (interfaceScales === null || interfaceScales.length === 0) { - console.log("WARNING: The discrete radio's are built depending on the number of scale points specified! Ensure you have some specified. Defaulting to 5 for now!"); - var numOptions = 5; - } - this.parent = audioObject; + var playing = false; - this.holder = document.createElement('div'); - this.title = document.createElement('div'); - this.discreteHolder = document.createElement('div'); - this.discretes = []; - this.play = document.createElement('button'); - - this.holder.className = 'track-slider'; - this.holder.style.width = window.innerWidth - 200 + 'px'; - this.holder.appendChild(this.title); - this.holder.appendChild(this.discreteHolder); - this.holder.appendChild(this.play); - this.holder.setAttribute('trackIndex', audioObject.id); - this.title.textContent = label; - this.title.className = 'track-slider-title'; - - this.discreteHolder.className = "track-slider-range"; - this.discreteHolder.style.width = window.innerWidth - 500 + 'px'; - this.radioClicked = function (event) { - var time = audioEngineContext.timer.getTestTime(); - if (audioEngineContext.status === 0) { - event.currentTarget.checked = false; - return; + function buttonClicked(event) { + if (!playing) { + audioEngineContext.play(audioObject.id); + } else { + audioEngineContext.stop(); } - var id = this.parent.id; - var position = this.getValue(); - this.parent.metric.moved(time, position); - console.log('slider ' + id + ' moved to ' + position + ' (' + time + ')'); - - }; - this.handleEvent = function (event) { - if (event.currentTarget.getAttribute("name") === this.parent.specification.id) { - this.radioClicked(event); - } - }; - for (var i = 0; i < interfaceScales.length; i++) { - var node = document.createElement('input'); - node.setAttribute('type', 'radio'); - node.className = 'track-radio'; - node.disabled = true; - node.setAttribute('position', interfaceScales[i].position); - node.setAttribute('name', audioObject.specification.id); - node.setAttribute('id', audioObject.specification.id + '-' + String(i)); - this.discretes.push(node); - this.discreteHolder.appendChild(node); - node.addEventListener("click", this); } - this.play.className = 'track-slider-button'; - this.play.textContent = "Loading..."; - this.play.value = audioObject.id; - this.play.disabled = true; - this.play.setAttribute("playstate", "ready"); - this.play.onclick = function (event) { - var id = Number(event.currentTarget.value); - //audioEngineContext.metric.sliderPlayed(id); - if (event.currentTarget.getAttribute("playstate") == "ready") - audioEngineContext.play(id); - else if (event.currentTarget.getAttribute("playstate") == "playing") - audioEngineContext.stop(); - }; - this.resize = function (event) { - this.holder.style.width = window.innerWidth - 200 + 'px'; - this.discreteHolder.style.width = window.innerWidth - 500 + 'px'; - //text.style.left = (posPix+150-($(text).width()/2)) +'px'; - for (var i = 0; i < this.discretes.length; i++) { - var width = $(this.discreteHolder).width() - 20; - var node = this.discretes[i]; - var nodeW = $(node).width(); - var position = node.getAttribute('position'); - var posPix = Math.round(width * (position / 100.0)); - node.style.left = (posPix + 10 - (nodeW / 2)) + 'px'; + function radioSelected(event) { + var time = audioEngineContext.timer.getTestTime(); + audioObject.metric.moved(time, event.currentTarget.value); + console.log("slider " + audioObject.id + " moved to " + event.currentTarget.value + "(" + time + ")"); + } + + var root = document.createElement("div"), + labelHolder = document.createElement("div"), + button = document.createElement("button"); + root.className = "discrete-row"; + labelHolder.className = "discrete-label"; + button.className = "discrete-button"; + root.appendChild(labelHolder); + + var labelSpan = document.createElement("span"); + labelHolder.appendChild(labelSpan); + labelSpan.textContent = label; + button.textContent = "Listen"; + button.disabled = "true"; + button.addEventListener("click", this); + + var numScales = audioObject.specification.parent.interfaces[0].scales.length; + root.style.gridTemplateColumns = "100px repeat(" + numScales + ", 1fr) 100px"; + for (var n = 0; n < numScales; n++) { + var input = document.createElement("input"); + input.type = "radio"; + input.disabled = "true"; + input.value = n / (numScales - 1); + input.addEventListener("click", this); + input.name = audioObject.specification.id; + root.appendChild(input); + } + root.appendChild(button); + this.handleEvent = function (event) { + if (event.currentTarget === button) { + buttonClicked(event); + } else if (event.currentTarget.type === "radio") { + radioSelected(event); } }; this.enable = function () { // This is used to tell the interface object that playback of this node is ready - this.play.disabled = false; - this.play.textContent = "Play"; - $(this.slider).removeClass('track-slider-disabled'); - this.discretes.forEach(function (elem) { - elem.disabled = false; - }); + button.disabled = ""; + var a = root.querySelectorAll("input[type=\"radio\"]"); + for (var n = 0; n < a.length; n++) { + a[n].disabled = false; + } + button.textContent = "Listen"; }; this.updateLoading = function (progress) { // progress is a value from 0 to 100 indicating the current download state of media files - if (progress != 100) { - progress = String(progress); - progress = progress.split('.')[0]; - this.play.textContent = progress + '%'; - } else { - this.play.textContent = "Play"; - } + button.textContent = progress + "%"; }; - this.startPlayback = function () { - // Called by audioObject when playback begins - this.play.setAttribute("playstate", "playing"); - $(".track-slider").removeClass('track-slider-playing'); - $(this.holder).addClass('track-slider-playing'); - var outsideReference = document.getElementById('outside-reference'); - this.play.textContent = "Listening"; - if (outsideReference !== null) { - $(outsideReference).removeClass('track-slider-playing'); - } - if (this.parent.specification.parent.playOne || specification.playOne) { - $('.track-slider-button').text = "Wait"; - $('.track-slider-button').attr("disabled", "true"); - } - interfaceContext.commentBoxes.highlightById(audioObject.id); - if (audioObject.specification.image !== undefined) { - interfaceContext.imageHolder.setImage(audioObject.specification.image); - } + // Called when playback has begun + playing = true; + $(root).addClass("discrete-row-playing"); + button.textContent = "Stop"; }; this.stopPlayback = function () { - // Called by audioObject when playback stops - if (this.play.getAttribute("playstate") == "playing") { - this.play.setAttribute("playstate", "ready"); - $(this.holder).removeClass('track-slider-playing'); - $('.track-slider-button').text = "Play"; - this.play.textContent = "Play"; - $('.track-slider-button').removeAttr("disabled"); - var box = interfaceContext.commentBoxes.boxes.find(function (a) { - return a.id === audioObject.id; - }); - if (box) { - box.highlight(false); - } - if (audioObject.specification.parent.interfaces[0].image !== undefined) { - interfaceContext.imageHolder.setImage(audioObject.specification.parent.interfaces[0].image); - } else { - interfaceContext.imageHolder.setImage(""); + // Called when playback has stopped. This gets called even if playback never started! + playing = false; + $(root).removeClass("discrete-row-playing"); + button.textContent = "Listen"; + }; + this.getValue = function () { + // Return the current value of the object. If there is no value, return 0 + var a = root.querySelectorAll("input[type=\"radio\"]"); + for (var n = 0; n < a.length; n++) { + if (a[n].checked) { + return Number(a[n].value); } } - }; - - this.getValue = function () { - // Return the current value of the object. If there is no value, return -1 - var checkedElement = this.discretes.find(function (elem) { - return elem.checked; - }); - if (checkedElement === undefined) { - return -1; - } - return checkedElement.getAttribute("position") / 100.0; + return -1; }; this.getPresentedId = function () { // Return the presented ID of the object. For instance, the APE has sliders starting from 0. Whilst AB has alphabetical scale - return this.title.textContent; + return label; }; this.canMove = function () { // Return either true or false if the interface object can be moved. AB / Reference cannot, whilst sliders can and therefore have a continuous scale. @@ -399,75 +362,36 @@ var node = storage.document.createElement('value'); node.textContent = this.getValue(); return node; + }; this.error = function () { - // audioObject has an error!! - this.playback.textContent = "Error"; - $(this.playback).addClass("error-colour"); + // If there is an error with the audioObject, this will be called to indicate a failure }; + Object.defineProperties(this, { + "DOMRoot": { + "value": root + } + }); } function resizeWindow(event) { // Called on every window resize event, use this to scale your page properly - var numObj = document.getElementsByClassName('track-slider').length; - var totalHeight = (numObj * 66) - 30; - document.getElementById('scale-holder').style.width = window.innerWidth - 220 + 'px'; - // Cheers edge for making me delete a canvas every resize. - var canvas = document.getElementById('scale-canvas'); - var new_canvas = document.createElement("canvas"); - new_canvas.id = 'scale-canvas'; - new_canvas.style.marginLeft = "150px"; - canvas.parentElement.appendChild(new_canvas); - canvas.parentElement.removeChild(canvas); - new_canvas.width = window.innerWidth - 520; - new_canvas.height = totalHeight; - for (var i in audioEngineContext.audioObjects) { - if (audioEngineContext.audioObjects[i].specification.type != 'outside-reference') { - audioEngineContext.audioObjects[i].interfaceDOM.resize(event); - } - } - document.getElementById('slider-holder').style.height = totalHeight + 'px'; - document.getElementById('slider').style.height = totalHeight + 70 + 'px'; - drawScale(); } -function drawScale() { - var interfaceObj = testState.currentStateMap.interfaces[0]; - var scales = testState.currentStateMap.interfaces[0].scales; - scales = scales.sort(function (a, b) { - return a.position - b.position; +function buttonSortFragmentClick() { + var sortIndex = interfaceContext.sortFragmentsByScore(); + var sliderBox = document.getElementById("slider-holder"); + var nodes = audioEngineContext.audioObjects.filter(function (ao) { + return ao.specification.type !== "outside-reference"; }); - var canvas = document.getElementById('scale-canvas'); - var ctx = canvas.getContext("2d"); - var height = canvas.height; - var width = canvas.width; - var textHolder = document.getElementById('scale-text-holder'); - textHolder.innerHTML = ""; - ctx.fillStyle = "#000000"; - ctx.setLineDash([1, 4]); - scales.forEach(function (scale) { - var posPercent = scale.position / 100.0; - var posPix = Math.round(width * posPercent); - if (posPix <= 0) { - posPix = 1; - } - if (posPix >= width) { - posPix = width - 1; - } - ctx.moveTo(posPix, 0); - ctx.lineTo(posPix, height); - ctx.stroke(); - - var text = document.createElement('div'); - text.align = "center"; - var textC = document.createElement('span'); - textC.textContent = scale.text; - text.appendChild(textC); - text.className = "scale-text"; - textHolder.appendChild(text); - text.style.width = $(text.children[0]).width() + 'px'; - text.style.left = (posPix + 150 - ($(text).width() / 2)) + 'px'; + var i; + nodes.forEach(function (ao) { + sliderBox.removeChild(ao.interfaceDOM.holder); }); + for (i = 0; i < nodes.length; i++) { + var j = sortIndex[i]; + sliderBox.appendChild(nodes[j].interfaceDOM.holder); + } } function buttonSubmitClick() // TODO: Only when all songs have been played! @@ -485,9 +409,12 @@ if (interfaceContext.checkFragmentMinPlays() === false) { return; } + if (interfaceContext.checkCommentQuestions() === false) { + return; + } for (var i = 0; i < checks.length; i++) { - var checkState; + var checkState = true; if (checks[i].type == 'check') { switch (checks[i].name) { case 'fragmentPlayed': @@ -510,16 +437,15 @@ case 'scalerange': // Check the scale has been used effectively checkState = interfaceContext.checkScaleRange(checks[i].errorMessage); + break; default: console.log("WARNING - Check option " + checks[i].check + " is not supported on this interface"); break; } - if (checkState === false) { - canContinue = false; - } } - if (!canContinue) { + if (checkState === false) { + canContinue = false; break; } }
--- a/interfaces/horizontal-sliders.js Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/horizontal-sliders.js Tue Apr 10 10:22:34 2018 +0100 @@ -62,9 +62,20 @@ submit.onclick = buttonSubmitClick; submit.id = 'submit-button'; submit.style.float = 'left'; + + // Create the sort button + var sort = document.createElement("button"); + sort.id = "sort-fragments"; + sort.textContent = "Sort"; + sort.style.display = "inline-block"; + sort.style.visibility = "hidden"; + sort.onclick = buttonSortFragmentClick; + // Append the interface buttons into the interfaceButtons object. interfaceButtons.appendChild(playback); interfaceButtons.appendChild(submit); + interfaceButtons.appendChild(sort); + // Create outside reference holder var outsideRef = document.createElement("div"); @@ -226,6 +237,10 @@ case "comments": interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; + case "fragmentSort": + var button = document.getElementById('sort-fragments'); + button.style.visibility = "visible"; + break; } } }); @@ -383,6 +398,14 @@ function drawScale() { var interfaceObj = testState.currentStateMap.interfaces[0]; var scales = testState.currentStateMap.interfaces[0].scales; + var ticks = specification.interfaces.options.concat(interfaceObj.options).find(function (a) { + return (a.type == "show" && a.name == "ticks"); + }); + if (ticks !== undefined) { + ticks = true; + } else { + ticks = false; + } scales = scales.sort(function (a, b) { return a.position - b.position; }); @@ -403,9 +426,11 @@ if (posPix >= width) { posPix = width - 1; } - ctx.moveTo(posPix, 0); - ctx.lineTo(posPix, height); - ctx.stroke(); + if (ticks) { + ctx.moveTo(posPix, 0); + ctx.lineTo(posPix, height); + ctx.stroke(); + } var text = document.createElement('div'); text.align = "center"; @@ -419,6 +444,22 @@ }); } +function buttonSortFragmentClick() { + var sortIndex = interfaceContext.sortFragmentsByScore(); + var sliderBox = document.getElementById("slider-holder"); + var nodes = audioEngineContext.audioObjects.filter(function (ao) { + return ao.specification.type !== "outside-reference"; + }); + var i; + nodes.forEach(function (ao) { + sliderBox.removeChild(ao.interfaceDOM.holder); + }); + for (i = 0; i < nodes.length; i++) { + var j = sortIndex[i]; + sliderBox.appendChild(nodes[j].interfaceDOM.holder); + } +} + function buttonSubmitClick() // TODO: Only when all songs have been played! { var checks = testState.currentStateMap.interfaces[0].options, @@ -434,6 +475,9 @@ if (interfaceContext.checkFragmentMinPlays() === false) { return; } + if (interfaceContext.checkCommentQuestions() === false) { + return; + } for (var i = 0; i < checks.length; i++) { var checkState = true;
--- a/interfaces/mushra.css Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/mushra.css Tue Apr 10 10:22:34 2018 +0100 @@ -39,6 +39,8 @@ } div.scale-text { position: absolute; + text-align: right; + min-width: 100px; } canvas#scale-canvas { position: relative;
--- a/interfaces/mushra.js Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/mushra.js Tue Apr 10 10:22:34 2018 +0100 @@ -67,9 +67,20 @@ submit.onclick = buttonSubmitClick; submit.id = 'submit-button'; submit.style.display = 'inline-block'; + + // Create the sort button + var sort = document.createElement("button"); + sort.id = "sort-fragments"; + sort.textContent = "Sort"; + sort.style.display = "inline-block"; + sort.style.visibility = "hidden"; + sort.onclick = buttonSortFragmentClick; + // Append the interface buttons into the interfaceButtons object. interfaceButtons.appendChild(playback); interfaceButtons.appendChild(submit); + interfaceButtons.appendChild(sort); + // Create outside reference holder var outsideRef = document.createElement("div"); @@ -206,6 +217,8 @@ var interfaceOptions = interfaceObj.options; + var sortButton = document.getElementById("sort-fragments"); + sortButton.style.visibility = "hidden"; interfaceOptions.forEach(function (option) { if (option.type == "show") { switch (option.name) { @@ -239,31 +252,8 @@ interfaceContext.commentBoxes.showCommentBoxes(feedbackHolder, true); break; case "fragmentSort": - var button = document.getElementById('sort'); - if (button === null) { - button = document.createElement("button"); - button.id = 'sort'; - button.textContent = "Sort"; - button.style.display = 'inline-block'; - var container = document.getElementById("interface-buttons"); - var neighbour = container.lastElementChild; - container.appendChild(button); - button.onclick = function () { - var sortIndex = interfaceContext.sortFragmentsByScore(); - var sliderBox = document.getElementById("slider-holder"); - var nodes = audioEngineContext.audioObjects.filter(function (ao) { - return ao.specification.type !== "outside-reference"; - }); - var i; - nodes.forEach(function (ao) { - sliderBox.removeChild(ao.interfaceDOM.holder); - }); - for (i = 0; i < nodes.length; i++) { - var j = sortIndex[i]; - sliderBox.appendChild(nodes[j].interfaceDOM.holder); - } - }; - } + var button = document.getElementById('sort-fragments'); + button.style.visibility = "visible"; break; } } @@ -480,6 +470,14 @@ function drawScale() { var interfaceObj = testState.currentStateMap.interfaces[0]; var scales = testState.currentStateMap.interfaces[0].scales; + var ticks = specification.interfaces.options.concat(interfaceObj.options).find(function (a) { + return (a.type == "show" && a.name == "ticks"); + }); + if (ticks !== undefined) { + ticks = true; + } else { + ticks = false; + } scales = scales.sort(function (a, b) { return a.position - b.position; }); @@ -495,11 +493,13 @@ scales.forEach(function (scale) { var posPercent = scale.position / 100.0; var posPix = (1 - posPercent) * (draw_heights[1] - draw_heights[0]) + draw_heights[0]; - ctx.fillStyle = "#000000"; - ctx.setLineDash([1, 2]); - ctx.moveTo(0, posPix); - ctx.lineTo(width, posPix); - ctx.stroke(); + if (ticks) { + ctx.fillStyle = "#000000"; + ctx.setLineDash([1, 2]); + ctx.moveTo(0, posPix); + ctx.lineTo(width, posPix); + ctx.stroke(); + } var text = document.createElement('div'); text.align = "right"; var textC = document.createElement('span'); @@ -508,11 +508,26 @@ text.className = "scale-text"; textHolder.appendChild(text); text.style.top = (posPix - 9) + 'px'; - text.style.left = 100 - ($(text).width() + 3) + 'px'; lastHeight = posPix; }); } +function buttonSortFragmentClick() { + var sortIndex = interfaceContext.sortFragmentsByScore(); + var sliderBox = document.getElementById("slider-holder"); + var nodes = audioEngineContext.audioObjects.filter(function (ao) { + return ao.specification.type !== "outside-reference"; + }); + var i; + nodes.forEach(function (ao) { + sliderBox.removeChild(ao.interfaceDOM.holder); + }); + for (i = 0; i < nodes.length; i++) { + var j = sortIndex[i]; + sliderBox.appendChild(nodes[j].interfaceDOM.holder); + } +} + function buttonSubmitClick() // TODO: Only when all songs have been played! { var checks = testState.currentStateMap.interfaces[0].options, @@ -528,6 +543,9 @@ if (interfaceContext.checkFragmentMinPlays() === false) { return; } + if (interfaceContext.checkCommentQuestions() === false) { + return; + } for (var i = 0; i < checks.length; i++) { var checkState = true;
--- a/interfaces/timeline.js Tue Apr 10 10:18:25 2018 +0100 +++ b/interfaces/timeline.js Tue Apr 10 10:22:34 2018 +0100 @@ -505,6 +505,9 @@ if (interfaceContext.checkFragmentMinPlays() === false) { return; } + if (interfaceContext.checkCommentQuestions() === false) { + return; + } for (var i = 0; i < checks.length; i++) { var checkState = true; if (checks[i].type == 'check') {
--- a/js/core.js Tue Apr 10 10:18:25 2018 +0100 +++ b/js/core.js Tue Apr 10 10:22:34 2018 +0100 @@ -146,11 +146,12 @@ // Create the specification object specification = new Specification(); + // Create the storage object + storage = new Storage(); + // Create the interface object interfaceContext = new Interface(specification); - // Create the storage object - storage = new Storage(); // Define window callbacks for interface window.onresize = function (event) { interfaceContext.resizeWindow(event); @@ -1145,8 +1146,7 @@ this.proceedClicked = function () { // Each time the popup button is clicked! - if (testState.stateIndex === 0 && specification.calibration) { - interfaceContext.calibrationModuleObject.collect(); + if (testState.stateIndex === -1 && specification.calibration) { advanceState(); return; } @@ -1362,14 +1362,18 @@ this.advanceState(); } } else if (this.stateIndex == -1) { - this.stateIndex++; - if (specification.calibration) { + if (interfaceContext.calibrationTests.checkFrequencies) { popup.showPopup(); - popup.popupTitle.textContent = "Calibration. Set the levels so all tones are of equal amplitude. Move your mouse over the sliders to hear the tones. The red slider is the reference tone"; - interfaceContext.calibrationModuleObject = new interfaceContext.calibrationModule(); - interfaceContext.calibrationModuleObject.build(popup.popupResponse); + popup.popupTitle.textContent = "Set the levels so all tones are of equal amplitude. Move your mouse over the sliders to hear the tones. The red slider is the reference tone"; + interfaceContext.calibrationTests.performFrequencyCheck(popup.popupResponse); + popup.hidePreviousButton(); + } else if (interfaceContext.calibrationTests.checkChannels) { + popup.showPopup(); + popup.popupTitle.textContent = "Click play to start the audio, the click the button corresponding to where the sound appears to be coming from."; + interfaceContext.calibrationTests.performChannelCheck(popup.popupResponse); popup.hidePreviousButton(); } else { + this.stateIndex++; this.advanceState(); } } else if (this.stateIndex == this.stateMap.length) { @@ -2221,10 +2225,19 @@ }; this.moved = function (time, position) { + var last; if (time > 0) { this.wasMoved = true; } - this.movementTracker[this.movementTracker.length] = [time, position]; + // Get the last entry + if (this.movementTracker.length > 0) { + last = this.movementTracker[this.movementTracker.length - 1]; + } else { + last = -1; + } + if (position != last[1]) { + this.movementTracker[this.movementTracker.length] = [time, position]; + } }; this.startListening = function (time) { @@ -2721,6 +2734,12 @@ this.textArea.style.width = boxwidth - 6 + "px"; }; this.resize(); + this.check = function () { + if (this.specification.mandatory && this.textArea.value.length === 0) { + return false; + } + return true; + }; }; this.radioBox = function (commentQuestion) { @@ -2795,6 +2814,15 @@ } this.holder.style.width = boxwidth + "px"; }; + this.check = function () { + var anyChecked = this.options.some(function (a) { + return a.checked; + }); + if (this.specification.mandatory && anyChecked === false) { + return false; + } + return true; + }; this.resize(); }; @@ -2861,6 +2889,15 @@ } this.holder.style.width = boxwidth + "px"; }; + this.check = function () { + var anyChecked = this.options.some(function (a) { + return a.checked; + }); + if (this.specification.mandatory && anyChecked === false) { + return false; + } + return true; + }; this.resize(); }; @@ -2918,6 +2955,9 @@ this.holder.style.width = boxwidth + "px"; this.slider.style.width = boxwidth - 24 + "px"; }; + this.check = function () { + return true; + }; this.resize(); }; @@ -2940,6 +2980,19 @@ this.commentQuestions = []; }; + this.checkCommentQuestions = function () { + var errored = this.commentQuestions.reduce(function (a, cq) { + if (cq.check() === false) { + a.push(cq); + } + return a; + }, []); + if (errored.length === 0) { + return true; + } + interfaceContext.lightbox.post("Message", "Not all the mandatory comment boxes below have been filled."); + }; + this.outsideReferenceDOM = function (audioObject, index, inject) { this.parent = audioObject; this.outsideReferenceHolder = document.createElement('button'); @@ -3171,93 +3224,200 @@ return imageController; })(); - this.calibrationModuleObject = null; - this.calibrationModule = function () { - // This creates an on-page calibration module - this.storeDOM = storage.document.createElement("calibration"); - storage.root.appendChild(this.storeDOM); - // The calibration is a fixed state module - this.calibrationNodes = []; - this.holder = null; - this.build = function (inject) { - var f0 = 62.5; - this.holder = document.createElement("div"); - this.holder.className = "calibration-holder"; - this.calibrationNodes = []; - while (f0 < 20000) { - /* jshint loopfunc: true */ - var obj = { - root: document.createElement("div"), - input: document.createElement("input"), - oscillator: audioContext.createOscillator(), - gain: audioContext.createGain(), - f: f0, - parent: this, - handleEvent: function (event) { - switch (event.type) { - case "mouseenter": - this.oscillator.start(0); - break; - case "mouseleave": - this.oscillator.stop(0); - this.oscillator = audioContext.createOscillator(); - this.oscillator.connect(this.gain); - this.oscillator.frequency.value = this.f; - break; - case "mousemove": - var value = Math.pow(10, this.input.value / 20); - if (this.f == 1000) { - audioEngineContext.outputGain.gain.value = value; - interfaceContext.volume.slider.value = this.input.value; - } else { - this.gain.gain.value = value; + this.calibrationTests = (function () { + function readonly(t) { + throw ("Cannot set read-only variable"); + } + + function getStorageRoot() { + var storageRoot = storage.root.querySelector("calibration"); + if (storageRoot === undefined) { + storageRoot = storage.document.createElement("calibration"); + storage.root.appendChild(storageRoot); + } + return storageRoot; + } + var calibrationObject, + _checkedFrequency = false, + _checkedChannels = false; + + // Define the checkFrequencies test! + var checkFrequencyUnit = function (htmlRoot, storageRoot) { + + function createFrequencyElement(frequency) { + return (function (frequency) { + var hold = document.createElement("div"); + hold.className = "calibration-slider"; + var range = document.createElement("input"); + range.type = "range"; + range.min = "-24"; + range.max = "24"; + range.step = "0.5"; + range.setAttribute("orient", "vertical"); + range.value = (Math.random() - 0.5) * 24; + range.setAttribute("frequency", frequency); + hold.appendChild(range); + htmlRoot.appendChild(hold); + + var gain = audioContext.createGain(); + gain.connect(outputGain); + gain.gain.value = Math.pow(10, Number(range.value) / 20.0); + var osc; + + var store = storage.document.createElement("response"); + store.setAttribute("frequency", frequency); + storageHook.appendChild(store); + var interface = {}; + Object.defineProperties(interface, { + "handleEvent": { + "value": function (e) { + if (e.type == "mouseenter") { + osc = audioContext.createOscillator(); + osc.frequency.value = frequency; + osc.connect(gain); + osc.start(); + console.log("start " + frequency); + } else if (e.type == "mouseleave") { + console.log("stop " + frequency); + osc.stop(); + osc = undefined; } - break; + store.textContent = e.currentTarget.value; + gain.gain.value = Math.pow(10, Number(e.currentTarget.value) / 20.0); + } } - }, - disconnect: function () { - this.gain.disconnect(); + }); + range.addEventListener("mousemove", interface); + range.addEventListener("mouseenter", interface); + range.addEventListener("mouseleave", interface); + return interface; + })(frequency); + } + var htmlHook = document.createElement("div"); + htmlRoot.appendChild(htmlHook); + var storageHook = storage.document.createElement("frequency"); + storageRoot.appendChild(storageHook); + var frequencies = [100, 200, 400, 800, 1200, 1600, 2000, 4000, 8000, 12000]; + var outputGain = audioContext.createGain(); + outputGain.gain.value = 0.25; + outputGain.connect(audioContext.destination); + this.sliders = frequencies.map(createFrequencyElement); + }; + + var checkChannelsUnit = function (htmlRoot, storageRoot) { + + function onclick(ev) { + var storageHook = storage.document.querySelector("calibration").querySelector("channels"); + storageHook.setAttribute("selected", ev.currentTarget.value); + storageHook.setAttribute("selectedText", ev.currentTarget.textContent); + osc.stop(); + gainL = undefined; + gainR = undefined; + cmerge = undefined; + popup.proceedClicked(); + } + var osc = audioContext.createOscillator(); + var gainL = audioContext.createGain(); + var gainR = audioContext.createGain(); + gainL.channelCount = 1; + gainR.channelCount = 1; + var cmerge = audioContext.createChannelMerger(2); + osc.connect(gainL, 0, 0); + osc.connect(gainR, 0, 0); + gainL.connect(cmerge, 0, 0); + gainR.connect(cmerge, 0, 1); + cmerge.connect(audioContext.destination); + var play = document.createElement("button"); + play.textContent = "Play Audio"; + play.onclick = function () { + osc.start(); + play.disabled = true; + }; + play.className = "calibration-button"; + htmlRoot.appendChild(play); + var choiceHolder = document.createElement("div"); + var leftButton = document.createElement("button"); + leftButton.textContent = "Left"; + leftButton.value = "-1"; + leftButton.className = "calibration-button"; + var centerButton = document.createElement("button"); + centerButton.textContent = "Middle"; + centerButton.value = "0"; + centerButton.className = "calibration-button"; + var rightButton = document.createElement("button"); + rightButton.textContent = "Right"; + rightButton.value = "1"; + rightButton.className = "calibration-button"; + choiceHolder.appendChild(leftButton); + choiceHolder.appendChild(centerButton); + choiceHolder.appendChild(rightButton); + htmlRoot.appendChild(choiceHolder); + leftButton.addEventListener("click", onclick); + centerButton.addEventListener("click", onclick); + rightButton.addEventListener("click", onclick); + + var storageHook = storage.document.createElement("channels"); + storageRoot.appendChild(storageHook); + + var pan; + if (Math.random() > 0.5) { + pan = 1; + gainL.gain.value = 0.0; + gainR.gain.value = 0.25; + storageHook.setAttribute("presented", pan); + storageHook.setAttribute("presentedText", "Right"); + } else { + pan = -1; + gainL.gain.value = 0.25; + gainR.gain.value = 0.0; + storageHook.setAttribute("presented", pan); + storageHook.setAttribute("presentedText", "Left"); + } + }; + + var interface = {}; + Object.defineProperties(interface, { + "calibrationObject": { + "get": function () { + return calibrationObject; + }, + "set": readonly + }, + "checkFrequencies": { + "get": function () { + if (specification.calibration.checkFrequencies && _checkedFrequency === false) { + return true; } - }; - obj.root.className = "calibration-slider"; - obj.root.appendChild(obj.input); - obj.oscillator.connect(obj.gain); - obj.gain.connect(audioEngineContext.outputGain); - obj.gain.gain.value = Math.random() * 2; - obj.input.value = obj.gain.gain.value; - obj.input.setAttribute('orient', 'vertical'); - obj.input.type = "range"; - obj.input.min = -12; - obj.input.max = 0; - obj.input.step = 0.25; - if (f0 != 1000) { - obj.input.value = (Math.random() * 12) - 6; - } else { - obj.input.value = 0; - obj.root.style.backgroundColor = "rgb(255,125,125)"; + return false; + }, + "set": readonly + }, + "checkChannels": { + "get": function () { + if (specification.calibration.checkChannels && _checkedChannels === false) { + return true; + } + return false; + }, + "set": readonly + }, + "performFrequencyCheck": { + "value": function (htmlRoot) { + htmlRoot.innerHTML = ""; + calibrationObject = new checkFrequencyUnit(htmlRoot, getStorageRoot()); + _checkedFrequency = true; } - obj.input.addEventListener("mousemove", obj); - obj.input.addEventListener("mouseenter", obj); - obj.input.addEventListener("mouseleave", obj); - obj.gain.gain.value = Math.pow(10, obj.input.value / 20); - obj.oscillator.frequency.value = f0; - this.calibrationNodes.push(obj); - this.holder.appendChild(obj.root); - f0 *= 2; + }, + "performChannelCheck": { + "value": function (htmlRoot) { + htmlRoot.innerHTML = ""; + calibrationObject = new checkChannelsUnit(htmlRoot, getStorageRoot()); + _checkedChannels = true; + } } - inject.appendChild(this.holder); - }; - this.collect = function () { - this.calibrationNodes.forEach(function (obj) { - var node = storage.document.createElement("calibrationresult"); - node.setAttribute("frequency", obj.f); - node.setAttribute("range-min", obj.input.min); - node.setAttribute("range-max", obj.input.max); - node.setAttribute("gain-lin", obj.gain.gain.value); - this.storeDOM.appendChild(node); - }, this); - }; - }; + }); + return interface; + })(); // Global Checkers @@ -3779,8 +3939,8 @@ }, "update": { "value": function () { - if (this.key === null || requestChains === undefined) { - throw ("Cannot save as key == null"); + if (requestChains === undefined) { + throw ("Initiate key exchange first"); } this.parent.root.setAttribute("state", "update"); requestChains = requestChains.then(postUpdate);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/min/core.min.js Tue Apr 10 10:22:34 2018 +0100 @@ -0,0 +1,1 @@ +function escapeHTML(e){return e.split("&").join("&").split("<").join("<").split('"').join(""")}function qualifyURL(e){var t=document.createElement("div");return t.innerHTML='<a href="'+escapeHTML(e)+'">x</a>',t.firstChild.href}function loadProjectSpec(e){var t=new XMLHttpRequest;t.open("GET","xml/test-schema.xsd",!0),t.onload=function(){specification.processSchema(t.response);var i=new XMLHttpRequest;i.open("GET",e,!0),i.onload=function(){loadProjectSpecCallback(i.response)},i.onerror=function(){document.getElementsByTagName("body")[0].innerHTML=null;var e=document.createElement("h3");e.textContent="FATAL ERROR";var t=document.createElement("p");t.textContent="There was an error when loading your XML file. Please check your path in the URL. After the path to this page, there should be '?url=path/to/your/file.xml'. Check the spelling of your filename as well. If you are still having issues, check the log of the python server or your webserver distribution for 404 codes for your file.",document.getElementsByTagName("body")[0].appendChild(e),document.getElementsByTagName("body")[0].appendChild(t)},i.send()},t.send()}function loadProjectSpecCallback(e){var t,i,n=(new DOMParser).parseFromString(e,"text/xml"),o=n.getElementsByTagName("parsererror");if(o.length>=1)return t=document.createElement("h3"),t.textContent="FATAL ERROR",i=document.createElement("span"),i.textContent="The XML parser returned the following errors when decoding your XML file",document.getElementsByTagName("body")[0].innerHTML=null,document.getElementsByTagName("body")[0].appendChild(t),document.getElementsByTagName("body")[0].appendChild(i),void document.getElementsByTagName("body")[0].appendChild(o[0]);if(void 0===n||void 0===n.firstChild)return t=document.createElement("h3"),t.textContent="FATAL ERROR",i=document.createElement("span"),i.textContent="The project XML was not decoded properly, try refreshing your browser and clearing caches. If the problem persists, contact the test creator.",document.getElementsByTagName("body")[0].innerHTML=null,document.getElementsByTagName("body")[0].appendChild(t),void document.getElementsByTagName("body")[0].appendChild(i);if("waet"==n.firstChild.nodeName){var s={xml:e,schema:specification.getSchemaString(),arguments:["--noout","--schema","test-schema.xsd","document.xml"]};projectXML=n;var r=validateXML(s);if(console.log(r),"document.xml validates\n"!=r){document.getElementsByTagName("body")[0].innerHTML=null,(t=document.createElement("h3")).textContent="FATAL ERROR",(i=document.createElement("h4")).textContent="The XML validator returned the following errors when decoding your XML file",document.getElementsByTagName("body")[0].appendChild(t),document.getElementsByTagName("body")[0].appendChild(i),r=r.split("\n");for(var a in r)document.getElementsByTagName("body")[0].appendChild(document.createElement("br")),(i=document.createElement("span")).textContent=r[a],document.getElementsByTagName("body")[0].appendChild(i);return}specification.decode(projectXML),storage.initialise()}else if("waetresult"==n.firstChild.nodeName){(projectXML=document.implementation.createDocument(null,"waet")).firstChild.appendChild(n.getElementsByTagName("waet")[0].getElementsByTagName("setup")[0].cloneNode(!0));for(var c,l=n.firstChild.firstChild;null!==l;){if("survey"==l.nodeName)if("complete"==l.getAttribute("state"))for(var u=l.getAttribute("location"),h=projectXML.getElementsByTagName("setup")[0].getElementsByTagName("survey")[0];null!==h;){if("pre"==u||"before"==u){if("pre"==h.getAttribute("location")||"before"==h.getAttribute("location")){projectXML.getElementsByTagName("setup")[0].removeChild(h);break}}else if("post"==h.getAttribute("location")||"after"==h.getAttribute("location")){projectXML.getElementsByTagName("setup")[0].removeChild(h);break}h=h.nextElementSibling}else c=l,l=l.previousElementSibling,n.firstChild.removeChild(c);else"page"==l.nodeName&&"empty"==l.getAttribute("state")&&(projectXML.firstChild.appendChild(n.getElementById(l.getAttribute("ref")).cloneNode(!0)),c=l,l=l.previousElementSibling,n.firstChild.removeChild(c));l=l.nextElementSibling}specification.decode(projectXML),storage.initialise(n)}if(isFinite(specification.sampleRate)&&Number(specification.sampleRate)!=audioContext.sampleRate){var p="Sample rates do not match! Requested "+Number(specification.sampleRate)+", got "+audioContext.sampleRate+". Please set the sample rate to match before completing this test.";interfaceContext.lightbox.post("Error",p)}else{var d=new XMLHttpRequest;d.open("GET","interfaces/interfaces.json"),d.onerror=function(e){throw e},d.onload=function(){if(200!==d.status)throw new Error(d.status);var e=specification.interface,t=document.getElementsByTagName("head")[0],i=JSON.parse(d.responseText).interfaces.find(function(t){return t.name==e});if(!i)throw"Cannot load desired interface";i.scripts.forEach(function(e){var i=document.createElement("script");i.setAttribute("type","text/javascript"),i.setAttribute("src",e),t.appendChild(i)}),i.css.forEach(function(e){var i=document.createElement("link");i.setAttribute("rel","stylesheet"),i.setAttribute("type","text/css"),i.setAttribute("href",e),t.appendChild(i)})},d.send(),void 0!==gReturnURL&&(console.log("returnURL Overide from "+specification.returnURL+" to "+gReturnURL),specification.returnURL=gReturnURL),void 0!==gSaveFilenamePrefix&&(specification.saveFilenamePrefix=gSaveFilenamePrefix),audioEngineContext=new AudioEngine(specification)}}function createProjectSave(e){window.onbeforeunload=null;var t=storage.finish(),i=document.createElement("div");i.appendChild(t);var n=[i.innerHTML];if("local"==e){var o=new Blob(n,{type:"application/xml"}),s=window.URL.createObjectURL(o),r=document.createElement("a");r.hidden="",r.href=s,r.download="save.xml",r.textContent="Save File",popup.showPopup(),popup.popupContent.innerHTML="<span>Please save the file below to give to your test supervisor</span><br>",popup.popupContent.appendChild(r)}else{"string"==typeof specification.projectReturn&&"http"==specification.projectReturn.substr(0,4)&&specification.projectReturn,storage.SessionKey.finish().then(function(e){"string"==typeof specification.returnURL&&specification.returnURL.length>0?window.location=specification.returnURL:popup.popupContent.textContent=specification.exitText},function(e){console.log("Save: Error! "+e.textContent),createProjectSave("local")}),popup.showPopup(),popup.popupContent.innerHTML=null,popup.popupContent.textContent="Submitting. Please Wait","function"==typeof popup.hideNextButton&&popup.hideNextButton(),"function"==typeof popup.hidePreviousButton&&popup.hidePreviousButton()}}function errorSessionDump(e){popup.showPopup(),popup.popupContent.innerHTML=null;var t=document.createElement("error"),i=document.createElement("div");"object"==typeof e?(t.appendChild(e),popup.popupContent.appendChild(e)):(t.textContent=e,popup.popupContent.innerHTML="ERROR : "+e);var n=interfaceXMLSave();n.appendChild(t),i.appendChild(n);var o=[i.innerHTML],s=new Blob(o,{type:"application/xml"}),r=window.URL.createObjectURL(s),a=document.createElement("a");a.hidden="",a.href=r,a.download="save.xml",a.textContent="Save File",popup.popupContent.appendChild(a)}function interfaceXMLSave(){return storage.finish()}function linearToDecibel(e){return 20*Math.log10(e)}function decibelToLinear(e){return Math.pow(10,e/20)}function secondsToSamples(e,t){return Math.round(e*t)}function samplesToSeconds(e,t){return e/t}function randomString(e){for(var t="",i=0;i<e;i+=2){t+=Math.floor(1295*Math.random()).toString(36)}return t}function randomiseOrder(e){for(var t=e.length,i=[],n=0;n<t;++n)i.push(n);for(var o=i.slice(0),s=[],r=[],a=0;a<t;a++){var c=Math.random();c=Math.floor(c*e.length),s.push(e.splice(c,1)[0]),r.push(i.splice(c,1)[0])}return console.log(o.toString()),console.log(r.toString()),s}function randomSubArray(e,t){t>e.length&&(t=e.length);for(var i=[];t>0;){var n=Math.floor(Math.random()*e.length);i.push(e.splice(n,1)[0]),t--}return i}function interfacePopup(){function e(e,r){function a(e){var t=this.popupOptions.findIndex(function(t,i,n){return t.specification.id==e},this);this.currentIndex=t-1}var c;if("question"===e.specification.type)c=t;else if("checkbox"===e.specification.type)c=i;else if("radio"===e.specification.type)c=n;else if("number"===e.specification.type)c=o;else{if("slider"!==e.specification.type)return;c=s}for(var l=0;l<e.specification.conditions.length;l++){var u,h=e.specification.conditions[l];if(null!==(u=c(h,r)?h.jumpToOnPass:h.jumpToOnFail)){a.call(this,u);break}}}function t(e,t){switch(e.check){case"equals":if(t==e.value)return!0;break;case"greaterThan":case"lessThan":console.log("Survey Element of type 'question' cannot interpret greaterThan/lessThan conditions. IGNORING");break;case"contains":if(t.includes(e.value))return!0}return!1}function i(e,t){switch(e.check){case"contains":for(var i=0;i<t.length;i++){var n=t[i];if(n.name===e.value&&n.checked)return!0}break;case"equals":case"greaterThan":case"lessThan":console.log("Survey Element of type 'checkbox' cannot interpret equals/greaterThan/lessThan conditions. IGNORING");break;default:console.log("Unknown condition. IGNORING")}return!1}function n(e,t){switch(e.check){case"equals":if(t===e.value)return!0;break;case"contains":case"greaterThan":case"lessThan":console.log("Survey Element of type 'radio' cannot interpret contains/greaterThan/lessThan conditions. IGNORING");break;default:console.log("Unknown condition. IGNORING")}return!1}function o(e,t){var i=i;switch(i.check){case"greaterThan":if(t>Number(i.value))return!0;break;case"lessThan":if(t<Number(i.value))return!0;break;case"equals":if(t==i.value)return!0;break;case"contains":console.log("Survey Element of type 'number' cannot interpret \"contains\" conditions. IGNORING");break;default:console.log("Unknown condition. IGNORING")}return!1}function s(e,t){switch(e.check){case"contains":console.log("Survey Element of type 'number' cannot interpret contains conditions. IGNORING");break;case"greaterThan":if(t>Number(e.value))return!0;break;case"lessThan":if(t<Number(e.value))return!0;break;case"equals":if(t==e.value)return!0;break;default:console.log("Unknown condition. IGNORING")}return!1}this.popup=null,this.popupContent=null,this.popupTitle=null,this.popupResponse=null,this.buttonProceed=null,this.buttonPrevious=null,this.popupOptions=null,this.currentIndex=null,this.node=null,this.store=null;var r;$(window).keypress(function(e){13==e.keyCode&&"visible"==popup.popup.style.visibility&&!1===interfaceContext.lightbox.isVisible()&&(console.log(e),popup.buttonProceed.onclick(),e.preventDefault())}),this.createPopup=function(){document.getElementById("topLevelBody");this.popup=document.getElementById("popupHolder"),this.popup.style.left=window.innerWidth/2-250+"px",this.popup.style.top=window.innerHeight/2-125+"px",this.popupContent=document.getElementById("popupContent"),this.popupTitle=document.getElementById("popupTitleHolder"),this.popupResponse=document.getElementById("popupResponse"),this.buttonProceed=document.getElementById("popup-proceed"),this.buttonProceed.onclick=function(){popup.proceedClicked()},this.buttonPrevious=document.getElementById("popup-previous"),this.buttonPrevious.onclick=function(){popup.previousClick()},this.hidePopup(),this.popup.style.visibility="hidden"},this.showPopup=function(){null===this.popup&&this.createPopup(),this.popup.style.visibility="visible";document.getElementsByClassName("testHalt")[0].style.visibility="visible",this.popupResponse.style.left="0%"},this.hidePopup=function(){if(this.popup){this.popup.style.visibility="hidden";document.getElementsByClassName("testHalt")[0].style.visibility="hidden",this.buttonPrevious.style.visibility="inherit"}},this.postNode=function(){var e=this.popupOptions[this.currentIndex],t=new showdown.Converter,i=new DOMParser;r=new Date,this.popupResponse.innerHTML="",this.popupTitle.innerHTML="";var n=e.specification.statement.split("\n");n.forEach(function(e,t,i){i[t]=e.trim()}),e.specification.statement=n.join("\n");for(var o=i.parseFromString(t.makeHtml(e.specification.statement),"text/html").querySelector("body").children;o.length>0;)this.popupTitle.appendChild(o[0]);"question"==e.specification.type?function(e){var t=document.createElement("textarea");switch(e.specification.boxsize){case"small":t.cols="20",t.rows="1";break;case"normal":t.cols="30",t.rows="2";break;case"large":t.cols="40",t.rows="5";break;case"huge":t.cols="50",t.rows="10"}void 0===e.response?e.response="":t.value=e.response,this.popupResponse.appendChild(t),t.focus(),this.popupResponse.style.textAlign="center",this.popupResponse.style.left="0%"}.call(this,e):"checkbox"==e.specification.type?function(e){null===e.response&&(e.response=[]);var t=document.createElement("table");t.className="popup-option-list",t.border="0";var i=[];e.specification.options.forEach(function(t,n){var o=document.createElement("tr");i.push(o);var s=document.createElement("td");o.appendChild(s);var r=document.createElement("input");r.id=t.name,r.type="checkbox",s.appendChild(r),s=document.createElement("td"),o.appendChild(s);var a=document.createElement("span");a.textContent=t.text,s.appendChild(a),(o=document.createElement("div")).setAttribute("name","option"),o.className="popup-option-checbox";var c;e.response.length>0&&(c=e.response.find(function(e){return e.name==t.name})),void 0!==c?!0===c.checked&&(r.checked="true"):e.response.push({name:t.name,text:t.text,checked:!1})}),e.specification.randomise&&(i=randomiseOrder(i)),i.forEach(function(e){t.appendChild(e)}),this.popupResponse.appendChild(t)}.call(this,e):"radio"==e.specification.type?function(e){null===e.response&&(e.response={name:"",text:""});var t=document.createElement("table");t.className="popup-option-list",t.border="0";var i=[];e.specification.options.forEach(function(t,n){var o=document.createElement("tr");i.push(o);var s=document.createElement("td");o.appendChild(s);var r=document.createElement("input");r.id=t.name,r.type="radio",r.name=e.specification.id,s.appendChild(r),s=document.createElement("td"),o.appendChild(s);var a=document.createElement("span");a.textContent=t.text,s.appendChild(a),(o=document.createElement("div")).setAttribute("name","option"),o.className="popup-option-checkbox",e.response.name===t.name&&(r.checked=!0)}),e.specification.randomise&&(i=randomiseOrder(i)),i.forEach(function(e){t.appendChild(e)}),this.popupResponse.appendChild(t)}.call(this,e):"number"==e.specification.type?function(e){var t=document.createElement("input");t.type="textarea",null!==e.specification.min&&(t.min=e.specification.min),null!==e.specification.max&&(t.max=e.specification.max),null!==e.specification.step&&(t.step=e.specification.step),void 0!==e.response&&(t.value=e.response),this.popupResponse.appendChild(t),this.popupResponse.style.textAlign="center",this.popupResponse.style.left="0%"}.call(this,e):"video"==e.specification.type?function(e){var t=document.createElement("video");t.src=e.specification.url,this.popupResponse.appendChild(t)}.call(this,e):"youtube"==e.specification.type?function(e){var t=document.createElement("iframe");t.className="youtube",t.src=e.specification.url,this.popupResponse.appendChild(t)}.call(this,e):"slider"==e.specification.type&&function(e){var t=document.createElement("div"),i=document.createElement("input");i.type="range",i.style.width="90%",null!==e.specification.min&&(i.min=e.specification.min),null!==e.specification.max&&(i.max=e.specification.max),void 0!==e.response&&(i.value=e.response),t.className="survey-slider-text-holder";var n=document.createElement("span"),o=document.createElement("span");n.textContent=e.specification.leftText,o.textContent=e.specification.rightText,t.appendChild(n),t.appendChild(o),this.popupResponse.appendChild(i),this.popupResponse.appendChild(t),this.popupResponse.style.textAlign="center"}.call(this,e),this.currentIndex+1==this.popupOptions.length?"pre"==this.node.location?this.buttonProceed.textContent="Start":this.buttonProceed.textContent="Submit":this.buttonProceed.textContent="Next",this.currentIndex>0?this.buttonPrevious.style.visibility="visible":this.buttonPrevious.style.visibility="hidden"},this.initState=function(e,t){e.options.length>0?(this.popupOptions=[],this.node=e,this.store=t,e.options.forEach(function(e){this.popupOptions.push({specification:e,response:null})},this),this.currentIndex=0,this.showPopup(),this.postNode()):advanceState()},this.proceedClicked=function(){if(0===testState.stateIndex&&specification.calibration)return interfaceContext.calibrationModuleObject.collect(),void advanceState();var t=this.popupOptions[this.currentIndex],i=!0,n=(new Date-r)/1e3;n<t.specification.minWait?interfaceContext.lightbox.post("Error","Not enough time has elapsed, please wait "+(t.specification.minWait-n).toFixed(0)+" seconds"):(t.elapsedTime=n,"question"==t.specification.type?i=function(t){var i=this.popupResponse.getElementsByTagName("textarea")[0];return!0===t.specification.mandatory&&0===i.value.length?(interfaceContext.lightbox.post("Error","This question is mandatory"),!1):(console.log("Question: "+t.specification.statement),console.log("Question Response: "+i.value),t.response=i.value,e.call(this,t,i.value),!0)}.call(this,t):"checkbox"==t.specification.type?i=function(t){console.log("Checkbox: "+t.specification.statement);var i,n=this.popupResponse.getElementsByTagName("input"),o=0;for(i=0;i<t.specification.options.length;i++)n[i].checked&&o++;if(void 0!==t.specification.min)if(void 0===t.specification.max){if(o<t.specification.min){var s="You must select at least "+t.specification.min+" option";return t.specification.min>1&&(s+="s"),void interfaceContext.lightbox.post("Error",s)}}else if(o<t.specification.min||o>t.specification.max)return t.specification.min==t.specification.max?interfaceContext.lightbox.post("Error","You must only select "+t.specification.min):interfaceContext.lightbox.post("Error","You must select between "+t.specification.min+" and "+t.specification.max),!1;for(i=0;i<t.specification.options.length;i++)t.response.forEach(function(e){var t=this.popupResponse.querySelector("#"+e.name);e.checked=t.checked}),console.log(t.specification.options[i].name+": "+n[i].checked);return e.call(this,t,t.response),!0}.call(this,t):"radio"==t.specification.type?i=function(t){var i=this.popupResponse;console.log("Radio: "+t.specification.statement),t.response=null;for(var n,o=0,s=i.getElementsByTagName("input");void 0===n;){if(o==s.length){if(!0===t.specification.mandatory)return interfaceContext.lightbox.post("Error","Please select one option"),!1;break}!0===s[o].checked&&(n=s[o]),o++}var r=t.specification.options.find(function(e){return n.id==e.name});if(void 0===r)throw interfaceContext.lightbox.post("Error","A configuration error has occured, the test cannot be continued"),"ERROR - Cannot find option";return t.response=r,e.call(this,t,t.response.name),!0}.call(this,t):"number"==t.specification.type?i=function(t){var i=this.popupContent.getElementsByTagName("input")[0];if(!0===t.specification.mandatory&&0===i.value.length)return interfaceContext.lightbox.post("Error","This question is mandatory. Please enter a number"),!1;var n=Number(i.value);return isNaN(n)?(interfaceContext.lightbox.post("Error","Please enter a valid number"),!1):n<t.specification.min&&null!==t.specification.min?(interfaceContext.lightbox.post("Error","Number is below the minimum value of "+t.specification.min),!1):n>t.specification.max&&null!==t.specification.max?(interfaceContext.lightbox.post("Error","Number is above the maximum value of "+t.specification.max),!1):(t.response=i.value,e.call(this,t,t.response),!0)}.call(this,t):"slider"==t.specification.type&&(i=function(t){var i=this.popupContent.getElementsByTagName("input")[0];return t.response=i.value,e.call(this,t,t.response),!0}.call(this,t)),!1!==i&&(this.currentIndex++,this.currentIndex<this.popupOptions.length?this.postNode():(this.popupTitle.innerHTML="",this.popupResponse.innerHTML="",this.hidePopup(),this.popupOptions.forEach(function(e){this.store.postResult(e)},this),this.store.complete(),advanceState())))},this.previousClick=function(){this.currentIndex>0&&(this.currentIndex--,this.postNode())},this.resize=function(e){if(null!==this.popup){this.popup.style.left=window.innerWidth/2-250+"px",this.popup.style.top=window.innerHeight/2-125+"px";var t=document.getElementsByClassName("testHalt")[0];t.style.width=window.innerWidth,t.style.height=window.innerHeight}},this.hideNextButton=function(){this.buttonProceed.style.visibility="hidden"},this.hidePreviousButton=function(){this.buttonPrevious.style.visibility="hidden"},this.showNextButton=function(){this.buttonProceed.style.visibility="visible"},this.showPreviousButton=function(){this.buttonPrevious.style.visibility="visible"}}function advanceState(){testState.advanceState()}function stateMachine(){function e(e,t){var i=[];return e.forEach(function(t,n){t.alwaysInclude&&i.push(e.splice(n,1)[0])}),i.concat(randomSubArray(e,t-i.length))}this.stateMap=[],this.preTestSurvey=null,this.postTestSurvey=null,this.stateIndex=null,this.currentStateMap=null,this.currentStatePosition=null,this.currentStore=null,this.initialise=function(){var t=[];specification.pages.forEach(function(e){(null!==e.position||e.alwaysInclude)&&(e.alwaysInclude=!0),t.push(e)}),specification.numPages>0&&(specification.randomiseOrder=!0,t=e(t,specification.numPages));var i=[];t.forEach(function(e){if(void 0!==e.position){i.push(e);var n=t.indexOf(e);t.splice(n,1)}}),specification.randomiseOrder&&(t=randomiseOrder(t)),i.forEach(function(e){t.splice(e.position,0,e)}),t.forEach(function(t,i){t.presentedId=i,this.stateMap.push(t);t.audioElements;!function(t){var i=[],n=[],o=[];t.audioElements.forEach(function(e){e.label.length>0||void 0!==e.postion?i.push(e):"outside-reference"===e.type?n.push(e):o.push(e)}),(t.poolSize>0||t.randomiseOrder)&&(t.randomiseOrder=!0,0===t.poolSize&&(t.poolSize=t.audioElements.length),t.poolSize-=i.length,o=e(o,t.poolSize)),t.randomiseOrder&&(o=randomiseOrder(o)),i=i.concat(o),t.audioElements=i.concat(n),t.audioElements.forEach(function(e,t){e.position=t})}(t),storage.createTestPageStore(t),audioEngineContext.loadPageData(t)},this),null!==specification.preTest&&(this.preTestSurvey=specification.preTest),null!==specification.postTest&&(this.postTestSurvey=specification.postTest),this.stateMap.length>0?(null!==this.stateIndex&&console.log("NOTE - State already initialise"),this.stateIndex=-2,console.log("Starting test...")):console.log("FATAL - StateMap not correctly constructed. EMPTY_STATE_MAP")},this.advanceState=function(){if(null===this.stateIndex&&this.initialise(),this.stateIndex>-2&&storage.update(),-2==this.stateIndex)this.stateIndex++,void 0!==this.preTestSurvey?popup.initState(this.preTestSurvey,storage.globalPreTest):this.advanceState();else if(-1==this.stateIndex)this.stateIndex++,specification.calibration?(popup.showPopup(),popup.popupTitle.textContent="Calibration. Set the levels so all tones are of equal amplitude. Move your mouse over the sliders to hear the tones. The red slider is the reference tone",interfaceContext.calibrationModuleObject=new interfaceContext.calibrationModule,interfaceContext.calibrationModuleObject.build(popup.popupResponse),popup.hidePreviousButton()):this.advanceState();else if(this.stateIndex==this.stateMap.length)console.log("Ending test ..."),this.stateIndex++,void 0===this.postTestSurvey?this.advanceState():popup.initState(this.postTestSurvey,storage.globalPostTest);else if(this.stateIndex>this.stateMap.length)createProjectSave(specification.projectReturn);else{if(popup.hidePopup(),null===this.currentStateMap)return this.currentStateMap=this.stateMap[this.stateIndex],this.currentStore=storage.testPages[this.stateIndex],void 0!==this.currentStateMap.preTest?(this.currentStatePosition="pre",popup.initState(this.currentStateMap.preTest,storage.testPages[this.stateIndex].preTest)):this.currentStatePosition="test",void interfaceContext.newPage(this.currentStateMap,storage.testPages[this.stateIndex]);switch(this.currentStatePosition){case"pre":this.currentStatePosition="test";break;case"test":if(this.currentStatePosition="post",this.testPageCompleted(),void 0===this.currentStateMap.postTest)return void this.advanceState();popup.initState(this.currentStateMap.postTest,storage.testPages[this.stateIndex].postTest);break;case"post":this.stateIndex++,this.currentStateMap=null,this.advanceState()}}},this.testPageCompleted=function(){var e=storage.testPages[this.stateIndex],t=e.XMLDOM.getElementsByTagName("metric")[0];if(audioEngineContext.metric.enableTestTimer){var i=e.parent.document.createElement("metricresult");i.id="testTime",i.textContent=audioEngineContext.timer.testDuration,t.appendChild(i)}audioEngineContext.audioObjects;audioEngineContext.audioObjects.forEach(function(e){e.exportXMLDOM()}),interfaceContext.commentQuestions.forEach(function(t){t.exportXMLDOM(e)}),pageXMLSave(e.XMLDOM,this.currentStateMap),e.complete()},this.getCurrentTestPage=function(){return this.stateIndex>=0&&this.stateIndex<this.stateMap.length?this.currentStateMap:null},this.getCurrentTestPageStore=function(){return this.stateIndex>=0&&this.stateIndex<this.stateMap.length?this.currentStore:null}}function AudioEngine(e){this.outputGain=audioContext.createGain(),this.fooGain=audioContext.createGain(),this.fooGain.gain.value=0,this.status=0,this.outputGain.connect(audioContext.destination),this.fooGain.connect(audioContext.destination),this.timer=new timer,this.metric=new sessionMetrics(this,e),this.loopPlayback=!1,this.synchPlayback=!1,this.pageSpecification=null,this.pageStore=null;var t=audioContext.createBuffer(1,audioContext.sampleRate,audioContext.sampleRate);this.nullBufferSource=audioContext.createBufferSource(),this.nullBufferSource.buffer=t,this.nullBufferSource.loop=!0,this.nullBufferSource.start(0),this.audioObjects=[],this.buffers=[],this.bufferObj=function(){var e=[];this.buffer=null,this.users=[],this.progress=0,this.status=0,this.ready=function(){this.status>=2&&(this.status=3);for(var e=0;e<this.users.length;e++)this.users[e].state=1,null!==this.users[e].interfaceDOM&&this.users[e].bufferLoaded(this)},this.setUrls=function(t){var i,n=audioContext.sampleRate,o=[];for(i=0;i<t.length;i++)t[i].sampleRate==n&&o.push(t.splice(i,1)[0]);o=o.concat(t),e=o},this.hasUrl=function(t){var i,n=e.length;for(i=0;i<n;i++)if(e[i].url==t)return!0;return!1},this.getMedia=function(){function t(e){return new Promise(function(t,i){var n=new XMLHttpRequest;n.open("GET",e,!0),n.responseType="arraybuffer",n.onload=function(){200==n.status&&t(n.response)},n.onerror=function(){i(new Error(n.statusText))},n.addEventListener("progress",function(e){if(e.lengthComputable){this.progress=e.loaded/e.total;for(var t=0;t<this.users.length;t++)null!==this.users[t].interfaceDOM&&"function"==typeof this.users[t].interfaceDOM.updateLoading&&this.users[t].interfaceDOM.updateLoading(100*this.progress)}}.bind(o)),n.send()})}function i(){if(!(++s>=e.length))return t(e[s].url).then(n.bind(this)).catch(i.bind(this));!function(){this.status=-1;for(var t=0;t<this.users.length;t++)this.users[t].state=-1,null!==this.users[t].interfaceDOM&&this.users[t].bufferLoaded(this);interfaceContext.lightbox.post("Error","Could not load resource "+e[s].url)}()}function n(e){var t=this;return audioContext.decodeAudioData(e,function(e){return t.buffer=e,t.status=2,calculateLoudness(t,"I"),!0},function(i){var n=new WAVE;if(0===n.open(e)){t.buffer=audioContext.createBuffer(n.num_channels,n.num_samples,n.sample_rate);for(var o=0;o<n.num_channels;o++)for(var s=t.buffer.getChannelData(o),r=0;r<n.num_samples;r++)s[r]=n.decoded_data[o][r]}return void 0!==t.buffer?(t.status=2,calculateLoudness(t,"I"),!0):(n=void 0,!1)})}var o=this,s=0;this.progress=0,this.status=1,s=0,t(e[0].url).then(n.bind(o)).catch(i.bind(o))},this.registerAudioObject=function(e){this.users.forEach(function(t){if(e.id==t.id)return 0}),this.users.push(e),3!=this.status&&-1!=this.status||e.bufferLoaded(this)},this.copyBuffer=function(e,t){void 0===e&&(e=0),void 0===t&&(t=0);var i,n=secondsToSamples(e,this.buffer.sampleRate),o=secondsToSamples(t,this.buffer.sampleRate),s=this.buffer.length+n+o,r=audioContext.createBuffer(this.buffer.numberOfChannels,s,this.buffer.sampleRate);if(0===n&&"function"==typeof r.copyToChannel)for(i=0;i<this.buffer.numberOfChannels;i++)r.copyToChannel(this.buffer.getChannelData(i),i);else for(i=0;i<this.buffer.numberOfChannels;i++)for(var a=this.buffer.getChannelData(i),c=r.getChannelData(i),l=0;l<a.length;l++)c[l+n]=a[l];return r.lufs=this.buffer.lufs,r.playbackGain=this.buffer.playbackGain,r},this.cropBuffer=function(e,t){for(var i=Math.floor(e*this.buffer.sampleRate),n=Math.floor(t*this.buffer.sampleRate),o=n-i,s=audioContext.createBuffer(this.buffer.numberOfChannels,o,this.buffer.sampleRate),r=0;r<this.buffer.numberOfChannels;r++){var a=this.buffer.getChannelData(r),c=a.subarray(i,n);if("function"==typeof s.copyToChannel)s.copyToChannel(c,r);else for(var l=s.getChannelData(r),u=0;u<o;u++)l[u]=a[u+i]}return s}},this.loadPageData=function(e){e.audioElements.forEach(function(t){var i=e.hostURL+t.url,n=this.buffers.find(function(e){return e.hasUrl(i)});if(void 0===n){n=new this.bufferObj;var o=[{url:i,sampleRate:t.sampleRate}];t.alternatives.forEach(function(e){o.push({url:e.url,sampleRate:e.sampleRate})}),n.setUrls(o),n.getMedia(),this.buffers.push(n)}},this)},this.play=function(t){if("number"!=typeof t||t<0||t>this.audioObjects.length)throw"FATAL - Passed id was undefined - AudioEngineContext.play(id)";var i=this.audioObjects[t].specification.maxNumberPlays||this.audioObjects[t].specification.parent.maxNumberPlays||e.maxNumberPlays;if(void 0!==i&&this.audioObjects[t].numberOfPlays>=i)interfaceContext.lightbox.post("Error","Cannot play this fragment more than "+i+" times");else if(1===this.status){if(this.timer.startTest(),interfaceContext.playhead.setTimePerPixel(this.audioObjects[t]),this.synchPlayback)(function(t){var i=audioContext.currentTime+.1;e.crossFade,this.audioObjects.forEach(function(e){e.setupPlayback(),e.bufferStart(i),e.id===t?e.listenStart(i):e.listenStop(i)})}).call(this,t);else{if(!1===this.bufferReady(t))return void console.log("Cannot play. Buffer not ready");(function(t){var i=audioContext.currentTime+.1,n=i+e.crossFade;this.audioObjects.forEach(function(e){e.id===t?(e.setupPlayback(),e.bufferStart(i),e.listenStart(i)):(e.listenStop(i),e.bufferStop(n))})}).call(this,t)}interfaceContext.playhead.start()}},this.stop=function(){if(1==this.status){var e=audioContext.currentTime+.1;this.audioObjects.forEach(function(t){t.listenStop(e),t.bufferStop(e)}),interfaceContext.playhead.stop()}},this.newTrack=function(e){var t=this.audioObjects.length;this.audioObjects[t]=new audioObject(t);var i=testState.currentStateMap.hostURL+e.url,n=this.buffers.find(function(e){return e.hasUrl(i)});void 0===n&&(console.log("[WARN]: Buffer was not loaded in pre-test! "+i),n=new this.bufferObj,this.buffers.push(n),n.getMedia(i)),this.audioObjects[t].specification=e,this.audioObjects[t].url=i;for(var o=this.pageStore.XMLDOM.getElementsByTagName("audioelement"),s=0;s<o.length;s++)if(o[s].getAttribute("ref")==e.id){this.audioObjects[t].storeDOM=o[s];break}return n.registerAudioObject(this.audioObjects[t]),this.audioObjects[t]},this.newTestPage=function(e,t){this.pageStore=t,this.pageSpecification=e,this.status=0,this.audioObjectsReady=!1,this.metric.reset(),this.buffers.forEach(function(e){e.users=[]}),this.audioObjects=[],this.timer=new timer,this.loopPlayback=e.loop,this.synchPlayback=e.synchronous,interfaceContext.keyboardInterface.resetKeyBindings()},this.checkAllPlayed=function(){for(var e=[],t=0;t<this.audioObjects.length;t++)!1===this.audioObjects[t].metric.wasListenedTo&&e.push(this.audioObjects[t].id);return e},this.checkAllReady=function(){for(var e=!0,t=0;t<this.audioObjects.length;t++)0===this.audioObjects[t].state&&(console.log("WAIT -- audioObject "+t+" not ready yet!"),e=!1);return e},this.setSynchronousLoop=function(){for(var e=0,t=0;t<this.audioObjects.length;t++)e<this.audioObjects[t].buffer.buffer.duration&&(e=this.audioObjects[t].buffer.buffer.duration,t);this.audioObjects.forEach(function(t){t.buffer.buffer.duration!==e&&(t.buffer.buffer=t.buffer.copyBuffer(0,e-t.buffer.buffer.duration))})},this.bufferReady=function(e){return!!this.checkAllReady()&&(this.synchPlayback&&this.setSynchronousLoop(),this.status=1,!0)}}function audioObject(e){var t=0;this.specification=void 0,this.id=e,this.state=0,this.url=null,this.metric=new metricTracker(this),this.storeDOM=null,this.playing=!1,this.interfaceDOM=null,this.commentDOM=null,this.bufferNode=void 0,this.outputGain=audioContext.createGain(),this.outputGain.gain.value=0,this.onplayGain=1,this.outputGain.connect(audioEngineContext.outputGain),audioEngineContext.nullBufferSource.connect(this.outputGain),this.buffer=void 0,this.bufferLoaded=function(t){if(-1==t.status)return this.state=-1,null!==this.interfaceDOM&&this.interfaceDOM.error(),void(this.buffer=t);this.buffer=t;var i=this.specification.preSilence||this.specification.parent.preSilence||specification.preSilence||0,n=this.specification.postSilence||this.specification.parent.postSilence||specification.postSilence||0,o=this.specification.startTime,s=this.specification.stopTime,r=new t.constructor;r.buffer=t.cropBuffer(o||0,s||t.buffer.duration),0===i&&0===n||(r.buffer=r.copyBuffer(i,n)),r.buffer.lufs=t.buffer.lufs,this.buffer=r;var a=this.specification.loudness||this.specification.parent.loudness||specification.loudness;"number"==typeof a&&isFinite(a)?this.buffer.buffer.playbackGain=decibelToLinear(a-this.buffer.buffer.lufs):this.buffer.buffer.playbackGain=1,null!==this.interfaceDOM&&this.interfaceDOM.enable(),this.onplayGain=decibelToLinear(this.specification.gain)*(this.buffer.buffer.playbackGain||1),this.storeDOM.setAttribute("playGain",linearToDecibel(this.onplayGain)),this.state=1,audioEngineContext.bufferReady(e)},this.bindInterface=function(e){if(this.interfaceDOM=e,this.metric.initialise(e.getValue()),1==this.state)this.interfaceDOM.enable();else if(-1==this.state)return void this.interfaceDOM.error();var t=e.getPresentedId();this.storeDOM.setAttribute("presentedId",t),1==t.length&&interfaceContext.keyboardInterface.registerKeyBinding(t,this)},this.listenStart=function(e){!1===this.playing&&(t++,this.outputGain.gain.linearRampToValueAtTime(this.onplayGain,e),this.metric.startListening(audioEngineContext.timer.getTestTime()),this.bufferNode.playbackStartTime=audioEngineContext.timer.getTestTime(),this.interfaceDOM.startPlayback(),this.playing=!0)},this.listenStop=function(e){!0===this.playing&&(this.outputGain.gain.linearRampToValueAtTime(0,e),this.metric.stopListening(audioEngineContext.timer.getTestTime(),this.getCurrentPosition())),this.interfaceDOM.stopPlayback(),this.playing=!1},this.setupPlayback=function(){void 0===this.bufferNode&&void 0!==this.buffer.buffer&&(this.bufferNode=audioContext.createBufferSource(),this.bufferNode.owner=this,this.bufferNode.connect(this.outputGain),this.bufferNode.buffer=this.buffer.buffer,audioEngineContext.loopPlayback&&(this.bufferNode.loopStart=this.specification.startTime||0,this.bufferNode.loopEnd=this.specification.stopTime-this.specification.startTime||this.buffer.buffer.duration,this.bufferNode.loop=!0),this.bufferNode.onended=function(e){null!==e.currentTarget&&(e.currentTarget.owner.bufferStop(audioContext.currentTime+.1),e.currentTarget.owner.listenStop(audioContext.currentTime+.1))},this.bufferNode.state=0)},this.bufferStart=function(e){this.outputGain.gain.cancelScheduledValues(audioContext.currentTime),this.bufferNode&&0===this.bufferNode.state&&(this.bufferNode.state=1,!0===this.bufferNode.loop?this.bufferNode.start(e):this.bufferNode.start(e,this.specification.startTime||0,this.specification.stopTime-this.specification.startTime||this.buffer.buffer.duration))},this.bufferStop=function(e){this.outputGain.gain.cancelScheduledValues(audioContext.currentTime),void 0!==this.bufferNode&&this.bufferNode.state>0&&(this.bufferNode.stop(e),this.bufferNode=void 0),this.outputGain.gain.linearRampToValueAtTime(0,e),this.interfaceDOM.stopPlayback()},this.getCurrentPosition=function(){var e=audioEngineContext.timer.getTestTime();if(void 0!==this.bufferNode){var t=(e-this.bufferNode.playbackStartTime)%this.buffer.buffer.duration;return isNaN(t)?0:t}return 0},this.exportXMLDOM=function(){var e=storage.document.createElement("file");if(e.setAttribute("sampleRate",this.buffer.buffer.sampleRate),e.setAttribute("channels",this.buffer.buffer.numberOfChannels),e.setAttribute("sampleCount",this.buffer.buffer.length),e.setAttribute("duration",this.buffer.buffer.duration),this.storeDOM.appendChild(e),"outside-reference"!=this.specification.type){var t=this.interfaceDOM.exportXMLDOM(this);if(null!==t)if(void 0===t.length)this.storeDOM.appendChild(t);else for(var i=0;i<t.length;i++)this.storeDOM.appendChild(t[i]);null!==this.commentDOM&&this.storeDOM.appendChild(this.commentDOM.exportXMLDOM(this))}this.metric.exportXMLDOM(this.storeDOM.getElementsByTagName("metric")[0])},Object.defineProperties(this,{numberOfPlays:{get:function(){return t},set:function(){return t}}})}function timer(){this.testStarted=!1,this.testStartTime=0,this.testDuration=0,this.minimumTestTime=0,this.startTest=function(){!1===this.testStarted&&(this.testStartTime=audioContext.currentTime,this.testStarted=!0,this.updateTestTime(),audioEngineContext.metric.initialiseTest())},this.stopTest=function(){this.testStarted?(this.testDuration=this.getTestTime(),this.testStarted=!1):console.log("ERR: Test tried to end before beginning")},this.updateTestTime=function(){this.testStarted&&(this.testDuration=audioContext.currentTime-this.testStartTime)},this.getTestTime=function(){return this.updateTestTime(),this.testDuration}}function sessionMetrics(e,t){this.engine=e,this.lastClicked=-1,this.data=-1,this.reset=function(){this.lastClicked=-1,this.data=-1},this.enableElementInitialPosition=!1,this.enableElementListenTracker=!1,this.enableElementTimer=!1,this.enableElementTracker=!1,this.enableFlagListenedTo=!1,this.enableFlagMoved=!1,this.enableTestTimer=!1;for(var i=0;i<t.metrics.enabled.length;i++){switch(t.metrics.enabled[i]){case"testTimer":this.enableTestTimer=!0;break;case"elementTimer":this.enableElementTimer=!0;break;case"elementTracker":this.enableElementTracker=!0;break;case"elementListenTracker":this.enableElementListenTracker=!0;break;case"elementInitialPosition":this.enableElementInitialPosition=!0;break;case"elementFlagListenedTo":this.enableFlagListenedTo=!0;break;case"elementFlagMoved":this.enableFlagMoved=!0;break;case"elementFlagComments":this.enableFlagComments=!0}}this.initialiseTest=function(){}}function metricTracker(e){this.listenedTimer=0,this.listenStart=0,this.listenHold=!1,this.initialPosition=-1,this.movementTracker=[],this.listenTracker=[],this.wasListenedTo=!1,this.wasMoved=!1,this.hasComments=!1,this.parent=e,this.initialise=function(e){-1==this.initialPosition&&(this.initialPosition=e,this.moved(0,e))},this.moved=function(e,t){e>0&&(this.wasMoved=!0),t!=(this.movementTracker.length>0?this.movementTracker[this.movementTracker.length-1]:-1)[1]&&(this.movementTracker[this.movementTracker.length]=[e,t])},this.startListening=function(e){if(!1===this.listenHold){this.wasListenedTo=!0,this.listenStart=e,this.listenHold=!0;var t=document.createElement("event"),i=document.createElement("testTime");i.setAttribute("start",e);var n=document.createElement("bufferTime");n.setAttribute("start",this.parent.getCurrentPosition()),t.appendChild(i),t.appendChild(n),this.listenTracker.push(t),console.log("slider "+this.parent.id+" played ("+e+")")}},this.stopListening=function(e,t){if(!0===this.listenHold){var i=e-this.listenStart;this.listenedTimer+=i,this.listenStart=0,this.listenHold=!1;var n=this.listenTracker[this.listenTracker.length-1],o=n.getElementsByTagName("testTime")[0],s=n.getElementsByTagName("bufferTime")[0];o.setAttribute("stop",e),void 0===t?s.setAttribute("stop",this.parent.getCurrentPosition()):s.setAttribute("stop",t),console.log("slider "+this.parent.id+" played for ("+i+")")}},this.exportXMLDOM=function(e){var t=[];return audioEngineContext.metric.enableElementTimer&&t.push(function(e){var t=storage.document.createElement("metricresult");return t.setAttribute("name","enableElementTimer"),t.textContent=this.listenedTimer,e.appendChild(t),t}.call(this,e)),audioEngineContext.metric.enableElementTracker&&t.push(function(e){var t=storage.document.createElement("metricresult");t.setAttribute("name","elementTrackerFull");for(var i=0;i<this.movementTracker.length;i++){var n=storage.document.createElement("movement");n.setAttribute("time",this.movementTracker[i][0]),n.setAttribute("value",this.movementTracker[i][1]),t.appendChild(n)}return e.appendChild(t),t}.call(this,e)),audioEngineContext.metric.enableElementListenTracker&&t.push(function(e){var t=storage.document.createElement("metricresult");t.setAttribute("name","elementListenTracker");for(var i=0;i<this.listenTracker.length;i++)t.appendChild(this.listenTracker[i]);return e.appendChild(t),t}.call(this,e)),audioEngineContext.metric.enableElementInitialPosition&&t.push(function(e){var t=storage.document.createElement("metricresult");return t.setAttribute("name","elementInitialPosition"),t.textContent=this.initialPosition,e.appendChild(t),t}.call(this,e)),audioEngineContext.metric.enableFlagListenedTo&&t.push(function(e){var t=storage.document.createElement("metricresult");return t.setAttribute("name","elementFlagListenedTo"),t.textContent=this.wasListenedTo,e.appendChild(t),t}.call(this,e)),audioEngineContext.metric.enableFlagMoved&&t.push(function(e){var t=storage.document.createElement("metricresult");return t.setAttribute("name","elementFlagMoved"),t.textContent=this.wasMoved,e.appendChild(t),t}.call(this,e)),audioEngineContext.metric.enableFlagComments&&t.push(function(e){var t=storage.document.createElement("metricresult");return t.setAttribute("name","elementFlagComments"),null===this.parent.commentDOM?t.textContent="false":0===this.parent.commentDOM.textContent.length?t.textContent="false":t.textContet="true",e.appendChild(t),t}.call(this,e)),t}}function Interface(e){this.specification=e,this.insertPoint=document.getElementById("topLevelBody"),this.newPage=function(e,t){audioEngineContext.newTestPage(e,t),interfaceContext.commentBoxes.deleteCommentBoxes(),interfaceContext.deleteCommentQuestions(),loadTest(e,t)},this.keyboardInterface=function(){var e={keys:[],registerKeyBinding:function(e,t){if("string"!=typeof e||1!=e.length)throw"Key must be a singular character";if(this.keys.findIndex(function(t){return t.key==e})>=0)throw"Key "+e+" already bounded!";return this.keys.push({key:e,audioObject:t}),!0},deregisterKeyBinding:function(e){var t=this.keys.findIndex(function(t){return t.key==e});if(-1==t)throw"Key "+e+" not bounded!";return this.keys.splice(t,1),!0},resetKeyBindings:function(){this.keys=[]},handleEvent:function(e){" "===e.key?audioEngineContext.audioObjects.some(function(e){return e.playing})&&document.activeElement.className.indexOf("trackComment")>=0==!1&&(e.preventDefault(),audioEngineContext.stop()):function(e){var t=this.keys.findIndex(function(t){return t.key==e});t>=0&&audioEngineContext.play(this.keys[t].audioObject.id)}.call(this,e.key),console.log(e)}};return document.addEventListener("keydown",e,!1),e}(),this.interfaceObjects=[],this.interfaceObject=function(){},this.resizeWindow=function(e){popup.resize(e),this.volume.resize(),this.lightbox.resize(),this.commentBoxes.boxes.forEach(function(e){e.resize()}),this.commentQuestions.forEach(function(e){e.resize()});try{resizeWindow(e)}catch(e){console.log("Warning - Interface does not have Resize option"),console.log(e)}},this.returnNavigator=function(){var e=storage.document.createElement("navigator"),t=storage.document.createElement("platform");t.textContent=navigator.platform;var i=storage.document.createElement("vendor");i.textContent=navigator.vendor;var n=storage.document.createElement("uagent");n.textContent=navigator.userAgent;var o=storage.document.createElement("window");return o.setAttribute("innerWidth",window.innerWidth),o.setAttribute("innerHeight",window.innerHeight),e.appendChild(t),e.appendChild(i),e.appendChild(n),e.appendChild(o),e},this.returnDateNode=function(){var e=new Date,t=storage.document.createElement("datetime"),i=storage.document.createElement("date"),n=storage.document.createElement("time");return i.setAttribute("year",e.getFullYear()),i.setAttribute("month",e.getMonth()+1),i.setAttribute("day",e.getDate()),n.setAttribute("hour",e.getHours()),n.setAttribute("minute",e.getMinutes()),n.setAttribute("secs",e.getSeconds()),t.appendChild(i),t.appendChild(n),t},this.lightbox={parent:this,root:document.createElement("div"),content:document.createElement("div"),accept:document.createElement("button"),blanker:document.createElement("div"),post:function(e,t){switch(e){case"Error":this.content.className="lightbox-error";break;case"Warning":this.content.className="lightbox-warning";break;default:this.content.className="lightbox-message"}var i=document.createElement("p");i.textContent=t,this.content.appendChild(i),this.show()},show:function(){this.root.style.visibility="visible",this.blanker.style.visibility="visible",this.accept.focus()},clear:function(){this.root.style.visibility="",this.blanker.style.visibility="",this.content.textContent=""},handleEvent:function(e){e.currentTarget==this.accept&&this.clear()},resize:function(e){this.root.style.left=window.innerWidth/2-250+"px"},isVisible:function(){return"visible"==this.root.style.visibility}},this.lightbox.root.appendChild(this.lightbox.content),this.lightbox.root.appendChild(this.lightbox.accept),this.lightbox.root.className="popupHolder",this.lightbox.root.id="lightbox-root",this.lightbox.accept.className="popupButton",this.lightbox.accept.style.bottom="10px",this.lightbox.accept.textContent="OK",this.lightbox.accept.style.left="237.5px",this.lightbox.accept.addEventListener("click",this.lightbox),this.lightbox.blanker.className="testHalt",this.lightbox.blanker.id="lightbox-blanker",document.getElementsByTagName("body")[0].appendChild(this.lightbox.root),document.getElementsByTagName("body")[0].appendChild(this.lightbox.blanker),this.commentBoxes=function(){var e={};return e.boxes=[],e.injectPoint=null,e.elementCommentBox=function(e){e.specification;this.audioObject=e,this.id=e.id;var t=e.specification.parent;this.trackComment=document.createElement("div"),this.trackComment.className="comment-div",this.trackComment.id="comment-div-"+e.id,this.trackString=document.createElement("span"),this.trackString.innerHTML=t.commentBoxPrefix+" "+e.interfaceDOM.getPresentedId(),this.trackCommentBox=document.createElement("textarea"),this.trackCommentBox.rows="4",this.trackCommentBox.cols="100",this.trackCommentBox.name="trackComment"+e.id,this.trackCommentBox.className="trackComment";var i=document.createElement("br");this.trackComment.appendChild(this.trackString),this.trackComment.appendChild(i),this.trackComment.appendChild(this.trackCommentBox),this.exportXMLDOM=function(){var e=document.createElement("comment"),t=document.createElement("question");t.textContent=this.trackString.textContent;var i=document.createElement("response");return i.textContent=this.trackCommentBox.value,console.log("Comment frag-"+this.id+": "+i.textContent),e.appendChild(t),e.appendChild(i),e},this.resize=function(){var e=(window.innerWidth-100)/2;e>=600?e=600:e<400&&(e=400),this.trackComment.style.width=e+"px",this.trackCommentBox.style.width=e-6+"px"},this.resize(),this.highlight=function(e){!0===e?$(this.trackComment).addClass("comment-box-playing"):$(this.trackComment).removeClass("comment-box-playing")}},e.createCommentBox=function(e){var t=new this.elementCommentBox(e);return this.boxes.push(t),e.commentDOM=t,t},e.sortCommentBoxes=function(){this.boxes.sort(function(e,t){return e.id-t.id})},e.showCommentBoxes=function(e,t){this.injectPoint=e,t&&this.sortCommentBoxes(),this.boxes.forEach(function(t){e.appendChild(t.trackComment)})},e.deleteCommentBoxes=function(){null!==this.injectPoint&&(this.boxes.forEach(function(e){this.injectPoint.removeChild(e.trackComment)},this),this.injectPoint=null),this.boxes=[]},e.highlightById=function(e){(void 0===e||"number"!=typeof e||e>=this.boxes.length)&&(console.log("Error - Invalid id"),e=-1),this.boxes.forEach(function(t){t.id===e?t.highlight(!0):t.highlight(!1)})},e}(),this.commentQuestions=[],this.commentBox=function(e){this.specification=e,this.holder=document.createElement("div"),this.holder.className="comment-div",this.string=document.createElement("span"),this.string.innerHTML=e.statement,this.textArea=document.createElement("textarea"),this.textArea.rows="4",this.textArea.cols="100",this.textArea.className="trackComment";var t=document.createElement("br");this.holder.appendChild(this.string),this.holder.appendChild(t),this.holder.appendChild(this.textArea),this.exportXMLDOM=function(e){var t=e.parent.document.createElement("comment");t.id=this.specification.id,t.setAttribute("type",this.specification.type),console.log("Question: "+this.string.textContent),console.log("Response: "+t.textContent);var i=e.parent.document.createElement("question");i.textContent=this.string.textContent;var n=e.parent.document.createElement("response");return n.textContent=this.textArea.value,t.appendChild(i),t.appendChild(n),e.XMLDOM.appendChild(t),t},this.resize=function(){var e=(window.innerWidth-100)/2;e>=600?e=600:e<400&&(e=400),this.holder.style.width=e+"px",this.textArea.style.width=e-6+"px"},this.resize(),this.check=function(){return!this.specification.mandatory||0!==this.textArea.value.length}},this.radioBox=function(e){this.specification=e,this.holder=document.createElement("div"),this.holder.className="comment-div",this.string=document.createElement("span"),this.string.innerHTML=e.statement,this.holder.appendChild(this.string),this.options=[],this.inputs=document.createElement("div"),this.inputs.className="comment-checkbox-inputs-holder";for(var t=e.options.length,i=0;i<t;i++){var n=document.createElement("div");n.className="comment-checkbox-inputs-flex";var o=document.createElement("span");o.textContent=e.options[i].text,o.className="comment-radio-span",n.appendChild(o);var s=document.createElement("input");s.type="radio",s.name=e.id,s.setAttribute("setvalue",e.options[i].name),s.className="comment-radio",n.appendChild(s),this.inputs.appendChild(n),this.options.push(s)}this.holder.appendChild(this.inputs),this.exportXMLDOM=function(e){var t=e.parent.document.createElement("comment");t.id=this.specification.id,t.setAttribute("type",this.specification.type);var i=document.createElement("question");i.textContent=this.string.textContent;for(var n=document.createElement("response"),o=0;!1===this.options[o].checked&&!(++o>=this.options.length););return o>=this.options.length?n.textContent="null":(n.textContent=this.options[o].getAttribute("setvalue"),n.setAttribute("number",o)),console.log("Comment: "+i.textContent),console.log("Response: "+n.textContent),t.appendChild(i),t.appendChild(n),e.XMLDOM.appendChild(t),t},this.resize=function(){var e=(window.innerWidth-100)/2;e>=600?e=600:e<400&&(e=400),this.holder.style.width=e+"px"},this.check=function(){var e=this.options.some(function(e){return e.checked});return!this.specification.mandatory||!1!==e},this.resize()},this.checkboxBox=function(e){this.specification=e,this.holder=document.createElement("div"),this.holder.className="comment-div",this.string=document.createElement("span"),this.string.innerHTML=e.statement,this.holder.appendChild(this.string),this.options=[],this.inputs=document.createElement("div"),this.inputs.className="comment-checkbox-inputs-holder";for(var t=e.options.length,i=0;i<t;i++){var n=document.createElement("div");n.className="comment-checkbox-inputs-flex";var o=document.createElement("span");o.textContent=e.options[i].text,o.className="comment-radio-span",n.appendChild(o);var s=document.createElement("input");s.type="checkbox",s.name=e.id,s.setAttribute("setvalue",e.options[i].name),s.className="comment-radio",n.appendChild(s),this.inputs.appendChild(n),this.options.push(s)}this.holder.appendChild(this.inputs),this.exportXMLDOM=function(e){var t=e.parent.document.createElement("comment");t.id=this.specification.id,t.setAttribute("type",this.specification.type);var i=document.createElement("question");i.textContent=this.string.textContent,t.appendChild(i),console.log("Comment: "+i.textContent);for(var n=0;n<this.options.length;n++){var o=document.createElement("response");o.textContent=this.options[n].checked,o.setAttribute("name",this.options[n].getAttribute("setvalue")),t.appendChild(o),console.log("Response "+o.getAttribute("name")+": "+o.textContent)}return e.XMLDOM.appendChild(t),t},this.resize=function(){var e=(window.innerWidth-100)/2;e>=600?e=600:e<400&&(e=400),this.holder.style.width=e+"px"},this.check=function(){var e=this.options.some(function(e){return e.checked});return!this.specification.mandatory||!1!==e},this.resize()},this.sliderBox=function(e){this.specification=e,this.holder=document.createElement("div"),this.holder.className="comment-div",this.string=document.createElement("span"),this.string.innerHTML=e.statement,this.slider=document.createElement("input"),this.slider.type="range",this.slider.min=e.min,this.slider.max=e.max,this.slider.step=e.step,this.slider.value=e.value;var t=document.createElement("br"),i=document.createElement("div");i.className="comment-slider-text-holder",this.leftText=document.createElement("span"),this.leftText.textContent=e.leftText,this.rightText=document.createElement("span"),this.rightText.textContent=e.rightText,i.appendChild(this.leftText),i.appendChild(this.rightText),this.holder.appendChild(this.string),this.holder.appendChild(t),this.holder.appendChild(this.slider),this.holder.appendChild(i),this.exportXMLDOM=function(e){var t=e.parent.document.createElement("comment");t.id=this.specification.id,t.setAttribute("type",this.specification.type),console.log("Question: "+this.string.textContent),console.log("Response: "+this.slider.value);var i=e.parent.document.createElement("question");i.textContent=this.string.textContent;var n=e.parent.document.createElement("response");return n.textContent=this.slider.value,t.appendChild(i),t.appendChild(n),e.XMLDOM.appendChild(t),t},this.resize=function(){var e=(window.innerWidth-100)/2;e>=600?e=600:e<400&&(e=400),this.holder.style.width=e+"px",this.slider.style.width=e-24+"px"},this.check=function(){return!0},this.resize()},this.createCommentQuestion=function(e){var t;return"question"==e.type?t=new this.commentBox(e):"radio"==e.type?t=new this.radioBox(e):"checkbox"==e.type?t=new this.checkboxBox(e):"slider"==e.type&&(t=new this.sliderBox(e)),this.commentQuestions.push(t),t},this.deleteCommentQuestions=function(){this.commentQuestions=[]},this.checkCommentQuestions=function(){if(0===this.commentQuestions.reduce(function(e,t){return!1===t.check()&&e.push(t),e},[]).length)return!0;interfaceContext.lightbox.post("Message","Not all the mandatory comment boxes below have been filled.")},this.outsideReferenceDOM=function(e,t,i){this.parent=e,this.outsideReferenceHolder=document.createElement("button"),this.outsideReferenceHolder.className="outside-reference",this.outsideReferenceHolder.setAttribute("track-id",t),this.outsideReferenceHolder.textContent=this.parent.specification.label||"Reference",this.outsideReferenceHolder.disabled=!0,this.handleEvent=function(e){audioEngineContext.play(this.parent.id)},this.outsideReferenceHolder.addEventListener("click",this),i.appendChild(this.outsideReferenceHolder),this.enable=function(){1==this.parent.state&&(this.outsideReferenceHolder.disabled=!1)},this.updateLoading=function(e){100!=e?(e=(e=String(e)).split(".")[0],this.outsideReferenceHolder.textContent=e+"%"):this.outsideReferenceHolder.textContent=this.parent.specification.label||"Reference"},this.startPlayback=function(){$(".track-slider").removeClass("track-slider-playing"),$(".comment-div").removeClass("comment-box-playing"),this.outsideReferenceHolder.style.backgroundColor="#FDD"},this.stopPlayback=function(){this.outsideReferenceHolder.style.backgroundColor=""},this.exportXMLDOM=function(e){return null},this.getValue=function(){return 0},this.getPresentedId=function(){return this.parent.specification.label||"Reference"},this.canMove=function(){return!1},this.error=function(){this.outsideReferenceHolder.textContent="Error",this.outsideReferenceHolder.style.backgroundColor="#F00"}},this.playhead=function(){var e={};e.object=document.createElement("div"),e.object.className="playhead",e.object.align="left";var t=document.createElement("div");return t.style.width="50px",e.curTimeSpan=document.createElement("span"),e.curTimeSpan.textContent="00:00",t.appendChild(e.curTimeSpan),e.object.appendChild(t),e.scrubberTrack=document.createElement("div"),e.scrubberTrack.className="playhead-scrub-track",e.scrubberHead=document.createElement("div"),e.scrubberHead.id="playhead-scrubber",e.scrubberTrack.appendChild(e.scrubberHead),e.object.appendChild(e.scrubberTrack),e.timePerPixel=0,e.maxTime=0,e.playbackObject=void 0,e.setTimePerPixel=function(e){this.playbackObject=e,this.maxTime=e.buffer.buffer.duration;this.timePerPixel=this.maxTime/490,this.maxTime<60?this.curTimeSpan.textContent="0.00":this.curTimeSpan.textContent="00:00"},e.update=function(){if(this.timePerPixel>0){var e=this.playbackObject.getCurrentPosition();if(e>0&&e<this.maxTime){var t=Math.floor(e/this.timePerPixel);if(this.scrubberHead.style.left=t+"px",this.maxTime>60){var i=e%60,n=Math.floor((e-i)/60);i=(i=i.toString()).substr(0,2),n=n.toString(),this.curTimeSpan.textContent=n+":"+i}else e=e.toString(),this.curTimeSpan.textContent=e.substr(0,4)}else this.scrubberHead.style.left="0px",this.maxTime<60?this.curTimeSpan.textContent="0.00":this.curTimeSpan.textContent="00:00"}void 0!==this.playbackObject&&void 0===this.interval&&window.requestAnimationFrame(this.update.bind(this))},e.interval=void 0,e.start=function(){void 0!==this.playbackObject&&void 0===this.interval&&window.requestAnimationFrame(this.update.bind(this))},e.stop=function(){this.timePerPixel=0},e}(),this.volume=function(){var e={};e.valueLin=1,e.valueDB=0,e.root=document.createElement("div"),e.root.id="master-volume-root",e.object=document.createElement("div"),e.object.className="master-volume-holder-float",e.object.appendChild(e.root),e.slider=document.createElement("input"),e.slider.id="master-volume-control",e.slider.type="range",e.valueText=document.createElement("span"),e.valueText.id="master-volume-feedback",e.valueText.textContent="0dB",e.slider.min=-60,e.slider.max=12,e.slider.value=0,e.slider.step=1,e.handleEvent=function(e){"mousemove"!=e.type&&"mouseup"!=e.type||(this.valueDB=Number(this.slider.value),this.valueLin=decibelToLinear(this.valueDB),this.valueText.textContent=this.valueDB+"dB",audioEngineContext.outputGain.gain.value=this.valueLin),"mouseup"==e.type&&this.onmouseup(),this.slider.value=this.valueDB,e.stopPropagation&&e.stopPropagation()},e.onmouseup=function(){var e=testState.currentStore.XMLDOM.getElementsByTagName("metric")[0].getAllElementsByName("volumeTracker");0===e.length?((e=storage.document.createElement("metricresult")).setAttribute("name","volumeTracker"),testState.currentStore.XMLDOM.getElementsByTagName("metric")[0].appendChild(e)):e=e[0];var t=storage.document.createElement("movement");t.setAttribute("test-time",audioEngineContext.timer.getTestTime()),t.setAttribute("volume",this.valueDB),t.setAttribute("format","dBFS"),e.appendChild(t)},e.slider.addEventListener("mousemove",e),e.root.addEventListener("mouseup",e);var t=document.createElement("div");return t.innerHTML="<span>Master Volume Control</span>",t.style.fontSize="0.75em",t.style.width="100%",t.align="center",e.root.appendChild(t),e.root.appendChild(e.slider),e.root.appendChild(e.valueText),e.resize=function(e){window.innerWidth<1e3?this.object.className="master-volume-holder-inline":this.object.className="master-volume-holder-float"},e}(),this.imageHolder=function(){var e={};return e.root=document.createElement("div"),e.root.id="imageController",e.img=document.createElement("img"),e.root.appendChild(e.img),e.setImage=function(t){e.img.src="","string"==typeof t&&void 0!==t.length&&(e.img.src=t)},e}(),this.calibrationModuleObject=null,this.calibrationModule=function(){this.storeDOM=storage.document.createElement("calibration"),storage.root.appendChild(this.storeDOM),this.calibrationNodes=[],this.holder=null,this.build=function(e){var t=62.5;for(this.holder=document.createElement("div"),this.holder.className="calibration-holder",this.calibrationNodes=[];t<2e4;){var i={root:document.createElement("div"),input:document.createElement("input"),oscillator:audioContext.createOscillator(),gain:audioContext.createGain(),f:t,parent:this,handleEvent:function(e){switch(e.type){case"mouseenter":this.oscillator.start(0);break;case"mouseleave":this.oscillator.stop(0),this.oscillator=audioContext.createOscillator(),this.oscillator.connect(this.gain),this.oscillator.frequency.value=this.f;break;case"mousemove":var t=Math.pow(10,this.input.value/20);1e3==this.f?(audioEngineContext.outputGain.gain.value=t,interfaceContext.volume.slider.value=this.input.value):this.gain.gain.value=t}},disconnect:function(){this.gain.disconnect()}};i.root.className="calibration-slider",i.root.appendChild(i.input),i.oscillator.connect(i.gain),i.gain.connect(audioEngineContext.outputGain),i.gain.gain.value=2*Math.random(),i.input.value=i.gain.gain.value,i.input.setAttribute("orient","vertical"),i.input.type="range",i.input.min=-12,i.input.max=0,i.input.step=.25,1e3!=t?i.input.value=12*Math.random()-6:(i.input.value=0,i.root.style.backgroundColor="rgb(255,125,125)"),i.input.addEventListener("mousemove",i),i.input.addEventListener("mouseenter",i),i.input.addEventListener("mouseleave",i),i.gain.gain.value=Math.pow(10,i.input.value/20),i.oscillator.frequency.value=t,this.calibrationNodes.push(i),this.holder.appendChild(i.root),t*=2}e.appendChild(this.holder)},this.collect=function(){this.calibrationNodes.forEach(function(e){var t=storage.document.createElement("calibrationresult");t.setAttribute("frequency",e.f),t.setAttribute("range-min",e.input.min),t.setAttribute("range-max",e.input.max),t.setAttribute("gain-lin",e.gain.gain.value),this.storeDOM.appendChild(t)},this)}},this.checkHiddenAnchor=function(e){return!audioEngineContext.audioObjects.filter(function(e){return"anchor"===e.specification.type}).some(function(e){return e.interfaceDOM.getValue()>e.specification.marker/100&&e.specification.marker>0})||(console.log("Anchor node not below marker value"),e?interfaceContext.lightbox.post("Message",e):interfaceContext.lightbox.post("Message","Please keep listening"),this.storeErrorNode("Anchor node not below marker value"),!1)},this.checkHiddenReference=function(e){return!audioEngineContext.audioObjects.filter(function(e){return"reference"===e.specification.type}).some(function(e){return e.interfaceDOM.getValue()<e.specification.marker/100&&e.specification.marker>0})||(console.log("Reference node not below marker value"),e?interfaceContext.lightbox.post("Message",e):interfaceContext.lightbox.post("Message","Please keep listening"),this.storeErrorNode("Reference node not below marker value"),!1)},this.checkFragmentsFullyPlayed=function(e){if(audioEngineContext.loopPlayback)return console.log("WARNING - Looped source: Cannot check fragments are fully played"),!0;var t,i=!0,n=[];for(t=0;t<audioEngineContext.audioObjects.length;t++){for(var o=audioEngineContext.audioObjects[t],s=o.buffer.buffer.duration,r=o.metric,a=!1,c=0;c<r.listenTracker.length;c++){var l=r.listenTracker[c].getElementsByTagName("testtime"),u=Number(l[0].getAttribute("start"));if(Number(l[0].getAttribute("stop"))-u>=s){a=!0;break}}!1===a&&(i=!1,console.log("Continue listening to track-"+o.interfaceDOM.getPresentedId()),n.push(o.interfaceDOM.getPresentedId()))}if(!1===i){var h="You have not completely listened to fragments ";for(t=0;t<n.length;t++)h+=n[t],t!=n.length-1&&(h+=", ");return h+=". Please keep listening",console.log(h),this.storeErrorNode(h),e&&(h=e),interfaceContext.lightbox.post("Error",h),!1}return!0},this.checkAllMoved=function(e){var t="You have not moved ",i=[];if(audioEngineContext.audioObjects.forEach(function(e){!1===e.metric.wasMoved&&!0===e.interfaceDOM.canMove()&&i.push(e.interfaceDOM.getPresentedId())},this),0===i.length)return!0;if(1==i.length)t+="track "+i[0];else{t+="tracks ";for(var n=0;n<i.length-1;n++)t+=i[n]+", ";t+="and "+i[n]}return t+=".",console.log(t),this.storeErrorNode(t),e&&(t=e),interfaceContext.lightbox.post("Error",t),!1},this.checkAllPlayed=function(e){var t="You have not played ",i=[];if(audioEngineContext.audioObjects.forEach(function(e){!1===e.metric.wasListenedTo&&i.push(e.interfaceDOM.getPresentedId())},this),0===i.length)return!0;if(1==i.length)t+="track "+i[0];else{t+="tracks ";for(var n=0;n<i.length-1;n++)t+=i[n]+", ";t+="and "+i[n]}return t+=".",console.log(t),this.storeErrorNode(t),e&&(t=e),interfaceContext.lightbox.post("Error",t),!1},this.checkAllCommented=function(e){var t,i="You have not commented on all the fragments.",n=this.commentBoxes.boxes,o=n.length;for(t=0;t<o;t++)if(""===n[t].trackCommentBox.value)return console.log(i),this.storeErrorNode(i),e&&(i=e),interfaceContext.lightbox.post("Error",i),!1;return!0},this.checkScaleRange=function(e){var t=testState.getCurrentTestPage().interfaces,i=!0,n="Please keep listening. ";if(void 0===t)return!0;t=t[0];var o=function(){var e=t.options.find(function(e){return"scalerange"==e.name});return{min:e.min,max:e.max}}(),s=audioEngineContext.audioObjects.reduce(function(e,t){var i=100*t.interfaceDOM.getValue();return{min:Math.min(e.min,i),max:Math.max(e.max,i)}},{min:100,max:0});return s.min>o.min?(n+="At least one fragment must be below the "+o.min+" mark.",i=!1):s.max<o.max&&(n+="At least one fragment must be above the "+o.max+" mark.",i=!1),!1===i&&(console.log(n),this.storeErrorNode(n),e&&(n=e),interfaceContext.lightbox.post("Error",n)),i},this.checkFragmentMinPlays=function(){var e=audioEngineContext.audioObjects.filter(function(e){var t=e.specification.minNumberPlays||e.specification.parent.minNumberPlays||specification.minNumberPlays;return!(void 0===t||e.numberOfPlays>=t)});if(0===e.length)return!0;var t=[];e.forEach(function(e){t.push(e.interfaceDOM.getPresentedId())});var i="You have not played fragments "+t.join(", ")+" enough. Please keep listening";return interfaceContext.lightbox.post("Message",i),this.storeErrorNode(i),!1},this.sortFragmentsByScore=function(){for(var e=audioEngineContext.audioObjects.filter(function(e){return"outside-reference"!==e.specification.type}),t=[],i=0;t.push(i++)<e.length;);return t.sort(function(t,i){var n=e[t].interfaceDOM.getValue(),o=e[i].interfaceDOM.getValue();return n>o?1:n<o?-1:0},e[0].interfaceDOM.getValue())},this.storeErrorNode=function(e){var t=audioEngineContext.timer.getTestTime(),i=storage.document.createElement("error");i.setAttribute("time",t),i.textContent=e,testState.currentStore.XMLDOM.appendChild(i)},this.getLabel=function(e,t,i){function n(e,t,i){if("none"==e)return"";switch(e){case"letter":return String.fromCharCode((t+i)%26+97);case"capital":return String.fromCharCode((t+i)%26+65);case"samediff":return 0===t?"Same":1==t?"Difference":"";case"number":return String(t+i);default:return""}}switch("string"==typeof i&&0!==i.length||(i=String.fromCharCode(0)),e){case"letter":((i=i.charCodeAt(0))<97||i>122)&&(i=97),i-=97;break;case"capital":((i=i.charCodeAt(0))<65||i>90)&&(i=65),i-=65;break;case"number":i=Number(i),isFinite(i)||(i=1);break;default:i=0}if("number"==typeof t)return n(e,t,i);if(t.length&&t.length>0){var o,s=[],r=t.length;for(o=0;o<r;o++)s[o]=n(e,t[o],i);return s}throw"Invalid arguments"},this.getCombinedInterfaces=function(e){var t=specification.interfaces,i=e.interfaces;return i.forEach(function(e){var i=[];t.options.forEach(function(t){e.options.find(function(e){return e.name==t.name&&e.type==t.type})||i.push(t)}),e.options=e.options.concat(i),!e.scales&&t.scales&&(e.scales=t.scales)}),i}}function Storage(){this.globalPreTest=null,this.globalPostTest=null,this.testPages=[],this.document=null,this.root=null,this.state=0;var e="save";this.initialise=function(e){if(void 0===e){this.SessionKey.requestKey(),this.document=document.implementation.createDocument(null,"waetresult",null),this.root=this.document.childNodes[0];var t=specification.projectXML;t.setAttribute("file-name",specification.url),t.setAttribute("url",qualifyURL(specification.url)),this.root.appendChild(t),this.root.appendChild(interfaceContext.returnDateNode()),this.root.appendChild(interfaceContext.returnNavigator())}else this.document=e,this.root=e.firstChild,this.SessionKey.key=this.root.getAttribute("key");void 0!==specification.preTest&&(this.globalPreTest=new this.surveyNode(this,this.root,specification.preTest)),void 0!==specification.postTest&&(this.globalPostTest=new this.surveyNode(this,this.root,specification.postTest))},this.SessionKey=function(e){function t(){var t=document.createElement("div"),n=e.root.cloneNode(!0);return t.appendChild(n),new Promise(function(n,s){console.log("Requested save...");var r=new XMLHttpRequest;r.open("POST",i+"php/save.php?key="+o+"&saveFilenamePrefix="+e.filenamePrefix),r.setRequestHeader("Content-Type","text/xml"),r.onload=function(){if(this.status>=300)console.log("WARNING - Could not update at this time");else{var e=(new DOMParser).parseFromString(r.responseText,"application/xml").getElementsByTagName("response")[0];if("OK"==e.getAttribute("state")){var t=e.getElementsByTagName("file")[0];console.log("Intermediate save: OK, written "+t.getAttribute("bytes")+"B"),n(!0)}else{var i=e.getElementsByTagName("message");console.log("Intermediate save: Error! "+i.textContent),s("Intermediate save: Error! "+i.textContent)}}},r.onerror=function(){s(Error("Network Error"))},r.send([t.innerHTML])})}var i="";void 0!==window.returnURL&&(i=String(window.returnURL));var n=null,o=null,s={};return Object.defineProperties(s,{key:{get:function(){return o},set:function(e){throw"Cannot set read-only property"}},request:{value:new XMLHttpRequest},parent:{value:e},requestKey:{value:function(){n=new Promise(function(t,n){var o=new XMLHttpRequest;o.open("GET",i+"php/requestKey.php?saveFilenamePrefix="+e.filenamePrefix,!0),o.onload=function(){200==o.status?t(o.response):n(Error(o.statusText))},o.onerror=function(){n(Error("Network Error"))},o.send()}).then(function(t){function i(){throw o=null,"An unspecified error occured, no server key could be generated"}var n=(new DOMParser).parseFromString(t,"text/xml");if(0===t.length&&i(),n.getElementsByTagName("state").length>0){if("OK"==n.getElementsByTagName("state")[0].textContent)return o=n.getAllElementsByTagName("key")[0].textContent,e.root.setAttribute("key",o),e.root.setAttribute("state","empty"),!0;if("ERROR"==n.getElementsByTagName("state")[0].textContent)return o=null,console.error('Could not generate server key. Server responded with error message: "'+n.getElementsByTagName("message")[0].textContent+'"'),!1}else i();return!0})}},update:{value:function(){if(null===this.key||void 0===n)throw"Cannot save as key == null";this.parent.root.setAttribute("state","update"),n=n.then(t)}},finish:{value:function(){if(null===this.key||void 0===n)throw"Cannot save as key == null";return this.parent.finish(),n.then(t()).then(function(){console.log("OK")},function(){createProjectSave("local")})}}}),s}(this),this.createTestPageStore=function(e){var t=new this.pageNode(this,e);return this.testPages.push(t),this.testPages[this.testPages.length-1]},this.surveyNode=function(e,t,i){this.specification=i,this.parent=e,this.state="empty",this.XMLDOM=this.parent.document.createElement("survey"),this.XMLDOM.setAttribute("location",this.specification.location),this.XMLDOM.setAttribute("state",this.state),this.specification.options.forEach(function(e){if("statement"!=e.type){var t=this.parent.document.createElement("surveyresult");t.setAttribute("ref",e.id),t.setAttribute("type",e.type),this.XMLDOM.appendChild(t)}},this),t.appendChild(this.XMLDOM),this.postResult=function(e){function t(e,t){var i=e.createElement("response");return i.setAttribute("name",t.name),i.setAttribute("checked",t.checked),i}if("statement"!=e.specification.type){for(var i=this.XMLDOM.firstChild;null!==i&&i.getAttribute("ref")!=e.specification.id;)i=i.nextElementSibling;switch(i.setAttribute("duration",e.elapsedTime),e.specification.type){case"number":case"question":case"slider":i.appendChild(function(e,t){var i=e.createElement("response");return i.textContent=t,i}(this.parent.document,e.response));break;case"radio":i.appendChild(function(e,t){var i=e.createElement("response");return null!==t.response&&(i.setAttribute("name",t.response.name),i.textContent=t.response.text),i}(this.parent.document,e));break;case"checkbox":if(void 0===e.response){i.appendChild(this.parent.document.createElement("response"));break}for(var n=0;n<e.response.length;n++)i.appendChild(t(this.parent.document,e.response[n]))}}},this.complete=function(){this.state="complete",this.XMLDOM.setAttribute("state",this.state)}},this.pageNode=function(e,t){this.specification=t,this.parent=e,this.state="empty",this.XMLDOM=this.parent.document.createElement("page"),this.XMLDOM.setAttribute("ref",t.id),this.XMLDOM.setAttribute("presentedId",t.presentedId),this.XMLDOM.setAttribute("state",this.state),void 0!==t.preTest&&(this.preTest=new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.preTest)),void 0!==t.postTest&&(this.postTest=new this.parent.surveyNode(this.parent,this.XMLDOM,this.specification.postTest));var i=this.parent.document.createElement("metric");this.XMLDOM.appendChild(i),this.specification.audioElements.forEach(function(e){var t=this.parent.document.createElement("audioelement");t.setAttribute("ref",e.id),void 0!==e.name&&t.setAttribute("name",e.name),t.setAttribute("type",e.type),t.setAttribute("url",e.url),t.setAttribute("fqurl",qualifyURL(e.url)),t.setAttribute("gain",e.gain),"anchor"!=e.type&&"reference"!=e.type||e.marker>0&&t.setAttribute("marker",e.marker);var i=this.parent.document.createElement("metric");t.appendChild(i),this.XMLDOM.appendChild(t)},this),this.parent.root.appendChild(this.XMLDOM),this.complete=function(){this.state="complete",this.XMLDOM.setAttribute("state","complete")}},this.update=function(){this.SessionKey.update()},this.finish=function(){return this.state=1,this.root.setAttribute("state","complete"),this.root},Object.defineProperties(this,{filenamePrefix:{get:function(){return e},set:function(t){return"string"!=typeof t&&(t=String(t)),e=t,t}}})}var audioContext,projectXML,schemaXSD,specification,interfaceContext,storage,popup,testState,audioEngineContext,gReturnURL,gSaveFilenamePrefix,currentTrackOrder=[];AudioBufferSourceNode.prototype.owner=void 0,AudioBufferSourceNode.prototype.playbackStartTime=void 0,AudioBuffer.prototype.playbackGain=void 0,AudioBuffer.prototype.lufs=void 0,XMLDocument.prototype.getAllElementsByName=function(e){e=String(e);return this.documentElement.getAllElementsByName(e)},Element.prototype.getAllElementsByName=function(e){e=String(e);for(var t=[],i=this.firstElementChild;null!==i;)i.getAttribute("name")==e&&t.push(i),i.childElementCount>0&&(t=t.concat(i.getAllElementsByName(e))),i=i.nextElementSibling;return t},XMLDocument.prototype.getAllElementsByTagName=function(e){e=String(e);return this.documentElement.getAllElementsByTagName(e)},Element.prototype.getAllElementsByTagName=function(e){e=String(e);for(var t=[],i=this.firstElementChild;null!==i;)i.nodeName==e&&t.push(i),i.childElementCount>0&&(t=t.concat(i.getAllElementsByTagName(e))),i=i.nextElementSibling;return t},"function"!=typeof XMLDocument.prototype.getElementsByName&&(XMLDocument.prototype.getElementsByName=function(e){e=String(e);for(var t=this.documentElement.firstElementChild,i=[];null!==t;)t.getAttribute("name")==e&&i.push(t),t=t.nextElementSibling;return i});var window_depedancy_callback,check_dependancies=function(){return"function"==typeof jQuery&&("function"==typeof Specification&&("function"==typeof calculateLoudness&&("function"==typeof WAVE&&"function"==typeof validateXML)))},onload=function(){var e=window.AudioContext||window.webkitAudioContext;if(audioContext=new e,testState=new stateMachine,popup=new interfacePopup,specification=new Specification,interfaceContext=new Interface(specification),storage=new Storage,window.onresize=function(e){interfaceContext.resizeWindow(e)},0!==window.location.search.length){var t,i=window.location.search.split("?")[1].split("&");for(var n in i){i[n]=i[n].split("=");var o=i[n][0],s=decodeURIComponent(i[n][1]);switch(o){case"url":t=s,specification.url=t;break;case"returnURL":gReturnURL=s;break;case"saveFilenamePrefix":storage.filenamePrefix=s}}loadProjectSpec(t),window.onbeforeunload=function(){return"Please only leave this page once you have completed the tests. Are you sure you have completed all testing?"}}interfaceContext.lightbox.resize()};window_depedancy_callback=window.setInterval(function(){check_dependancies()?(window.clearInterval(window_depedancy_callback),onload()):document.getElementById("topLevelBody").innerHTML="<h1>Loading Resources</h1>"},100); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/min/jquery-2.1.4.min.js Tue Apr 10 10:22:34 2018 +0100 @@ -0,0 +1,1 @@ +!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t="length"in e&&e.length,n=V.type(e);return"function"!==n&&!V.isWindow(e)&&(!(1!==e.nodeType||!t)||("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e))}function r(e,t,n){if(V.isFunction(t))return V.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return V.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(te.test(t))return V.filter(t,e,n);t=V.filter(t,e)}return V.grep(e,function(e){return I.call(t,e)>=0!==n})}function i(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}function o(){U.removeEventListener("DOMContentLoaded",o,!1),e.removeEventListener("load",o,!1),V.ready()}function s(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=V.expando+s.uid++}function a(e,t,n){var r;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(de,"-$1").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:pe.test(n)?V.parseJSON(n):n)}catch(e){}fe.set(e,t,n)}else n=void 0;return n}function u(){return!0}function l(){return!1}function c(){try{return U.activeElement}catch(e){}}function f(e,t){return V.nodeName(e,"table")&&V.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function p(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function d(e){var t=je.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function h(e,t){for(var n=0,r=e.length;n<r;n++)ce.set(e[n],"globalEval",!t||ce.get(t[n],"globalEval"))}function g(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(ce.hasData(e)&&(o=ce.access(e),s=ce.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;n<r;n++)V.event.add(t,i,l[i][n])}fe.hasData(e)&&(a=fe.access(e),u=V.extend({},a),fe.set(t,u))}}function m(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return void 0===t||t&&V.nodeName(e,t)?V.merge([e],n):n}function v(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ve.test(e.type)?t.checked=e.checked:"input"!==n&&"textarea"!==n||(t.defaultValue=e.defaultValue)}function y(t,n){var r,i=V(n.createElement(t)).appendTo(n.body),o=e.getDefaultComputedStyle&&(r=e.getDefaultComputedStyle(i[0]))?r.display:V.css(i[0],"display");return i.detach(),o}function x(e){var t=U,n=He[e];return n||("none"!==(n=y(e,t))&&n||((t=(qe=(qe||V("<iframe frameborder='0' width='0' height='0'/>")).appendTo(t.documentElement))[0].contentDocument).write(),t.close(),n=y(e,t),qe.detach()),He[e]=n),n}function b(e,t,n){var r,i,o,s,a=e.style;return(n=n||Pe(e))&&(s=n.getPropertyValue(t)||n[t]),n&&(""!==s||V.contains(e.ownerDocument,e)||(s=V.style(e,t)),Fe.test(s)&&Oe.test(t)&&(r=a.width,i=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=s,s=n.width,a.width=r,a.minWidth=i,a.maxWidth=o)),void 0!==s?s+"":s}function w(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}function T(e,t){if(t in e)return t;for(var n=t[0].toUpperCase()+t.slice(1),r=t,i=Be.length;i--;)if((t=Be[i]+n)in e)return t;return r}function C(e,t,n){var r=Me.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function N(e,t,n,r,i){for(var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;o<4;o+=2)"margin"===n&&(s+=V.css(e,n+ge[o],!0,i)),r?("content"===n&&(s-=V.css(e,"padding"+ge[o],!0,i)),"margin"!==n&&(s-=V.css(e,"border"+ge[o]+"Width",!0,i))):(s+=V.css(e,"padding"+ge[o],!0,i),"padding"!==n&&(s+=V.css(e,"border"+ge[o]+"Width",!0,i)));return s}function k(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Pe(e),s="border-box"===V.css(e,"boxSizing",!1,o);if(i<=0||null==i){if(((i=b(e,t,o))<0||null==i)&&(i=e.style[t]),Fe.test(i))return i;r=s&&(X.boxSizingReliable()||i===e.style[t]),i=parseFloat(i)||0}return i+N(e,t,n||(s?"border":"content"),r,o)+"px"}function E(e,t){for(var n,r,i,o=[],s=0,a=e.length;s<a;s++)(r=e[s]).style&&(o[s]=ce.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&me(r)&&(o[s]=ce.access(r,"olddisplay",x(r.nodeName)))):(i=me(r),"none"===n&&i||ce.set(r,"olddisplay",i?n:V.css(r,"display"))));for(s=0;s<a;s++)(r=e[s]).style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}function S(e,t,n,r,i){return new S.prototype.init(e,t,n,r,i)}function D(){return setTimeout(function(){_e=void 0}),_e=V.now()}function j(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ge[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function A(e,t,n){for(var r,i=(Ge[t]||[]).concat(Ge["*"]),o=0,s=i.length;o<s;o++)if(r=i[o].call(n,t,e))return r}function L(e,t,n){var r,i,o=0,s=Ye.length,a=V.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;for(var t=_e||D(),n=Math.max(0,l.startTime+l.duration-t),r=1-(n/l.duration||0),o=0,s=l.tweens.length;o<s;o++)l.tweens[o].run(r);return a.notifyWith(e,[l,r,n]),r<1&&s?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:V.extend({},t),opts:V.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:_e||D(),duration:n.duration,tweens:[],createTween:function(t,n){var r=V.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;n<r;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,s;for(n in e)if(r=V.camelCase(n),i=t[r],o=e[n],V.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(s=V.cssHooks[r])&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}(c,l.opts.specialEasing);o<s;o++)if(r=Ye[o].call(l,e,c,l.opts))return r;return V.map(c,A,l),V.isFunction(l.opts.start)&&l.opts.start.call(e,l),V.fx.timer(V.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function q(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(se)||[];if(V.isFunction(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function H(e,t,n,r){function i(a){var u;return o[a]=!0,V.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||s||o[l]?s?!(u=l):void 0:(t.dataTypes.unshift(l),i(l),!1)}),u}var o={},s=e===ct;return i(t.dataTypes[0])||!o["*"]&&i("*")}function O(e,t){var n,r,i=V.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&V.extend(!0,e,r),e}function F(e,t,n,r){var i;if(V.isArray(t))V.each(t,function(t,i){n||gt.test(e)?r(e,i):F(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==V.type(t))r(e,t);else for(i in t)F(e+"["+i+"]",t[i],n,r)}function P(e){return V.isWindow(e)?e:9===e.nodeType&&e.defaultView}var R=[],M=R.slice,W=R.concat,$=R.push,I=R.indexOf,B={},_=B.toString,z=B.hasOwnProperty,X={},U=e.document,V=function(e,t){return new V.fn.init(e,t)},Y=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,G=/^-ms-/,Q=/-([\da-z])/gi,J=function(e,t){return t.toUpperCase()};V.fn=V.prototype={jquery:"2.1.4",constructor:V,selector:"",length:0,toArray:function(){return M.call(this)},get:function(e){return null!=e?e<0?this[e+this.length]:this[e]:M.call(this)},pushStack:function(e){var t=V.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return V.each(this,e,t)},map:function(e){return this.pushStack(V.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(M.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:$,sort:R.sort,splice:R.splice},V.extend=V.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[a]||{},a++),"object"==typeof s||V.isFunction(s)||(s={}),a===u&&(s=this,a--);a<u;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],s!==(r=e[t])&&(l&&r&&(V.isPlainObject(r)||(i=V.isArray(r)))?(i?(i=!1,o=n&&V.isArray(n)?n:[]):o=n&&V.isPlainObject(n)?n:{},s[t]=V.extend(l,o,r)):void 0!==r&&(s[t]=r));return s},V.extend({expando:"jQuery"+("2.1.4"+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isFunction:function(e){return"function"===V.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!V.isArray(e)&&e-parseFloat(e)+1>=0},isPlainObject:function(e){return"object"===V.type(e)&&!e.nodeType&&!V.isWindow(e)&&!(e.constructor&&!z.call(e.constructor.prototype,"isPrototypeOf"))},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?B[_.call(e)]||"object":typeof e},globalEval:function(e){var t,n=eval;(e=V.trim(e))&&(1===e.indexOf("use strict")?((t=U.createElement("script")).text=e,U.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(G,"ms-").replace(Q,J)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,r){var i=0,o=e.length,s=n(e);if(r){if(s)for(;i<o&&!1!==t.apply(e[i],r);i++);else for(i in e)if(!1===t.apply(e[i],r))break}else if(s)for(;i<o&&!1!==t.call(e[i],i,e[i]);i++);else for(i in e)if(!1===t.call(e[i],i,e[i]))break;return e},trim:function(e){return null==e?"":(e+"").replace(Y,"")},makeArray:function(e,t){var r=t||[];return null!=e&&(n(Object(e))?V.merge(r,"string"==typeof e?[e]:e):$.call(r,e)),r},inArray:function(e,t,n){return null==t?-1:I.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,s=!n;i<o;i++)!t(e[i],i)!==s&&r.push(e[i]);return r},map:function(e,t,r){var i,o=0,s=e.length,a=[];if(n(e))for(;o<s;o++)null!=(i=t(e[o],o,r))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,r))&&a.push(i);return W.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),V.isFunction(e))return r=M.call(arguments,2),i=function(){return e.apply(t||this,r.concat(M.call(arguments)))},i.guid=e.guid=e.guid||V.guid++,i},now:Date.now,support:X}),V.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){B["[object "+t+"]"]=t.toLowerCase()});var K=function(e){function t(e,t,n,r){var i,o,s,a,u,l,f,d,h,g;if((t?t.ownerDocument||t:M)!==A&&j(t),t=t||A,n=n||[],a=t.nodeType,"string"!=typeof e||!e||1!==a&&9!==a&&11!==a)return n;if(!r&&q){if(11!==a&&(i=me.exec(e)))if(s=i[1]){if(9===a){if(!(o=t.getElementById(s))||!o.parentNode)return n;if(o.id===s)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(s))&&P(t,o)&&o.id===s)return n.push(o),n}else{if(i[2])return Q.apply(n,t.getElementsByTagName(e)),n;if((s=i[3])&&x.getElementsByClassName)return Q.apply(n,t.getElementsByClassName(s)),n}if(x.qsa&&(!H||!H.test(e))){if(d=f=R,h=t,g=1!==a&&e,1===a&&"object"!==t.nodeName.toLowerCase()){for(l=C(e),(f=t.getAttribute("id"))?d=f.replace(ye,"\\$&"):t.setAttribute("id",d),d="[id='"+d+"'] ",u=l.length;u--;)l[u]=d+p(l[u]);h=ve.test(e)&&c(t.parentNode)||t,g=l.join(",")}if(g)try{return Q.apply(n,h.querySelectorAll(g)),n}catch(e){}finally{f||t.removeAttribute("id")}}}return k(e.replace(se,"$1"),t,n,r)}function n(){function e(n,r){return t.push(n+" ")>b.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[R]=!0,e}function i(e){var t=A.createElement("div");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=e.length;r--;)b.attrHandle[n[r]]=t}function s(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||X)-(~e.sourceIndex||X);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function a(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),s=o.length;s--;)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&void 0!==e.getElementsByTagName&&e}function f(){}function p(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function d(e,t,n){var r=t.dir,i=n&&"parentNode"===r,o=$++;return t.first?function(t,n,o){for(;t=t[r];)if(1===t.nodeType||i)return e(t,n,o)}:function(t,n,s){var a,u,l=[W,o];if(s){for(;t=t[r];)if((1===t.nodeType||i)&&e(t,n,s))return!0}else for(;t=t[r];)if(1===t.nodeType||i){if(u=t[R]||(t[R]={}),(a=u[r])&&a[0]===W&&a[1]===o)return l[2]=a[2];if(u[r]=l,l[2]=e(t,n,s))return!0}}}function h(e){return e.length>1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,t,n,r,i){for(var o,s=[],a=0,u=e.length,l=null!=t;a<u;a++)(o=e[a])&&(n&&!n(o,r,i)||(s.push(o),l&&t.push(a)));return s}function m(e,n,i,o,s,a){return o&&!o[R]&&(o=m(o)),s&&!s[R]&&(s=m(s,a)),r(function(r,a,u,l){var c,f,p,d=[],h=[],m=a.length,v=r||function(e,n,r){for(var i=0,o=n.length;i<o;i++)t(e,n[i],r);return r}(n||"*",u.nodeType?[u]:u,[]),y=!e||!r&&n?v:g(v,d,e,u,l),x=i?s||(r?e:m||o)?[]:a:y;if(i&&i(y,x,u,l),o)for(c=g(x,h),o(c,[],u,l),f=c.length;f--;)(p=c[f])&&(x[h[f]]=!(y[h[f]]=p));if(r){if(s||e){if(s){for(c=[],f=x.length;f--;)(p=x[f])&&c.push(y[f]=p);s(null,x=[],c,l)}for(f=x.length;f--;)(p=x[f])&&(c=s?K(r,p):d[f])>-1&&(r[c]=!(a[c]=p))}}else x=g(x===a?x.splice(m,x.length):x),s?s(null,a,x,l):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=b.relative[e[0].type],s=o||b.relative[" "],a=o?1:0,u=d(function(e){return e===t},s,!0),l=d(function(e){return K(t,e)>-1},s,!0),c=[function(e,n,r){var i=!o&&(r||n!==E)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];a<i;a++)if(n=b.relative[e[a].type])c=[d(h(c),n)];else{if((n=b.filter[e[a].type].apply(null,e[a].matches))[R]){for(r=++a;r<i&&!b.relative[e[r].type];r++);return m(a>1&&h(c),a>1&&p(e.slice(0,a-1).concat({value:" "===e[a-2].type?"*":""})).replace(se,"$1"),n,a<r&&v(e.slice(a,r)),r<i&&v(e=e.slice(r)),r<i&&p(e))}c.push(n)}return h(c)}var y,x,b,w,T,C,N,k,E,S,D,j,A,L,q,H,O,F,P,R="sizzle"+1*new Date,M=e.document,W=0,$=0,I=n(),B=n(),_=n(),z=function(e,t){return e===t&&(D=!0),0},X=1<<31,U={}.hasOwnProperty,V=[],Y=V.pop,G=V.push,Q=V.push,J=V.slice,K=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},Z="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",ee="[\\x20\\t\\r\\n\\f]",te="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",ne=te.replace("w","w#"),re="\\["+ee+"*("+te+")(?:"+ee+"*([*^$|!~]?=)"+ee+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+ne+"))|)"+ee+"*\\]",ie=":("+te+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+re+")*)|.*)\\)|)",oe=new RegExp(ee+"+","g"),se=new RegExp("^"+ee+"+|((?:^|[^\\\\])(?:\\\\.)*)"+ee+"+$","g"),ae=new RegExp("^"+ee+"*,"+ee+"*"),ue=new RegExp("^"+ee+"*([>+~]|"+ee+")"+ee+"*"),le=new RegExp("="+ee+"*([^\\]'\"]*?)"+ee+"*\\]","g"),ce=new RegExp(ie),fe=new RegExp("^"+ne+"$"),pe={ID:new RegExp("^#("+te+")"),CLASS:new RegExp("^\\.("+te+")"),TAG:new RegExp("^("+te.replace("w","w*")+")"),ATTR:new RegExp("^"+re),PSEUDO:new RegExp("^"+ie),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ee+"*(even|odd|(([+-]|)(\\d*)n|)"+ee+"*(?:([+-]|)"+ee+"*(\\d+)|))"+ee+"*\\)|)","i"),bool:new RegExp("^(?:"+Z+")$","i"),needsContext:new RegExp("^"+ee+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ee+"*((?:-\\d)?\\d*)"+ee+"*\\)|)(?=[^-]|$)","i")},de=/^(?:input|select|textarea|button)$/i,he=/^h\d$/i,ge=/^[^{]+\{\s*\[native \w/,me=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,ye=/'|\\/g,xe=new RegExp("\\\\([\\da-f]{1,6}"+ee+"?|("+ee+")|.)","ig"),be=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},we=function(){j()};try{Q.apply(V=J.call(M.childNodes),M.childNodes),V[M.childNodes.length].nodeType}catch(e){Q={apply:V.length?function(e,t){G.apply(e,J.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}x=t.support={},T=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},j=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:M;return r!==A&&9===r.nodeType&&r.documentElement?(A=r,L=r.documentElement,(n=r.defaultView)&&n!==n.top&&(n.addEventListener?n.addEventListener("unload",we,!1):n.attachEvent&&n.attachEvent("onunload",we)),q=!T(r),x.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),x.getElementsByTagName=i(function(e){return e.appendChild(r.createComment("")),!e.getElementsByTagName("*").length}),x.getElementsByClassName=ge.test(r.getElementsByClassName),x.getById=i(function(e){return L.appendChild(e).id=R,!r.getElementsByName||!r.getElementsByName(R).length}),x.getById?(b.find.ID=function(e,t){if(void 0!==t.getElementById&&q){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},b.filter.ID=function(e){var t=e.replace(xe,be);return function(e){return e.getAttribute("id")===t}}):(delete b.find.ID,b.filter.ID=function(e){var t=e.replace(xe,be);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),b.find.TAG=x.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):x.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=x.getElementsByClassName&&function(e,t){if(q)return t.getElementsByClassName(e)},O=[],H=[],(x.qsa=ge.test(r.querySelectorAll))&&(i(function(e){L.appendChild(e).innerHTML="<a id='"+R+"'></a><select id='"+R+"-\f]' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&H.push("[*^$]="+ee+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||H.push("\\["+ee+"*(?:value|"+Z+")"),e.querySelectorAll("[id~="+R+"-]").length||H.push("~="),e.querySelectorAll(":checked").length||H.push(":checked"),e.querySelectorAll("a#"+R+"+*").length||H.push(".#.+[+~]")}),i(function(e){var t=r.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&H.push("name"+ee+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||H.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),H.push(",.*:")})),(x.matchesSelector=ge.test(F=L.matches||L.webkitMatchesSelector||L.mozMatchesSelector||L.oMatchesSelector||L.msMatchesSelector))&&i(function(e){x.disconnectedMatch=F.call(e,"div"),F.call(e,"[s!='']:x"),O.push("!=",ie)}),H=H.length&&new RegExp(H.join("|")),O=O.length&&new RegExp(O.join("|")),t=ge.test(L.compareDocumentPosition),P=t||ge.test(L.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},z=t?function(e,t){if(e===t)return D=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!x.sortDetached&&t.compareDocumentPosition(e)===n?e===r||e.ownerDocument===M&&P(M,e)?-1:t===r||t.ownerDocument===M&&P(M,t)?1:S?K(S,e)-K(S,t):0:4&n?-1:1)}:function(e,t){if(e===t)return D=!0,0;var n,i=0,o=e.parentNode,a=t.parentNode,u=[e],l=[t];if(!o||!a)return e===r?-1:t===r?1:o?-1:a?1:S?K(S,e)-K(S,t):0;if(o===a)return s(e,t);for(n=e;n=n.parentNode;)u.unshift(n);for(n=t;n=n.parentNode;)l.unshift(n);for(;u[i]===l[i];)i++;return i?s(u[i],l[i]):u[i]===M?-1:l[i]===M?1:0},r):A},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==A&&j(e),n=n.replace(le,"='$1']"),x.matchesSelector&&q&&(!O||!O.test(n))&&(!H||!H.test(n)))try{var r=F.call(e,n);if(r||x.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return t(n,A,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==A&&j(e),P(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==A&&j(e);var n=b.attrHandle[t.toLowerCase()],r=n&&U.call(b.attrHandle,t.toLowerCase())?n(e,t,!q):void 0;return void 0!==r?r:x.attributes||!q?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(D=!x.detectDuplicates,S=!x.sortStable&&e.slice(0),e.sort(z),D){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return S=null,e},w=t.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=w(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=w(t);return n},(b=t.selectors={cacheLength:50,createPseudo:r,match:pe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(xe,be),e[3]=(e[3]||e[4]||e[5]||"").replace(xe,be),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&ce.test(n)&&(t=C(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(xe,be).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=I[e+" "];return t||(t=new RegExp("(^|"+ee+")"+e+"("+ee+"|$)"))&&I(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(oe," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,v=a&&t.nodeName.toLowerCase(),y=!u&&!a;if(m){if(o){for(;g;){for(f=t;f=f[g];)if(a?f.nodeName.toLowerCase()===v:1===f.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[s?m.firstChild:m.lastChild],s&&y){for(d=(l=(c=m[R]||(m[R]={}))[e]||[])[0]===W&&l[1],p=l[0]===W&&l[2],f=d&&m.childNodes[d];f=++d&&f&&f[g]||(p=d=0)||h.pop();)if(1===f.nodeType&&++p&&f===t){c[e]=[W,d,p];break}}else if(y&&(l=(t[R]||(t[R]={}))[e])&&l[0]===W)p=l[1];else for(;(f=++d&&f&&f[g]||(p=d=0)||h.pop())&&((a?f.nodeName.toLowerCase()!==v:1!==f.nodeType)||!++p||(y&&((f[R]||(f[R]={}))[e]=[W,p]),f!==t)););return(p-=i)===r||p%r==0&&p/r>=0}}},PSEUDO:function(e,n){var i,o=b.pseudos[e]||b.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[R]?o(n):o.length>1?(i=[e,e,"",n],b.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),s=i.length;s--;)e[r=K(e,i[s])]=!(t[r]=i[s])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=N(e.replace(se,"$1"));return i[R]?r(function(e,t,n,r){for(var o,s=i(e,null,r,[]),a=e.length;a--;)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(xe,be),function(t){return(t.textContent||t.innerText||w(t)).indexOf(e)>-1}}),lang:r(function(e){return fe.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(xe,be).toLowerCase(),function(t){var n;do{if(n=q?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===L},focus:function(e){return e===A.activeElement&&(!A.hasFocus||A.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return!1===e.disabled},disabled:function(e){return!0===e.disabled},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return he.test(e.nodeName)},input:function(e){return de.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:l(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:l(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq;for(y in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[y]=a(y);for(y in{submit:!0,reset:!0})b.pseudos[y]=u(y);return f.prototype=b.filters=b.pseudos,b.setFilters=new f,C=t.tokenize=function(e,n){var r,i,o,s,a,u,l,c=B[e+" "];if(c)return n?0:c.slice(0);for(a=e,u=[],l=b.preFilter;a;){r&&!(i=ae.exec(a))||(i&&(a=a.slice(i[0].length)||a),u.push(o=[])),r=!1,(i=ue.exec(a))&&(r=i.shift(),o.push({value:r,type:i[0].replace(se," ")}),a=a.slice(r.length));for(s in b.filter)!(i=pe[s].exec(a))||l[s]&&!(i=l[s](i))||(r=i.shift(),o.push({value:r,type:s,matches:i}),a=a.slice(r.length));if(!r)break}return n?a.length:a?t.error(e):B(e,u).slice(0)},N=t.compile=function(e,n){var i,o=[],s=[],a=_[e+" "];if(!a){for(n||(n=C(e)),i=n.length;i--;)(a=v(n[i]))[R]?o.push(a):s.push(a);(a=_(e,function(e,n){var i=n.length>0,o=e.length>0,s=function(r,s,a,u,l){var c,f,p,d=0,h="0",m=r&&[],v=[],y=E,x=r||o&&b.find.TAG("*",l),w=W+=null==y?1:Math.random()||.1,T=x.length;for(l&&(E=s!==A&&s);h!==T&&null!=(c=x[h]);h++){if(o&&c){for(f=0;p=e[f++];)if(p(c,s,a)){u.push(c);break}l&&(W=w)}i&&((c=!p&&c)&&d--,r&&m.push(c))}if(d+=h,i&&h!==d){for(f=0;p=n[f++];)p(m,v,s,a);if(r){if(d>0)for(;h--;)m[h]||v[h]||(v[h]=Y.call(u));v=g(v)}Q.apply(u,v),l&&!r&&v.length>0&&d+n.length>1&&t.uniqueSort(u)}return l&&(W=w,E=y),m};return i?r(s):s}(s,o))).selector=e}return a},k=t.select=function(e,t,n,r){var i,o,s,a,u,l="function"==typeof e&&e,f=!r&&C(e=l.selector||e);if(n=n||[],1===f.length){if((o=f[0]=f[0].slice(0)).length>2&&"ID"===(s=o[0]).type&&x.getById&&9===t.nodeType&&q&&b.relative[o[1].type]){if(!(t=(b.find.ID(s.matches[0].replace(xe,be),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(s=o[i],!b.relative[a=s.type]);)if((u=b.find[a])&&(r=u(s.matches[0].replace(xe,be),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&p(o)))return Q.apply(n,r),n;break}}return(l||N(e,f))(r,t,!q,n,ve.test(e)&&c(t.parentNode)||t),n},x.sortStable=R.split("").sort(z).join("")===R,x.detectDuplicates=!!D,j(),x.sortDetached=i(function(e){return 1&e.compareDocumentPosition(A.createElement("div"))}),i(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),x.attributes&&i(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(Z,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);V.find=K,V.expr=K.selectors,V.expr[":"]=V.expr.pseudos,V.unique=K.uniqueSort,V.text=K.getText,V.isXMLDoc=K.isXML,V.contains=K.contains;var Z=V.expr.match.needsContext,ee=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,te=/^.[^:#\[\.,]*$/;V.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?V.find.matchesSelector(r,e)?[r]:[]:V.find.matches(e,V.grep(t,function(e){return 1===e.nodeType}))},V.fn.extend({find:function(e){var t,n=this.length,r=[],i=this;if("string"!=typeof e)return this.pushStack(V(e).filter(function(){for(t=0;t<n;t++)if(V.contains(i[t],this))return!0}));for(t=0;t<n;t++)V.find(e,i[t],r);return r=this.pushStack(n>1?V.unique(r):r),r.selector=this.selector?this.selector+" "+e:e,r},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,"string"==typeof e&&Z.test(e)?V(e):e||[],!1).length}});var ne,re=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;(V.fn.init=function(e,t){var n,r;if(!e)return this;if("string"==typeof e){if(!(n="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:re.exec(e))||!n[1]&&t)return!t||t.jquery?(t||ne).find(e):this.constructor(t).find(e);if(n[1]){if(t=t instanceof V?t[0]:t,V.merge(this,V.parseHTML(n[1],t&&t.nodeType?t.ownerDocument||t:U,!0)),ee.test(n[1])&&V.isPlainObject(t))for(n in t)V.isFunction(this[n])?this[n](t[n]):this.attr(n,t[n]);return this}return(r=U.getElementById(n[2]))&&r.parentNode&&(this.length=1,this[0]=r),this.context=U,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):V.isFunction(e)?void 0!==ne.ready?ne.ready(e):e(V):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),V.makeArray(e,this))}).prototype=V.fn,ne=V(U);var ie=/^(?:parents|prev(?:Until|All))/,oe={children:!0,contents:!0,next:!0,prev:!0};V.extend({dir:function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&V(e).is(n))break;r.push(e)}return r},sibling:function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}}),V.fn.extend({has:function(e){var t=V(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(V.contains(this,t[e]))return!0})},closest:function(e,t){for(var n,r=0,i=this.length,o=[],s=Z.test(e)||"string"!=typeof e?V(e,t||this.context):0;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(s?s.index(n)>-1:1===n.nodeType&&V.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?V.unique(o):o)},index:function(e){return e?"string"==typeof e?I.call(V(e),this[0]):I.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(V.unique(V.merge(this.get(),V(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),V.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return V.dir(e,"parentNode")},parentsUntil:function(e,t,n){return V.dir(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return V.dir(e,"nextSibling")},prevAll:function(e){return V.dir(e,"previousSibling")},nextUntil:function(e,t,n){return V.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return V.dir(e,"previousSibling",n)},siblings:function(e){return V.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return V.sibling(e.firstChild)},contents:function(e){return e.contentDocument||V.merge([],e.childNodes)}},function(e,t){V.fn[e]=function(n,r){var i=V.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=V.filter(r,i)),this.length>1&&(oe[e]||V.unique(i),ie.test(e)&&i.reverse()),this.pushStack(i)}});var se=/\S+/g,ae={};V.Callbacks=function(e){var t,n,r,i,o,s,a=[],u=!(e="string"==typeof e?ae[e]||function(e){var t=ae[e]={};return V.each(e.match(se)||[],function(e,n){t[n]=!0}),t}(e):V.extend({},e)).once&&[],l=function(f){for(t=e.memory&&f,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&s<o;s++)if(!1===a[s].apply(f[0],f[1])&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;!function t(n){V.each(n,function(n,r){var i=V.type(r);"function"===i?e.unique&&c.has(r)||a.push(r):r&&r.length&&"string"!==i&&t(r)})}(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&V.each(arguments,function(e,t){for(var n;(n=V.inArray(t,a,n))>-1;)a.splice(n,1),r&&(n<=o&&o--,n<=s&&s--)}),this},has:function(e){return e?V.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=void 0,this},disabled:function(){return!a},lock:function(){return u=void 0,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=[e,(t=t||[]).slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},V.extend({Deferred:function(e){var t=[["resolve","done",V.Callbacks("once memory"),"resolved"],["reject","fail",V.Callbacks("once memory"),"rejected"],["notify","progress",V.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return V.Deferred(function(n){V.each(t,function(t,o){var s=V.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&V.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[o[0]+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?V.extend(e,r):r}},i={};return r.pipe=r.then,V.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=M.call(arguments),s=o.length,a=1!==s||e&&V.isFunction(e.promise)?s:0,u=1===a?e:V.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?M.call(arguments):i,r===t?u.notifyWith(n,r):--a||u.resolveWith(n,r)}};if(s>1)for(t=new Array(s),n=new Array(s),r=new Array(s);i<s;i++)o[i]&&V.isFunction(o[i].promise)?o[i].promise().done(l(i,r,o)).fail(u.reject).progress(l(i,n,t)):--a;return a||u.resolveWith(r,o),u.promise()}});var ue;V.fn.ready=function(e){return V.ready.promise().done(e),this},V.extend({isReady:!1,readyWait:1,holdReady:function(e){e?V.readyWait++:V.ready(!0)},ready:function(e){(!0===e?--V.readyWait:V.isReady)||(V.isReady=!0,!0!==e&&--V.readyWait>0||(ue.resolveWith(U,[V]),V.fn.triggerHandler&&(V(U).triggerHandler("ready"),V(U).off("ready"))))}}),V.ready.promise=function(t){return ue||(ue=V.Deferred(),"complete"===U.readyState?setTimeout(V.ready):(U.addEventListener("DOMContentLoaded",o,!1),e.addEventListener("load",o,!1))),ue.promise(t)},V.ready.promise();var le=V.access=function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===V.type(n)){i=!0;for(a in n)V.access(e,t,a,n[a],!0,o,s)}else if(void 0!==r&&(i=!0,V.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(V(e),n)})),t))for(;a<u;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o};V.acceptData=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType},s.uid=1,s.accepts=V.acceptData,s.prototype={key:function(e){if(!s.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=s.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,V.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(V.isEmptyObject(o))V.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return void 0===t?n:n[t]},access:function(e,t,n){var r;return void 0===t||t&&"string"==typeof t&&void 0===n?void 0!==(r=this.get(e,t))?r:this.get(e,V.camelCase(t)):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(void 0===t)this.cache[o]={};else{V.isArray(t)?r=t.concat(t.map(V.camelCase)):(i=V.camelCase(t),r=t in s?[t,i]:(r=i)in s?[r]:r.match(se)||[]),n=r.length;for(;n--;)delete s[r[n]]}},hasData:function(e){return!V.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}};var ce=new s,fe=new s,pe=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,de=/([A-Z])/g;V.extend({hasData:function(e){return fe.hasData(e)||ce.hasData(e)},data:function(e,t,n){return fe.access(e,t,n)},removeData:function(e,t){fe.remove(e,t)},_data:function(e,t,n){return ce.access(e,t,n)},_removeData:function(e,t){ce.remove(e,t)}}),V.fn.extend({data:function(e,t){var n,r,i,o=this[0],s=o&&o.attributes;if(void 0===e){if(this.length&&(i=fe.get(o),1===o.nodeType&&!ce.get(o,"hasDataAttrs"))){for(n=s.length;n--;)s[n]&&0===(r=s[n].name).indexOf("data-")&&(r=V.camelCase(r.slice(5)),a(o,r,i[r]));ce.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof e?this.each(function(){fe.set(this,e)}):le(this,function(t){var n,r=V.camelCase(e);if(o&&void 0===t){if(void 0!==(n=fe.get(o,e)))return n;if(void 0!==(n=fe.get(o,r)))return n;if(void 0!==(n=a(o,r,void 0)))return n}else this.each(function(){var n=fe.get(this,r);fe.set(this,r,t),-1!==e.indexOf("-")&&void 0!==n&&fe.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){fe.remove(this,e)})}}),V.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=ce.get(e,t),n&&(!r||V.isArray(n)?r=ce.access(e,t,V.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=V.queue(e,t),r=n.length,i=n.shift(),o=V._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){V.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return ce.get(e,n)||ce.access(e,n,{empty:V.Callbacks("once memory").add(function(){ce.remove(e,[t+"queue",n])})})}}),V.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length<n?V.queue(this[0],e):void 0===t?this:this.each(function(){var n=V.queue(this,e,t);V._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&V.dequeue(this,e)})},dequeue:function(e){return this.each(function(){V.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=V.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};for("string"!=typeof e&&(t=e,e=void 0),e=e||"fx";s--;)(n=ce.get(o[s],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var he=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ge=["Top","Right","Bottom","Left"],me=function(e,t){return e=t||e,"none"===V.css(e,"display")||!V.contains(e.ownerDocument,e)},ve=/^(?:checkbox|radio)$/i;!function(){var e=U.createDocumentFragment().appendChild(U.createElement("div")),t=U.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),X.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="<textarea>x</textarea>",X.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var ye="undefined";X.focusinBubbles="onfocusin"in e;var xe=/^key/,be=/^(?:mouse|pointer|contextmenu)|click/,we=/^(?:focusinfocus|focusoutblur)$/,Te=/^([^.]*)(?:\.(.+)|)$/;V.event={global:{},add:function(e,t,n,r,i){var o,s,a,u,l,c,f,p,d,h,g,m=ce.get(e);if(m)for(n.handler&&(n=(o=n).handler,i=o.selector),n.guid||(n.guid=V.guid++),(u=m.events)||(u=m.events={}),(s=m.handle)||(s=m.handle=function(t){return typeof V!==ye&&V.event.triggered!==t.type?V.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(se)||[""]).length;l--;)d=g=(a=Te.exec(t[l])||[])[1],h=(a[2]||"").split(".").sort(),d&&(f=V.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=V.event.special[d]||{},c=V.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&V.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,s)||e.addEventListener&&e.addEventListener(d,s,!1)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),V.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,s,a,u,l,c,f,p,d,h,g,m=ce.hasData(e)&&ce.get(e);if(m&&(u=m.events)){for(l=(t=(t||"").match(se)||[""]).length;l--;)if(a=Te.exec(t[l])||[],d=g=a[1],h=(a[2]||"").split(".").sort(),d){for(f=V.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],a=a[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));s&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,m.handle)||V.removeEvent(e,d,m.handle),delete u[d])}else for(d in u)V.event.remove(e,d+t[l],n,r,!0);V.isEmptyObject(u)&&(delete m.handle,ce.remove(e,"events"))}},trigger:function(t,n,r,i){var o,s,a,u,l,c,f,p=[r||U],d=z.call(t,"type")?t.type:t,h=z.call(t,"namespace")?t.namespace.split("."):[];if(s=a=r=r||U,3!==r.nodeType&&8!==r.nodeType&&!we.test(d+V.event.triggered)&&(d.indexOf(".")>=0&&(d=(h=d.split(".")).shift(),h.sort()),l=d.indexOf(":")<0&&"on"+d,t=t[V.expando]?t:new V.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join("."),t.namespace_re=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:V.makeArray(n,[t]),f=V.event.special[d]||{},i||!f.trigger||!1!==f.trigger.apply(r,n))){if(!i&&!f.noBubble&&!V.isWindow(r)){for(u=f.delegateType||d,we.test(u+d)||(s=s.parentNode);s;s=s.parentNode)p.push(s),a=s;a===(r.ownerDocument||U)&&p.push(a.defaultView||a.parentWindow||e)}for(o=0;(s=p[o++])&&!t.isPropagationStopped();)t.type=o>1?u:f.bindType||d,(c=(ce.get(s,"events")||{})[t.type]&&ce.get(s,"handle"))&&c.apply(s,n),(c=l&&s[l])&&c.apply&&V.acceptData(s)&&(t.result=c.apply(s,n),!1===t.result&&t.preventDefault());return t.type=d,i||t.isDefaultPrevented()||f._default&&!1!==f._default.apply(p.pop(),n)||!V.acceptData(r)||l&&V.isFunction(r[d])&&!V.isWindow(r)&&((a=r[l])&&(r[l]=null),V.event.triggered=d,r[d](),V.event.triggered=void 0,a&&(r[l]=a)),t.result}},dispatch:function(e){e=V.event.fix(e);var t,n,r,i,o,s=[],a=M.call(arguments),u=(ce.get(this,"events")||{})[e.type]||[],l=V.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||!1!==l.preDispatch.call(this,e)){for(s=V.event.handlers.call(this,e,u),t=0;(i=s[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.namespace_re&&!e.namespace_re.test(o.namespace)||(e.handleObj=o,e.data=o.data,void 0!==(r=((V.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a))&&!1===(e.result=r)&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(!0!==u.disabled||"click"!==e.type){for(r=[],n=0;n<a;n++)void 0===r[i=(o=t[n]).selector+" "]&&(r[i]=o.needsContext?V(i,this).index(u)>=0:V.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return a<t.length&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,o=t.button;return null==e.pageX&&null!=t.clientX&&(r=(n=e.target.ownerDocument||U).documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||void 0===o||(e.which=1&o?1:2&o?3:4&o?2:0),e}},fix:function(e){if(e[V.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];for(s||(this.fixHooks[i]=s=be.test(i)?this.mouseHooks:xe.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new V.Event(o),t=r.length;t--;)e[n=r[t]]=o[n];return e.target||(e.target=U),3===e.target.nodeType&&(e.target=e.target.parentNode),s.filter?s.filter(e,o):e},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==c()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===c()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&V.nodeName(this,"input"))return this.click(),!1},_default:function(e){return V.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=V.extend(new V.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?V.event.trigger(i,null,t):V.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},V.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},V.Event=function(e,t){if(!(this instanceof V.Event))return new V.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?u:l):this.type=e,t&&V.extend(this,t),this.timeStamp=e&&e.timeStamp||V.now(),this[V.expando]=!0},V.Event.prototype={isDefaultPrevented:l,isPropagationStopped:l,isImmediatePropagationStopped:l,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=u,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=u,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=u,e&&e.stopImmediatePropagation&&e.stopImmediatePropagation(),this.stopPropagation()}},V.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,t){V.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=e.relatedTarget,i=e.handleObj;return r&&(r===this||V.contains(this,r))||(e.type=i.origType,n=i.handler.apply(this,arguments),e.type=t),n}}}),X.focusinBubbles||V.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){V.event.simulate(t,e.target,V.event.fix(e),!0)};V.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=ce.access(r,t);i||r.addEventListener(e,n,!0),ce.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=ce.access(r,t)-1;i?ce.access(r,t,i):(r.removeEventListener(e,n,!0),ce.remove(r,t))}}}),V.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=void 0);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=void 0):null==r&&("string"==typeof t?(r=n,n=void 0):(r=n,n=t,t=void 0)),!1===r)r=l;else if(!r)return this;return 1===i&&(o=r,(r=function(e){return V().off(e),o.apply(this,arguments)}).guid=o.guid||(o.guid=V.guid++)),this.each(function(){V.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,V(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=l),this.each(function(){V.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){V.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return V.event.trigger(e,t,n,!0)}});var Ce=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Ne=/<([\w:]+)/,ke=/<|&#?\w+;/,Ee=/<(?:script|style|link)/i,Se=/checked\s*(?:[^=]|=\s*.checked.)/i,De=/^$|\/(?:java|ecma)script/i,je=/^true\/(.*)/,Ae=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,Le={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};Le.optgroup=Le.option,Le.tbody=Le.tfoot=Le.colgroup=Le.caption=Le.thead,Le.th=Le.td,V.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=V.contains(e.ownerDocument,e);if(!(X.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||V.isXMLDoc(e)))for(s=m(a),r=0,i=(o=m(e)).length;r<i;r++)v(o[r],s[r]);if(t)if(n)for(o=o||m(e),s=s||m(a),r=0,i=o.length;r<i;r++)g(o[r],s[r]);else g(e,a);return(s=m(a,"script")).length>0&&h(s,!u&&m(e,"script")),a},buildFragment:function(e,t,n,r){for(var i,o,s,a,u,l,c=t.createDocumentFragment(),f=[],p=0,d=e.length;p<d;p++)if((i=e[p])||0===i)if("object"===V.type(i))V.merge(f,i.nodeType?[i]:i);else if(ke.test(i)){for(o=o||c.appendChild(t.createElement("div")),s=(Ne.exec(i)||["",""])[1].toLowerCase(),a=Le[s]||Le._default,o.innerHTML=a[1]+i.replace(Ce,"<$1></$2>")+a[2],l=a[0];l--;)o=o.lastChild;V.merge(f,o.childNodes),(o=c.firstChild).textContent=""}else f.push(t.createTextNode(i));for(c.textContent="",p=0;i=f[p++];)if((!r||-1===V.inArray(i,r))&&(u=V.contains(i.ownerDocument,i),o=m(c.appendChild(i),"script"),u&&h(o),n))for(l=0;i=o[l++];)De.test(i.type||"")&&n.push(i);return c},cleanData:function(e){for(var t,n,r,i,o=V.event.special,s=0;void 0!==(n=e[s]);s++){if(V.acceptData(n)&&(i=n[ce.expando])&&(t=ce.cache[i])){if(t.events)for(r in t.events)o[r]?V.event.remove(n,r):V.removeEvent(n,r,t.handle);ce.cache[i]&&delete ce.cache[i]}delete fe.cache[n[fe.expando]]}}}),V.fn.extend({text:function(e){return le(this,function(e){return void 0===e?V.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){f(this,e).appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=f(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){for(var n,r=e?V.filter(e,this):this,i=0;null!=(n=r[i]);i++)t||1!==n.nodeType||V.cleanData(m(n)),n.parentNode&&(t&&V.contains(n.ownerDocument,n)&&h(m(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(V.cleanData(m(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return V.clone(this,e,t)})},html:function(e){return le(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ee.test(e)&&!Le[(Ne.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(Ce,"<$1></$2>");try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(V.cleanData(m(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=arguments[0];return this.domManip(arguments,function(t){e=this.parentNode,V.cleanData(m(this)),e&&e.replaceChild(t,this)}),e&&(e.length||e.nodeType)?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t){e=W.apply([],e);var n,r,i,o,s,a,u=0,l=this.length,c=this,f=l-1,h=e[0],g=V.isFunction(h);if(g||l>1&&"string"==typeof h&&!X.checkClone&&Se.test(h))return this.each(function(n){var r=c.eq(n);g&&(e[0]=h.call(this,n,r.html())),r.domManip(e,t)});if(l&&(n=V.buildFragment(e,this[0].ownerDocument,!1,this),r=n.firstChild,1===n.childNodes.length&&(n=r),r)){for(o=(i=V.map(m(n,"script"),p)).length;u<l;u++)s=n,u!==f&&(s=V.clone(s,!0,!0),o&&V.merge(i,m(s,"script"))),t.call(this[u],s,u);if(o)for(a=i[i.length-1].ownerDocument,V.map(i,d),u=0;u<o;u++)s=i[u],De.test(s.type||"")&&!ce.access(s,"globalEval")&&V.contains(a,s)&&(s.src?V._evalUrl&&V._evalUrl(s.src):V.globalEval(s.textContent.replace(Ae,"")))}return this}}),V.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){V.fn[e]=function(e){for(var n,r=[],i=V(e),o=i.length-1,s=0;s<=o;s++)n=s===o?this:this.clone(!0),V(i[s])[t](n),$.apply(r,n.get());return this.pushStack(r)}});var qe,He={},Oe=/^margin/,Fe=new RegExp("^("+he+")(?!px)[a-z%]+$","i"),Pe=function(t){return t.ownerDocument.defaultView.opener?t.ownerDocument.defaultView.getComputedStyle(t,null):e.getComputedStyle(t,null)};!function(){function t(){s.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",s.innerHTML="",i.appendChild(o);var t=e.getComputedStyle(s,null);n="1%"!==t.top,r="4px"===t.width,i.removeChild(o)}var n,r,i=U.documentElement,o=U.createElement("div"),s=U.createElement("div");s.style&&(s.style.backgroundClip="content-box",s.cloneNode(!0).style.backgroundClip="",X.clearCloneStyle="content-box"===s.style.backgroundClip,o.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",o.appendChild(s),e.getComputedStyle&&V.extend(X,{pixelPosition:function(){return t(),n},boxSizingReliable:function(){return null==r&&t(),r},reliableMarginRight:function(){var t,n=s.appendChild(U.createElement("div"));return n.style.cssText=s.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",n.style.marginRight=n.style.width="0",s.style.width="1px",i.appendChild(o),t=!parseFloat(e.getComputedStyle(n,null).marginRight),i.removeChild(o),s.removeChild(n),t}}))}(),V.swap=function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i};var Re=/^(none|table(?!-c[ea]).+)/,Me=new RegExp("^("+he+")(.*)$","i"),We=new RegExp("^([+-])=("+he+")","i"),$e={position:"absolute",visibility:"hidden",display:"block"},Ie={letterSpacing:"0",fontWeight:"400"},Be=["Webkit","O","Moz","ms"];V.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=b(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{float:"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=V.camelCase(t),u=e.style;if(t=V.cssProps[a]||(V.cssProps[a]=T(u,a)),s=V.cssHooks[t]||V.cssHooks[a],void 0===n)return s&&"get"in s&&void 0!==(i=s.get(e,!1,r))?i:u[t];"string"==(o=typeof n)&&(i=We.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(V.css(e,t)),o="number"),null!=n&&n==n&&("number"!==o||V.cssNumber[a]||(n+="px"),X.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&void 0===(n=s.set(e,n,r))||(u[t]=n))}},css:function(e,t,n,r){var i,o,s,a=V.camelCase(t);return t=V.cssProps[a]||(V.cssProps[a]=T(e.style,a)),(s=V.cssHooks[t]||V.cssHooks[a])&&"get"in s&&(i=s.get(e,!0,n)),void 0===i&&(i=b(e,t,r)),"normal"===i&&t in Ie&&(i=Ie[t]),""===n||n?(o=parseFloat(i),!0===n||V.isNumeric(o)?o||0:i):i}}),V.each(["height","width"],function(e,t){V.cssHooks[t]={get:function(e,n,r){if(n)return Re.test(V.css(e,"display"))&&0===e.offsetWidth?V.swap(e,$e,function(){return k(e,t,r)}):k(e,t,r)},set:function(e,n,r){var i=r&&Pe(e);return C(0,n,r?N(e,t,r,"border-box"===V.css(e,"boxSizing",!1,i),i):0)}}}),V.cssHooks.marginRight=w(X.reliableMarginRight,function(e,t){if(t)return V.swap(e,{display:"inline-block"},b,[e,"marginRight"])}),V.each({margin:"",padding:"",border:"Width"},function(e,t){V.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+ge[r]+t]=o[r]||o[r-2]||o[0];return i}},Oe.test(e)||(V.cssHooks[e+t].set=C)}),V.fn.extend({css:function(e,t){return le(this,function(e,t,n){var r,i,o={},s=0;if(V.isArray(t)){for(r=Pe(e),i=t.length;s<i;s++)o[t[s]]=V.css(e,t[s],!1,r);return o}return void 0!==n?V.style(e,t,n):V.css(e,t)},e,t,arguments.length>1)},show:function(){return E(this,!0)},hide:function(){return E(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){me(this)?V(this).show():V(this).hide()})}}),V.Tween=S,(S.prototype={constructor:S,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(V.cssNumber[n]?"":"px")},cur:function(){var e=S.propHooks[this.prop];return e&&e.get?e.get(this):S.propHooks._default.get(this)},run:function(e){var t,n=S.propHooks[this.prop];return this.options.duration?this.pos=t=V.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):S.propHooks._default.set(this),this}}).init.prototype=S.prototype,(S.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=V.css(e.elem,e.prop,""))&&"auto"!==t?t:0:e.elem[e.prop]},set:function(e){V.fx.step[e.prop]?V.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[V.cssProps[e.prop]]||V.cssHooks[e.prop])?V.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}}).scrollTop=S.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},V.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},V.fx=S.prototype.init,V.fx.step={};var _e,ze,Xe=/^(?:toggle|show|hide)$/,Ue=new RegExp("^(?:([+-])=|)("+he+")([a-z%]*)$","i"),Ve=/queueHooks$/,Ye=[function(e,t,n){var r,i,o,s,a,u,l,c=this,f={},p=e.style,d=e.nodeType&&me(e),h=ce.get(e,"fxshow");n.queue||(null==(a=V._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,u=a.empty.fire,a.empty.fire=function(){a.unqueued||u()}),a.unqueued++,c.always(function(){c.always(function(){a.unqueued--,V.queue(e,"fx").length||a.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===("none"===(l=V.css(e,"display"))?ce.get(e,"olddisplay")||x(e.nodeName):l)&&"none"===V.css(e,"float")&&(p.display="inline-block")),n.overflow&&(p.overflow="hidden",c.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Xe.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(d?"hide":"show")){if("show"!==i||!h||void 0===h[r])continue;d=!0}f[r]=h&&h[r]||V.style(e,r)}else l=void 0;if(V.isEmptyObject(f))"inline"===("none"===l?x(e.nodeName):l)&&(p.display=l);else{h?"hidden"in h&&(d=h.hidden):h=ce.access(e,"fxshow",{}),o&&(h.hidden=!d),d?V(e).show():c.done(function(){V(e).hide()}),c.done(function(){var t;ce.remove(e,"fxshow");for(t in f)V.style(e,t,f[t])});for(r in f)s=A(d?h[r]:0,r,c),r in h||(h[r]=s.start,d&&(s.end=s.start,s.start="width"===r||"height"===r?1:0))}}],Ge={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Ue.exec(t),o=i&&i[3]||(V.cssNumber[e]?"":"px"),s=(V.cssNumber[e]||"px"!==o&&+r)&&Ue.exec(V.css(n.elem,e)),a=1,u=20;if(s&&s[3]!==o){o=o||s[3],i=i||[],s=+r||1;do{s/=a=a||".5",V.style(n.elem,e,s+o)}while(a!==(a=n.cur()/r)&&1!==a&&--u)}return i&&(s=n.start=+s||+r||0,n.unit=o,n.end=i[1]?s+(i[1]+1)*i[2]:+i[2]),n}]};V.Animation=V.extend(L,{tweener:function(e,t){V.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");for(var n,r=0,i=e.length;r<i;r++)n=e[r],Ge[n]=Ge[n]||[],Ge[n].unshift(t)},prefilter:function(e,t){t?Ye.unshift(e):Ye.push(e)}}),V.speed=function(e,t,n){var r=e&&"object"==typeof e?V.extend({},e):{complete:n||!n&&t||V.isFunction(e)&&e,duration:e,easing:n&&t||t&&!V.isFunction(t)&&t};return r.duration=V.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in V.fx.speeds?V.fx.speeds[r.duration]:V.fx.speeds._default,null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){V.isFunction(r.old)&&r.old.call(this),r.queue&&V.dequeue(this,r.queue)},r},V.fn.extend({fadeTo:function(e,t,n,r){return this.filter(me).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=V.isEmptyObject(e),o=V.speed(t,n,r),s=function(){var t=L(this,V.extend({},e),o);(i||ce.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||!1===o.queue?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=void 0),t&&!1!==e&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=V.timers,s=ce.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Ve.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));!t&&n||V.dequeue(this,e)})},finish:function(e){return!1!==e&&(e=e||"fx"),this.each(function(){var t,n=ce.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=V.timers,s=r?r.length:0;for(n.finish=!0,V.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;t<s;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}}),V.each(["toggle","show","hide"],function(e,t){var n=V.fn[t];V.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(j(t,!0),e,r,i)}}),V.each({slideDown:j("show"),slideUp:j("hide"),slideToggle:j("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){V.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),V.timers=[],V.fx.tick=function(){var e,t=0,n=V.timers;for(_e=V.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||V.fx.stop(),_e=void 0},V.fx.timer=function(e){V.timers.push(e),e()?V.fx.start():V.timers.pop()},V.fx.interval=13,V.fx.start=function(){ze||(ze=setInterval(V.fx.tick,V.fx.interval))},V.fx.stop=function(){clearInterval(ze),ze=null},V.fx.speeds={slow:600,fast:200,_default:400},V.fn.delay=function(e,t){return e=V.fx?V.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},function(){var e=U.createElement("input"),t=U.createElement("select"),n=t.appendChild(U.createElement("option"));e.type="checkbox",X.checkOn=""!==e.value,X.optSelected=n.selected,t.disabled=!0,X.optDisabled=!n.disabled,(e=U.createElement("input")).value="t",e.type="radio",X.radioValue="t"===e.value}();var Qe,Je=V.expr.attrHandle;V.fn.extend({attr:function(e,t){return le(this,V.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){V.removeAttr(this,e)})}}),V.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(e&&3!==o&&8!==o&&2!==o)return typeof e.getAttribute===ye?V.prop(e,t,n):(1===o&&V.isXMLDoc(e)||(t=t.toLowerCase(),r=V.attrHooks[t]||(V.expr.match.bool.test(t)?Qe:void 0)),void 0===n?r&&"get"in r&&null!==(i=r.get(e,t))?i:null==(i=V.find.attr(e,t))?void 0:i:null!==n?r&&"set"in r&&void 0!==(i=r.set(e,n,t))?i:(e.setAttribute(t,n+""),n):void V.removeAttr(e,t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(se);if(o&&1===e.nodeType)for(;n=o[i++];)r=V.propFix[n]||n,V.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!X.radioValue&&"radio"===t&&V.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}}}),Qe={set:function(e,t,n){return!1===t?V.removeAttr(e,n):e.setAttribute(n,n),n}},V.each(V.expr.match.bool.source.match(/\w+/g),function(e,t){var n=Je[t]||V.find.attr;Je[t]=function(e,t,r){var i,o;return r||(o=Je[t],Je[t]=i,i=null!=n(e,t,r)?t.toLowerCase():null,Je[t]=o),i}});var Ke=/^(?:input|select|textarea|button)$/i;V.fn.extend({prop:function(e,t){return le(this,V.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[V.propFix[e]||e]})}}),V.extend({propFix:{for:"htmlFor",class:"className"},prop:function(e,t,n){var r,i,o=e.nodeType;if(e&&3!==o&&8!==o&&2!==o)return(1!==o||!V.isXMLDoc(e))&&(t=V.propFix[t]||t,i=V.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||Ke.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),X.optSelected||(V.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),V.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){V.propFix[this.toLowerCase()]=this});var Ze=/[\t\r\n\f]/g;V.fn.extend({addClass:function(e){var t,n,r,i,o,s,a="string"==typeof e&&e,u=0,l=this.length;if(V.isFunction(e))return this.each(function(t){V(this).addClass(e.call(this,t,this.className))});if(a)for(t=(e||"").match(se)||[];u<l;u++)if(n=this[u],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Ze," "):" ")){for(o=0;i=t[o++];)r.indexOf(" "+i+" ")<0&&(r+=i+" ");s=V.trim(r),n.className!==s&&(n.className=s)}return this},removeClass:function(e){var t,n,r,i,o,s,a=0===arguments.length||"string"==typeof e&&e,u=0,l=this.length;if(V.isFunction(e))return this.each(function(t){V(this).removeClass(e.call(this,t,this.className))});if(a)for(t=(e||"").match(se)||[];u<l;u++)if(n=this[u],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(Ze," "):"")){for(o=0;i=t[o++];)for(;r.indexOf(" "+i+" ")>=0;)r=r.replace(" "+i+" "," ");s=e?V.trim(r):"",n.className!==s&&(n.className=s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):V.isFunction(e)?this.each(function(n){V(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n)for(var t,r=0,i=V(this),o=e.match(se)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else n!==ye&&"boolean"!==n||(this.className&&ce.set(this,"__className__",this.className),this.className=this.className||!1===e?"":ce.get(this,"__className__")||"")})},hasClass:function(e){for(var t=" "+e+" ",n=0,r=this.length;n<r;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(Ze," ").indexOf(t)>=0)return!0;return!1}});var et=/\r/g;V.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=V.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,V(this).val()):e)?i="":"number"==typeof i?i+="":V.isArray(i)&&(i=V.map(i,function(e){return null==e?"":e+""})),(t=V.valHooks[this.type]||V.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=V.valHooks[i.type]||V.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(et,""):null==n?"":n}}}),V.extend({valHooks:{option:{get:function(e){var t=V.find.attr(e,"value");return null!=t?t:V.trim(V.text(e))}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||i<0,s=o?null:[],a=o?i+1:r.length,u=i<0?a:o?i:0;u<a;u++)if(((n=r[u]).selected||u===i)&&(X.optDisabled?!n.disabled:null===n.getAttribute("disabled"))&&(!n.parentNode.disabled||!V.nodeName(n.parentNode,"optgroup"))){if(t=V(n).val(),o)return t;s.push(t)}return s},set:function(e,t){for(var n,r,i=e.options,o=V.makeArray(t),s=i.length;s--;)((r=i[s]).selected=V.inArray(r.value,o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),V.each(["radio","checkbox"],function(){V.valHooks[this]={set:function(e,t){if(V.isArray(t))return e.checked=V.inArray(V(e).val(),t)>=0}},X.checkOn||(V.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),V.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){V.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),V.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var tt=V.now(),nt=/\?/;V.parseJSON=function(e){return JSON.parse(e+"")},V.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||V.error("Invalid XML: "+e),t};var rt=/#.*$/,it=/([?&])_=[^&]*/,ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,st=/^(?:GET|HEAD)$/,at=/^\/\//,ut=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lt={},ct={},ft="*/".concat("*"),pt=e.location.href,dt=ut.exec(pt.toLowerCase())||[];V.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:pt,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(dt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":ft,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":V.parseJSON,"text xml":V.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?O(O(e,V.ajaxSettings),t):O(V.ajaxSettings,e)},ajaxPrefilter:q(lt),ajaxTransport:q(ct),ajax:function(e,t){function n(e,t,n,s){var u,c,v,y,b,T=t;2!==x&&(x=2,a&&clearTimeout(a),r=void 0,o=s||"",w.readyState=e>0?4:0,u=e>=200&&e<300||304===e,n&&(y=function(e,t,n){for(var r,i,o,s,a=e.contents,u=e.dataTypes;"*"===u[0];)u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}if(o)return o!==u[0]&&u.unshift(o),n[o]}(f,w,n)),y=function(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(s=l[u+" "+o]||l["* "+o]))for(i in l)if((a=i.split(" "))[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){!0===s?s=l[i]:!0!==l[i]&&(o=a[0],c.unshift(a[1]));break}if(!0!==s)if(s&&e.throws)t=s(t);else try{t=s(t)}catch(e){return{state:"parsererror",error:s?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(f,y,w,u),u?(f.ifModified&&((b=w.getResponseHeader("Last-Modified"))&&(V.lastModified[i]=b),(b=w.getResponseHeader("etag"))&&(V.etag[i]=b)),204===e||"HEAD"===f.type?T="nocontent":304===e?T="notmodified":(T=y.state,c=y.data,u=!(v=y.error))):(v=T,!e&&T||(T="error",e<0&&(e=0))),w.status=e,w.statusText=(t||T)+"",u?h.resolveWith(p,[c,T,w]):h.rejectWith(p,[w,T,v]),w.statusCode(m),m=void 0,l&&d.trigger(u?"ajaxSuccess":"ajaxError",[w,f,u?c:v]),g.fireWith(p,[w,T]),l&&(d.trigger("ajaxComplete",[w,f]),--V.active||V.event.trigger("ajaxStop")))}"object"==typeof e&&(t=e,e=void 0),t=t||{};var r,i,o,s,a,u,l,c,f=V.ajaxSetup({},t),p=f.context||f,d=f.context&&(p.nodeType||p.jquery)?V(p):V.event,h=V.Deferred(),g=V.Callbacks("once memory"),m=f.statusCode||{},v={},y={},x=0,b="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(2===x){if(!s)for(s={};t=ot.exec(o);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===x?o:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return x||(e=y[n]=y[n]||e,v[e]=t),this},overrideMimeType:function(e){return x||(f.mimeType=e),this},statusCode:function(e){var t;if(e)if(x<2)for(t in e)m[t]=[m[t],e[t]];else w.always(e[w.status]);return this},abort:function(e){var t=e||b;return r&&r.abort(t),n(0,t),this}};if(h.promise(w).complete=g.add,w.success=w.done,w.error=w.fail,f.url=((e||f.url||pt)+"").replace(rt,"").replace(at,dt[1]+"//"),f.type=t.method||t.type||f.method||f.type,f.dataTypes=V.trim(f.dataType||"*").toLowerCase().match(se)||[""],null==f.crossDomain&&(u=ut.exec(f.url.toLowerCase()),f.crossDomain=!(!u||u[1]===dt[1]&&u[2]===dt[2]&&(u[3]||("http:"===u[1]?"80":"443"))===(dt[3]||("http:"===dt[1]?"80":"443")))),f.data&&f.processData&&"string"!=typeof f.data&&(f.data=V.param(f.data,f.traditional)),H(lt,f,t,w),2===x)return w;(l=V.event&&f.global)&&0==V.active++&&V.event.trigger("ajaxStart"),f.type=f.type.toUpperCase(),f.hasContent=!st.test(f.type),i=f.url,f.hasContent||(f.data&&(i=f.url+=(nt.test(i)?"&":"?")+f.data,delete f.data),!1===f.cache&&(f.url=it.test(i)?i.replace(it,"$1_="+tt++):i+(nt.test(i)?"&":"?")+"_="+tt++)),f.ifModified&&(V.lastModified[i]&&w.setRequestHeader("If-Modified-Since",V.lastModified[i]),V.etag[i]&&w.setRequestHeader("If-None-Match",V.etag[i])),(f.data&&f.hasContent&&!1!==f.contentType||t.contentType)&&w.setRequestHeader("Content-Type",f.contentType),w.setRequestHeader("Accept",f.dataTypes[0]&&f.accepts[f.dataTypes[0]]?f.accepts[f.dataTypes[0]]+("*"!==f.dataTypes[0]?", "+ft+"; q=0.01":""):f.accepts["*"]);for(c in f.headers)w.setRequestHeader(c,f.headers[c]);if(f.beforeSend&&(!1===f.beforeSend.call(p,w,f)||2===x))return w.abort();b="abort";for(c in{success:1,error:1,complete:1})w[c](f[c]);if(r=H(ct,f,t,w)){w.readyState=1,l&&d.trigger("ajaxSend",[w,f]),f.async&&f.timeout>0&&(a=setTimeout(function(){w.abort("timeout")},f.timeout));try{x=1,r.send(v,n)}catch(e){if(!(x<2))throw e;n(-1,e)}}else n(-1,"No Transport");return w},getJSON:function(e,t,n){return V.get(e,t,n,"json")},getScript:function(e,t){return V.get(e,void 0,t,"script")}}),V.each(["get","post"],function(e,t){V[t]=function(e,n,r,i){return V.isFunction(n)&&(i=i||r,r=n,n=void 0),V.ajax({url:e,type:t,dataType:i,data:n,success:r})}}),V._evalUrl=function(e){return V.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,throws:!0})},V.fn.extend({wrapAll:function(e){var t;return V.isFunction(e)?this.each(function(t){V(this).wrapAll(e.call(this,t))}):(this[0]&&(t=V(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return V.isFunction(e)?this.each(function(t){V(this).wrapInner(e.call(this,t))}):this.each(function(){var t=V(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=V.isFunction(e);return this.each(function(n){V(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){V.nodeName(this,"body")||V(this).replaceWith(this.childNodes)}).end()}}),V.expr.filters.hidden=function(e){return e.offsetWidth<=0&&e.offsetHeight<=0},V.expr.filters.visible=function(e){return!V.expr.filters.hidden(e)};var ht=/%20/g,gt=/\[\]$/,mt=/\r?\n/g,vt=/^(?:submit|button|image|reset|file)$/i,yt=/^(?:input|select|textarea|keygen)/i;V.param=function(e,t){var n,r=[],i=function(e,t){t=V.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=V.ajaxSettings&&V.ajaxSettings.traditional),V.isArray(e)||e.jquery&&!V.isPlainObject(e))V.each(e,function(){i(this.name,this.value)});else for(n in e)F(n,e[n],t,i);return r.join("&").replace(ht,"+")},V.fn.extend({serialize:function(){return V.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=V.prop(this,"elements");return e?V.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!V(this).is(":disabled")&&yt.test(this.nodeName)&&!vt.test(e)&&(this.checked||!ve.test(e))}).map(function(e,t){var n=V(this).val();return null==n?null:V.isArray(n)?V.map(n,function(e){return{name:t.name,value:e.replace(mt,"\r\n")}}):{name:t.name,value:n.replace(mt,"\r\n")}}).get()}}),V.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var xt=0,bt={},wt={0:200,1223:204},Tt=V.ajaxSettings.xhr();e.attachEvent&&e.attachEvent("onunload",function(){for(var e in bt)bt[e]()}),X.cors=!!Tt&&"withCredentials"in Tt,X.ajax=Tt=!!Tt,V.ajaxTransport(function(e){var t;if(X.cors||Tt&&!e.crossDomain)return{send:function(n,r){var i,o=e.xhr(),s=++xt;if(o.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)o[i]=e.xhrFields[i];e.mimeType&&o.overrideMimeType&&o.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)o.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete bt[s],t=o.onload=o.onerror=null,"abort"===e?o.abort():"error"===e?r(o.status,o.statusText):r(wt[o.status]||o.status,o.statusText,"string"==typeof o.responseText?{text:o.responseText}:void 0,o.getAllResponseHeaders()))}},o.onload=t(),o.onerror=t("error"),t=bt[s]=t("abort");try{o.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}}),V.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return V.globalEval(e),e}}}),V.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),V.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=V("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),U.head.appendChild(t[0])},abort:function(){n&&n()}}}});var Ct=[],Nt=/(=)\?(?=&|$)|\?\?/;V.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Ct.pop()||V.expando+"_"+tt++;return this[e]=!0,e}}),V.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=!1!==t.jsonp&&(Nt.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&Nt.test(t.data)&&"data");if(a||"jsonp"===t.dataTypes[0])return i=t.jsonpCallback=V.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(Nt,"$1"+i):!1!==t.jsonp&&(t.url+=(nt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||V.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,Ct.push(i)),s&&V.isFunction(o)&&o(s[0]),s=o=void 0}),"script"}),V.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||U;var r=ee.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=V.buildFragment([e],t,i),i&&i.length&&V(i).remove(),V.merge([],r.childNodes))};var kt=V.fn.load;V.fn.load=function(e,t,n){if("string"!=typeof e&&kt)return kt.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=V.trim(e.slice(a)),e=e.slice(0,a)),V.isFunction(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),s.length>0&&V.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?V("<div>").append(V.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},V.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){V.fn[t]=function(e){return this.on(t,e)}}),V.expr.filters.animated=function(e){return V.grep(V.timers,function(t){return e===t.elem}).length};var Et=e.document.documentElement;V.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l=V.css(e,"position"),c=V(e),f={};"static"===l&&(e.style.position="relative"),a=c.offset(),o=V.css(e,"top"),u=V.css(e,"left"),("absolute"===l||"fixed"===l)&&(o+u).indexOf("auto")>-1?(s=(r=c.position()).top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),V.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):c.css(f)}},V.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){V.offset.setOffset(this,e,t)});var t,n,r=this[0],i={top:0,left:0},o=r&&r.ownerDocument;if(o)return t=o.documentElement,V.contains(t,r)?(typeof r.getBoundingClientRect!==ye&&(i=r.getBoundingClientRect()),n=P(o),{top:i.top+n.pageYOffset-t.clientTop,left:i.left+n.pageXOffset-t.clientLeft}):i},position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===V.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),V.nodeName(e[0],"html")||(r=e.offset()),r.top+=V.css(e[0],"borderTopWidth",!0),r.left+=V.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-V.css(n,"marginTop",!0),left:t.left-r.left-V.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var e=this.offsetParent||Et;e&&!V.nodeName(e,"html")&&"static"===V.css(e,"position");)e=e.offsetParent;return e||Et})}}),V.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;V.fn[t]=function(i){return le(this,function(t,i,o){var s=P(t);if(void 0===o)return s?s[n]:t[i];s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o},t,i,arguments.length,null)}}),V.each(["top","left"],function(e,t){V.cssHooks[t]=w(X.pixelPosition,function(e,n){if(n)return n=b(e,t),Fe.test(n)?V(e).position()[t]+"px":n})}),V.each({Height:"height",Width:"width"},function(e,t){V.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){V.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(!0===r||!0===i?"margin":"border");return le(this,function(t,n,r){var i;return V.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):void 0===r?V.css(t,n,s):V.style(t,n,r,s)},t,o?r:void 0,o,null)}})}),V.fn.size=function(){return this.length},V.fn.andSelf=V.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return V});var St=e.jQuery,Dt=e.$;return V.noConflict=function(t){return e.$===V&&(e.$=Dt),t&&e.jQuery===V&&(e.jQuery=St),V},typeof t===ye&&(e.jQuery=e.$=V),V}); \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/min/loader.min.js Tue Apr 10 10:22:34 2018 +0100 @@ -0,0 +1,1 @@ +window.onload=function(){if(void 0===window.AudioContext&&void 0===window.webkitAudioContext){var e=document.getElementsByTagName("body")[0];e.innerHTML="<h1>Sorry! Your browser is not supported :(</h1><p>Your browser does not support the HTML5 Web Audio API. Please use one of the following supported browsers instead.<p>";var t=document.createElement("table");t.border="0",t.innerHTML="<tr><td>Chrome</td><td>v10 or newer</td></tr>",t.innerHTML+="<tr><td>Firefox</td><td>v25 or newer</td></tr><tr><td>Safari (OSX)</td><td> v6 or newer, OSX only</td></tr>",t.innerHTML+="<tr><td>Safari (iOS)</td><td>iOS 6.1 or newer</td></tr>",t.innerHTML+="<tr><td>Edge</td><td>12 or newer</td></tr>",e.appendChild(t)}else for(var r=document.getElementsByTagName("head")[0],d=["js/specification.js","js/core.js","js/loudness.js","js/xmllint.js","js/WAVE.js"],o=0;o<d.length;o++){var n=d[o],i=document.createElement("script");i.type="text/javascript",i.async=!1,i.defer=!0,i.src=n,r.appendChild(i)}}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/min/loudness.min.js Tue Apr 10 10:22:34 2018 +0100 @@ -0,0 +1,1 @@ +function calculateLoudness(e,a,r,n){if("iPad"!=navigator.platform&&"iPhone"!=navigator.platform||e.ready(),void 0===e)return 0;void 0===a&&(a="I"),void 0===r&&(r=-23),void 0===n&&(n=new OfflineAudioContext(audioContext.destination.channelCount,Math.max(.4,e.buffer.duration)*audioContext.sampleRate,audioContext.sampleRate));var t=n.createBiquadFilter();t.type="highshelf",t.gain.value=4,t.frequency.value=1500;var o=n.createBiquadFilter();o.type="highpass",o.Q.value=.5,o.frequency.value=38;var l=n.createBufferSource();l.buffer=e.buffer,l.connect(t),t.connect(o),o.connect(n.destination),n.oncomplete=function(r){switch("object"==typeof r.renderedBuffer&&(r=r.renderedBuffer),a){case"I":var n=calculateMeanSquared(r,.4,.75),t=calculateLoudnessFromBlocks(n),o=loudnessOfBlocks(loudnessGate(t,n,loudnessOfBlocks(loudnessGate(t,n,-70))-10));e.buffer.lufs=o}e.ready()},l.start(0),n.startRendering()}function calculateMeanSquared(e,a,r){var n=Math.floor(e.sampleRate*a),t=Math.floor(n*(1-r)),o=Math.floor((e.length-n)/t);o=Math.max(o,1);for(var l=Array(e.numberOfChannels),u=0;u<e.numberOfChannels;u++){l[u]=new Float32Array(o);for(var f=e.getChannelData(u),i=0;i<o;i++){l[u][i]=0;for(var s=0;s<n;s++){var c=i*t+s;if(c>=e.length)break;var d=f[c];l[u][i]+=d*d}l[u][i]/=n}}return l}function calculateLoudnessFromBlocks(e){for(var a=e[0].length,r=e.length,n=Array(a),t=0;t<a;t++){for(var o=0,l=0;l<r;l++){var u=1;u>=3&&(u=1.41),o+=e[l][t]*u}n[t]=10*Math.log10(o)-.691}return n}function loudnessGate(e,a,r){var n,t,o=a[0].length,l=a.length,u=Array(l);for(t=0;t<l;t++)u[t]=[];for(n=0;n<o;n++)if(e[n]>r)for(t=0;t<l;t++)u[t].push(a[t][n]);return u}function loudnessOfBlocks(e){for(var a=e[0].length,r=e.length,n=0,t=0;t<a;t++){for(var o=0,l=0;l<r;l++){var u=1;u>=3&&(u=1.41),o+=e[l][t]*u}n+=o/=a}return n=10*Math.log10(n)-.691}var interval_cal_loudness_event=null;if(void 0===OfflineAudioContext)var OfflineAudioContext=webkitOfflineAudioContext; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/min/specification.min.js Tue Apr 10 10:22:34 2018 +0100 @@ -0,0 +1,1 @@ +function Specification(){function t(t){this.location=void 0,this.options=[],this.parent=void 0,this.showBackButton=!0,this.specification=t,this.addOption=function(){var t=new this.OptionNode(this.specification);return this.options.push(t),t},this.OptionNode=function(t){this.type=void 0,this.schema=void 0,this.id=void 0,this.name=void 0,this.mandatory=void 0,this.statement=void 0,this.boxsize=void 0,this.options=[],this.min=void 0,this.max=void 0,this.minWait=void 0,this.step=void 0,this.conditions=[],this.decode=function(t,e){this.schema=s.querySelector("[name="+e.nodeName+"]");var i,n=this.schema.querySelectorAll("attribute");for(i in n){if(!0===isNaN(Number(i)))break;var r=n[i].getAttribute("name")||n[i].getAttribute("ref"),o=e.getAttribute(r);null!==(o=a(o,n[i]))&&(this[r]=o)}if("surveyentry"==e.nodeName){if(console.log("NOTE - Use of <surveyelement> is now deprecated. Whilst these will still work, newer nodes and tighter error checking will not be enforced"),console.log("Please use the newer, type specifc nodes"),!this.type)throw"Type not specified"}else this.type=e.nodeName.split("survey")[1];if(this.statement=e.getElementsByTagName("statement")[0].textContent,"checkbox"==this.type||"radio"==this.type){var h=e.getElementsByTagName("option");if(null===h.length)console.log("Malformed"+e.nodeName+"entry"),this.statement="Malformed"+e.nodeName+"entry",this.type="statement";else for(this.options=[],i=0;i<h.length;i++)this.options.push({name:h[i].getAttribute("name"),text:h[i].textContent})}else if("slider"==this.type){this.leftText="",this.rightText="";var l=e.getElementsByTagName("minText"),m=e.getElementsByTagName("maxText");l.length>0&&(this.leftText=l[0].textContent),m.length>0&&(this.rightText=m[0].textContent)}var c=e.getElementsByTagName("conditional");for(i=0;i<c.length;i++){var d=c[i],u={check:d.getAttribute("check"),value:d.getAttribute("value"),jumpToOnPass:d.getAttribute("jumpToOnPass"),jumpToOnFail:d.getAttribute("jumpToOnFail")};this.conditions.push(u)}},this.exportXML=function(t){var e=t.createElement("survey"+this.type),i=t.createElement("statement");switch(i.textContent=this.statement,e.appendChild(i),e.id=this.id,void 0!==this.name&&e.setAttribute("name",this.name),void 0!==this.mandatory&&e.setAttribute("mandatory",this.mandatory),e.id=this.id,void 0!==this.name&&e.setAttribute("name",this.name),this.type){case"checkbox":void 0!==this.min?e.setAttribute("min",this.min):e.setAttribute("min","0"),void 0!==this.max?e.setAttribute("max",this.max):e.setAttribute("max","undefined");case"radio":for(var s=0;s<this.options.length;s++){var n=this.options[s],a=t.createElement("option");a.setAttribute("name",n.name),a.textContent=n.text,e.appendChild(a)}break;case"number":void 0!==this.min&&e.setAttribute("min",this.min),void 0!==this.max&&e.setAttribute("max",this.max);break;case"question":void 0!==this.boxsize&&e.setAttribute("boxsize",this.boxsize),void 0!==this.mandatory&&e.setAttribute("mandatory",this.mandatory);break;case"video":void 0!==this.mandatory&&e.setAttribute("mandatory",this.mandatory);case"youtube":void 0!==this.url&&e.setAttribute("url",this.url);break;case"slider":if(e.setAttribute("min",this.min),e.setAttribute("max",this.max),this.leftText){var r=t.createElement("minText");r.textContent=this.leftText,e.appendChild(r)}if(this.rightText){var o=t.createElement("maxText");o.textContent=this.rightText,e.appendChild(o)}}return this.conditions.forEach(function(i){var s=t.createElement("conditional");s.setAttribute("check",i.check),s.setAttribute("value",i.value),s.setAttribute("jumpToOnPass",i.jumpToOnPass),s.setAttribute("jumpToOnFail",i.jumpToOnFail),e.appendChild(s)}),e}},this.decode=function(t,e){this.schema=s.querySelector("[name=survey]"),this.parent=t,this.location=e.getAttribute("location"),"before"==this.location?this.location="pre":"after"==this.location&&(this.location="post"),this.showBackButton=e.getAttribute("showBackButton"),"false"==this.showBackButton?this.showBackButton=!1:this.showBackButton=!0;for(var i=e.firstElementChild;i;){var n=new this.OptionNode(this.specification);n.decode(t,i),this.options.push(n),i=i.nextElementSibling}0===this.options.length&&(console.log("Empty survey node"),console.log(this))},this.encode=function(t){var e=t.createElement("survey");e.setAttribute("location",this.location),e.setAttribute("showBackButton",this.showBackButton);for(var i=0;i<this.options.length;i++)e.appendChild(this.options[i].exportXML(t));return e}}function e(t){this.title=void 0,this.name=void 0,this.image=void 0,this.options=[],this.scales=[],this.schema=void 0,this.decode=function(t,e){this.schema=s.querySelectorAll("[name=interface]")[1],this.name=e.getAttribute("name");var i=e.getElementsByTagName("title");1==i.length&&(this.title=i[0].textContent);var n,r,o=e.getElementsByTagName("interfaceoption"),h=this.schema.querySelector("[name=interfaceoption]").querySelectorAll("attribute");for(n=0;n<o.length;n++){var l=o[n],m={};for(r=0;r<h.length;r++){var c=h[r].getAttribute("name")||h[r].getAttribute("ref"),d=l.getAttribute(c);null!==(d=a(d,h[r]))&&(m[c]=d)}"check"==m.type&&l.firstElementChild&&(m.errorMessage=l.firstElementChild.textContent),this.options.push(m)}var u=e.getElementsByTagName("image");1==u.length&&(this.image=u[0].getAttribute("src"));var p=e.getElementsByTagName("scales");if(1==p.length){var g=(p=p[0]).querySelectorAll("scalelabel");for(n=0;n<g.length;n++)this.scales.push({text:g[n].textContent,position:Number(g[n].getAttribute("position"))})}},this.encode=function(t){var e=t.createElement("interface");if("string"==typeof this.name&&this.name.length>0&&e.setAttribute("name",this.name),"string"==typeof this.title){var i=t.createElement("title");i.textContent=this.title,e.appendChild(i)}if(this.options.forEach(function(i){var s=t.createElement("interfaceoption");if(s.setAttribute("type",i.type),s.setAttribute("name",i.name),"check"==i.type&&void 0!==i.errorMessage){var n=t.createElement("errormessage");n.textContent=i.errorMessage,s.appendChild(n)}e.appendChild(s)}),"string"==typeof this.image&&0!==this.image.length){var s=t.createElement("image");s.setAttribute("src",this.image),e.appendChild(s)}if(0!==this.scales.length){var n=t.createElement("scales");this.scales.forEach(function(e){var i=t.createElement("scalelabel");i.setAttribute("position",e.position),i.textContent=e.text,n.appendChild(i)}),e.appendChild(n)}return e}}function i(i){function n(t){this.id=void 0,this.name=void 0,this.type=void 0,this.statement=void 0,this.mandatory=void 0,this.schema=s.querySelector("[name=commentquestion]"),this.decode=function(t,e){switch(this.id=e.id,this.name=e.getAttribute("name"),this.mandatory="true"==e.getAttribute("mandatory"),null===this.name&&(this.name=void 0),e.nodeName){case"commentradio":this.type="radio",this.options=[];break;case"commentcheckbox":this.type="checkbox",this.options=[];break;case"commentslider":this.type="slider",this.min=void 0,this.max=void 0,this.step=void 0;break;case"commentquestion":this.type="question";break;default:throw"Unknown comment type "+e.nodeName}if(this.statement=e.getElementsByTagName("statement")[0].textContent,"radio"==this.type||"checkbox"==this.type)for(var i=e.getElementsByTagName("option"),s=0;s<i.length;s++){var n=i[s];this.options.push({name:n.getAttribute("name"),text:n.textContent})}"slider"==this.type&&(this.min=Number(e.getAttribute("min")),this.max=Number(e.getAttribute("max")),this.step=Number(e.getAttribute("step")),void 0===this.step&&(this.step=1),this.value=Number(e.getAttribute("value")),void 0===this.value&&(this.value=this.min),this.leftText=e.getElementsByTagName("minText"),this.leftText&&this.leftText.length>0?this.leftText=this.leftText[0].textContent:this.leftText="",this.rightText=e.getElementsByTagName("maxText"),this.rightText&&this.rightText.length>0?this.rightText=this.rightText[0].textContent:this.rightText="")},this.encode=function(t){var e;switch(this.type){case"radio":e=t.createElement("commentradio");break;case"checkbox":e=t.createElement("commentcheckbox");break;case"slider":e=t.createElement("commentslider");break;case"question":e=t.createElement("commentquestion");break;default:throw"Unknown type "+this.type}e.id=this.id,e.setAttribute("mandatory",this.mandatory),e.setAttribute("type",this.type),void 0!==this.name&&e.setAttribute("name",this.name);var i=t.createElement("statement");if(i.textContent=this.statement,e.appendChild(i),"radio"!=this.type&&"checkbox"!=this.type||this.options.forEach(function(i){var s=t.createElement("option");s.setAttribute("name",i.name),s.textContent=i.text,e.appendChild(s)}),"slider"==this.type){if(e.setAttribute("min",this.min),e.setAttribute("max",this.max),1!==this.step&&e.setAttribute("step",this.step),this.value!==this.min&&e.setAttribute("value",this.value),this.leftText.length>0){var s=t.createElement("minText");s.textContent=this.leftText,e.appendChild(s)}if(this.rightText.length>0){var n=t.createElement("maxText");n.textContent=this.rightText,e.appendChild(n)}}return e}}function r(t){this.url=void 0,this.id=void 0,this.name=void 0,this.parent=void 0,this.type=void 0,this.marker=void 0,this.enforce=!1,this.gain=0,this.label=void 0,this.startTime=void 0,this.stopTime=void 0,this.sampleRate=void 0,this.image=void 0,this.minNumberPlays=void 0,this.maxNumberPlays=void 0,this.alternatives=[],this.schema=s.querySelector("[name=audioelement]"),this.parent=void 0,this.decode=function(t,e){this.parent=t;for(var i=this.schema.querySelectorAll("attribute"),s=0;s<i.length;s++){var n=i[s].getAttribute("name")||i[s].getAttribute("ref"),r=e.getAttribute(n);null!==(r=a(r,i[s]))&&(this[n]=r)}for(var o=e.firstElementChild;o;)"alternative"==o.nodeName&&this.alternatives.push({url:o.getAttribute("url"),sampleRate:o.getAttribute("sampleRate")}),o=o.nextElementSibling},this.encode=function(t){for(var e=t.createElement("audioelement"),i=this.schema.querySelectorAll("attribute"),s=0;s<i.length;s++){var n=i[s].getAttribute("name");null===n&&(n=i[s].getAttribute("ref")),void 0===this[n]&&"required"!=i[s].getAttribute("use")||e.setAttribute(n,this[n])}return this.alternatives.forEach(function(i){var s=t.createElement("alternative");s.setAttribute("url",i.url),s.setAttribute("sampleRate",i.sampleRate),e.appendChild(s)}),e}}this.presentedId=void 0,this.id=void 0,this.title=void 0,this.hostURL=void 0,this.randomiseOrder=void 0,this.loop=void 0,this.outsideReference=void 0,this.loudness=void 0,this.label=void 0,this.labelStart=void 0,this.preTest=new t(i),this.postTest=new t(i),this.preTest.location="pre",this.postTest.location="post",this.interfaces=[],this.playOne=void 0,this.restrictMovement=void 0,this.position=void 0,this.commentBoxPrefix="Comment on track",this.minNumberPlays=void 0,this.maxNumberPlays=void 0,this.randomiseAxisOrder=void 0,this.audioElements=[],this.commentQuestions=[],this.schema=s.querySelector("[name=page]"),this.specification=i,this.parent=void 0,this.addInterface=function(){var t=new e(i);return this.interfaces.push(t),t},this.addCommentQuestion=function(){var t=new n(i);return this.commentQuestions.push(t),t},this.addAudioElement=function(){var t=new r(i);return this.audioElements.push(t),t},this.decode=function(t,i){this.parent=t;var s,o,h=this.schema.querySelectorAll("attribute");for(s=0;s<h.length;s++){var l=h[s].getAttribute("name")||h[s].getAttribute("ref"),m=i.getAttribute(l);null!==(m=a(m,h[s]))&&(this[l]=m)}var c=i.getElementsByTagName("title");0!==c.length&&c[0].parentElement==i&&(this.title=c[0].textContent);var d=i.getElementsByTagName("commentboxprefix");0!==d.length&&d[0].parentElement==i&&(this.commentBoxPrefix=d[0].textContent);var u=i.getElementsByTagName("interface");for(s=0;s<u.length;s++)(o=new e(this.specification)).decode(this,u[s],t.schema.querySelectorAll("[name=interface]")[1]),this.interfaces.push(o);var p=i.getElementsByTagName("survey"),g=t.schema.querySelector("[name=survey]");for(s=0;s<p.length;s++){var v=p[s].getAttribute("location");"pre"==v||"before"==v?0!==this.preTest.options.length?this.errors.push("Already a pre/before test survey defined! Ignoring second!!"):this.preTest.decode(t,p[s],g):"post"!=v&&"after"!=v||(0!==this.postTest.options.length?this.errors.push("Already a post/after test survey defined! Ignoring second!!"):this.postTest.decode(t,p[s],g))}var f=i.getElementsByTagName("audioelement");for(s=0;s<f.length;s++){var b=new r(this.specification);b.decode(this,f[s]),this.audioElements.push(b)}var x=i.getElementsByTagName("commentquestions");if(0!==x.length)for(var y=(x=x[0]).firstElementChild;y;)(o=new n(this.specification)).decode(t,y),this.commentQuestions.push(o),y=y.nextElementSibling},this.encode=function(t){var e,i=t.createElement("page"),s=this.schema.querySelectorAll("attribute");for(e=0;e<s.length;e++){var n=s[e].getAttribute("name");null===n&&(n=s[e].getAttribute("ref")),void 0===this[n]&&"required"!=s[e].getAttribute("use")||i.setAttribute(n,this[n])}var a=t.createElement("commentboxprefix");for(a.textContent=this.commentBoxPrefix,i.appendChild(a),e=0;e<this.interfaces.length;e++)i.appendChild(this.interfaces[e].encode(t));for(e=0;e<this.audioElements.length;e++)i.appendChild(this.audioElements[e].encode(t));if(this.commentQuestions.length>0){var r=t.createElement("commentquestions");for(e=0;e<this.commentQuestions.length;e++)r.appendChild(this.commentQuestions[e].encode(t));i.appendChild(r)}return i.appendChild(this.preTest.encode(t)),i.appendChild(this.postTest.encode(t)),i}}var s,n;this.interface=void 0,this.projectReturn=void 0,this.returnURL=void 0,this.randomiseOrder=void 0,this.poolSize=void 0,this.loudness=void 0,this.sampleRate=void 0,this.calibration=void 0,this.crossFade=void 0,this.preSilence=void 0,this.postSilence=void 0,this.playOne=void 0,this.minNumberPlays=void 0,this.maxNumberPlays=void 0,this.randomiseAxisOrder=void 0,this.metrics=new function(){this.enabled=[],this.decode=function(t,e){var i=e.getElementsByTagName("metricenable");for(var s in i){if(!0===isNaN(Number(s)))break;this.enabled.push(i[s].textContent)}},this.encode=function(t){var e=t.createElement("metric");for(var i in this.enabled){if(!0===isNaN(Number(i)))break;var s=t.createElement("metricenable");s.textContent=this.enabled[i],e.appendChild(s)}return e}},this.preTest=new t(this),this.postTest=new t(this),this.preTest.location="pre",this.postTest.location="post",this.pages=[],this.interfaces=new e(this),this.errors=[],this.exitText="Thank you.",this.createNewPage=function(){var t=new i(this);return this.pages.push(t),t};var a=function(t,e){null===e.getAttribute("name")&&void 0!==e.getAttribute("ref")&&(e=s.querySelector("[name="+e.getAttribute("ref")+"]"));var i=e.getAttribute("default");null===t&&(t=i);var n=e.getAttribute("type");if("string"==typeof n)n=n.substr(3);else{var a=e.querySelectorAll("restriction,enumeration");n=a.length>0&&"string"==typeof(n=a[0].getAttribute("base"))?n.substr(3):"string"}if(null===t)return t;switch(n){case"boolean":t="true"==t;break;case"negativeInteger":case"positiveInteger":case"nonNegativeInteger":case"nonPositiveInteger":case"integer":case"decimal":case"short":t=Number(t);break;default:t=String(t)}return t};this.processSchema=function(t){if(void 0===s){n=t;var e=new DOMParser;s=e.parseFromString(n,"text/xml"),Object.defineProperties(this,{schema:{value:s},schemaString:{value:n}})}},this.getSchema=function(){return s},this.getSchemaString=function(){return n},this.decode=function(t){s=this.schema,this.errors=[],this.projectXML=t.childNodes[0];var e,n=t.getElementsByTagName("setup")[0],r=s.querySelector("[name=setup]").querySelectorAll("attribute");for(e=0;e<r.length;e++){var o=r[e].getAttribute("name")||r[e].getAttribute("ref"),h=n.getAttribute(o);null!==(h=a(h,r[e]))&&(this[o]=h)}var l=n.getElementsByTagName("exitText");1==l.length&&(this.exitText=l[0].textContent),this.metrics.decode(this,n.getElementsByTagName("metric")[0]);var m=n.getElementsByTagName("survey");for(e=0;e<m.length;e++){switch(m[e].getAttribute("location")){case"pre":case"before":this.preTest.decode(this,m[e]);break;case"post":case"after":this.postTest.decode(this,m[e])}}var c=n.getElementsByTagName("interface");c.length>1&&this.errors.push("Only one <interface> node in the <setup> node allowed! Others except first ingnored!"),0!==c.length&&(c=c[0],this.interfaces.decode(this,c,this.schema.querySelectorAll("[name=interface]")[1]));var d=t.getElementsByTagName("page"),u=this.schema.querySelector("[name=page]");for(e=0;e<d.length;e++){var p=new i(this);p.decode(this,d[e],u),this.pages.push(p);for(var g=0;g<p.repeatCount;g++){var v=new i(this);v.decode(this,d[e],u),v.id+="-repeat-"+g,this.pages.push(v)}}},this.encode=function(){var t=document.implementation.createDocument(null,"waet"),e=t.firstChild;e.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"),e.setAttribute("xsi:noNamespaceSchemaLocation","test-schema.xsd");for(var i=t.createElement("setup"),n=s.querySelector("[name=setup]").querySelectorAll("attribute"),a=0;a<n.length;a++){var r=n[a].getAttribute("name");null===r&&(r=n[a].getAttribute("ref")),void 0===this[r]&&"required"!=n[a].getAttribute("use")||i.setAttribute(r,this[r])}if(e.appendChild(i),null!==this.exitText){var o=t.createElement("exitText");o.textContent=this.exitText,i.appendChild(o)}return i.appendChild(this.preTest.encode(t)),i.appendChild(this.postTest.encode(t)),i.appendChild(this.metrics.encode(t)),i.appendChild(this.interfaces.encode(t)),this.pages.forEach(function(i){e.appendChild(i.encode(t))}),t}} \ No newline at end of file
--- a/js/specification.js Tue Apr 10 10:18:25 2018 +0100 +++ b/js/specification.js Tue Apr 10 10:22:34 2018 +0100 @@ -12,13 +12,13 @@ this.poolSize = undefined; this.loudness = undefined; this.sampleRate = undefined; - this.calibration = undefined; this.crossFade = undefined; this.preSilence = undefined; this.postSilence = undefined; this.playOne = undefined; this.minNumberPlays = undefined; this.maxNumberPlays = undefined; + this.randomiseAxisOrder = undefined; // nodes this.metrics = new metricNode(); @@ -130,7 +130,9 @@ if (projectAttr !== null) { this[attributeName] = projectAttr; } - + } + if (projectXML.getElementsByTagName('calibration').length > 0) { + this.calibration.decode(this, projectXML.getElementsByTagName('calibration')[0]); } var exitTextNode = setupNode.getElementsByTagName('exitText'); @@ -208,6 +210,7 @@ exitTextNode.textContent = this.exitText; setup.appendChild(exitTextNode); } + setup.appendChild(this.calibration.encode(RootDocument)); setup.appendChild(this.preTest.encode(RootDocument)); setup.appendChild(this.postTest.encode(RootDocument)); setup.appendChild(this.metrics.encode(RootDocument)); @@ -218,10 +221,88 @@ return RootDocument; }; + this.calibration = (function () { + var frequencies = false, + levels = false, + channels = false, + schema = undefined; + var Calibration = {}; + Object.defineProperties(Calibration, { + "parent": { + "value": this + }, + "schema": { + "get": function () { + return schema; + }, + "set": function (t) { + if (schema === undefined) { + schema = t; + } else { + throw ("Cannot set readonly"); + } + } + }, + "checkFrequencies": { + "get": function () { + return frequencies; + }, + "set": function (t) { + frequencies = (t === true); + } + }, + "checkLevels": { + "get": function () { + return levels; + }, + "set": function (t) { + levels = (t === true); + } + }, + "checkChannels": { + "get": function () { + return channels; + }, + "set": function (t) { + channels = (t === true); + } + }, + "encode": { + "value": function (doc) { + var node = doc.createElement("calibration"); + node.setAttribute("checkFrequencies", frequencies); + node.setAttribute("checkLevels", levels); + node.setAttribute("checkChannels", channels); + return node; + } + }, + "decode": { + "value": function (parent, xml) { + this.schema = schemaRoot.querySelector("[name=calibration]"); + var attributeMap = this.schema.querySelectorAll('attribute'), + i; + for (i in attributeMap) { + if (isNaN(Number(i)) === true) { + break; + } + var attributeName = attributeMap[i].getAttribute('name') || attributeMap[i].getAttribute('ref'); + var projectAttr = xml.getAttribute(attributeName); + projectAttr = processAttribute(projectAttr, attributeMap[i]); + if (projectAttr !== null) { + this[attributeName] = projectAttr; + } + } + } + } + }); + return Calibration; + })(); + function surveyNode(specification) { this.location = undefined; this.options = []; this.parent = undefined; + this.showBackButton = true; this.specification = specification; this.addOption = function () { @@ -409,6 +490,12 @@ } else if (this.location == 'after') { this.location = 'post'; } + this.showBackButton = xml.getAttribute("showBackButton"); + if (this.showBackButton == "false") { + this.showBackButton = false; + } else { + this.showBackButton = true; + } var child = xml.firstElementChild; while (child) { var node = new this.OptionNode(this.specification); @@ -424,6 +511,7 @@ this.encode = function (doc) { var node = doc.createElement('survey'); node.setAttribute('location', this.location); + node.setAttribute('showBackButton', this.showBackButton); for (var i = 0; i < this.options.length; i++) { node.appendChild(this.options[i].exportXML(doc)); } @@ -572,6 +660,7 @@ this.commentBoxPrefix = "Comment on track"; this.minNumberPlays = undefined; this.maxNumberPlays = undefined; + this.randomiseAxisOrder = undefined; this.audioElements = []; this.commentQuestions = []; this.schema = schemaRoot.querySelector("[name=page]"); @@ -696,8 +785,12 @@ AHNode.appendChild(this.audioElements[i].encode(root)); } // Create <CommentQuestion> - for (i = 0; i < this.commentQuestions.length; i++) { - AHNode.appendChild(this.commentQuestions[i].encode(root)); + if (this.commentQuestions.length > 0) { + var node = root.createElement("commentquestions"); + for (i = 0; i < this.commentQuestions.length; i++) { + node.appendChild(this.commentQuestions[i].encode(root)); + } + AHNode.appendChild(node); } AHNode.appendChild(this.preTest.encode(root)); @@ -710,10 +803,12 @@ this.name = undefined; this.type = undefined; this.statement = undefined; + this.mandatory = undefined; this.schema = schemaRoot.querySelector('[name=commentquestion]'); this.decode = function (parent, xml) { this.id = xml.id; this.name = xml.getAttribute('name'); + this.mandatory = xml.getAttribute("mandatory") == "true"; if (this.name === null) { this.name = undefined; } @@ -794,6 +889,7 @@ throw ("Unknown type " + this.type); } node.id = this.id; + node.setAttribute("mandatory", this.mandatory); node.setAttribute("type", this.type); if (this.name !== undefined) { node.setAttribute("name", this.name);
--- a/php/requestKey.php Tue Apr 10 10:18:25 2018 +0100 +++ b/php/requestKey.php Tue Apr 10 10:22:34 2018 +0100 @@ -11,6 +11,10 @@ return $randomString; } +if (!file_exists("../saves")) { + mkdir("../saves"); +} + // Request a new session key from the server header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); header("Cache-Control: post-check=0, pre-check=0", false);
--- a/php/save.php Tue Apr 10 10:18:25 2018 +0100 +++ b/php/save.php Tue Apr 10 10:22:34 2018 +0100 @@ -33,7 +33,17 @@ } $postText = file_get_contents('php://input'); $file_key = $_GET['key']; -$filename = '../saves/'.$saveFilenamePrefix.$file_key.".xml"; + +$update = false; +if (isset($_GET["update"])) { + $update = $_GET["update"] == "update"; +} + +if ($update) { + $filename = '../saves/update-'.$saveFilenamePrefix.$file_key.".xml"; +} else { + $filename = '../saves/'.$saveFilenamePrefix.$file_key.".xml"; +} if (!file_exists($filename)) { die('<response state="error"><message>Could not find save</message></response>'); @@ -132,4 +142,8 @@ // Return XML confirmation data $xml = '<response state="OK"><message>OK</message><file bytes="'.$wbytes.'">"'.$filename.'"</file></response>'; echo $xml; + +if (!$update) { + unlink('../saves/update-'.$saveFilenamePrefix.$file_key.".xml"); +} ?>
--- a/python/generate_report.py Tue Apr 10 10:18:25 2018 +0100 +++ b/python/generate_report.py Tue Apr 10 10:22:34 2018 +0100 @@ -232,17 +232,18 @@ # number of comments (interesting if comments not mandatory) for audioelement in audioelements: - response = audioelement.find("./comment/response") - was_played = audioelement.find("./metric/metricresult/[@name='elementFlagListenedTo']") - was_moved = audioelement.find("./metric/metricresult/[@name='elementFlagMoved']") - if response is not None and response.text is not None and len(response.text) > 1: - number_of_comments += 1 - else: - number_of_missing_comments += 1 - if was_played is not None and was_played.text == 'false': - not_played.append(audioelement.get('name')) - if was_moved is not None and was_moved.text == 'false': - not_moved.append(audioelement.get('name')) + if audioelement.get("type") != "outside-reference": + response = audioelement.find("./comment/response") + was_played = audioelement.find("./metric/metricresult/[@name='elementFlagListenedTo']") + was_moved = audioelement.find("./metric/metricresult/[@name='elementFlagMoved']") + if response is not None and response.text is not None and len(response.text) > 1: + number_of_comments += 1 + else: + number_of_missing_comments += 1 + if was_played is not None and was_played.text == 'false': + not_played.append(audioelement.get('name')) + if was_moved is not None and was_moved.text == 'false': + not_moved.append(audioelement.get('name')) # update global counters total_empty_comments += number_of_missing_comments
--- a/python/pythonServer.py Tue Apr 10 10:18:25 2018 +0100 +++ b/python/pythonServer.py Tue Apr 10 10:22:34 2018 +0100 @@ -13,6 +13,7 @@ import copy import string import random +import errno if sys.version_info[0] == 2: # Version 2.x @@ -28,6 +29,12 @@ scriptdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) # script directory os.chdir(scriptdir) # does this work? +try: + os.makedirs("../saves") +except OSError as e: + if e.errno != errno.EEXIST: + raise + PSEUDO_PATH = '../tests/' pseudo_files = [] pseudo_index = 0 @@ -147,12 +154,15 @@ global curSaveIndex options = self.path.rsplit('?') options = options[1].rsplit('&') + update = False for option in options: optionPair = option.rsplit('=') if optionPair[0] == "key": key = optionPair[1] elif optionPair[0] == "saveFilenamePrefix": prefix = optionPair[1] + elif optionPair[0] == "state": + update = optionPair[1] == "update" if key == None: self.send_response(404) return @@ -162,6 +172,8 @@ postVars = self.rfile.read(varLen) print("Saving file key "+key) filename = prefix+'-'+key+'.xml' + if update: + filename = "update-"+filename file = open('../saves/'+filename,'wb') file.write(postVars) file.close() @@ -182,6 +194,9 @@ self.wfile.write(bytes(reply, "utf-8")) curSaveIndex += 1 curFileName = 'test-'+str(curSaveIndex)+'.xml' + if update == False: + if(os.path.isfile("../saves/update-"+filename)): + os.remove("../saves/update-"+filename) def testSave(self): self.send_response(200) @@ -210,7 +225,6 @@ self.wfile.write(message) elif sys.version_info[0] == 3: self.wfile.write(bytes(message, "utf-8")) - def poolXML(s): pool = ET.parse('../tests/pool.xml')
--- a/python/timeline_view_movement.py Tue Apr 10 10:18:25 2018 +0100 +++ b/python/timeline_view_movement.py Tue Apr 10 10:22:34 2018 +0100 @@ -74,6 +74,10 @@ if page_name is None: # ignore 'empty' audio_holders print("Skipping empty page name from "+subject_id+".") break + + if page.get("state") != "complete": + print("Skipping non-completed page "+page_name+" from "+subject_id+".") + break # subtract total page length from subsequent page event times page_time_temp = page.find("./metric/metricresult/[@id='testTime']") @@ -108,11 +112,20 @@ if audioelement is not None: # Check it exists audio_id = str(audioelement.get('ref')) - # break if no initial position or move events registered + # break if outside-reference + if audioelement.get("type") == "outside-reference": + break; + + # break if no initial position.... initial_position_temp = audioelement.find("./metric/metricresult/[@name='elementInitialPosition']") if initial_position_temp is None: print("Skipping "+page_name+" from "+subject_id+": does not have initial positions specified.") break + # ... or move events registered + movements = audioelement.find("./metric/metricresult[@name='elementTrackerFull']") + if movements is None: + print("Skipping "+page_name+" from "+subject_id+": does not have trackers.") + break # get move events, initial and eventual position initial_position = float(initial_position_temp.text) @@ -299,13 +312,20 @@ interfaces = page_setup.findall("./interface") interface_title = interfaces[0].find("./title") scales = interfaces[0].findall("./scales") # get first interface by default - scalelabels = scales[0].findall("./scalelabel") # get first scale by default - + labelpos = [] # array of scalelabel positions labelstr = [] # array of strings at labels - for scalelabel in scalelabels: - labelpos.append(float(scalelabel.get('position'))/100.0) - labelstr.append(scalelabel.text) + + # No scales given. Use normal floats + if len(scales) is 0: + labelpos = [0.0, 1.0] + labelstr = ["0", "100"] + else: + scalelabels = scales[0].findall("./scalelabel") # get first scale by default + + for scalelabel in scalelabels: + labelpos.append(float(scalelabel.get('position'))/100.0) + labelstr.append(scalelabel.text) # use interface name as Y axis label if interface_title is not None:
--- a/test.html Tue Apr 10 10:18:25 2018 +0100 +++ b/test.html Tue Apr 10 10:22:34 2018 +0100 @@ -37,7 +37,7 @@ <button id="popup-previous" class="popupButton">Back</button> </div> <div class="testHalt" style="visibility: hidden"></div> - <div id="footer"><a target="_blank" href="https://github.com/BrechtDeMan/WebAudioEvaluationTool">Web Audio Evaluation Toolbox (v1.2.2)</a></div> + <div id="footer"><a target="_blank" href="https://github.com/BrechtDeMan/WebAudioEvaluationTool">Web Audio Evaluation Toolbox (v1.2.3)</a></div> </body> </html>
--- a/test_create.html Tue Apr 10 10:18:25 2018 +0100 +++ b/test_create.html Tue Apr 10 10:22:34 2018 +0100 @@ -19,7 +19,7 @@ <div class="container"> <div id="pageRoot"> <h1>Web Audio Evaluation Tool</h1> - <h3>Test Creator <span class="label label-primary">v1.2.2</span></h3> + <h3>Test Creator <span class="label label-primary">v1.2.3</span></h3> </div> <button type="button" class="btn btn-info" ng-click="validate()">Validate</button> <button type="button" class="btn btn-success" ng-click="exportXML()" ng-disabled="validated == false">Export XML</button> @@ -74,10 +74,6 @@ <span>Fixed Sampling Rate: </span> <input type="number" ng-model="specification.sampleRate" min="0" placeholder="{{placeholder('sampleRate')}}" /> </div> - <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show a 'method of adjustment' audio calibration before testing."> - <span>Pre-Test audio calibration: </span> - <input type="checkbox" ng-model="specification.calibration" /> - </div> <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Default cross-fade time when switching between elements. Can be over-ridden on each page"> <span>Global Cross-fade time: </span> <input type="number" ng-model="specification.crossFade" min="0" step="0.1" placeholder="{{placeholder('crossFade')}}" /> @@ -107,6 +103,23 @@ <h2>Test Completed Message</h2> <textarea ng-model="specification.exitText" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Once the test is completed, you can show a message to the user. Markdown syntax is supported for formatting."></textarea> </div> + <div class="node"> + <h2>Pre-Test Calibrations</h2> + <div class="attributes"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Perform a frequency listening response"> + <span>Check Frequency Response</span> + <input type="checkbox" value="testTimer" ng-model="specification.calibration.checkFrequencies" /> + </div> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Set the output levels"> + <span>Check Levels</span> + <input type="checkbox" value="testTimer" ng-model="specification.calibration.checkLevels" /> + </div> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Check L/R configuration"> + <span>Check Channels</span> + <input type="checkbox" value="testTimer" ng-model="specification.calibration.checkChannels" /> + </div> + </div> + </div> <div id="metricsNode" class="node"> <h3>Session Metrics</h3> <div class="attributes"> @@ -142,6 +155,12 @@ </div> <div id="globalpresurvey" class="node" ng-controller="survey" ng-init="survey = specification.preTest"> <h2>Pre Test Survey</h2> + <div class="attributes"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Allow users to go both back and forward in the test"> + <span>Show back button: </span> + <input type="checkbox" ng-model="survey.showBackButton" /> + </div> + </div> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> @@ -273,6 +292,12 @@ </div> <div id="globalpostsurvey" class="node" ng-controller="survey" ng-init="survey = specification.postTest"> <h2>Post Test Survey</h2> + <div class="attributes"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Allow users to go both back and forward in the test"> + <span>Show back button: </span> + <input type="checkbox" ng-model="survey.showBackButton" /> + </div> + </div> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> @@ -446,6 +471,10 @@ <span>Show Fragment Comments: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> + <div class="attribute" name="ticks" type="show" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show tick marks for each scale label"> + <span>Show Scale Ticks: </span> + <input type="checkbox" ng-click="enableInterfaceOption($event)" /> + </div> </div> </div> </div> @@ -453,7 +482,7 @@ <div style="text-align: center;"> <button type="button" class="btn btn-success" ng-click="addPage()">Add Page</button> </div> - <div class="node pageNode" ng-controller="page" ng-repeat="page in specification.pages"> + <div class="node pageNode" ng-controller="page" ng-repeat="page in specification.pages" dropzone> <h2>Page</h2> <button type="button" class="btn btn-danger" ng-click="removePage(page)">Remove Page</button> <div class="attributes"> @@ -550,6 +579,12 @@ </div> <div class="node" ng-controller="survey" ng-init="survey = page.preTest"> <h2>Pre Page Survey</h2> + <div class="attributes"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Allow users to go both back and forward in the test"> + <span>Show back button: </span> + <input type="checkbox" ng-model="survey.showBackButton" /> + </div> + </div> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> @@ -681,6 +716,12 @@ </div> <div class="node" ng-controller="survey" ng-init="survey = page.postTest"> <h2>Post Page Survey</h2> + <div class="attributes"> + <div class="attribute" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Allow users to go both back and forward in the test"> + <span>Show back button: </span> + <input type="checkbox" ng-model="survey.showBackButton" /> + </div> + </div> <button type="button" class="btn btn-success" ng-click="addSurveyEntry()">Add Entry</button> <div class="node surveyentry" ng-repeat="opt in survey.options" ng-controller="surveyOption"> <h3>Survey Entry</h3> @@ -856,6 +897,10 @@ <span>Show Fragment Comments: </span> <input type="checkbox" ng-click="enableInterfaceOption($event)" /> </div> + <div class="attribute" name="ticks" type="show" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="hover" data-content="Show tick marks for each scale label"> + <span>Show Scale Ticks: </span> + <input type="checkbox" ng-click="enableInterfaceOption($event)" /> + </div> </div> </div> <div class="node"> @@ -909,6 +954,15 @@ <button type="button" class="btn btn-danger" ng-click="removeCommentQuestion(cq)">Remove Comment Question</button> <div class="attributes"> <div class="attribute"> + <span>Type:</span> + <select ng-model="cq.type"> + <option value="question">Question</option> + <option value="checkbox">Checkbox</option> + <option value="radio">Radio</option> + <option value="slider">Slider</option> + </select> + </div> + <div class="attribute"> <span>Unique ID:</span> <input type="text" ng-model="cq.id" required/> </div> @@ -916,6 +970,10 @@ <span>Common Name:</span> <input type="text" ng-model="cq.name" /> </div> + <div class="attribute"> + <span>Mandatory:</span> + <input type="checkbox" ng-model="cq.mandatory" /> + </div> <div class="attribute" ng-show="cq.type == 'slider'"> <span>Minimum:</span> <input type="number" ng-model="cq.min" /> @@ -1044,46 +1102,69 @@ </div> </div> </div> - <div id="popupHolder" ng-show="popupVisible"> - <div ng-controller="introduction" class="popup" ng-show="popupVisible"> - <div class="popupTitle" ng-switch="state"> - <span ng-switch-when="0">Test Creator <span class="label label-primary">v1.2.2</span></span> - <span ng-switch-when="1">Create New Test</span> - </div> - <div class="popupContent container-fluid" ng-switch="state"> - <div ng-switch-when="0"> - <h3>Please wait while assets load...</h3> + <div class="modal fade bs-example-modal-lg" id="popupHolder" tabindex="-1" role="dialog" ng-controller="introduction"> + <div class="modal-dialog modal-lg" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h3>Test Creator</h3> + <h3 class="label label-primary">v1.2.3</h3> </div> - <div ng-switch-when="1"> - <div> - <span>Welcome to the WAET test creator tool. This will allow you to create a new test from scratch to suit your testing needs. If you wish to update a test file, please drag and drop the XML document into the area below for processing, otherwise press 'Next' to start a new test. This tool generates files for the WAET 1.2.2 version.</span> + <div class="modal-body" ng-switch="state"> + <div ng-switch-when="0"> + <div> + <h3>Please wait while assets load...</h3> + </div> </div> - <div> - <input type="file" id="files" ng-model="files" onchange="handleFiles(event)" /> + <div ng-switch-when="1"> + <div> + <span>Welcome to the WAET test creator tool. This will allow you to create a new test from scratch to suit your testing needs. If you wish to update a test file, please drag and drop the XML document into the area below for processing, otherwise press 'Next' to start a new test. This tool generates files for the WAET 1.2.3 version.</span> + </div> + <div> + <input type="file" id="files" ng-model="files" onchange="handleFiles(event)" /> + </div> + </div> + <div ng-switch-when="2"> + <div> + <span>Please select the interface you would like to use below. Selecting an interface will give a brief description of the interface type.</span> + </div> + <div class="row"> + <div class="col-md-6"> + <div class="new-test" ng-repeat="i in testSpecifications.interfaces" ng-mouseover="mouseover(i.name)" ng-click="select(i.name)"> + <label style="cursor:pointer"> + <input type="radio" name="new-test" value="{{i.name}}" id="i.name" style="cursor:pointer" /> {{i.name}} + </label> + </div> + </div> + <div class="col-md-6"> + <span>{{description}}</span> + </div> + </div> + </div> + <div ng-switch-when="3" dropzone> + <div> + <h4>Audio Files</h4> + <p>{{selected}} is a pairwise test with only two fragments per page. To make it easy to add a lot of fragments (and therefore pages) you can automatically drop your fragments onto here, set a name for each and we will populate your page elements for you!</p> + </div> + <table class="table table-bordered"> + <tr> + <td>Filename</td> + <td>Name</td> + </tr> + <tr ng-repeat="elem in audioFragments"> + <td>{{elem.fname}}</td> + <td> + <input type="text" ng-model="elem.name" required /> + </td> + </tr> + </table> </div> </div> - <div ng-switch-when="2"> - <div> - <span>Please select the interface you would like to use below. Selecting an interface will give a brief description of the interface type.</span> - </div> - <div class="row"> - <div class="col-md-6" style="overflow-y: scroll;height: 333px;"> - <div class="new-test" ng-repeat="i in testSpecifications.interfaces" ng-mouseover="mouseover(i.name)" ng-click="select(i.name)"> - <label style="cursor:pointer"> - <input type="radio" name="new-test" value="{{i.name}}" id="i.name" style="cursor:pointer" /> {{i.name}} - </label> - </div> - </div> - <div class="col-md-6"> - <span>{{description}}</span> - </div> - </div> + <div class="modal-footer"> + <button id="popupBack" type="button" class="btn btn-default" ng-show="state>0" ng-click="back()">Back</button> + <button id="popupNext" type="button" class="btn btn-warning" ng-show="state>1" ng-click="skip()">Skip</button> + <button id="popupNext" type="button" class="btn btn-default" ng-click="next()">Next</button> </div> </div> - <div class="popupButtons"> - <button id="popupBack" type="button" class="btn btn-default" ng-show="state>0" ng-click="back()">Back</button> - <button id="popupNext" type="button" class="btn btn-default" ng-click="next()">Next</button> - </div> </div> </div> <div id="screenblank" ng-show="popupVisible"></div>
--- a/test_create/style.css Tue Apr 10 10:18:25 2018 +0100 +++ b/test_create/style.css Tue Apr 10 10:22:34 2018 +0100 @@ -8,12 +8,6 @@ background-color: rgba(0, 0, 0, 0.75); } #popupHolder { - text-align: center; - width: 100%; - height: 100%; - position: fixed; - top: 0px; - z-index: 2; } .popup { position: relative;
--- a/test_create/test_core.js Tue Apr 10 10:18:25 2018 +0100 +++ b/test_create/test_core.js Tue Apr 10 10:22:34 2018 +0100 @@ -31,11 +31,48 @@ var AngularInterface = angular.module("creator", []); +AngularInterface.directive("dropzone", function () { + return { + restrict: "A", + link: function (scope, elem) { + elem.bind('dragover', function (evt) { + evt.stopPropagation(); + evt.preventDefault(); + }); + elem.bind('dragend', function (evt) { + console.log(evt); + evt.stopPropagation(); + evt.preventDefault(); + }); + elem.bind('drop', function (event) { + var evt = event.originalEvent; + console.log(evt); + evt.stopPropagation(); + evt.preventDefault(); + + var files = evt.dataTransfer.files; + for (var i = 0, f; f = files[i]; i++) { + var reader = new FileReader(); + reader.readAsArrayBuffer(f); + + reader.onload = (function (theFile) { + return function (e) { + scope.ondrop(theFile.name); + scope.$apply(); + }; + })(f); + } + }); + } + } +}); + var specification = new Specification(); window.onload = function () { // Get the test interface specifications toggleDropdowns(); + $("#popupHolder").modal("show"); }; function toggleDropdowns() { @@ -51,7 +88,6 @@ } AngularInterface.controller("view", ['$scope', '$element', '$window', function ($s, $e, $w) { - $s.popupVisible = true; $s.testSpecifications = {}; (function () { @@ -75,12 +111,6 @@ }); })(); - $s.showPopup = function () { - $s.popupVisible = true; - }; - $s.hidePopup = function () { - $s.popupVisible = false; - }; $s.globalSchema = undefined; get("xml/test-schema.xsd").then(function (text) { specification.processSchema(text); @@ -178,13 +208,39 @@ AngularInterface.controller("introduction", ['$scope', '$element', '$window', function ($s, $e, $w) { $s.state = 0; $s.selected = undefined; + $s.close = function () { + $($e[0]).modal('hide'); + } $s.next = function () { + if (($s.state === 1 && $s.file) || $s.state === 2) { + $s.initialise($s.selected); + if ($s.selected != "AB" && $s.selected != "ABX") { + $s.close(); + } + } else if ($s.state === 3 && $s.audioFragments.length > 0) { + // Populate the audio pages by creating a pairwise set of pairs + $s.populatePages((function (a) { + var b = []; + a.forEach(function (e1, i1, a) { + a.forEach(function (e2, i2) { + var entry = [e1, e2]; + if (i1 > i2) { + b.push(entry); + } + }); + }); + return b; + })($s.audioFragments)); + $s.close(); + } else if ($s.state > 3) { + $s.close(); + } $s.state++; - if ($s.state > 2 || $s.file) { - $s.hidePopup(); - $s.initialise($s.selected); - } + console.log("Modal state " + $s.state); }; + $s.skip = function () { + $s.close(); + } $s.back = function () { $s.state--; }; @@ -221,9 +277,9 @@ } }; $s.select = function (name) { - $s.selected = name; - } - // Get the test interface specifications + $s.selected = name; + }; + // Get the test interface specifications $s.file = undefined; $s.description = ""; @@ -241,6 +297,28 @@ }; r.readAsText($s.file); }; + + $s.audioFragments = []; + $s.ondrop = function (filename) { + $s.audioFragments.push({ + fname: filename, + name: "fragment-" + String($s.audioFragments.length) + }); + }; + + $s.populatePages = function (structures) { + structures.forEach(function (p, i) { + var page = $w.specification.createNewPage(); + page.id = "page-" + String(i); + p.forEach(function (a) { + var fragment = page.addAudioElement(); + fragment.name = a.name; + fragment.id = a.name + "-p" + String(i); + fragment.url = a.fname; + }); + page.addInterface(); + }); + } }]); AngularInterface.controller("setup", ['$scope', '$element', '$window', function ($s, $e, $w) { @@ -502,6 +580,10 @@ $s.addAudioElement = function () { $s.page.addAudioElement(); }; + $s.ondrop = function (filename) { + var fragment = $s.page.addAudioElement(); + fragment.url = filename; + }; $s.removeAudioElement = function (element) { var index = $s.page.audioElements.findIndex(function (a) { return a == element;
--- a/tests/examples/AB_example.xml Tue Apr 10 10:18:25 2018 +0100 +++ b/tests/examples/AB_example.xml Tue Apr 10 10:22:34 2018 +0100 @@ -45,10 +45,6 @@ <metricenable>elementListenTracker</metricenable> </metric> <interface> - <interfaceoption type="check" name="fragmentMoved" /> - <interfaceoption type="check" name="scalerange" min="25" max="75"> - <errormessage>Test Error Message</errormessage> - </interfaceoption> <interfaceoption type="show" name='playhead' /> <interfaceoption type="show" name="page-count" /> <interfaceoption type="show" name='volume' />
--- a/tests/examples/APE_example.xml Tue Apr 10 10:18:25 2018 +0100 +++ b/tests/examples/APE_example.xml Tue Apr 10 10:22:34 2018 +0100 @@ -1,145 +1,146 @@ <?xml version="1.0" encoding="ISO-8859-1"?> -<waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> - <setup interface="APE" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23" calibration="true"> - <survey location="before"> - <surveyquestion id="sessionId" mandatory="true"> - <statement>Please enter your name.</statement> - <conditional check="equals" value="John" jumpToOnPass="test-intro" jumpToOnFail="checkboxtest" /> - </surveyquestion> - <surveycheckbox id="checkboxtest" mandatory="true" min="2" max="4" randomise="true"> - <statement>Please select with which activities you have any experience (example checkbox question)</statement> - <option name="musician">Playing a musical instrument</option> - <option name="soundengineer">Recording or mixing audio</option> - <option name="developer">Developing audio software</option> - <option name="hwdesigner">Designing or building audio hardware</option> - <option name="researcher">Research in the field of audio</option> - </surveycheckbox> - <surveyquestion id="instrument" mandatory="false"> - <statement>What instrument did you play?</statement> - </surveyquestion> - <surveystatement id="test-intro"> - <statement>This is an example of an 'APE'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement> - </surveystatement> - </survey> - <survey location="after"> - <surveyquestion id="location" mandatory="true" boxsize="large"> - <statement>Please enter your location. (example mandatory text question)</statement> - </surveyquestion> - <surveynumber id="age" min="0"> - <statement>Please enter your age (example non-mandatory number question)</statement> - </surveynumber> - <surveyradio id="rating"> - <statement>Please rate this interface (example radio button question)</statement> - <option name="bad">Bad</option> - <option name="poor">Poor</option> - <option name="good">Good</option> - <option name="great">Great</option> - </surveyradio> - <surveystatement id="thankyou"> - <statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement> - </surveystatement> - </survey> - <metric> - <metricenable>testTimer</metricenable> - <metricenable>elementTimer</metricenable> - <metricenable>elementInitialPosition</metricenable> - <metricenable>elementTracker</metricenable> - <metricenable>elementFlagListenedTo</metricenable> - <metricenable>elementFlagMoved</metricenable> - <metricenable>elementListenTracker</metricenable> - </metric> - <interface> - <interfaceoption type="check" name="fragmentMoved" /> - <interfaceoption type="check" name="fragmentPlayed" /> - <interfaceoption type="check" name="scalerange" min="25" max="75" /> - <interfaceoption type="show" name='playhead' /> - <interfaceoption type="show" name="page-count" /> - <interfaceoption type="show" name="comments" /> - </interface> - </setup> - <page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' synchronous="true" loudness="-12"> - <commentboxprefix>Comment on fragment</commentboxprefix> - <interface name="preference"> - <title>Preference</title> - <scales> - <scalelabel position="0">Min</scalelabel> - <scalelabel position="100">Max</scalelabel> - <scalelabel position="50">Middle</scalelabel> - <scalelabel position="20">20</scalelabel> - </scales> - </interface> - <interface name="depth"> - <title>Depth</title> - <scales> - <scalelabel position="0">Low</scalelabel> - <scalelabel position="100">High</scalelabel> - <scalelabel position="50">Middle</scalelabel> - <scalelabel position="50">Middle</scalelabel> - </scales> - </interface> - <audioelement url="0.wav" id="track-0" type="anchor" /> - <audioelement url="1.wav" id="track-1" /> - <audioelement url="2.wav" id="track-2" /> - <audioelement url="3.wav" id="track-3" /> - <audioelement url="4.wav" id="track-4" /> - <survey location="before"> - <surveyentry type="statement" id="test-0-intro"> - <statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="genre-0" mandatory="true"> - <statement>Please enter the genre.</statement> - </surveyentry> - </survey> - </page> - <page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false' synchronous="true" label="letter"> - <commentboxprefix>Comment on fragment</commentboxprefix> - <interface name="preference"> - <title>Example Test Question</title> - <scales> - <scalelabel position="0">Min</scalelabel> - <scalelabel position="100">Max</scalelabel> - <scalelabel position="50">Middle</scalelabel> - <scalelabel position="20">20</scalelabel> - </scales> - </interface> - <audioelement url="0.wav" gain="-6" id="track-5" type="anchor" marker="20" /> - <audioelement url="1.wav" gain="0.0" id="track-6" type="reference" marker="80" /> - <audioelement url="2.wav" gain="0.0" id="track-7" /> - <audioelement url="3.wav" gain="0.0" id="track-8" /> - <audioelement url="4.wav" gain="0.0" id="track-9" /> - <audioelement url="5.wav" gain="0.0" id="track-10" /> - <audioelement url="6.wav" gain="0.0" id="track-11" type="outside-reference" /> - <commentquestions> - <commentquestion id='mixingExperience'> - <statement>What is your general experience with numbers?</statement> - </commentquestion> - <commentradio id="preference"> - <statement>Please enter your overall preference</statement> - <option name="worst">Very Bad</option> - <option name="bad"></option> - <option name="OK">OK</option> - <option name="Good"></option> - <option name="Great">Great</option> - </commentradio> - <commentcheckbox id="character" type="checkbox"> - <statement>Please describe the overall character</statement> - <option name="funky">Funky</option> - <option name="mellow">Mellow</option> - <option name="laidback">Laid back</option> - <option name="heavy">Heavy</option> - </commentcheckbox> - </commentquestions> - <survey location="before"> - <surveyentry type="statement" id="test-1-intro"> - <statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement> - </surveyentry> - </survey> - <survey location="after"> - <surveyentry type="question" id="genre-1" mandatory="true"> - <statement>Please enter the genre.</statement> - </surveyentry> - </survey> - </page> -</waet> + <waet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="test-schema.xsd"> + <setup interface="APE" projectReturn="save.php" randomiseOrder='true' poolSize="2" loudness="-23"> + <calibration checkFrequencies="true" checkLevels="true" checkChannels="true" /> + <survey location="before"> + <surveyquestion id="sessionId" mandatory="true"> + <statement>Please enter your name.</statement> + <conditional check="equals" value="John" jumpToOnPass="test-intro" jumpToOnFail="checkboxtest" /> + </surveyquestion> + <surveycheckbox id="checkboxtest" mandatory="true" min="2" max="4" randomise="true"> + <statement>Please select with which activities you have any experience (example checkbox question)</statement> + <option name="musician">Playing a musical instrument</option> + <option name="soundengineer">Recording or mixing audio</option> + <option name="developer">Developing audio software</option> + <option name="hwdesigner">Designing or building audio hardware</option> + <option name="researcher">Research in the field of audio</option> + </surveycheckbox> + <surveyquestion id="instrument" mandatory="false"> + <statement>What instrument did you play?</statement> + </surveyquestion> + <surveystatement id="test-intro"> + <statement>This is an example of an 'APE'-style test, with two pages, using the test stimuli in 'example_eval/'.</statement> + </surveystatement> + </survey> + <survey location="after"> + <surveyquestion id="location" mandatory="true" boxsize="large"> + <statement>Please enter your location. (example mandatory text question)</statement> + </surveyquestion> + <surveynumber id="age" min="0"> + <statement>Please enter your age (example non-mandatory number question)</statement> + </surveynumber> + <surveyradio id="rating"> + <statement>Please rate this interface (example radio button question)</statement> + <option name="bad">Bad</option> + <option name="poor">Poor</option> + <option name="good">Good</option> + <option name="great">Great</option> + </surveyradio> + <surveystatement id="thankyou"> + <statement>Thank you for taking this listening test. Please click 'submit' and your results will appear in the 'saves/' folder.</statement> + </surveystatement> + </survey> + <metric> + <metricenable>testTimer</metricenable> + <metricenable>elementTimer</metricenable> + <metricenable>elementInitialPosition</metricenable> + <metricenable>elementTracker</metricenable> + <metricenable>elementFlagListenedTo</metricenable> + <metricenable>elementFlagMoved</metricenable> + <metricenable>elementListenTracker</metricenable> + </metric> + <interface> + <interfaceoption type="check" name="fragmentMoved" /> + <interfaceoption type="check" name="fragmentPlayed" /> + <interfaceoption type="check" name="scalerange" min="25" max="75" /> + <interfaceoption type="show" name='playhead' /> + <interfaceoption type="show" name="page-count" /> + <interfaceoption type="show" name="comments" /> + </interface> + </setup> + <page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' synchronous="true" loudness="-12"> + <commentboxprefix>Comment on fragment</commentboxprefix> + <interface name="preference"> + <title>Preference</title> + <scales> + <scalelabel position="0">Min</scalelabel> + <scalelabel position="100">Max</scalelabel> + <scalelabel position="50">Middle</scalelabel> + <scalelabel position="20">20</scalelabel> + </scales> + </interface> + <interface name="depth"> + <title>Depth</title> + <scales> + <scalelabel position="0">Low</scalelabel> + <scalelabel position="100">High</scalelabel> + <scalelabel position="50">Middle</scalelabel> + <scalelabel position="50">Middle</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" id="track-0" type="anchor" /> + <audioelement url="1.wav" id="track-1" /> + <audioelement url="2.wav" id="track-2" /> + <audioelement url="3.wav" id="track-3" /> + <audioelement url="4.wav" id="track-4" /> + <survey location="before"> + <surveyentry type="statement" id="test-0-intro"> + <statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="genre-0" mandatory="true"> + <statement>Please enter the genre.</statement> + </surveyentry> + </survey> + </page> + <page id='test-1' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='false' synchronous="true" label="letter"> + <commentboxprefix>Comment on fragment</commentboxprefix> + <interface name="preference"> + <title>Example Test Question</title> + <scales> + <scalelabel position="0">Min</scalelabel> + <scalelabel position="100">Max</scalelabel> + <scalelabel position="50">Middle</scalelabel> + <scalelabel position="20">20</scalelabel> + </scales> + </interface> + <audioelement url="0.wav" gain="-6" id="track-5" type="anchor" marker="20" /> + <audioelement url="1.wav" gain="0.0" id="track-6" type="reference" marker="80" /> + <audioelement url="2.wav" gain="0.0" id="track-7" /> + <audioelement url="3.wav" gain="0.0" id="track-8" /> + <audioelement url="4.wav" gain="0.0" id="track-9" /> + <audioelement url="5.wav" gain="0.0" id="track-10" /> + <audioelement url="6.wav" gain="0.0" id="track-11" type="outside-reference" /> + <commentquestions> + <commentquestion id='mixingExperience'> + <statement>What is your general experience with numbers?</statement> + </commentquestion> + <commentradio id="preference"> + <statement>Please enter your overall preference</statement> + <option name="worst">Very Bad</option> + <option name="bad"></option> + <option name="OK">OK</option> + <option name="Good"></option> + <option name="Great">Great</option> + </commentradio> + <commentcheckbox id="character"> + <statement>Please describe the overall character</statement> + <option name="funky">Funky</option> + <option name="mellow">Mellow</option> + <option name="laidback">Laid back</option> + <option name="heavy">Heavy</option> + </commentcheckbox> + </commentquestions> + <survey location="before"> + <surveyentry type="statement" id="test-1-intro"> + <statement>Example of an 'APE' style interface with hidden anchor 'zero' (which needs to be below 20%), looping of the samples, randomisation of marker labels, mandatory moving of every sample, and a forced scale usage of at least 25%-75%.</statement> + </surveyentry> + </survey> + <survey location="after"> + <surveyentry type="question" id="genre-1" mandatory="true"> + <statement>Please enter the genre.</statement> + </surveyentry> + </survey> + </page> + </waet>
--- a/tests/examples/horizontal_example.xml Tue Apr 10 10:18:25 2018 +0100 +++ b/tests/examples/horizontal_example.xml Tue Apr 10 10:22:34 2018 +0100 @@ -17,6 +17,7 @@ <interfaceoption type="show" name="page-count" /> <interfaceoption type="show" name="volume" /> <interfaceoption type="show" name="comments" /> + <interfaceoption type="show" name="ticks" /> </interface> </setup> <page id='test-0' hostURL="media/example/" randomiseOrder='true' repeatCount='0' loop='true' loudness="-12">
--- a/tests/examples/mushra_example.xml Tue Apr 10 10:18:25 2018 +0100 +++ b/tests/examples/mushra_example.xml Tue Apr 10 10:22:34 2018 +0100 @@ -112,24 +112,24 @@ <audioelement url="5.wav" gain="0.0" id="track-10" /> <audioelement url="1.wav" gain="0.0" id="track-11" type="outside-reference" /> <commentquestions> - <commentquestion id='mixingExperience' type="question"> + <commentquestion id='mixingExperience'> <statement>What is your general experience with numbers?</statement> </commentquestion> - <commentquestion id="preference" type="radio"> + <commentradio id="preference"> <statement>Please enter your overall preference</statement> <option name="worst">Very Bad</option> <option name="bad"></option> <option name="OK">OK</option> <option name="Good"></option> <option name="Great">Great</option> - </commentquestion> - <commentquestion id="character" type="checkbox"> + </commentradio> + <commentcheckbox id="character"> <statement>Please describe the overall character</statement> <option name="funky">Funky</option> <option name="mellow">Mellow</option> <option name="laidback">Laid back</option> <option name="heavy">Heavy</option> - </commentquestion> + </commentcheckbox> </commentquestions> <survey location="before"> <surveyentry type="statement" id="test-1-intro">
--- a/tests/examples/radio_example.xml Tue Apr 10 10:18:25 2018 +0100 +++ b/tests/examples/radio_example.xml Tue Apr 10 10:22:34 2018 +0100 @@ -29,9 +29,9 @@ <scalelabel position="100">(5) Inaudible</scalelabel> </scales> </interface> - <audioelement url="0.wav" id="track-1" alwaysInclude="true" /> - <audioelement url="1.wav" id="track-2" /> - <audioelement url="3.wav" id="track-4" /> - <audioelement url="3.wav" id="track-5" /> + <audioelement url="0.wav" id="track-0" alwaysInclude="true" /> + <audioelement url="1.wav" id="track-1" /> + <audioelement url="2.wav" id="track-2" /> + <audioelement url="3.wav" id="track-3" /> </page> </waet>
--- a/xml/test-schema.xsd Tue Apr 10 10:18:25 2018 +0100 +++ b/xml/test-schema.xsd Tue Apr 10 10:22:34 2018 +0100 @@ -48,6 +48,7 @@ <xs:complexType> <xs:sequence> <xs:element name="exitText" type="xs:string" minOccurs="0" maxOccurs="1" /> + <xs:element ref="calibration" minOccurs="0" maxOccurs="1" /> <xs:element ref="survey" minOccurs="0" maxOccurs="2" /> <xs:element ref="metric" maxOccurs="1" /> <xs:element ref="interface" maxOccurs="1" /> @@ -59,7 +60,6 @@ <xs:attribute ref="poolSize" /> <xs:attribute name="loudness" type="xs:nonPositiveInteger" use="optional" /> <xs:attribute name="sampleRate" type="xs:positiveInteger" use="optional" /> - <xs:attribute name="calibration" type="xs:boolean" default="false" /> <xs:attribute name="crossFade" default="0.0"> <xs:simpleType> <xs:restriction base="xs:decimal"> @@ -67,6 +67,7 @@ </xs:restriction> </xs:simpleType> </xs:attribute> + <xs:attribute name="randomiseAxisOrder" type="xs:boolean" default="false" /> <xs:attribute ref="preSilence" /> <xs:attribute ref="postSilence" /> <xs:attribute ref="playOne" /> @@ -75,6 +76,14 @@ </xs:complexType> </xs:element> + <xs:element name="calibration"> + <xs:complexType> + <xs:attribute name="checkFrequencies" type="xs:boolean" default="false" /> + <xs:attribute name="checkLevels" type="xs:boolean" default="false" /> + <xs:attribute name="checkChannels" type="xs:boolean" default="false" /> + </xs:complexType> + </xs:element> + <xs:element name="page"> <xs:complexType> <xs:sequence> @@ -105,6 +114,7 @@ </xs:simpleType> </xs:attribute> <xs:attribute name="labelStart" type="xs:string" use="optional" default="" /> + <xs:attribute name="randomiseAxisOrder" type="xs:boolean" use="optional" /> <xs:attribute ref="poolSize" /> <xs:attribute ref="alwaysInclude" /> <xs:attribute name="position" use="optional" type="xs:nonNegativeInteger" /> @@ -277,6 +287,7 @@ </xs:sequence> <xs:attribute ref="id" use="optional" /> <xs:attribute ref="name" use="optional" /> + <xs:attribute ref="mandatory" use="optional" /> </xs:complexType> </xs:element> @@ -296,6 +307,7 @@ </xs:sequence> <xs:attribute ref="id" use="optional" /> <xs:attribute ref="name" use="optional" /> + <xs:attribute ref="mandatory" use="optional" /> </xs:complexType> </xs:element> @@ -306,6 +318,7 @@ </xs:sequence> <xs:attribute ref="id" use="optional" /> <xs:attribute ref="name" use="optional" /> + <xs:attribute ref="mandatory" use="optional" /> </xs:complexType> </xs:element> @@ -322,6 +335,7 @@ <xs:attribute name="max" type="xs:decimal" use="required" /> <xs:attribute name="step" type="xs:decimal" use="optional" default="1" /> <xs:attribute name="value" type="xs:decimal" use="optional" /> + <xs:attribute ref="mandatory" use="optional" /> </xs:complexType> </xs:element> @@ -547,6 +561,7 @@ </xs:restriction> </xs:simpleType> </xs:attribute> + <xs:attribute name="showBackButton" type="xs:boolean" default="true" /> </xs:complexType> </xs:element>