# HG changeset patch # User Nicholas Jillings # Date 1523352154 -3600 # Node ID 1ae8c03dd6a64fdd63dc4a139cb3ae98a3adbe0a # Parent 171706465aa98699b94429cde32d1eb1530b33a1# Parent f99b888f57e98104689dd632a6e7c8d3af4ad799 Merge branch 'master' into vnext # Conflicts: # test_create.html # test_create/test_core.js diff -r f99b888f57e9 -r 1ae8c03dd6a6 .brackets.json --- /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 diff -r f99b888f57e9 -r 1ae8c03dd6a6 .gitignore --- 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/* diff -r f99b888f57e9 -r 1ae8c03dd6a6 css/core.css --- 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 */ diff -r f99b888f57e9 -r 1ae8c03dd6a6 index.html --- 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 @@
-

Web Audio Evaluation Toolbox (v1.2.2)

+

Web Audio Evaluation Toolbox (v1.2.3)

Start menu

- + diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/AB.css --- 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; } diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/AB.js --- 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') { diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/ABX.css --- 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; diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/ABX.js --- 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; diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/ape.css --- 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; diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/ape.js --- 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); } diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/discrete.css --- 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; -} diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/discrete.js --- 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 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; } } diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/horizontal-sliders.js --- 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; diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/mushra.css --- 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; diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/mushra.js --- 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; diff -r f99b888f57e9 -r 1ae8c03dd6a6 interfaces/timeline.js --- 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') { diff -r f99b888f57e9 -r 1ae8c03dd6a6 js/core.js --- 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); diff -r f99b888f57e9 -r 1ae8c03dd6a6 js/min/core.min.js --- /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='x',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="Please save the file below to give to your test supervisor
",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;ie.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;lNumber(i.value))return!0;break;case"lessThan":if(tNumber(e.value))return!0;break;case"lessThan":if(t0;)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;n1&&(s+="s"),void interfaceContext.lightbox.post("Error",s)}}else if(ot.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;it.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.currentIndex0&&(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=0&&this.stateIndex=2&&(this.status=3);for(var e=0;e=e.length))return t(e[s].url).then(n.bind(this)).catch(i.bind(this));!function(){this.status=-1;for(var t=0;tthis.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;s0&&(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;i0&&(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=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=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=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&&e60){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="Master Volume Control",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()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=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;to.min?(n+="At least one fragment must be below the "+o.min+" mark.",i=!1):s.max=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++)o?1:n122)&&(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=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;n0&&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="

Loading Resources

"},100); \ No newline at end of file diff -r f99b888f57e9 -r 1ae8c03dd6a6 js/min/jquery-2.1.4.min.js --- /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")).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=0&&n=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(;ib.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="";t1?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-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}];a1&&h(c),a>1&&p(e.slice(0,a-1).concat({value:" "===e[a-2].type?"*":""})).replace(se,"$1"),n,a+~]|"+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="",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=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r0,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="","#"===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="",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;t1?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-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-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);i0||(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(;a1,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.lengthx",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=0:V.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return a]*)\/>/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*\s*$/g,Le={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_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;r0&&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")+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>");try{for(;n1&&"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;u1)},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;r1)},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=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=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=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("