summaryrefslogtreecommitdiff
path: root/assets/trading-in-the-rain/MIDI.js/inc/shim
diff options
context:
space:
mode:
Diffstat (limited to 'assets/trading-in-the-rain/MIDI.js/inc/shim')
-rw-r--r--assets/trading-in-the-rain/MIDI.js/inc/shim/Base64.js61
-rw-r--r--assets/trading-in-the-rain/MIDI.js/inc/shim/Base64binary.js81
-rw-r--r--assets/trading-in-the-rain/MIDI.js/inc/shim/WebAudioAPI.js111
-rw-r--r--assets/trading-in-the-rain/MIDI.js/inc/shim/WebMIDIAPI.js421
4 files changed, 674 insertions, 0 deletions
diff --git a/assets/trading-in-the-rain/MIDI.js/inc/shim/Base64.js b/assets/trading-in-the-rain/MIDI.js/inc/shim/Base64.js
new file mode 100644
index 0000000..b5a59ce
--- /dev/null
+++ b/assets/trading-in-the-rain/MIDI.js/inc/shim/Base64.js
@@ -0,0 +1,61 @@
+//https://github.com/davidchambers/Base64.js
+
+;(function () {
+ var object = typeof exports != 'undefined' ? exports : this; // #8: web workers
+ var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+ function InvalidCharacterError(message) {
+ this.message = message;
+ }
+ InvalidCharacterError.prototype = new Error;
+ InvalidCharacterError.prototype.name = 'InvalidCharacterError';
+
+ // encoder
+ // [https://gist.github.com/999166] by [https://github.com/nignag]
+ object.btoa || (
+ object.btoa = function (input) {
+ for (
+ // initialize result and counter
+ var block, charCode, idx = 0, map = chars, output = '';
+ // if the next input index does not exist:
+ // change the mapping table to "="
+ // check if d has no fractional digits
+ input.charAt(idx | 0) || (map = '=', idx % 1);
+ // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
+ output += map.charAt(63 & block >> 8 - idx % 1 * 8)
+ ) {
+ charCode = input.charCodeAt(idx += 3/4);
+ if (charCode > 0xFF) {
+ throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
+ }
+ block = block << 8 | charCode;
+ }
+ return output;
+ });
+
+ // decoder
+ // [https://gist.github.com/1020396] by [https://github.com/atk]
+ object.atob || (
+ object.atob = function (input) {
+ input = input.replace(/=+$/, '')
+ if (input.length % 4 == 1) {
+ throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
+ }
+ for (
+ // initialize result and counters
+ var bc = 0, bs, buffer, idx = 0, output = '';
+ // get next character
+ buffer = input.charAt(idx++);
+ // character found in table? initialize bit storage and add its ascii value;
+ ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
+ // and if not first of each 4 characters,
+ // convert the first 8 bits to one ascii character
+ bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
+ ) {
+ // try to find character in table (0-63, not found => -1)
+ buffer = chars.indexOf(buffer);
+ }
+ return output;
+ });
+
+}()); \ No newline at end of file
diff --git a/assets/trading-in-the-rain/MIDI.js/inc/shim/Base64binary.js b/assets/trading-in-the-rain/MIDI.js/inc/shim/Base64binary.js
new file mode 100644
index 0000000..2c59f8f
--- /dev/null
+++ b/assets/trading-in-the-rain/MIDI.js/inc/shim/Base64binary.js
@@ -0,0 +1,81 @@
+/**
+ * @license -------------------------------------------------------------------
+ * module: Base64Binary
+ * src: http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/
+ * license: Simplified BSD License
+ * -------------------------------------------------------------------
+ * Copyright 2011, Daniel Guerrero. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL GUERRERO BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+var Base64Binary = {
+ _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+
+ /* will return a Uint8Array type */
+ decodeArrayBuffer: function(input) {
+ var bytes = Math.ceil( (3*input.length) / 4.0);
+ var ab = new ArrayBuffer(bytes);
+ this.decode(input, ab);
+
+ return ab;
+ },
+
+ decode: function(input, arrayBuffer) {
+ //get last chars to see if are valid
+ var lkey1 = this._keyStr.indexOf(input.charAt(input.length-1));
+ var lkey2 = this._keyStr.indexOf(input.charAt(input.length-1));
+
+ var bytes = Math.ceil( (3*input.length) / 4.0);
+ if (lkey1 == 64) bytes--; //padding chars, so skip
+ if (lkey2 == 64) bytes--; //padding chars, so skip
+
+ var uarray;
+ var chr1, chr2, chr3;
+ var enc1, enc2, enc3, enc4;
+ var i = 0;
+ var j = 0;
+
+ if (arrayBuffer)
+ uarray = new Uint8Array(arrayBuffer);
+ else
+ uarray = new Uint8Array(bytes);
+
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+ for (i=0; i<bytes; i+=3) {
+ //get the 3 octects in 4 ascii chars
+ enc1 = this._keyStr.indexOf(input.charAt(j++));
+ enc2 = this._keyStr.indexOf(input.charAt(j++));
+ enc3 = this._keyStr.indexOf(input.charAt(j++));
+ enc4 = this._keyStr.indexOf(input.charAt(j++));
+
+ chr1 = (enc1 << 2) | (enc2 >> 4);
+ chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+ chr3 = ((enc3 & 3) << 6) | enc4;
+
+ uarray[i] = chr1;
+ if (enc3 != 64) uarray[i+1] = chr2;
+ if (enc4 != 64) uarray[i+2] = chr3;
+ }
+
+ return uarray;
+ }
+}; \ No newline at end of file
diff --git a/assets/trading-in-the-rain/MIDI.js/inc/shim/WebAudioAPI.js b/assets/trading-in-the-rain/MIDI.js/inc/shim/WebAudioAPI.js
new file mode 100644
index 0000000..17e9eb9
--- /dev/null
+++ b/assets/trading-in-the-rain/MIDI.js/inc/shim/WebAudioAPI.js
@@ -0,0 +1,111 @@
+/**
+ * @license -------------------------------------------------------------------
+ * module: WebAudioShim - Fix naming issues for WebAudioAPI supports
+ * src: https://github.com/Dinahmoe/webaudioshim
+ * author: Dinahmoe AB
+ * -------------------------------------------------------------------
+ * Copyright (c) 2012 DinahMoe AB
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+window.AudioContext = window.AudioContext || window.webkitAudioContext || null;
+window.OfflineAudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext || null;
+
+(function (Context) {
+ var isFunction = function (f) {
+ return Object.prototype.toString.call(f) === "[object Function]" ||
+ Object.prototype.toString.call(f) === "[object AudioContextConstructor]";
+ };
+ var contextMethods = [
+ ["createGainNode", "createGain"],
+ ["createDelayNode", "createDelay"],
+ ["createJavaScriptNode", "createScriptProcessor"]
+ ];
+ ///
+ var proto;
+ var instance;
+ var sourceProto;
+ ///
+ if (!isFunction(Context)) {
+ return;
+ }
+ instance = new Context();
+ if (!instance.destination || !instance.sampleRate) {
+ return;
+ }
+ proto = Context.prototype;
+ sourceProto = Object.getPrototypeOf(instance.createBufferSource());
+
+ if (!isFunction(sourceProto.start)) {
+ if (isFunction(sourceProto.noteOn)) {
+ sourceProto.start = function (when, offset, duration) {
+ switch (arguments.length) {
+ case 0:
+ throw new Error("Not enough arguments.");
+ case 1:
+ this.noteOn(when);
+ break;
+ case 2:
+ if (this.buffer) {
+ this.noteGrainOn(when, offset, this.buffer.duration - offset);
+ } else {
+ throw new Error("Missing AudioBuffer");
+ }
+ break;
+ case 3:
+ this.noteGrainOn(when, offset, duration);
+ }
+ };
+ }
+ }
+
+ if (!isFunction(sourceProto.noteOn)) {
+ sourceProto.noteOn = sourceProto.start;
+ }
+
+ if (!isFunction(sourceProto.noteGrainOn)) {
+ sourceProto.noteGrainOn = sourceProto.start;
+ }
+
+ if (!isFunction(sourceProto.stop)) {
+ sourceProto.stop = sourceProto.noteOff;
+ }
+
+ if (!isFunction(sourceProto.noteOff)) {
+ sourceProto.noteOff = sourceProto.stop;
+ }
+
+ contextMethods.forEach(function (names) {
+ var name1;
+ var name2;
+ while (names.length) {
+ name1 = names.pop();
+ if (isFunction(this[name1])) {
+ this[names.pop()] = this[name1];
+ } else {
+ name2 = names.pop();
+ this[name1] = this[name2];
+ }
+ }
+ }, proto);
+})(window.AudioContext); \ No newline at end of file
diff --git a/assets/trading-in-the-rain/MIDI.js/inc/shim/WebMIDIAPI.js b/assets/trading-in-the-rain/MIDI.js/inc/shim/WebMIDIAPI.js
new file mode 100644
index 0000000..000a916
--- /dev/null
+++ b/assets/trading-in-the-rain/MIDI.js/inc/shim/WebMIDIAPI.js
@@ -0,0 +1,421 @@
+/* Copyright 2013 Chris Wilson
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+// Initialize the MIDI library.
+(function (global) {
+ 'use strict';
+ var midiIO, _requestMIDIAccess, MIDIAccess, _onReady, MIDIPort, MIDIInput, MIDIOutput, _midiProc;
+
+ function Promise() {
+
+ }
+
+ Promise.prototype.then = function(accept, reject) {
+ this.accept = accept;
+ this.reject = reject;
+ }
+
+ Promise.prototype.succeed = function(access) {
+ if (this.accept)
+ this.accept(access);
+ }
+
+ Promise.prototype.fail = function(error) {
+ if (this.reject)
+ this.reject(error);
+ }
+
+ function _JazzInstance() {
+ this.inputInUse = false;
+ this.outputInUse = false;
+
+ // load the Jazz plugin
+ var o1 = document.createElement("object");
+ o1.id = "_Jazz" + Math.random() + "ie";
+ o1.classid = "CLSID:1ACE1618-1C7D-4561-AEE1-34842AA85E90";
+
+ this.activeX = o1;
+
+ var o2 = document.createElement("object");
+ o2.id = "_Jazz" + Math.random();
+ o2.type="audio/x-jazz";
+ o1.appendChild(o2);
+
+ this.objRef = o2;
+
+ var e = document.createElement("p");
+ e.appendChild(document.createTextNode("This page requires the "));
+
+ var a = document.createElement("a");
+ a.appendChild(document.createTextNode("Jazz plugin"));
+ a.href = "http://jazz-soft.net/";
+
+ e.appendChild(a);
+ e.appendChild(document.createTextNode("."));
+ o2.appendChild(e);
+
+ var insertionPoint = document.getElementById("MIDIPlugin");
+ if (!insertionPoint) {
+ // Create hidden element
+ var insertionPoint = document.createElement("div");
+ insertionPoint.id = "MIDIPlugin";
+ insertionPoint.style.position = "absolute";
+ insertionPoint.style.visibility = "hidden";
+ insertionPoint.style.left = "-9999px";
+ insertionPoint.style.top = "-9999px";
+ document.body.appendChild(insertionPoint);
+ }
+ insertionPoint.appendChild(o1);
+
+ if (this.objRef.isJazz)
+ this._Jazz = this.objRef;
+ else if (this.activeX.isJazz)
+ this._Jazz = this.activeX;
+ else
+ this._Jazz = null;
+ if (this._Jazz) {
+ this._Jazz._jazzTimeZero = this._Jazz.Time();
+ this._Jazz._perfTimeZero = window.performance.now();
+ }
+ }
+
+ _requestMIDIAccess = function _requestMIDIAccess() {
+ var access = new MIDIAccess();
+ return access._promise;
+ };
+
+ // API Methods
+
+ MIDIAccess = function() {
+ this._jazzInstances = new Array();
+ this._jazzInstances.push( new _JazzInstance() );
+ this._promise = new Promise;
+
+ if (this._jazzInstances[0]._Jazz) {
+ this._Jazz = this._jazzInstances[0]._Jazz;
+ window.setTimeout( _onReady.bind(this), 3 );
+ } else {
+ window.setTimeout( _onNotReady.bind(this), 3 );
+ }
+ };
+
+ _onReady = function _onReady() {
+ if (this._promise)
+ this._promise.succeed(this);
+ };
+
+ function _onNotReady() {
+ if (this._promise)
+ this._promise.fail( { code: 1 } );
+ };
+
+ MIDIAccess.prototype.inputs = function( ) {
+ if (!this._Jazz)
+ return null;
+ var list=this._Jazz.MidiInList();
+ var inputs = new Array( list.length );
+
+ for ( var i=0; i<list.length; i++ ) {
+ inputs[i] = new MIDIInput( this, list[i], i );
+ }
+ return inputs;
+ }
+
+ MIDIAccess.prototype.outputs = function( ) {
+ if (!this._Jazz)
+ return null;
+ var list=this._Jazz.MidiOutList();
+ var outputs = new Array( list.length );
+
+ for ( var i=0; i<list.length; i++ ) {
+ outputs[i] = new MIDIOutput( this, list[i], i );
+ }
+ return outputs;
+ };
+
+ MIDIInput = function MIDIInput( midiAccess, name, index ) {
+ this._listeners = [];
+ this._midiAccess = midiAccess;
+ this._index = index;
+ this._inLongSysexMessage = false;
+ this._sysexBuffer = new Uint8Array();
+ this.id = "" + index + "." + name;
+ this.manufacturer = "";
+ this.name = name;
+ this.type = "input";
+ this.version = "";
+ this.onmidimessage = null;
+
+ var inputInstance = null;
+ for (var i=0; (i<midiAccess._jazzInstances.length)&&(!inputInstance); i++) {
+ if (!midiAccess._jazzInstances[i].inputInUse)
+ inputInstance=midiAccess._jazzInstances[i];
+ }
+ if (!inputInstance) {
+ inputInstance = new _JazzInstance();
+ midiAccess._jazzInstances.push( inputInstance );
+ }
+ inputInstance.inputInUse = true;
+
+ this._jazzInstance = inputInstance._Jazz;
+ this._input = this._jazzInstance.MidiInOpen( this._index, _midiProc.bind(this) );
+ };
+
+ // Introduced in DOM Level 2:
+ MIDIInput.prototype.addEventListener = function (type, listener, useCapture ) {
+ if (type !== "midimessage")
+ return;
+ for (var i=0; i<this._listeners.length; i++)
+ if (this._listeners[i] == listener)
+ return;
+ this._listeners.push( listener );
+ };
+
+ MIDIInput.prototype.removeEventListener = function (type, listener, useCapture ) {
+ if (type !== "midimessage")
+ return;
+ for (var i=0; i<this._listeners.length; i++)
+ if (this._listeners[i] == listener) {
+ this._listeners.splice( i, 1 ); //remove it
+ return;
+ }
+ };
+
+ MIDIInput.prototype.preventDefault = function() {
+ this._pvtDef = true;
+ };
+
+ MIDIInput.prototype.dispatchEvent = function (evt) {
+ this._pvtDef = false;
+
+ // dispatch to listeners
+ for (var i=0; i<this._listeners.length; i++)
+ if (this._listeners[i].handleEvent)
+ this._listeners[i].handleEvent.bind(this)( evt );
+ else
+ this._listeners[i].bind(this)( evt );
+
+ if (this.onmidimessage)
+ this.onmidimessage( evt );
+
+ return this._pvtDef;
+ };
+
+ MIDIInput.prototype.appendToSysexBuffer = function ( data ) {
+ var oldLength = this._sysexBuffer.length;
+ var tmpBuffer = new Uint8Array( oldLength + data.length );
+ tmpBuffer.set( this._sysexBuffer );
+ tmpBuffer.set( data, oldLength );
+ this._sysexBuffer = tmpBuffer;
+ };
+
+ MIDIInput.prototype.bufferLongSysex = function ( data, initialOffset ) {
+ var j = initialOffset;
+ while (j<data.length) {
+ if (data[j] == 0xF7) {
+ // end of sysex!
+ j++;
+ this.appendToSysexBuffer( data.slice(initialOffset, j) );
+ return j;
+ }
+ j++;
+ }
+ // didn't reach the end; just tack it on.
+ this.appendToSysexBuffer( data.slice(initialOffset, j) );
+ this._inLongSysexMessage = true;
+ return j;
+ };
+
+ _midiProc = function _midiProc( timestamp, data ) {
+ // Have to use createEvent/initEvent because IE10 fails on new CustomEvent. Thanks, IE!
+ var length = 0;
+ var i,j;
+ var isSysexMessage = false;
+
+ // Jazz sometimes passes us multiple messages at once, so we need to parse them out
+ // and pass them one at a time.
+
+ for (i=0; i<data.length; i+=length) {
+ if (this._inLongSysexMessage) {
+ i = this.bufferLongSysex(data,i);
+ if ( data[i-1] != 0xf7 ) {
+ // ran off the end without hitting the end of the sysex message
+ return;
+ }
+ isSysexMessage = true;
+ } else {
+ isSysexMessage = false;
+ switch (data[i] & 0xF0) {
+ case 0x80: // note off
+ case 0x90: // note on
+ case 0xA0: // polyphonic aftertouch
+ case 0xB0: // control change
+ case 0xE0: // channel mode
+ length = 3;
+ break;
+
+ case 0xC0: // program change
+ case 0xD0: // channel aftertouch
+ length = 2;
+ break;
+
+ case 0xF0:
+ switch (data[i]) {
+ case 0xf0: // variable-length sysex.
+ i = this.bufferLongSysex(data,i);
+ if ( data[i-1] != 0xf7 ) {
+ // ran off the end without hitting the end of the sysex message
+ return;
+ }
+ isSysexMessage = true;
+ break;
+
+ case 0xF1: // MTC quarter frame
+ case 0xF3: // song select
+ length = 2;
+ break;
+
+ case 0xF2: // song position pointer
+ length = 3;
+ break;
+
+ default:
+ length = 1;
+ break;
+ }
+ break;
+ }
+ }
+ var evt = document.createEvent( "Event" );
+ evt.initEvent( "midimessage", false, false );
+ evt.receivedTime = parseFloat( timestamp.toString()) + this._jazzInstance._perfTimeZero;
+ if (isSysexMessage || this._inLongSysexMessage) {
+ evt.data = new Uint8Array( this._sysexBuffer );
+ this._sysexBuffer = new Uint8Array(0);
+ this._inLongSysexMessage = false;
+ } else
+ evt.data = new Uint8Array(data.slice(i, length+i));
+ this.dispatchEvent( evt );
+ }
+ };
+
+ MIDIOutput = function MIDIOutput( midiAccess, name, index ) {
+ this._listeners = [];
+ this._midiAccess = midiAccess;
+ this._index = index;
+ this.id = "" + index + "." + name;
+ this.manufacturer = "";
+ this.name = name;
+ this.type = "output";
+ this.version = "";
+
+ var outputInstance = null;
+ for (var i=0; (i<midiAccess._jazzInstances.length)&&(!outputInstance); i++) {
+ if (!midiAccess._jazzInstances[i].outputInUse)
+ outputInstance=midiAccess._jazzInstances[i];
+ }
+ if (!outputInstance) {
+ outputInstance = new _JazzInstance();
+ midiAccess._jazzInstances.push( outputInstance );
+ }
+ outputInstance.outputInUse = true;
+
+ this._jazzInstance = outputInstance._Jazz;
+ this._jazzInstance.MidiOutOpen(this.name);
+ };
+
+ function _sendLater() {
+ this.jazz.MidiOutLong( this.data ); // handle send as sysex
+ }
+
+ MIDIOutput.prototype.send = function( data, timestamp ) {
+ var delayBeforeSend = 0;
+ if (data.length === 0)
+ return false;
+
+ if (timestamp)
+ delayBeforeSend = Math.floor( timestamp - window.performance.now() );
+
+ if (timestamp && (delayBeforeSend>1)) {
+ var sendObj = new Object();
+ sendObj.jazz = this._jazzInstance;
+ sendObj.data = data;
+
+ window.setTimeout( _sendLater.bind(sendObj), delayBeforeSend );
+ } else {
+ this._jazzInstance.MidiOutLong( data );
+ }
+ return true;
+ };
+
+ //init: create plugin
+ if (!window.navigator.requestMIDIAccess)
+ window.navigator.requestMIDIAccess = _requestMIDIAccess;
+
+}(window));
+
+// Polyfill window.performance.now() if necessary.
+(function (exports) {
+ var perf = {}, props;
+
+ function findAlt() {
+ var prefix = ['moz', 'webkit', 'o', 'ms'],
+ i = prefix.length,
+ //worst case, we use Date.now()
+ props = {
+ value: (function (start) {
+ return function () {
+ return Date.now() - start;
+ };
+ }(Date.now()))
+ };
+
+ //seach for vendor prefixed version
+ for (; i >= 0; i--) {
+ if ((prefix[i] + "Now") in exports.performance) {
+ props.value = function (method) {
+ return function () {
+ exports.performance[method]();
+ }
+ }(prefix[i] + "Now");
+ return props;
+ }
+ }
+
+ //otherwise, try to use connectionStart
+ if ("timing" in exports.performance && "connectStart" in exports.performance.timing) {
+ //this pretty much approximates performance.now() to the millisecond
+ props.value = (function (start) {
+ return function() {
+ Date.now() - start;
+ };
+ }(exports.performance.timing.connectStart));
+ }
+ return props;
+ }
+
+ //if already defined, bail
+ if (("performance" in exports) && ("now" in exports.performance))
+ return;
+ if (!("performance" in exports))
+ Object.defineProperty(exports, "performance", {
+ get: function () {
+ return perf;
+ }});
+ //otherwise, performance is there, but not "now()"
+
+ props = findAlt();
+ Object.defineProperty(exports.performance, "now", props);
+}(window));