├── .gitignore ├── emulator ├── images │ └── black_linen_v2.png ├── fonts │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── css │ ├── timeline.css │ └── emulator.css ├── js │ ├── supports.js │ ├── utils.js │ ├── emulator.js │ ├── timeliner.js │ └── libs │ │ └── jquery-1.10.2.min.js ├── screen.html └── index.html ├── .editorconfig ├── controller ├── css │ └── controls.css ├── index.html └── js │ ├── utils.js │ ├── controls.js │ ├── third_party │ ├── tween.min.js │ └── fulltilt.min.js │ ├── DeviceOrientationEmulatorControls.js │ └── app.js ├── README.md └── doe.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /tmp/* 3 | .grunt 4 | logs 5 | *.log 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /emulator/images/black_linen_v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/richtr/doe/HEAD/emulator/images/black_linen_v2.png -------------------------------------------------------------------------------- /emulator/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/richtr/doe/HEAD/emulator/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /emulator/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/richtr/doe/HEAD/emulator/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /emulator/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/richtr/doe/HEAD/emulator/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 2 6 | end_of_line = lf 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | charset = utf-8 10 | -------------------------------------------------------------------------------- /controller/css/controls.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0px; 3 | overflow: hidden; 4 | background-color: #ffffff; 5 | } 6 | #info { 7 | position: fixed; 8 | top: 0; 9 | left: 0; 10 | right: 0; 11 | display: block; 12 | overflow: hidden; 13 | font-family: Arial, Helvetica, sans-serif; 14 | margin: 0; 15 | color: #ddd; 16 | background-color: #383636; 17 | padding: 5px; 18 | font-family: Monospace; 19 | font-size: 13px; 20 | font-weight: bold; 21 | text-align: center; 22 | z-index: 10; 23 | } 24 | .small { 25 | font-size: 0.8em; 26 | text-align: center; 27 | } 28 | .data_output { 29 | display: inline-block; 30 | position: relative; 31 | width: 40px; 32 | overflow: hidden; 33 | } 34 | -------------------------------------------------------------------------------- /controller/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | doe - Device Orientation Events Controller 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /controller/js/utils.js: -------------------------------------------------------------------------------- 1 | function dispatchDeviceOrientationEvent( values ) { 2 | var data = values || {}; 3 | 4 | // Create and dispatch an emulated device orientation event at window 5 | // object 6 | var event = document.createEvent( 'Event' ); 7 | event.initEvent( 'deviceorientation', true, true ); 8 | 9 | var eventData = { 10 | 'alpha': data.alpha % 360, 11 | 'beta': data.beta, 12 | 'gamma': data.gamma, 13 | 'absolute': true, 14 | 'roll': data.roll || 0 // custom attribute for emulator roll adjustment 15 | }; 16 | 17 | for ( var key in eventData ) event[ key ] = eventData[ key ]; 18 | event[ 'simulation' ] = true; // add 'simulated event' flag 19 | 20 | window.dispatchEvent( event ); 21 | } 22 | 23 | function sendMessage( target, json, origin ) { 24 | target[ 'postMessage' ]( JSON.stringify( json ), origin || '*' ); 25 | } 26 | -------------------------------------------------------------------------------- /emulator/css/timeline.css: -------------------------------------------------------------------------------- 1 | #timeline { 2 | line-height: 1; 3 | position: fixed; 4 | display: none; 5 | bottom: 0; 6 | left: 0; 7 | padding: 10px; 8 | } 9 | #timeline ul { 10 | font-size: 13px; 11 | display: inline-block; 12 | margin: -0.2em auto 0.2em; 13 | -webkit-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 14 | -moz-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 15 | -ms-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 16 | -o-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 17 | filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 18 | -ms-transform: translateZ(0); 19 | -o-transform: translateZ(0); 20 | -moz-transform: translateZ(0); 21 | -webkit-transform: translateZ(0); 22 | transform: translateZ(0); 23 | } 24 | div.frame { 25 | display: block; 26 | font-family: Helvetica, Arial, sans-serif; 27 | font-size: 11px; 28 | height: 27.5px; 29 | padding: 8px 20px; 30 | margin: 0 10px; 31 | background-color: #383636; 32 | color: #cccccc; 33 | } 34 | -------------------------------------------------------------------------------- /emulator/js/supports.js: -------------------------------------------------------------------------------- 1 | ( function() { 2 | 3 | // If deviceorientation events are supported, kick the user out of emulator 4 | 5 | var isFirstEvent = true; 6 | 7 | var starter = window.setTimeout( function() { 8 | // Remove this device orientation check 9 | window.removeEventListener( 'deviceorientation', check, false ); 10 | 11 | if ( document.readyState == 'complete' ) { 12 | startEmulator(); // emulator.js 13 | } else { 14 | window.addEventListener( 'load', startEmulator, false ); 15 | } 16 | }, 2000 ); 17 | 18 | function check() { 19 | // Discard first event (false positive on Chromium Desktop browsers) 20 | if ( isFirstEvent ) { 21 | isFirstEvent = false; 22 | return; 23 | } 24 | 25 | window.clearTimeout( starter ); 26 | 27 | // Remove this device orientation check 28 | window.removeEventListener( 'deviceorientation', check, false ); 29 | 30 | // Open the original page 31 | var pageUrl = getParameterByName( 'url' ); 32 | window.location = pageUrl || 'https://github.com/richtr/doe'; 33 | }; 34 | 35 | window.addEventListener( 'deviceorientation', check, false ); 36 | 37 | } )(); 38 | -------------------------------------------------------------------------------- /emulator/js/utils.js: -------------------------------------------------------------------------------- 1 | function getParameterByName( name ) { 2 | name = name.replace( /[\[]/, "\\[" ).replace( /[\]]/, "\\]" ); 3 | var regex = new RegExp( "[\\?&]" + name + "=([^&#]*)" ), 4 | results = regex.exec( location.search ); 5 | return results === null ? "" : decodeURIComponent( results[ 1 ].replace( /\+/g, " " ) ); 6 | } 7 | 8 | function printDataValue( input ) { 9 | input *= 1; // force to number for emulator display 10 | return Math.round( ( input + 0.00001 ) * 100 ) / 100; // return to 2 decimal places 11 | } 12 | 13 | function sendMessage( target, json, origin ) { 14 | // If frame is not loaded, dispatch it when it loads 15 | if ( !target.isLoaded ) { 16 | target.addEventListener( 'load', function() { 17 | target.contentWindow[ 'postMessage' ]( JSON.stringify( json ), origin || '*' ); 18 | }, false ); 19 | } else { // Otherwise, send message immediately 20 | target.contentWindow[ 'postMessage' ]( JSON.stringify( json ), origin || '*' ); 21 | } 22 | } 23 | 24 | function replaceURL( urlObj ) { 25 | if ( 'replaceState' in history ) { 26 | history.replaceState( null, null, urlObj.toString() ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /controller/js/controls.js: -------------------------------------------------------------------------------- 1 | window.addEventListener( 'load', function() { 2 | 3 | var url = new URL( document.location ); 4 | 5 | var loader = new THREE.XHRLoader(); 6 | 7 | loader.load( 'data/app.json', function( text ) { 8 | 9 | var player = new APP.Player(); 10 | player.load( JSON.parse( text ) ); 11 | player.setSize( window.innerWidth, window.innerHeight ); 12 | 13 | document.body.appendChild( player.dom ); 14 | 15 | window.addEventListener( 'resize', function() { 16 | player.setSize( window.innerWidth, window.innerHeight ); 17 | } ); 18 | 19 | var currentScreenOrientation = 0; 20 | 21 | // Listen for device orientation events fired from the emulator 22 | // and dispatch them on to the parent window 23 | window.addEventListener( 'deviceorientation', function( event ) { 24 | 25 | if ( !window.parent ) return; 26 | 27 | sendMessage( 28 | window.parent, { 29 | 'action': 'newData', 30 | 'data': { 31 | 'alpha': event.alpha, 32 | 'beta': event.beta, 33 | 'gamma': event.gamma, 34 | 'absolute': event.absolute, 35 | 'screen': currentScreenOrientation, 36 | 'roll': event.roll 37 | } 38 | }, 39 | url.origin 40 | ); 41 | 42 | }, false ); 43 | 44 | var actions = { 45 | 'start': function( data ) { 46 | player.play(); 47 | }, 48 | 'restart': function( data ) { 49 | player.stop(); 50 | player.play(); 51 | }, 52 | 'setCoords': function( data ) { 53 | player.setManualOrientation( data.alpha, data.beta, data.gamma ); 54 | 55 | if ( window.parent ) { 56 | sendMessage( 57 | window.parent, { 58 | 'action': 'updatePosition' 59 | }, 60 | url.origin 61 | ); 62 | } 63 | }, 64 | 'rotateScreen': function( data ) { 65 | player.updateScreenOrientation( data ); 66 | 67 | currentScreenOrientation = ( 360 - data.totalRotation ) % 360; 68 | 69 | if ( window.parent ) { 70 | sendMessage( 71 | window.parent, { 72 | 'action': 'updatePosition' 73 | }, 74 | url.origin 75 | ); 76 | } 77 | }, 78 | 'playback': function( data ) { 79 | player.playback( data ); 80 | } 81 | }; 82 | 83 | // Receive messages from window.parent 84 | window.addEventListener( 'message', function( event ) { 85 | 86 | if ( event.origin != url.origin ) return; 87 | 88 | var json = JSON.parse( event.data ); 89 | 90 | if ( !json.action || !actions[ json.action ] ) return; 91 | 92 | actions[ json.action ]( json.data ); 93 | 94 | }, false ); 95 | 96 | // Kick off the controller by telling its parent window that it is now ready 97 | if ( window.parent ) { 98 | 99 | sendMessage( 100 | window.parent, { 101 | 'action': 'connect' 102 | }, url.origin 103 | ); 104 | } 105 | 106 | } ); 107 | }, false ); 108 | -------------------------------------------------------------------------------- /emulator/css/emulator.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | width: 100%; 3 | height: 100%; 4 | text-align: center; 5 | background: #333 url('../images/black_linen_v2.png') center repeat; 6 | overflow: hidden; 7 | color: #fff; 8 | font-family: Helvetica, Arial, sans-serif; 9 | } 10 | .emulator-page { 11 | display: block; 12 | height: 100%; 13 | } 14 | a, a:visited { 15 | color: inherit; 16 | } 17 | #deviceFrame { 18 | min-width: 320px; 19 | min-height: 640px; 20 | margin: 0 auto; 21 | background: #fff; 22 | box-shadow: 0 0 50px #000; 23 | border-top: 20px solid #008000; 24 | border-bottom: 20px solid #CC0000; 25 | display: none; 26 | } 27 | #deviceFrameWrapper { 28 | position: relative; 29 | height: 100%; 30 | padding-top: 40px; 31 | } 32 | #emulator { 33 | text-align: center; 34 | line-height: 1; 35 | position: fixed; 36 | display: none; 37 | top: 0; 38 | right: 0; 39 | } 40 | #controller { 41 | position: fixed; 42 | display: none; 43 | top: 0; 44 | left: 0; 45 | width: 100%; 46 | max-width: 300px; 47 | height: 100%; 48 | max-height: 300px; 49 | text-align: center; 50 | background: #383636; 51 | z-index: 3; 52 | } 53 | #emulator ul { 54 | font-size: 13px; 55 | display: inline-block; 56 | margin: -0.2em auto 0.2em; 57 | -webkit-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 58 | -moz-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 59 | -ms-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 60 | -o-filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 61 | filter: drop-shadow(0 1px 5px rgba(0, 0, 0, .25)); 62 | -ms-transform: translateZ(0); 63 | -o-transform: translateZ(0); 64 | -moz-transform: translateZ(0); 65 | -webkit-transform: translateZ(0); 66 | transform: translateZ(0); 67 | } 68 | div.info { 69 | display: block; 70 | font-family: Helvetica, Arial, sans-serif; 71 | font-size: 11px; 72 | height: 27.5px; 73 | padding: 8px 20px; 74 | margin: 0 10px; 75 | background-color: #383636; 76 | color: #cccccc; 77 | } 78 | div.info input[type=number] { 79 | display: inline-block; 80 | overflow: hidden; 81 | font-size: 11px; 82 | margin: 0px; 83 | padding: 0 2px; 84 | width: 70px; 85 | height: 15px; 86 | text-align: center; 87 | background-color: #383636; 88 | color: #cccccc; 89 | border-style: hidden; 90 | border: 1px solid #383636; 91 | } 92 | div.info input[type=number]:hover { 93 | border: 1px solid #605E5E; 94 | } 95 | div.info input[type=number]:active { 96 | background-color: #333333; 97 | border: 1px solid #605E5E; 98 | } 99 | button.rotate { 100 | width: 39px; 101 | } 102 | .landscape i:before { 103 | -webkit-transform: rotate(-90deg); 104 | -moz-transform: rotate(-90deg); 105 | -ms-transform: rotate(-90deg); 106 | -o-transform: rotate(-90deg); 107 | transform: rotate(-90deg); 108 | } 109 | #credits { 110 | line-height: 1; 111 | position: fixed; 112 | display: none; 113 | bottom: 0; 114 | right: 0; 115 | padding: 10px 20px; 116 | color: #CCCCCC; 117 | font-size: 11px; 118 | } 119 | #credits a:hover, #credits a:active, #credits a:visited { 120 | text-decoration: none; 121 | } 122 | [data-max="150"] { 123 | font-size: 150px; 124 | } 125 | [data-max="95"] { 126 | font-size: 95px; 127 | } 128 | [data-max="30"] { 129 | font-size: 30px; 130 | } 131 | @media (max-width: 480px) { 132 | [data-min="60"] { 133 | font-size: 60px; 134 | } 135 | [data-min="52"] { 136 | font-size: 52px; 137 | } 138 | [data-min="20"] { 139 | font-size: 20px; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /emulator/screen.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 31 | 32 |
33 | 34 |
35 | 36 | 132 | -------------------------------------------------------------------------------- /controller/js/third_party/tween.min.js: -------------------------------------------------------------------------------- 1 | // tween.js v.0.15.0 https://github.com/sole/tween.js 2 | void 0===Date.now&&(Date.now=function(){return(new Date).valueOf()});var TWEEN=TWEEN||function(){var n=[];return{REVISION:"14",getAll:function(){return n},removeAll:function(){n=[]},add:function(t){n.push(t)},remove:function(t){var r=n.indexOf(t);-1!==r&&n.splice(r,1)},update:function(t){if(0===n.length)return!1;var r=0;for(t=void 0!==t?t:"undefined"!=typeof window&&void 0!==window.performance&&void 0!==window.performance.now?window.performance.now():Date.now();rn;n++)E[n].stop()},this.delay=function(n){return s=n,this},this.repeat=function(n){return e=n,this},this.yoyo=function(n){return a=n,this},this.easing=function(n){return l=n,this},this.interpolation=function(n){return p=n,this},this.chain=function(){return E=arguments,this},this.onStart=function(n){return d=n,this},this.onUpdate=function(n){return I=n,this},this.onComplete=function(n){return w=n,this},this.onStop=function(n){return M=n,this},this.update=function(n){var f;if(h>n)return!0;v===!1&&(null!==d&&d.call(t),v=!0);var M=(n-h)/o;M=M>1?1:M;var O=l(M);for(f in i){var m=r[f]||0,N=i[f];N instanceof Array?t[f]=p(N,O):("string"==typeof N&&(N=m+parseFloat(N,10)),"number"==typeof N&&(t[f]=m+(N-m)*O))}if(null!==I&&I.call(t,O),1==M){if(e>0){isFinite(e)&&e--;for(f in u){if("string"==typeof i[f]&&(u[f]=u[f]+parseFloat(i[f],10)),a){var T=u[f];u[f]=i[f],i[f]=T}r[f]=u[f]}return a&&(c=!c),h=n+s,!0}null!==w&&w.call(t);for(var g=0,W=E.length;W>g;g++)E[g].start(n);return!1}return!0}},TWEEN.Easing={Linear:{None:function(n){return n}},Quadratic:{In:function(n){return n*n},Out:function(n){return n*(2-n)},InOut:function(n){return(n*=2)<1?.5*n*n:-.5*(--n*(n-2)-1)}},Cubic:{In:function(n){return n*n*n},Out:function(n){return--n*n*n+1},InOut:function(n){return(n*=2)<1?.5*n*n*n:.5*((n-=2)*n*n+2)}},Quartic:{In:function(n){return n*n*n*n},Out:function(n){return 1- --n*n*n*n},InOut:function(n){return(n*=2)<1?.5*n*n*n*n:-.5*((n-=2)*n*n*n-2)}},Quintic:{In:function(n){return n*n*n*n*n},Out:function(n){return--n*n*n*n*n+1},InOut:function(n){return(n*=2)<1?.5*n*n*n*n*n:.5*((n-=2)*n*n*n*n+2)}},Sinusoidal:{In:function(n){return 1-Math.cos(n*Math.PI/2)},Out:function(n){return Math.sin(n*Math.PI/2)},InOut:function(n){return.5*(1-Math.cos(Math.PI*n))}},Exponential:{In:function(n){return 0===n?0:Math.pow(1024,n-1)},Out:function(n){return 1===n?1:1-Math.pow(2,-10*n)},InOut:function(n){return 0===n?0:1===n?1:(n*=2)<1?.5*Math.pow(1024,n-1):.5*(-Math.pow(2,-10*(n-1))+2)}},Circular:{In:function(n){return 1-Math.sqrt(1-n*n)},Out:function(n){return Math.sqrt(1- --n*n)},InOut:function(n){return(n*=2)<1?-.5*(Math.sqrt(1-n*n)-1):.5*(Math.sqrt(1-(n-=2)*n)+1)}},Elastic:{In:function(n){var t,r=.1,i=.4;return 0===n?0:1===n?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),-(r*Math.pow(2,10*(n-=1))*Math.sin(2*(n-t)*Math.PI/i)))},Out:function(n){var t,r=.1,i=.4;return 0===n?0:1===n?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),r*Math.pow(2,-10*n)*Math.sin(2*(n-t)*Math.PI/i)+1)},InOut:function(n){var t,r=.1,i=.4;return 0===n?0:1===n?1:(!r||1>r?(r=1,t=i/4):t=i*Math.asin(1/r)/(2*Math.PI),(n*=2)<1?-.5*r*Math.pow(2,10*(n-=1))*Math.sin(2*(n-t)*Math.PI/i):r*Math.pow(2,-10*(n-=1))*Math.sin(2*(n-t)*Math.PI/i)*.5+1)}},Back:{In:function(n){var t=1.70158;return n*n*((t+1)*n-t)},Out:function(n){var t=1.70158;return--n*n*((t+1)*n+t)+1},InOut:function(n){var t=2.5949095;return(n*=2)<1?.5*n*n*((t+1)*n-t):.5*((n-=2)*n*((t+1)*n+t)+2)}},Bounce:{In:function(n){return 1-TWEEN.Easing.Bounce.Out(1-n)},Out:function(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375},InOut:function(n){return.5>n?.5*TWEEN.Easing.Bounce.In(2*n):.5*TWEEN.Easing.Bounce.Out(2*n-1)+.5}}},TWEEN.Interpolation={Linear:function(n,t){var r=n.length-1,i=r*t,u=Math.floor(i),o=TWEEN.Interpolation.Utils.Linear;return 0>t?o(n[0],n[1],i):t>1?o(n[r],n[r-1],r-i):o(n[u],n[u+1>r?r:u+1],i-u)},Bezier:function(n,t){var r,i=0,u=n.length-1,o=Math.pow,e=TWEEN.Interpolation.Utils.Bernstein;for(r=0;u>=r;r++)i+=o(1-t,u-r)*o(t,r)*n[r]*e(u,r);return i},CatmullRom:function(n,t){var r=n.length-1,i=r*t,u=Math.floor(i),o=TWEEN.Interpolation.Utils.CatmullRom;return n[0]===n[r]?(0>t&&(u=Math.floor(i=r*(1+t))),o(n[(u-1+r)%r],n[u],n[(u+1)%r],n[(u+2)%r],i-u)):0>t?n[0]-(o(n[0],n[0],n[1],n[1],-i)-n[0]):t>1?n[r]-(o(n[r],n[r],n[r-1],n[r-1],i-r)-n[r]):o(n[u?u-1:0],n[u],n[u+1>r?r:u+1],n[u+2>r?r:u+2],i-u)},Utils:{Linear:function(n,t,r){return(t-n)*r+n},Bernstein:function(n,t){var r=TWEEN.Interpolation.Utils.Factorial;return r(n)/r(t)/r(n-t)},Factorial:function(){var n=[1];return function(t){var r,i=1;if(n[t])return n[t];for(r=t;r>1;r--)i*=r;return n[t]=i}}(),CatmullRom:function(n,t,r,i,u){var o=.5*(r-n),e=.5*(i-t),a=u*u,f=u*a;return(2*t-2*r+o+e)*f+(-3*t+3*r-2*o-e)*a+o*u+t}}},"undefined"!=typeof module&&module.exports&&(module.exports=TWEEN); 3 | -------------------------------------------------------------------------------- /emulator/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | doe - The Device and Screen Orientation Emulator 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 75 |
76 | 77 |
78 | 79 |
80 | 81 |
82 | 92 | 98 | 103 | 108 |
109 | 110 |
111 | doe v0.9 112 | 113 |
114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Doe 2 | 3 | ##### Doe is a highly precise device and screen orientation emulator for developing and debugging sensor-related web apps on desktop computers 4 | 5 | It can be used to build and debug device orientation and screen orientation aware applications without needing to constantly test on mobile devices. 6 | 7 | #### Demos 8 | 9 | In any web browser that does not support device orientation (e.g. Desktop browsers) you can open one of the following pages: 10 | 11 | [https://richtr.github.io/threeVR/examples/vr_basic.html](https://richtr.github.io/threeVR/examples/vr_basic.html) 12 | 13 | [https://richtr.github.io/Marine-Compass/](https://richtr.github.io/Marine-Compass/) 14 | 15 | [https://richtr.github.io/Full-Tilt/examples/vr_interactive.html](https://richtr.github.io/Full-Tilt/examples/vr_interactive.html) 16 | 17 | [https://people.opera.com/richt/release/tests/doe/screenorientation.html](https://people.opera.com/richt/release/tests/doe/screenorientation.html) 18 | 19 | ##### Advanced demo 20 | 21 | The doe emulator can also record key frames and play back those key frames as an animation. 22 | 23 | You can check out an example key framed animation [here](https://richtr.github.io/doe/emulator/?url=https%3A%2F%2Frichtr.github.io%2FFull-Tilt%2Fexamples%2Fvr_test.html#W1sxLDEsMCwwLDkwLDAsMF0sWzEsMSwwLDkwLDkwLDAsMF0sWzEsMSwwLDE4MCw5MCwwLDBdLFsxLDEsMCwyNzAsOTAsMCwwXSxbMSwxLDAsMCw5MCwwLDBdLFsxLDEsMCw0NSw0NSwwLDBdLFsxLDEsMCwzMTUsNDUsMCwwXSxbMSwxLDAsMCw5MCwwLDBdLFsxLDEsMCwwLC0xODAsMCwwXSxbMSwxLDAsMCwtOTAsMCwwXSxbMSwxLDAsMjcwLDAsLTkwLDI3MF0sWzEsMSwwLDE4MCwwLC05MCwyNzBdLFsxLDEsMCwwLDAsLTkwLDI3MF0sWzEsMSwwLDI3MCwwLC05MCwyNzBdLFswLDEsMCwxODAsOTAsMCwxODBdLFsxLDEsMCwwLDkwLDAsMTgwXSxbMCwxLDAsMCw5MCwwLDBdXQ==). 24 | 25 | #### Developer Usage 26 | 27 | Just add the [Device Orientation Emulator script](https://github.com/richtr/doe/blob/gh-pages/doe.js) to any web page on which you want to enable the doe emulator: 28 | 29 | ```html 30 | 31 | ``` 32 | 33 | Now open your web page and follow the prompt to open it in the doe emulator. 34 | 35 | #### User Interface Guide 36 | 37 | When you open doe you will be presented with the following screen: 38 | 39 | 40 | 41 | ##### 1. The Web App Viewport 42 | 43 | This is where the web application that is being emulated is displayed. 44 | 45 | You can customize the scale of the viewport and the dimensions of the viewport via tools available in the emulator menu bar. 46 | 47 | ##### 2. The Device Controller 48 | 49 | The device controller is an interactive model of a real device. As a user of the emulator you can change the physical orientation of the 'device' within space. 50 | 51 | To change the physical orientation of the device just click on the device shown, and drag your mouse in the desired direction of movement. The device should move on screen. 52 | 53 | Any changes you make using your mouse in the device controller will produce updated device orientation data within the emulator menu bar. 54 | 55 | ##### 3. The Emulator Menu Bar 56 | 57 | The doe emulator menu bar lets you refine different important characteristics of your device within real world space. The values displayed or overridden in the menu bar will affect how the Web App Viewport will be oriented on the screen. 58 | 59 | 60 | 61 | ###### 3.1. Viewport Scaling 62 | 63 | Using the slider you can change the scale of the Web App Viewport. This does not affect the screen dimensions within the Web App Viewport. 64 | 65 | ###### 3.2. Device type 66 | 67 | Using this part of the menu bar lets you change the screen dimensions within the Web App Viewport to the dimensions that can be found on typical hardware devices. 68 | 69 | The device types currently available in the doe emulator, from left to right, are as follows: 70 | 71 | * iPhone 72 | * Android phone 73 | * Android tablet 74 | * iPad 75 | 76 | Just select one of these options and the Web App Viewport will update to the device's screen dimensions. 77 | 78 | ###### 3.3. Device Orientation Data 79 | 80 | This part of the emulator menu bar displays the current device orientation data that is being emitted from the Device Controller. 81 | 82 | The data is as follows: 83 | 84 | * 'a' (or `DeviceOrientationEvent.alpha`) in the range (0, 360) 85 | * 'b' (or `DeviceOrientationEvent.beta`) in the range (-180, 180) 86 | * 'g' (or `DeviceOrientationEvent.gamma`) in the range (-90, 90) 87 | 88 | You can also manually enter device orientation data here. Just select the value shown next to 'a', 'b' or 'g' and enter a new value. The Device Controller will automatically readjust to orient to the chosen values. 89 | 90 | The button on the right side allows you to reset the device orientation data to its default position. 91 | 92 | ###### 3.4. Screen Orientation Data 93 | 94 | This part of the emulator menu bar displays the current screen orientation data that is being emitted from the Device Controller. 95 | 96 | The data is as follows: 97 | 98 | * 's' (or `window.orientation` and `window.screen.orientation.angle`) 99 | * `0` (aka `portrait-primary`): The screen is in its default (natural) orientation. 100 | * `90` (aka `landscape-primary`): The screen is rotated 90 degrees clockwise from its natural orientation. 101 | * `180` (aka `portrait-secondary`): The screen is rotated 180 degrees clockwise from its natural orientation. 102 | * `270` (aka `landscape-secondary`): The screen is rotated 270 degrees clockwise (or, 90 degrees counter-clockwise) from its natural orientation. 103 | 104 | You can change the screen orientation of the device using the button to the right. This rotates the screen in 90 degree increments and simulates the effect of the screen orientation changing from e.g. portrait to landscape. 105 | 106 | If the web app within the Web App Viewport uses the Screen Orientation API to lock the device to a specific screen orientation then the screen rotation button is disabled and is replaced by a lock icon. If or when the emulated web app unlocks the device from a specific screen orientation then the screen rotation button will be enabled again and the lock icon will disappear. 107 | 108 | ##### 4. The Animation Timeline 109 | 110 | The animation timeline lets you record and share pre-defined movements of the emulated device using key frames to mark the waypoints of that movement. 111 | 112 | 113 | 114 | ###### 4.1. Play the current animation timeline 115 | 116 | When the doe emulator loads it will auto-play any animations that have been included in the emulator URL. 117 | 118 | At any time you want to replay the animation timeline you can click this button and the doe emulator will replay the recorded key frame(s). 119 | 120 | When the doe emulator is playing a timeline it will disable buttons within the Emulator Menu Bar and also disable the Device Controller. Once animation ends, the emulator will be reset to the position of the first key frame and any disabled controls will be reenabled. 121 | 122 | ###### 4.2. Key frame(s) 123 | 124 | The current key frames for this animation. 125 | 126 | At any time you can click on one of these items and then, any changes you make to device or screen orientation will be recorded against this key frame. 127 | 128 | ###### 4.3. Add a new key frame 129 | 130 | Clicking this button adds a new key frame to the animation timeline. 131 | 132 | The device and screen orientation of the previous frame will be maintained and you can now change the values of this new frame. 133 | 134 | By clicking the play button the doe emulator will interpolate between these frames to create a smooth transition between the device and screen orientation values between the key frames. 135 | 136 | You can add up to a maximum of 20 key frames within the doe emulator. 137 | 138 | ###### 4.4. Delete all key frames 139 | 140 | This button will remove all key frames, only keeping the first key frame that was created within the animation timeline. 141 | 142 | #### License 143 | 144 | MIT. Copyright © Rich Tibbett. 145 | -------------------------------------------------------------------------------- /doe.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * doe - The Device and Screen Orientation Emulator 4 | * https://github.com/richtr/doe 5 | * 6 | * A simple, accurate device orientation emulator for use in web browsers 7 | * that do not support device orientation events 8 | * (https://w3c.github.io/deviceorientation/spec-source-orientation.html) 9 | * 10 | * This emulator also supports Screen Orientation API events 11 | * (http://www.w3.org/TR/screen-orientation/) 12 | * 13 | * Copyright: 2015 Rich Tibbett 14 | * License: MIT 15 | * 16 | */ 17 | 18 | ( function() { 19 | 20 | var emulatorUrl = new URL( 'https://richtr.github.io/doe/emulator' ); 21 | 22 | var Detector = ( function() { 23 | 24 | var detectorLoaded = false; 25 | 26 | return function() { 27 | 28 | if ( detectorLoaded ) return; 29 | 30 | var detectionCheckTimeout = 1000; 31 | 32 | var deviceOrientationCheck = window.setTimeout( function() { 33 | 34 | SweetAlertLoader( function() { 35 | swal( { 36 | title: 'No compass detected.', 37 | text: 'This page is built for browsers that emit hardware sensor events. If you would still like to try this page you can use an emulator.', 38 | type: 'error', 39 | showCancelButton: true, 40 | confirmButtonColor: '#DD6B55', 41 | confirmButtonText: 'Open page in emulator', 42 | cancelButtonText: 'Cancel', 43 | closeOnConfirm: true 44 | }, 45 | function() { 46 | // Open the mobile emulator with the current URL 47 | var pageUrl = encodeURIComponent( window.location ); 48 | window.location = emulatorUrl.toString() + '/?url=' + pageUrl; 49 | } ); 50 | } ); 51 | 52 | }, detectionCheckTimeout ); 53 | 54 | var isFirstEvent = true; 55 | 56 | window.addEventListener( 'deviceorientation', function check() { 57 | // Discard first event (false positive on Chromium Desktop browsers) 58 | if ( isFirstEvent ) { 59 | isFirstEvent = false; 60 | return; 61 | } 62 | 63 | // Prevent emulator alert from kicking in 64 | window.clearTimeout( deviceOrientationCheck ); 65 | // Remove this device orientation check 66 | window.removeEventListener( 'deviceorientation', check, false ); 67 | }, false ); 68 | 69 | detectorLoaded = true; 70 | 71 | }; 72 | 73 | } )(); 74 | 75 | var Emulator = ( function() { 76 | 77 | var _this = this; 78 | 79 | var emulatorLoaded = false; 80 | 81 | var actions = { 82 | 'deviceorientation': function( data ) { 83 | 84 | var event = document.createEvent( 'Event' ); 85 | event.initEvent( 'deviceorientation', true, true ); 86 | 87 | for ( var key in data ) event[ key ] = data[ key ]; 88 | event[ 'simulation' ] = true; // add 'simulated event' flag 89 | 90 | window.dispatchEvent( event ); 91 | 92 | }, 93 | 'screenOrientationChange': function( data ) { 94 | 95 | // Update window.screen.orientation.angle 96 | _this.screenOrientationAPI.update( data ); 97 | 98 | } 99 | }; 100 | 101 | var listener = function( event ) { 102 | 103 | if ( event.origin !== emulatorUrl.origin ) return; 104 | 105 | var json = JSON.parse( event.data ); 106 | 107 | if ( !json.action || !actions[ json.action ] ) return; 108 | 109 | actions[ json.action ]( json.data ); 110 | 111 | }.bind( this ); 112 | 113 | return function() { 114 | 115 | if ( emulatorLoaded ) return; 116 | 117 | // Set up Screen Orientation API 118 | _this.screenOrientationAPI = new ScreenOrientationAPI(); 119 | 120 | // Listen for incoming window messages from parent 121 | window.addEventListener( 'message', listener, false ); 122 | 123 | emulatorLoaded = true; 124 | 125 | }; 126 | 127 | } )(); 128 | 129 | function ScreenOrientationAPI() { 130 | 131 | var _this = this; 132 | 133 | var angleToType = { 134 | '0': 'portrait-primary', 135 | '90': 'landscape-primary', 136 | '180': 'portrait-secondary', 137 | '270': 'landscape-secondary', 138 | // Aliases 139 | '-90': 'landscape-secondary', 140 | '-180': 'portrait-secondary', 141 | '-270': 'landscape-primary', 142 | '360': 'portrait-primary', 143 | }; 144 | var typeToAngle = { 145 | 'portrait-primary': 0, 146 | 'portrait-secondary': 180, 147 | 'landscape-primary': 90, 148 | 'landscape-secondary': 270, 149 | // Additional types 150 | 'any': 0, 151 | 'natural': 0, 152 | 'landscape': 90, 153 | 'portrait': 0 154 | }; 155 | 156 | var hasScreenOrientationAPI = window.screen && window.screen.orientation ? true : false; 157 | 158 | _this._angle = 0; 159 | _this._type = 'portrait-primary'; 160 | 161 | function Emitter() { 162 | var eventTarget = document.createDocumentFragment(); 163 | 164 | function delegate( method ) { 165 | this[ method ] = eventTarget[ method ].bind( eventTarget ); 166 | } 167 | 168 | [ 169 | "addEventListener", 170 | "dispatchEvent", 171 | "removeEventListener" 172 | ].forEach( delegate, this ); 173 | } 174 | 175 | function _ScreenOrientation() { 176 | Emitter.call( this ); 177 | } 178 | 179 | // Update internal screen orientation and fire the appropriate DOM events 180 | this.update = function( angle ) { 181 | 182 | var _angle = angle % 360; 183 | 184 | // Update internal API values 185 | _this._angle = _angle; 186 | _this._type = angleToType[ _angle ]; 187 | 188 | // Update window.orientation 189 | window.orientation = _this._angle; 190 | 191 | // Fire a 'orientationchange' event at window 192 | var event = document.createEvent( 'Event' ); 193 | event.initEvent( 'orientationchange', true, true ); 194 | window.dispatchEvent( event ); 195 | 196 | // Fire a 'change' event at window.screen.orientation 197 | var event = document.createEvent( 'Event' ); 198 | event.initEvent( 'change', true, true ); 199 | window.screen.orientation.dispatchEvent( event ); 200 | 201 | }; 202 | 203 | // If browser does not support the Screen Orientation API, add a stub for it 204 | if ( !hasScreenOrientationAPI ) { 205 | if ( !window.screen ) window.screen = {}; 206 | if ( !window.screen.orientation ) window.screen.orientation = new _ScreenOrientation(); 207 | } 208 | 209 | // Override Screen Orientation API 'angle' built-in getter 210 | window.screen.orientation.__defineGetter__( 'angle', function() { 211 | return _this._angle; 212 | } ); 213 | 214 | // Override Screen Orientation API 'type' built-in getter 215 | window.screen.orientation.__defineGetter__( 'type', function() { 216 | return _this._type; 217 | } ); 218 | 219 | window.screen.orientation.__proto__.lock = function( val ) { 220 | var p = new Promise( function( resolve, reject ) { 221 | 222 | // Check a valid type is provided 223 | var angle = typeToAngle[ val ]; 224 | 225 | if ( angle === undefined || angle === null ) { 226 | window.setTimeout( function() { 227 | reject( "Cannot lock to given screen orientation" ); // reject as invalid 228 | }, 1 ); 229 | return; 230 | } 231 | 232 | _this.update( angle ); 233 | 234 | window.setTimeout( function() { 235 | resolve(); 236 | }, 1 ); 237 | 238 | // Lock the screen orientation icon in parent emulator 239 | if ( window.parent ) { 240 | 241 | window.parent.postMessage( JSON.stringify( { 242 | 'action': 'lockScreenOrientation', 243 | 'data': angle 244 | } ), '*' ); 245 | 246 | } 247 | 248 | } ); 249 | 250 | return p; 251 | }; 252 | 253 | window.screen.orientation.__proto__.unlock = function( val ) { 254 | if ( !window.parent ) return; 255 | 256 | window.parent.postMessage( JSON.stringify( { 257 | 'action': 'unlockScreenOrientation' 258 | } ), '*' ); 259 | }; 260 | 261 | return this; 262 | 263 | } 264 | 265 | var SweetAlertLoader = ( function() { 266 | 267 | var isSWALLoaded = false; 268 | 269 | return function( callback ) { 270 | 271 | if ( isSWALLoaded ) { 272 | // Fire callback after current script runs to completion 273 | window.setTimeout(function() { 274 | callback(); 275 | }, 1); 276 | return; 277 | } 278 | 279 | var swalCSSEl = document.createElement( 'link' ); 280 | swalCSSEl.href = 'https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.0.1/sweetalert.min.css'; 281 | swalCSSEl.type = 'text/css'; 282 | swalCSSEl.rel = 'stylesheet'; 283 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( swalCSSEl ); 284 | 285 | var swalJSEl = document.createElement( 'script' ); 286 | swalJSEl.src = 'https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.0.1/sweetalert.min.js'; 287 | swalJSEl.type = 'text/javascript'; 288 | 289 | swalJSEl.onload = function() { 290 | callback(); 291 | }; 292 | 293 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( swalJSEl ); 294 | 295 | isSWALLoaded = true; 296 | 297 | } 298 | 299 | } )(); 300 | 301 | // Run on start 302 | 303 | var referrerUrl = new URL( document.referrer || 'http:a' ); 304 | var referrerPath = referrerUrl.pathname; 305 | 306 | var originsMatch = referrerUrl.origin === emulatorUrl.origin; 307 | var pathsMath = referrerPath.indexOf( emulatorUrl.pathname, 0 ) === 0; 308 | var notScreenEmbedded = referrerPath.indexOf( "/screen", 0 ) < 0; 309 | 310 | if ( originsMatch && pathsMath && notScreenEmbedded ) { 311 | // We have been kicked from the emulator. 312 | // Display an alert that we were kicked. 313 | SweetAlertLoader( function() { 314 | swal( { 315 | title: "Compass detected.", 316 | text: "You have been redirected here from the emulator because your device supports the required hardware sensor events.", 317 | type: "success", 318 | confirmButtonColor: "#638450" 319 | } ); 320 | } ); 321 | } else if ( window == window.parent ) { 322 | // Check if the current UA supports device orientation events. 323 | // If not, then display a prompt to try this page in the emulator. 324 | if ( document.readyState === 'complete' ) { 325 | Detector(); 326 | } else { 327 | window.addEventListener( 'load', Detector, false ); 328 | } 329 | } else { 330 | // Run the emulator (listen for proxied events from parent window) 331 | Emulator(); 332 | } 333 | 334 | } )(); 335 | -------------------------------------------------------------------------------- /emulator/js/emulator.js: -------------------------------------------------------------------------------- 1 | var selfUrl = new URL( window.location ); 2 | 3 | function startEmulator() { 4 | 5 | var controller = document.querySelector( 'iframe#controller' ); 6 | var emulatorMenu = document.querySelector( '#emulator' ); 7 | var credits = document.querySelector( '#credits' ); 8 | 9 | var deviceFrame = document.querySelector( 'iframe#deviceFrame' ); 10 | 11 | controller.addEventListener( 'load', function() { 12 | controller.isLoaded = true; 13 | 14 | controller.style.display = 'block'; 15 | emulatorMenu.style.display = 'block'; 16 | credits.style.display = 'block'; 17 | }, false ); 18 | 19 | // Load controller 20 | controller.src = '../controller/index.html'; 21 | 22 | deviceFrame.addEventListener( 'load', function() { 23 | deviceFrame.isLoaded = true; 24 | deviceFrame.style.display = 'block'; 25 | }, false ); 26 | 27 | // Load target in screen iframe 28 | deviceFrame.src = "screen.html" + location.search; 29 | 30 | var scaleFactor = 1; 31 | 32 | $( 'button[data-viewport-width]' ).on( 'click', function( e ) { 33 | if ( $( this ).attr( 'data-viewport-width' ) == '100%' ) { 34 | newWidth = '100%'; 35 | } else { 36 | newWidth = $( this ).attr( 'data-viewport-width' ); 37 | } 38 | if ( $( this ).attr( 'data-viewport-height' ) == '100%' ) { 39 | newHeight = '100%'; 40 | } else { 41 | newHeight = $( this ).attr( 'data-viewport-height' ); 42 | } 43 | $( 'button[data-viewport-width]' ).removeClass( 'asphalt active' ).addClass( 'charcoal' ); 44 | $( this ).addClass( 'asphalt active' ).removeClass( 'charcoal' ); 45 | $( '#deviceFrame' ).css( { 46 | 'min-width': newWidth, 47 | 'min-height': newHeight 48 | } ); 49 | e.preventDefault(); 50 | 51 | var w = parseInt( newWidth, 10 ); 52 | var h = parseInt( newHeight, 10 ); 53 | var newDimension = 0; 54 | 55 | // Take the larger of the two values 56 | if ( w >= h ) { 57 | newDimension = w; 58 | } else { 59 | newDimension = h; 60 | } 61 | 62 | // Relay new dimensions on to deviceFrame 63 | sendMessage( 64 | deviceFrame, { 65 | 'action': 'updateScreenDimensions', 66 | 'data': { 67 | 'newWidth': newDimension + "px", 68 | 'newHeight': newDimension + "px" 69 | } 70 | }, 71 | selfUrl.origin 72 | ); 73 | 74 | return false; 75 | } ); 76 | 77 | $( 'button.rotate' ).on( 'click', function( e ) { 78 | 79 | var currentRotation = currentScreenOrientation == 0 ? 360 : currentScreenOrientation; 80 | 81 | // Post message to self to update screen orientation 82 | postMessage( JSON.stringify( { 83 | 'action': 'updateScreenOrientation', 84 | 'data': { 85 | 'totalRotation': currentRotation - 90, 86 | 'updateControls': true 87 | } 88 | } ), selfUrl.origin ); 89 | 90 | } ); 91 | 92 | var deviceScaleValue = $( '#deviceScaleValue' ); 93 | 94 | $( '#deviceScaling' ).on( 'input', function( e ) { 95 | scaleFactor = e.target.value; 96 | deviceScaleValue.text( scaleFactor + "x" ); 97 | } ); 98 | 99 | $( 'button.reset' ).on( 'click', function( e ) { 100 | 101 | // reset the controller 102 | sendMessage( 103 | controller, { 104 | 'action': 'restart' 105 | }, 106 | selfUrl.origin 107 | ); 108 | 109 | // Update controller rendering 110 | sendMessage( 111 | controller, { 112 | 'action': 'rotateScreen', 113 | 'data': { 114 | 'rotationDiff': currentScreenOrientation, 115 | 'totalRotation': currentScreenOrientation, 116 | 'updateControls': true 117 | } 118 | }, 119 | selfUrl.origin 120 | ); 121 | 122 | } ); 123 | 124 | var orientationAlpha = document.querySelector( 'input#orientationAlpha' ); 125 | var orientationBeta = document.querySelector( 'input#orientationBeta' ); 126 | var orientationGamma = document.querySelector( 'input#orientationGamma' ); 127 | 128 | var currentScreenOrientation = 360; 129 | 130 | var userIsEditing = false; 131 | 132 | function onUserIsEditingStart( e ) { 133 | userIsEditing = true; 134 | } 135 | 136 | function onUserIsEditingEnd( e ) { 137 | var alpha = parseFloat( orientationAlpha.value, 10 ); 138 | var beta = parseFloat( orientationBeta.value, 10 ); 139 | var gamma = parseFloat( orientationGamma.value, 10 ); 140 | 141 | // Fit all inputs within acceptable interval 142 | alpha = alpha % 360; 143 | if ( beta < -180 ) beta = -180; 144 | if ( beta > 180 ) beta = 180; 145 | if ( gamma < -90 ) gamma = -90; 146 | if ( gamma > 90 ) gamma = 90; 147 | 148 | sendMessage( 149 | controller, { 150 | 'action': 'setCoords', 151 | 'data': { 152 | 'alpha': alpha || 0, 153 | 'beta': beta || 0, 154 | 'gamma': gamma || 0 155 | } 156 | }, 157 | selfUrl.origin 158 | ); 159 | 160 | } 161 | 162 | function stopUserEditing( e ) { 163 | userIsEditing = false; 164 | } 165 | 166 | function stopUserEditingKey( e ) { 167 | var keyCode = e.which || e.keyCode; 168 | if ( keyCode !== 13 ) { 169 | return true; 170 | } 171 | // Force blur when return key is pressed 172 | var target = e.target; 173 | target.blur(); 174 | } 175 | 176 | orientationAlpha.addEventListener( 'focus', onUserIsEditingStart, false ); 177 | orientationAlpha.addEventListener( 'change', onUserIsEditingEnd, false ); 178 | orientationAlpha.addEventListener( 'keypress', stopUserEditingKey, false ); 179 | orientationAlpha.addEventListener( 'blur', stopUserEditing, false ); 180 | 181 | orientationBeta.addEventListener( 'focus', onUserIsEditingStart, false ); 182 | orientationBeta.addEventListener( 'change', onUserIsEditingEnd, false ); 183 | orientationBeta.addEventListener( 'keypress', stopUserEditingKey, false ); 184 | orientationBeta.addEventListener( 'blur', stopUserEditing, false ); 185 | 186 | orientationGamma.addEventListener( 'focus', onUserIsEditingStart, false ); 187 | orientationGamma.addEventListener( 'change', onUserIsEditingEnd, false ); 188 | orientationGamma.addEventListener( 'keypress', stopUserEditingKey, false ); 189 | orientationGamma.addEventListener( 'blur', stopUserEditing, false ); 190 | 191 | var screenOrientationEl = document.querySelector( '#screenOrientation' ); 192 | 193 | var actions = { 194 | 'newData': function( data ) { 195 | 196 | // Print deviceorientation data values in GUI 197 | if ( !userIsEditing ) { 198 | orientationAlpha.value = printDataValue( data.alpha ); 199 | orientationBeta.value = printDataValue( data.beta ); 200 | orientationGamma.value = printDataValue( data.gamma ); 201 | } 202 | 203 | // Indicate that certain values are shown rounded for display purposes 204 | if ( orientationBeta.textContent === "180" ) orientationBeta.textContent += "*"; 205 | if ( orientationGamma.textContent === "90" ) orientationGamma.textContent += "*"; 206 | 207 | var roll = data[ 'roll' ] || 0; 208 | delete data[ 'roll' ]; // remove roll attribute from json 209 | 210 | // Post deviceorientation data to deviceFrame window 211 | sendMessage( 212 | deviceFrame, { 213 | 'action': 'deviceorientation', 214 | 'data': data 215 | }, 216 | selfUrl.origin 217 | ); 218 | 219 | // Apply roll compensation to deviceFrame 220 | deviceFrame.style.webkitTransform = deviceFrame.style.msTransform = deviceFrame.style.transform = 'rotate(' + ( roll - currentScreenOrientation ) + 'deg) scale(' + scaleFactor + ')'; 221 | 222 | }, 223 | 'updateScreenOrientation': function( data ) { 224 | 225 | var requestedScreenOrientation = data.totalRotation % 360; 226 | var updateControls = data.updateControls; 227 | 228 | // Calculate rotation difference 229 | var currentRotation = currentScreenOrientation == 0 ? 360 : currentScreenOrientation; 230 | 231 | var rotationDiff = currentRotation - requestedScreenOrientation; 232 | 233 | // Update controller rendering 234 | sendMessage( 235 | controller, { 236 | 'action': 'rotateScreen', 237 | 'data': { 238 | 'rotationDiff': -rotationDiff, 239 | 'totalRotation': requestedScreenOrientation, 240 | 'updateControls': updateControls 241 | } 242 | }, 243 | selfUrl.origin 244 | ); 245 | 246 | // Notify emulated page that screen orientation has changed 247 | sendMessage( 248 | deviceFrame, { 249 | 'action': 'screenOrientationChange', 250 | 'data': 360 - requestedScreenOrientation 251 | }, 252 | selfUrl.origin 253 | ); 254 | 255 | if ( ( ( currentRotation / 90 ) % 2 ) !== ( ( requestedScreenOrientation / 90 ) % 2 ) ) { 256 | 257 | $( 'button[data-rotate=true]' ).each( function() { 258 | width = $( this ).attr( 'data-viewport-width' ); 259 | height = $( this ).attr( 'data-viewport-height' ); 260 | $( this ).attr( 'data-viewport-width', height ); 261 | $( this ).attr( 'data-viewport-height', width ); 262 | if ( $( this ).hasClass( 'active' ) ) { 263 | $( this ).trigger( 'click' ); 264 | } 265 | } ); 266 | 267 | } 268 | 269 | screenOrientationEl.textContent = ( 360 - requestedScreenOrientation ) % 360; 270 | 271 | // Update current screen orientation 272 | currentScreenOrientation = requestedScreenOrientation; 273 | 274 | }, 275 | 'lockScreenOrientation': function( data ) { 276 | 277 | // Post message to self to update screen orientation 278 | postMessage( JSON.stringify( { 279 | 'action': 'updateScreenOrientation', 280 | 'data': { 281 | 'totalRotation': 360 - data, 282 | 'updateControls': true 283 | } 284 | } ), selfUrl.origin ); 285 | 286 | $( 'button.rotate' ).prop( "disabled", true ).attr( "title", "Screen Rotation is locked by page" ); 287 | $( 'i', 'button.rotate' ).addClass( 'icon-lock' ).removeClass( 'icon-rotate-left' ); 288 | 289 | }, 290 | 'unlockScreenOrientation': function( data ) { 291 | 292 | $( 'button.rotate' ).attr( "title", "Rotate the Screen" ).prop( "disabled", false ); 293 | $( 'i', 'button.rotate' ).addClass( 'icon-rotate-left' ).removeClass( 'icon-lock' ); 294 | 295 | } 296 | } 297 | 298 | // Relay deviceorientation events on to content iframe 299 | window.addEventListener( 'message', function( event ) { 300 | 301 | if ( event.origin != selfUrl.origin ) return; 302 | 303 | var json = JSON.parse( event.data ); 304 | 305 | if ( !json.action || !actions[ json.action ] ) return; 306 | 307 | actions[ json.action ]( json.data ); 308 | 309 | }, false ); 310 | 311 | } 312 | -------------------------------------------------------------------------------- /controller/js/DeviceOrientationEmulatorControls.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ------- 3 | * Modified version of threeVR (https://github.com/richtr/threeVR) 4 | * ------- 5 | * 6 | * Author: Rich Tibbett (http://github.com/richtr) 7 | * License: The MIT License 8 | * 9 | **/ 10 | 11 | var DeviceOrientationEmulatorControls = function( object, domElement ) { 12 | 13 | this.object = object; 14 | this.element = domElement || document; 15 | 16 | this.enableManualDrag = true; // enable manual user drag override control by default 17 | this.enableManualZoom = true; // enable manual user zoom override control by default 18 | 19 | this.useQuaternions = true; // use quaternions for orientation calculation by default 20 | 21 | // Manual rotate override components 22 | var startX = 0, 23 | startY = 0, 24 | currentX = 0, 25 | currentY = 0, 26 | scrollSpeedX, scrollSpeedY, 27 | tmpQuat = new THREE.Quaternion(); 28 | 29 | // Manual zoom override components 30 | var zoomStart = 1, 31 | zoomCurrent = 1, 32 | zoomP1 = new THREE.Vector2(), 33 | zoomP2 = new THREE.Vector2(), 34 | tmpFOV; 35 | 36 | var CONTROLLER_STATE = { 37 | AUTO: 0, 38 | MANUAL_ROTATE: 1, 39 | MANUAL_ZOOM: 2 40 | }; 41 | 42 | var appState = CONTROLLER_STATE.AUTO; 43 | 44 | var CONTROLLER_EVENT = { 45 | MANUAL_CONTROL: 'userinteraction', // userinteractionstart, userinteractionend 46 | ZOOM_CONTROL: 'zoom', // zoomstart, zoomend 47 | ROTATE_CONTROL: 'rotate', // rotatestart, rotateend 48 | }; 49 | 50 | // Consistent Object Field-Of-View fix components 51 | var startClientHeight = window.innerHeight, 52 | startFOVFrustrumHeight = 2000 * Math.tan( THREE.Math.degToRad( ( this.object.fov || 75 ) / 2 ) ), 53 | relativeFOVFrustrumHeight, relativeVerticalFOV; 54 | 55 | var deviceQuat = new THREE.Quaternion(); 56 | 57 | var fireEvent = function() { 58 | var eventData; 59 | 60 | return function( name ) { 61 | window.setTimeout(function() { 62 | eventData = arguments || {}; 63 | 64 | eventData.type = name; 65 | eventData.target = this; 66 | 67 | this.dispatchEvent( eventData ); 68 | }.bind( this ), 1); 69 | }.bind( this ); 70 | }.bind( this )(); 71 | 72 | this.constrainObjectFOV = function() { 73 | relativeFOVFrustrumHeight = startFOVFrustrumHeight * ( window.innerHeight / startClientHeight ); 74 | 75 | relativeVerticalFOV = THREE.Math.radToDeg( 2 * Math.atan( relativeFOVFrustrumHeight / 2000 ) ); 76 | 77 | this.object.fov = relativeVerticalFOV; 78 | }.bind( this ); 79 | 80 | this.onDocumentMouseDown = function( event ) { 81 | event.preventDefault(); 82 | 83 | appState = CONTROLLER_STATE.MANUAL_ROTATE; 84 | 85 | tmpQuat.copy( this.object.quaternion ); 86 | 87 | startX = currentX = event.pageX; 88 | startY = currentY = event.pageY; 89 | 90 | // Set consistent scroll speed based on current viewport width/height 91 | scrollSpeedX = ( 1200 / window.innerWidth ) * 0.2; 92 | scrollSpeedY = ( 800 / window.innerHeight ) * 0.2; 93 | 94 | this.element.addEventListener( 'mousemove', this.onDocumentMouseMove, false ); 95 | this.element.addEventListener( 'mouseup', this.onDocumentMouseUp, false ); 96 | this.element.addEventListener( 'mouseout', this.onDocumentMouseUp, false ); 97 | 98 | fireEvent( CONTROLLER_EVENT.MANUAL_CONTROL + 'start' ); 99 | fireEvent( CONTROLLER_EVENT.ROTATE_CONTROL + 'start' ); 100 | }.bind( this ); 101 | 102 | this.onDocumentMouseMove = function( event ) { 103 | currentX = event.pageX; 104 | currentY = event.pageY; 105 | }.bind( this ); 106 | 107 | this.onDocumentMouseUp = function( event ) { 108 | this.element.removeEventListener( 'mousemove', this.onDocumentMouseMove, false ); 109 | this.element.removeEventListener( 'mouseup', this.onDocumentMouseUp, false ); 110 | this.element.removeEventListener( 'mouseout', this.onDocumentMouseUp, false ); 111 | 112 | appState = CONTROLLER_STATE.AUTO; 113 | 114 | fireEvent( CONTROLLER_EVENT.MANUAL_CONTROL + 'end' ); 115 | fireEvent( CONTROLLER_EVENT.ROTATE_CONTROL + 'end' ); 116 | }.bind( this ); 117 | 118 | this.onDocumentTouchStart = function( event ) { 119 | event.preventDefault(); 120 | event.stopPropagation(); 121 | 122 | switch ( event.touches.length ) { 123 | case 1: // ROTATE 124 | 125 | appState = CONTROLLER_STATE.MANUAL_ROTATE; 126 | 127 | tmpQuat.copy( this.object.quaternion ); 128 | 129 | startX = currentX = event.touches[ 0 ].pageX; 130 | startY = currentY = event.touches[ 0 ].pageY; 131 | 132 | // Set consistent scroll speed based on current viewport width/height 133 | scrollSpeedX = ( 1200 / window.innerWidth ) * 0.1; 134 | scrollSpeedY = ( 800 / window.innerHeight ) * 0.1; 135 | 136 | this.element.addEventListener( 'touchmove', this.onDocumentTouchMove, false ); 137 | this.element.addEventListener( 'touchend', this.onDocumentTouchEnd, false ); 138 | 139 | fireEvent( CONTROLLER_EVENT.MANUAL_CONTROL + 'start' ); 140 | fireEvent( CONTROLLER_EVENT.ROTATE_CONTROL + 'start' ); 141 | 142 | break; 143 | 144 | case 2: // ZOOM 145 | 146 | appState = CONTROLLER_STATE.MANUAL_ZOOM; 147 | 148 | tmpFOV = this.object.fov; 149 | 150 | zoomP1.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 151 | zoomP2.set( event.touches[ 1 ].pageX, event.touches[ 1 ].pageY ); 152 | 153 | zoomStart = zoomCurrent = zoomP1.distanceTo( zoomP2 ); 154 | 155 | this.element.addEventListener( 'touchmove', this.onDocumentTouchMove, false ); 156 | this.element.addEventListener( 'touchend', this.onDocumentTouchEnd, false ); 157 | 158 | fireEvent( CONTROLLER_EVENT.MANUAL_CONTROL + 'start' ); 159 | fireEvent( CONTROLLER_EVENT.ZOOM_CONTROL + 'start' ); 160 | 161 | break; 162 | } 163 | }.bind( this ); 164 | 165 | this.onDocumentTouchMove = function( event ) { 166 | switch ( event.touches.length ) { 167 | case 1: 168 | currentX = event.touches[ 0 ].pageX; 169 | currentY = event.touches[ 0 ].pageY; 170 | break; 171 | 172 | case 2: 173 | zoomP1.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY ); 174 | zoomP2.set( event.touches[ 1 ].pageX, event.touches[ 1 ].pageY ); 175 | break; 176 | } 177 | }.bind( this ); 178 | 179 | this.onDocumentTouchEnd = function( event ) { 180 | this.element.removeEventListener( 'touchmove', this.onDocumentTouchMove, false ); 181 | this.element.removeEventListener( 'touchend', this.onDocumentTouchEnd, false ); 182 | 183 | if ( appState === CONTROLLER_STATE.MANUAL_ROTATE ) { 184 | 185 | appState = CONTROLLER_STATE.AUTO; // reset control state 186 | 187 | fireEvent( CONTROLLER_EVENT.MANUAL_CONTROL + 'end' ); 188 | fireEvent( CONTROLLER_EVENT.ROTATE_CONTROL + 'end' ); 189 | 190 | } else if ( appState === CONTROLLER_STATE.MANUAL_ZOOM ) { 191 | 192 | this.constrainObjectFOV(); // re-instate original object FOV 193 | 194 | appState = CONTROLLER_STATE.AUTO; // reset control state 195 | 196 | fireEvent( CONTROLLER_EVENT.MANUAL_CONTROL + 'end' ); 197 | fireEvent( CONTROLLER_EVENT.ZOOM_CONTROL + 'end' ); 198 | 199 | } 200 | }.bind( this ); 201 | 202 | this.updateManualMove = function() { 203 | 204 | var lat, lon; 205 | var phi, theta; 206 | 207 | var rotation = new THREE.Euler( 0, 0, 0, 'YXZ' ); 208 | 209 | var rotQuat = new THREE.Quaternion(); 210 | var objQuat = new THREE.Quaternion(); 211 | 212 | var tmpZ, objZ, realZ; 213 | 214 | var zoomFactor, minZoomFactor = 1; // maxZoomFactor = Infinity 215 | 216 | return function() { 217 | 218 | if ( appState === CONTROLLER_STATE.MANUAL_ROTATE ) { 219 | 220 | lat = - ( startY - currentY ) * scrollSpeedY; 221 | lon = - ( startX - currentX ) * scrollSpeedX; 222 | 223 | phi = THREE.Math.degToRad( lat ); 224 | theta = THREE.Math.degToRad( lon ); 225 | 226 | // Reset objQuat 227 | objQuat.set(0,0,0,1); 228 | 229 | // Apply y-based mouse rotation 230 | rotQuat.set( 0, Math.sin( theta / 2 ), 0, Math.cos( theta / 2 ) ); 231 | objQuat.multiply( rotQuat ); 232 | 233 | // Apply z-based mouse rotation 234 | rotQuat.set( Math.sin( phi / 2 ), 0, 0, Math.cos( phi / 2 ) ); 235 | objQuat.multiply( rotQuat ); 236 | 237 | // Apply existing object rotation to calculated mouse rotation 238 | objQuat.multiply( tmpQuat ); 239 | 240 | this.object.quaternion.copy( objQuat ); 241 | 242 | } else if ( appState === CONTROLLER_STATE.MANUAL_ZOOM ) { 243 | 244 | zoomCurrent = zoomP1.distanceTo( zoomP2 ); 245 | 246 | zoomFactor = zoomStart / zoomCurrent; 247 | 248 | if ( zoomFactor <= minZoomFactor ) { 249 | 250 | this.object.fov = tmpFOV * zoomFactor; 251 | 252 | this.object.updateProjectionMatrix(); 253 | 254 | } 255 | 256 | // Add device's current z-axis rotation 257 | 258 | if ( deviceQuat ) { 259 | 260 | tmpZ = rotation.setFromQuaternion( tmpQuat, 'YXZ' ).z; 261 | realZ = rotation.setFromQuaternion( deviceQuat, 'YXZ' ).z; 262 | 263 | rotQuat.set( 0, 0, Math.sin( ( realZ - tmpZ ) / 2 ), Math.cos( ( realZ - tmpZ ) / 2 ) ); 264 | 265 | tmpQuat.multiply( rotQuat ); 266 | 267 | this.object.quaternion.copy( tmpQuat ); 268 | 269 | } 270 | 271 | } 272 | 273 | }; 274 | 275 | }(); 276 | 277 | this.update = function() { 278 | if ( appState !== CONTROLLER_STATE.AUTO ) { 279 | this.updateManualMove(); 280 | } 281 | }; 282 | 283 | this.updateScreenOrientation = function( diffRotation ) { 284 | var screenTransform = new THREE.Quaternion(); 285 | var minusHalfAngle = 0; 286 | 287 | // Add new screen rotation 288 | minusHalfAngle = -( THREE.Math.degToRad( diffRotation ) ) / 2; 289 | screenTransform.set( 0, 0, Math.sin( minusHalfAngle ), Math.cos( minusHalfAngle ) ); 290 | this.object.quaternion.multiply( screenTransform ); 291 | }; 292 | 293 | this.connect = function() { 294 | window.addEventListener( 'resize', this.constrainObjectFOV, false ); 295 | 296 | this.element.addEventListener( 'mousedown', this.onDocumentMouseDown, false ); 297 | this.element.addEventListener( 'touchstart', this.onDocumentTouchStart, false ); 298 | 299 | this.element.style.cursor = 'move'; 300 | }; 301 | 302 | this.disconnect = function() { 303 | window.removeEventListener( 'resize', this.constrainObjectFOV, false ); 304 | 305 | this.element.removeEventListener( 'mousedown', this.onDocumentMouseDown, false ); 306 | this.element.removeEventListener( 'touchstart', this.onDocumentTouchStart, false ); 307 | 308 | this.element.style.cursor = 'not-allowed'; 309 | }; 310 | 311 | }; 312 | 313 | DeviceOrientationEmulatorControls.prototype = Object.create( THREE.EventDispatcher.prototype ); 314 | -------------------------------------------------------------------------------- /emulator/js/timeliner.js: -------------------------------------------------------------------------------- 1 | function EmulatorTimeline( alpha, beta, gamma, screen ) { 2 | 3 | var _frames = []; 4 | 5 | this.import = function( frames ) { 6 | _frames = frames; 7 | }; 8 | 9 | this.getAll = function( index ) { 10 | return _frames; 11 | }; 12 | 13 | this.get = function( index ) { 14 | return _frames[ index ]; 15 | }; 16 | 17 | this.set = function( obj, duration, offset, index ) { 18 | 19 | var frame = { 20 | 'type': 0, // FIX TO POSITION 21 | 'duration': duration || 1, 22 | 'offset': offset || 0, 23 | 'data': obj || {} 24 | }; 25 | 26 | if ( index !== undefined && index !== null ) { 27 | // Update an existing animation frame 28 | _frames[ index ] = frame; 29 | } else { 30 | // Append a new animation frame 31 | _frames.push( frame ); 32 | } 33 | 34 | return this; 35 | 36 | }; 37 | 38 | this.length = function() { 39 | return _frames.length; 40 | }; 41 | 42 | this.animate = function( obj, duration, offset, index ) { 43 | 44 | var frame = { 45 | 'type': 1, // ANIMATE TO POSITION 46 | 'duration': duration || 1, 47 | 'offset': offset || 0, 48 | 'data': obj || {} 49 | }; 50 | 51 | if ( index !== undefined && index !== null ) { 52 | // Update an existing animation frame 53 | _frames[ index ] = frame; 54 | } else { 55 | // Append a new animation frame 56 | _frames.push( frame ); 57 | } 58 | 59 | return this; 60 | 61 | }; 62 | 63 | this.start = function() { 64 | 65 | sendMessage( 66 | controller, { 67 | 'action': 'playback', 68 | 'data': { 69 | 'frames': _frames 70 | } 71 | }, 72 | selfUrl.origin 73 | ); 74 | 75 | return this; 76 | 77 | }; 78 | 79 | // Set initial device orientation frame data 80 | var data = { 81 | 'alpha': alpha || 0, 82 | 'beta': beta || 0, 83 | 'gamma': gamma || 0, 84 | 'screen': screen || 0 85 | }; 86 | 87 | this.set( data, 1, 0 ); 88 | 89 | }; 90 | 91 | EmulatorTimeline.prototype = { 92 | 93 | 'constructor': EmulatorTimeline, 94 | 95 | // Static method 96 | 'compress': function( framesOriginal ) { 97 | var framesCompressed = []; 98 | 99 | for ( var i = 0, l = framesOriginal.length; i < l; i++ ) { 100 | framesCompressed.push( [ 101 | framesOriginal[ i ].type, 102 | framesOriginal[ i ].duration, 103 | framesOriginal[ i ].offset, 104 | framesOriginal[ i ].data.alpha, 105 | framesOriginal[ i ].data.beta, 106 | framesOriginal[ i ].data.gamma, 107 | framesOriginal[ i ].data.screen 108 | ] ); 109 | } 110 | 111 | return framesCompressed; 112 | }, 113 | 114 | 'uncompress': function( framesCompressed ) { 115 | var framesOriginal = []; 116 | 117 | for ( var i = 0, l = framesCompressed.length; i < l; i++ ) { 118 | var data = { 119 | 'type': framesCompressed[ i ][ 0 ], 120 | 'duration': framesCompressed[ i ][ 1 ], 121 | 'offset': framesCompressed[ i ][ 2 ], 122 | 'data': { 123 | 'alpha': framesCompressed[ i ][ 3 ], 124 | 'beta': framesCompressed[ i ][ 4 ], 125 | 'gamma': framesCompressed[ i ][ 5 ], 126 | 'screen': framesCompressed[ i ][ 6 ] 127 | } 128 | }; 129 | 130 | framesOriginal.push( data ); 131 | } 132 | 133 | return framesOriginal; 134 | } 135 | 136 | }; 137 | 138 | // Create a new emulator timeline 139 | var timeline = new EmulatorTimeline( 0, 0, 0, 0 ); 140 | 141 | var activeFrameIndex = 0; 142 | var _lastData = {}; 143 | 144 | var actions = { 145 | 'connect': function( data ) { 146 | 147 | $( 'button#play' ).on( 'click', function() { 148 | $( 'button[data-frame-number=0]' ).removeClass( 'charcoal' ).addClass( 'asphalt active' ); 149 | 150 | $( 'button[data-frame-number=0]' ).trigger( 'click' ); 151 | 152 | timeline.start(); 153 | } ); 154 | 155 | $( 'body' ).on( 'click', 'button[data-frame-number]', function() { 156 | 157 | activeFrameIndex = $( this ).attr( 'data-frame-number' ); 158 | 159 | var activeFrame = timeline.get( activeFrameIndex ); 160 | 161 | sendMessage( 162 | controller, { 163 | 'action': 'setCoords', 164 | 'data': activeFrame.data 165 | }, 166 | selfUrl.origin 167 | ); 168 | 169 | // Post message to self to update screen orientation 170 | postMessage( JSON.stringify( { 171 | 'action': 'updateScreenOrientation', 172 | 'data': { 173 | 'totalRotation': ( 360 - activeFrame.data.screen ) % 360, 174 | 'updateControls': false 175 | } 176 | } ), selfUrl.origin ); 177 | 178 | $( 'button.active[data-frame-number]' ).removeClass( 'asphalt active' ).addClass( 'charcoal' ); 179 | $( 'button[data-frame-number=' + activeFrameIndex + ']' ).removeClass( 'charcoal' ).addClass( 'asphalt active' ); 180 | 181 | } ); 182 | 183 | $( 'button#clearTimeline' ).on( 'click', function() { 184 | 185 | // Trash all frame buttons except the first one 186 | $( 'button[data-frame-number]' ).not( ':first' ).remove(); 187 | 188 | var startFrame = timeline.get( 0 ); 189 | // Reset timeline 190 | timeline.import( [ startFrame ] ); 191 | 192 | // Focus the first frame 193 | $( 'button[data-frame-number=0]' ).trigger( 'click' ); 194 | 195 | } ); 196 | 197 | $( 'button#addNewFrame' ).on( 'click', function() { 198 | 199 | var newFrameId = timeline.length(); 200 | 201 | if ( timeline.get( newFrameId ) == undefined ) { 202 | 203 | // Use last known device orientation values to initialize new animation frame 204 | var data = { 205 | alpha: printDataValue( _lastData.alpha ), 206 | beta: printDataValue( _lastData.beta ), 207 | gamma: printDataValue( _lastData.gamma ), 208 | screen: _lastData.screen 209 | }; 210 | 211 | timeline.animate( data, 1, 0 ); 212 | 213 | } 214 | 215 | // Create and add a new frame button to GUI 216 | $( '#frame-group' ).append( 217 | $( '
  • ' ).append( 218 | $( '' ) 219 | .attr( 'data-frame-number', newFrameId ) 220 | .attr( 'data-disable-during-playback', 'true' ) 221 | .text( newFrameId + 1 ) 222 | ) 223 | ); 224 | 225 | // Highlight new frame 226 | $( 'button[data-frame-number=' + newFrameId + ']' ).trigger( 'click' ); 227 | 228 | // Don't allow more than 20 frames 229 | if ( newFrameId >= 19 ) { 230 | 231 | $( 'button#addNewFrame' ).attr( 'disabled', 'disabled' ); 232 | 233 | } 234 | 235 | } ); 236 | 237 | // Tell controller to start rendering 238 | sendMessage( 239 | controller, { 240 | 'action': 'start' 241 | }, 242 | selfUrl.origin 243 | ); 244 | 245 | var urlHash = selfUrl.hash; 246 | 247 | // Parse provided JSON animation hash object (if any) 248 | if ( urlHash && urlHash.length > 3 ) { 249 | // Remove leading '#' 250 | var jsonBase64 = urlHash.substring( 1 ); 251 | 252 | // Base64 decode this data 253 | var jsonStr = window.atob( jsonBase64 ); 254 | 255 | try { 256 | var json = JSON.parse( "{\"d\": " + jsonStr + " }" ); 257 | 258 | // 'Unzip' the data 259 | var frames = EmulatorTimeline.prototype.uncompress( json.d ); 260 | 261 | if ( frames && frames.length > 0 ) { 262 | 263 | // Create the correct number of animation frame buttons 264 | for ( var i = 1; i < frames.length; i++ ) { 265 | $( 'button#addNewFrame' ).trigger( 'click' ); 266 | } 267 | 268 | // Import json as the emulator timeline 269 | timeline.import( frames ); 270 | 271 | // Focus the first frame 272 | $( 'button[data-frame-number=0]' ).trigger( 'click' ); 273 | 274 | // Update onscreen coords 275 | sendMessage( 276 | controller, { 277 | 'action': 'setCoords', 278 | 'data': { 279 | 'alpha': frames[ 0 ].data.alpha || 0, 280 | 'beta': frames[ 0 ].data.beta || 0, 281 | 'gamma': frames[ 0 ].data.gamma || 0 282 | } 283 | }, 284 | selfUrl.origin 285 | ); 286 | 287 | // Post message to self to then update controller screen orientation 288 | postMessage( JSON.stringify( { 289 | 'action': 'updateScreenOrientation', 290 | 'data': { 291 | 'totalRotation': ( 360 - frames[ 0 ].data.screen ) % 360, 292 | 'updateControls': false 293 | } 294 | } ), selfUrl.origin ); 295 | 296 | // Start whatever animation was loaded when page loads 297 | window.setTimeout(function() { 298 | timeline.start(); 299 | }, 500); // delay until setCoords and updateScreenOrientation above complete 300 | 301 | } 302 | } catch ( e ) { 303 | console.log( e ); 304 | } 305 | 306 | } 307 | 308 | $( '#timeline' ).css( { 309 | 'display': 'block' 310 | } ); 311 | 312 | }, 313 | 'newData': function( data ) { 314 | var _data = { 315 | alpha: printDataValue( data.alpha ), 316 | beta: printDataValue( data.beta ), 317 | gamma: printDataValue( data.gamma ), 318 | screen: data.screen 319 | } 320 | 321 | if ( _data.alpha == _lastData.alpha && _data.beta == _lastData.beta && _data.gamma == _lastData.gamma && _data.screen == _lastData.screen ) return; 322 | 323 | // If this data applies to the first frame or a screen orientation change 324 | // is being observed then use .set instead of .animate! 325 | if ( activeFrameIndex === 0 || _data.screen !== _lastData.screen ) { 326 | timeline.set( _data, _data.screen !== _lastData.screen ? 1 : 0.5, 0, activeFrameIndex ); 327 | } else { 328 | timeline.animate( _data, 1, 0, activeFrameIndex ); 329 | } 330 | 331 | _lastData = _data; // store for next loop 332 | }, 333 | 'updatePosition': function( data ) { 334 | window.setTimeout( function() { 335 | // 'Zip' the current timeline data 336 | var framesCompressed = EmulatorTimeline.prototype.compress( timeline.getAll() ); 337 | 338 | // Stringify the data object 339 | var jsonStr = JSON.stringify( framesCompressed ); 340 | 341 | // Base64 encode the data object 342 | var jsonBase64 = window.btoa( jsonStr ); 343 | 344 | // Replace current URL hash with compressed, stringified, encoded data! 345 | selfUrl.hash = '#' + jsonBase64; 346 | replaceURL( selfUrl ); 347 | }, 150 ); 348 | }, 349 | 'playbackStarted': function( data ) { 350 | 351 | // Disable buttons 352 | $( '[data-disable-during-playback]' ).each( function() { 353 | $( this ).attr( 'disabled', 'disabled' ); 354 | } ); 355 | 356 | }, 357 | 'playbackTransition': function( data ) { 358 | 359 | // Disable the previous frame if we have one 360 | if ( data > 0 ) { 361 | var previousFrameButton = $( 'button[data-frame-number=' + ( data - 1 ) + ']' ); 362 | 363 | previousFrameButton.removeClass( 'asphalt active' ) 364 | previousFrameButton.addClass( 'charcoal' ); 365 | previousFrameButton.attr( 'disabled', 'disabled' ); 366 | } 367 | 368 | $( 'button[data-frame-number=' + data + ']' ).removeAttr( 'disabled' ).trigger( 'click' ); 369 | 370 | }, 371 | 'playbackEnded': function( data ) { 372 | 373 | // Re-enable buttons 374 | $( '[data-disable-during-playback]' ).each( function() { 375 | $( this ).removeAttr( 'disabled' ); 376 | } ); 377 | 378 | $( 'button[data-frame-number=0]' ).trigger( 'click' ); 379 | 380 | } 381 | }; 382 | 383 | window.addEventListener( 'message', function( event ) { 384 | 385 | if ( event.origin != selfUrl.origin ) return; 386 | 387 | var json = JSON.parse( event.data ); 388 | 389 | if ( !json.action || !actions[ json.action ] ) return; 390 | 391 | actions[ json.action ]( json.data ); 392 | 393 | }, false ); 394 | -------------------------------------------------------------------------------- /controller/js/app.js: -------------------------------------------------------------------------------- 1 | var APP = { 2 | 3 | Player: function() { 4 | 5 | var scope = this; 6 | 7 | var loader = new THREE.ObjectLoader(); 8 | var camera, scene, renderer; 9 | 10 | var controls; 11 | 12 | var events = {}; 13 | 14 | this.dom = undefined; 15 | 16 | this.width = 500; 17 | this.height = 500; 18 | 19 | var prevTime, request; 20 | 21 | var euler = new THREE.Euler(); 22 | var deviceOrientation = new FULLTILT.Euler(); 23 | 24 | var worldQuat = new THREE.Quaternion( -Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); 25 | 26 | var camQuat = new THREE.Quaternion(); 27 | 28 | var rotation = new THREE.Euler( 0, 0, 0, 'YXZ' ); 29 | var rotQuat = new THREE.Quaternion(); 30 | 31 | var tweenInProgress = false; 32 | 33 | this.load = function( json ) { 34 | 35 | renderer = new THREE.WebGLRenderer( { 36 | antialias: true 37 | } ); 38 | renderer.setClearColor( 0xFFFFFF, 1 ); 39 | renderer.setPixelRatio( window.devicePixelRatio ); 40 | this.dom = renderer.domElement; 41 | 42 | this.setScene( loader.parse( json.scene ) ); 43 | this.setCamera( loader.parse( json.camera ) ); 44 | 45 | events = { 46 | update: [] 47 | }; 48 | 49 | for ( var uuid in json.scripts ) { 50 | 51 | var object = scene.getObjectByProperty( 'uuid', uuid, true ); 52 | 53 | var scripts = json.scripts[ uuid ]; 54 | 55 | for ( var i = 0; i < scripts.length; i++ ) { 56 | 57 | var script = scripts[ i ]; 58 | 59 | var functions = ( new Function( 'player, scene, update', script.source + '\nreturn { update: update };' ).bind( object ) )( this, scene ); 60 | 61 | for ( var name in functions ) { 62 | 63 | if ( functions[ name ] === undefined ) continue; 64 | 65 | if ( events[ name ] === undefined ) { 66 | 67 | console.warn( 'APP.Player: event type not supported (', name, ')' ); 68 | continue; 69 | 70 | } 71 | 72 | events[ name ].push( functions[ name ].bind( object ) ); 73 | 74 | } 75 | 76 | } 77 | 78 | } 79 | 80 | // Rotate the phone group in the scene, not the camera as usual 81 | var phoneGroupObj = scene.getObjectByProperty( 'uuid', 'D5083881-7A5B-40AF-8A5F-19F401AF1C70', true ); 82 | 83 | // Set up device orientation emulator controls 84 | controls = new DeviceOrientationEmulatorControls( phoneGroupObj, scope.dom ); 85 | controls.enableManualZoom = false; 86 | controls.connect(); 87 | 88 | // Tell parent window to update its URL hash whenever interfaction with controls ends 89 | controls.addEventListener( 'userinteractionend', function() { 90 | if ( window.parent ) { 91 | 92 | sendMessage( 93 | window.parent, { 94 | 'action': 'updatePosition' 95 | } 96 | ); 97 | 98 | } 99 | }, false ); 100 | 101 | }; 102 | 103 | this.setCamera = function( value ) { 104 | 105 | camera = value; 106 | camera.aspect = this.width / this.height; 107 | camera.updateProjectionMatrix(); 108 | 109 | }; 110 | 111 | this.setScene = function( value ) { 112 | 113 | scene = value; 114 | 115 | }; 116 | 117 | this.setSize = function( width, height ) { 118 | 119 | if ( renderer._fullScreen ) return; 120 | 121 | this.width = width; 122 | this.height = height; 123 | 124 | camera.aspect = this.width / this.height; 125 | camera.updateProjectionMatrix(); 126 | 127 | renderer.setSize( width, height ); 128 | 129 | }; 130 | 131 | this.setManualOrientation = ( function() { 132 | 133 | var _q = new THREE.Quaternion(); 134 | 135 | return function( alpha, beta, gamma ) { 136 | 137 | var _x = THREE.Math.degToRad( beta || 0 ); 138 | var _y = THREE.Math.degToRad( alpha || 0 ); 139 | var _z = THREE.Math.degToRad( gamma || 0 ); 140 | 141 | euler.set( _x, _y, -_z, 'YXZ' ); 142 | 143 | // Apply provided deviceorientation values to controller 144 | _q.setFromEuler( euler ); 145 | _q.multiply( worldQuat ); 146 | 147 | controls.object.quaternion.copy( _q ); 148 | 149 | }; 150 | 151 | } )(); 152 | 153 | this.playback = ( function() { 154 | 155 | var source, destination; 156 | var _this; 157 | 158 | var _a0, _b0, _g0; 159 | 160 | return function( data ) { 161 | 162 | _this = this; 163 | 164 | // Disconnect controls 165 | controls.disconnect(); 166 | 167 | // Store original device orientation values 168 | _a0 = deviceOrientation.alpha; 169 | _b0 = deviceOrientation.beta; 170 | _g0 = deviceOrientation.gamma; 171 | 172 | var frameNumber = 0; 173 | 174 | sendMessage( 175 | window.parent, { 176 | 'action': 'playbackStarted' 177 | } 178 | ); 179 | 180 | // Tween through each of our animation frames 181 | data.frames.reduce( function( chain, frame ) { 182 | // Add these actions to the end of the promise chain 183 | return chain.then( function() { 184 | sendMessage( 185 | window.parent, { 186 | 'action': 'playbackTransition', 187 | 'data': frameNumber++ 188 | } 189 | ); 190 | 191 | if ( frame.type === 0 ) { // SET 192 | return _this.set( frame ); 193 | } else { // ANIMATION 194 | return _this.tween( frame ); 195 | } 196 | } ); 197 | }, Promise.resolve() ).then( function() { 198 | // Rollback to original device orientation values 199 | window.setTimeout( function() { 200 | sendMessage( 201 | window.parent, { 202 | 'action': 'playbackEnded' 203 | } 204 | ); 205 | 206 | _this.setManualOrientation( _a0, _b0, _g0 ); 207 | 208 | // Re-connect controls 209 | controls.connect(); 210 | }, 1000 ); 211 | } ).catch( function() { 212 | // Clean-up on error 213 | sendMessage( 214 | window.parent, { 215 | 'action': 'playbackEnded' 216 | } 217 | ); 218 | 219 | _this.setManualOrientation( _a0, _b0, _g0 ); 220 | 221 | // Re-connect controls 222 | controls.connect(); 223 | } ); 224 | 225 | }; 226 | 227 | } )(); 228 | 229 | this.set = ( function() { 230 | 231 | var _this; 232 | 233 | var waitTime, playTime; 234 | 235 | return function( frame ) { 236 | 237 | _this = this; 238 | 239 | var setPromise = new Promise( function( resolve, reject ) { 240 | 241 | waitTime = frame.offset * 1000; 242 | playTime = frame.duration * 1000; 243 | 244 | window.setTimeout( function() { 245 | 246 | _this.setManualOrientation( frame.data.alpha, frame.data.beta, frame.data.gamma ); 247 | 248 | window.setTimeout( function() { 249 | resolve(); // this Promise can never reject 250 | }, playTime ); 251 | 252 | }, waitTime ); 253 | 254 | } ); 255 | 256 | return setPromise; 257 | 258 | }; 259 | 260 | } )(); 261 | 262 | this.tween = ( function() { 263 | 264 | var waitTime, playTime; 265 | 266 | var destRot = new THREE.Euler(); // input euler values 267 | 268 | var qa = new THREE.Quaternion(); // source quaternion 269 | var qb = new THREE.Quaternion(); // destination quaternion 270 | var qm = new THREE.Quaternion(); // worker 271 | 272 | return function( frame ) { 273 | 274 | var tweenPromise = new Promise( function( resolve, reject ) { 275 | 276 | tweenInProgress = true; 277 | 278 | waitTime = frame.offset * 1000; 279 | playTime = frame.duration * 1000; 280 | 281 | var _x = THREE.Math.degToRad( frame.data.beta || 0 ); 282 | var _y = THREE.Math.degToRad( frame.data.alpha || 0 ); 283 | var _z = THREE.Math.degToRad( frame.data.gamma || 0 ); 284 | 285 | destRot.set( _x, _y, -_z, 'YXZ' ); 286 | 287 | // Obtain target quaternion from provided Euler angles 288 | qb.setFromEuler( destRot ); 289 | qb.multiply( worldQuat ); 290 | 291 | // Set source as the current camera's quaternion 292 | qa.copy( controls.object.quaternion ); 293 | 294 | // Reset our worker quaternion 295 | qm.set( 0, 0, 0, 1 ); 296 | 297 | var throwError = window.setTimeout( function() { 298 | tweenInProgress = false; 299 | reject(); 300 | }, waitTime + 5000 ); 301 | 302 | var o = { 303 | t: 0 304 | }; 305 | 306 | new TWEEN.Tween( o ) 307 | .delay( waitTime ) 308 | .to( { 309 | t: 1 310 | }, playTime ) 311 | .onStart( function() { 312 | window.clearTimeout( throwError ); 313 | } ) 314 | .onUpdate( function() { 315 | THREE.Quaternion.slerp( qa, qb, qm, o.t ); 316 | controls.object.quaternion.copy( qm ); 317 | } ) 318 | .onComplete( function() { 319 | tweenInProgress = false; 320 | resolve(); 321 | } ) 322 | .start(); 323 | 324 | } ); 325 | 326 | return tweenPromise; 327 | 328 | }; 329 | 330 | } )(); 331 | 332 | this.updateScreenOrientation = function( data ) { 333 | 334 | // Update the screen display bars 335 | 336 | var screenTop = scene.getObjectByProperty( 'name', 'screen_top', true ); 337 | var screenBottom = scene.getObjectByProperty( 'name', 'screen_bottom', true ); 338 | var screenTopInv = scene.getObjectByProperty( 'name', 'screen_top_inverse', true ); 339 | var screenBottomInv = scene.getObjectByProperty( 'name', 'screen_bottom_inverse', true ); 340 | 341 | var screenLeft = scene.getObjectByProperty( 'name', 'screen_left', true ); 342 | var screenRight = scene.getObjectByProperty( 'name', 'screen_right', true ); 343 | var screenLeftInv = scene.getObjectByProperty( 'name', 'screen_left_inverse', true ); 344 | var screenRightInv = scene.getObjectByProperty( 'name', 'screen_right_inverse', true ); 345 | 346 | if ( data.totalRotation % 180 !== 0 ) { 347 | 348 | screenTop.visible = false; 349 | screenBottom.visible = false; 350 | screenTopInv.visible = false; 351 | screenBottomInv.visible = false; 352 | 353 | if ( data.totalRotation == 90 ) { 354 | 355 | screenLeft.visible = true; 356 | screenRight.visible = true; 357 | screenLeftInv.visible = false; 358 | screenRightInv.visible = false; 359 | 360 | } else { 361 | 362 | screenLeft.visible = false; 363 | screenRight.visible = false; 364 | screenLeftInv.visible = true; 365 | screenRightInv.visible = true; 366 | 367 | } 368 | 369 | } else { 370 | 371 | screenLeft.visible = false; 372 | screenRight.visible = false; 373 | screenLeftInv.visible = false; 374 | screenRightInv.visible = false; 375 | 376 | if ( data.totalRotation == 180 ) { 377 | 378 | screenTop.visible = false; 379 | screenBottom.visible = false; 380 | screenTopInv.visible = true; 381 | screenBottomInv.visible = true; 382 | 383 | } else { 384 | 385 | screenTop.visible = true; 386 | screenBottom.visible = true; 387 | screenTopInv.visible = false; 388 | screenBottomInv.visible = false; 389 | 390 | } 391 | 392 | } 393 | 394 | if ( data.updateControls ) { 395 | 396 | controls.updateScreenOrientation( data.rotationDiff ); 397 | 398 | } 399 | 400 | } 401 | 402 | var dispatch = function( array, event ) { 403 | 404 | for ( var i = 0, l = array.length; i < l; i++ ) { 405 | 406 | array[ i ]( event ); 407 | 408 | } 409 | 410 | }; 411 | 412 | var animate = function( time ) { 413 | 414 | request = requestAnimationFrame( animate ); 415 | 416 | dispatch( events.update, { 417 | time: time, 418 | delta: time - prevTime 419 | } ); 420 | 421 | if ( tweenInProgress ) { 422 | TWEEN.update( time ); 423 | } 424 | 425 | controls.update(); 426 | 427 | // *** Calculate device orientation quaternion (without affecting rendering) 428 | camQuat.copy( controls.object.quaternion ); 429 | camQuat.inverse(); 430 | camQuat.multiply( worldQuat ); 431 | camQuat.inverse(); 432 | 433 | // Derive Tait-Bryan angles from calculated device orientation quaternion 434 | deviceOrientation.setFromQuaternion( camQuat, 'YXZ' ); 435 | 436 | // Calculate required emulator screen roll compensation required 437 | var rollZ = rotation.setFromQuaternion( controls.object.quaternion, 'YXZ' ).z; 438 | deviceOrientation.roll = THREE.Math.radToDeg( -rollZ ); 439 | 440 | // Dispatch a new 'deviceorientation' event based on derived device orientation 441 | dispatchDeviceOrientationEvent( deviceOrientation ); 442 | 443 | // Render the controller 444 | renderer.render( scene, camera ); 445 | 446 | prevTime = time; 447 | 448 | }; 449 | 450 | this.play = function( url ) { 451 | 452 | controls.object.quaternion.set( 0, 0, 0, 1 ); 453 | 454 | request = requestAnimationFrame( animate ); 455 | prevTime = performance.now(); 456 | 457 | }; 458 | 459 | this.stop = function() { 460 | 461 | cancelAnimationFrame( request ); 462 | 463 | }; 464 | 465 | } 466 | 467 | }; 468 | -------------------------------------------------------------------------------- /controller/js/third_party/fulltilt.min.js: -------------------------------------------------------------------------------- 1 | /*! Full Tilt v0.5.3 / http://github.com/richtr/Full-Tilt */ 2 | !function(a){function b(a){return a=+a,0===a||isNaN(a)?a:a>0?1:-1}function c(a){var b=new Promise(function(b,c){var d=function(e){setTimeout(function(){a&&a.data?b():e>=20?c():d(++e)},50)};d(0)});return b}function d(){o=n?(a.screen.orientation.angle||0)*j:(a.orientation||0)*j}function e(a){l.orientation.data=a;for(var b in l.orientation.callbacks)l.orientation.callbacks[b].call(this)}function f(a){l.motion.data=a;for(var b in l.motion.callbacks)l.motion.callbacks[b].call(this)}if(void 0===a.FULLTILT||null===a.FULLTILT){var g=Math.PI,h=g/2,i=2*g,j=g/180,k=180/g,l={orientation:{active:!1,callbacks:[],data:void 0},motion:{active:!1,callbacks:[],data:void 0}},m=!1,n=a.screen&&a.screen.orientation&&void 0!==a.screen.orientation.angle&&null!==a.screen.orientation.angle?!0:!1,o=(n?a.screen.orientation.angle:a.orientation||0)*j,p=h,q=g,r=i/3,s=-h,t={};t.version="0.5.3",t.getDeviceOrientation=function(a){var b=new Promise(function(b,d){var e=new t.DeviceOrientation(a);e.start();var f=new c(l.orientation);f.then(function(){e._alphaAvailable=l.orientation.data.alpha&&null!==l.orientation.data.alpha,e._betaAvailable=l.orientation.data.beta&&null!==l.orientation.data.beta,e._gammaAvailable=l.orientation.data.gamma&&null!==l.orientation.data.gamma,b(e)})["catch"](function(){e.stop(),d("DeviceOrientation is not supported")})});return b},t.getDeviceMotion=function(a){var b=new Promise(function(b,d){var e=new t.DeviceMotion(a);e.start();var f=new c(l.motion);f.then(function(){e._accelerationXAvailable=l.motion.data.acceleration&&l.motion.data.acceleration.x,e._accelerationYAvailable=l.motion.data.acceleration&&l.motion.data.acceleration.y,e._accelerationZAvailable=l.motion.data.acceleration&&l.motion.data.acceleration.z,e._accelerationIncludingGravityXAvailable=l.motion.data.accelerationIncludingGravity&&l.motion.data.accelerationIncludingGravity.x,e._accelerationIncludingGravityYAvailable=l.motion.data.accelerationIncludingGravity&&l.motion.data.accelerationIncludingGravity.y,e._accelerationIncludingGravityZAvailable=l.motion.data.accelerationIncludingGravity&&l.motion.data.accelerationIncludingGravity.z,e._rotationRateAlphaAvailable=l.motion.data.rotationRate&&l.motion.data.rotationRate.alpha,e._rotationRateBetaAvailable=l.motion.data.rotationRate&&l.motion.data.rotationRate.beta,e._rotationRateGammaAvailable=l.motion.data.rotationRate&&l.motion.data.rotationRate.gamma,b(e)})["catch"](function(){e.stop(),d("DeviceMotion is not supported")})});return b},t.Quaternion=function(a,c,d,e){var f;this.set=function(a,b,c,d){this.x=a||0,this.y=b||0,this.z=c||0,this.w=d||1},this.copy=function(a){this.x=a.x,this.y=a.y,this.z=a.z,this.w=a.w},this.setFromEuler=function(){var a,b,c,d,e,f,g,h,i,k,l,m;return function(n){return n=n||{},c=(n.alpha||0)*j,a=(n.beta||0)*j,b=(n.gamma||0)*j,f=c/2,d=a/2,e=b/2,g=Math.cos(d),h=Math.cos(e),i=Math.cos(f),k=Math.sin(d),l=Math.sin(e),m=Math.sin(f),this.set(k*h*i-g*l*m,g*l*i+k*h*m,g*h*m+k*l*i,g*h*i-k*l*m),this.normalize(),this}}(),this.setFromRotationMatrix=function(){var a;return function(c){return a=c.elements,this.set(.5*Math.sqrt(1+a[0]-a[4]-a[8])*b(a[7]-a[5]),.5*Math.sqrt(1-a[0]+a[4]-a[8])*b(a[2]-a[6]),.5*Math.sqrt(1-a[0]-a[4]+a[8])*b(a[3]-a[1]),.5*Math.sqrt(1+a[0]+a[4]+a[8])),this}}(),this.multiply=function(a){return f=t.Quaternion.prototype.multiplyQuaternions(this,a),this.copy(f),this},this.rotateX=function(a){return f=t.Quaternion.prototype.rotateByAxisAngle(this,[1,0,0],a),this.copy(f),this},this.rotateY=function(a){return f=t.Quaternion.prototype.rotateByAxisAngle(this,[0,1,0],a),this.copy(f),this},this.rotateZ=function(a){return f=t.Quaternion.prototype.rotateByAxisAngle(this,[0,0,1],a),this.copy(f),this},this.normalize=function(){return t.Quaternion.prototype.normalize(this)},this.set(a,c,d,e)},t.Quaternion.prototype={constructor:t.Quaternion,multiplyQuaternions:function(){var a=new t.Quaternion;return function(b,c){var d=b.x,e=b.y,f=b.z,g=b.w,h=c.x,i=c.y,j=c.z,k=c.w;return a.set(d*k+g*h+e*j-f*i,e*k+g*i+f*h-d*j,f*k+g*j+d*i-e*h,g*k-d*h-e*i-f*j),a}}(),normalize:function(a){var b=Math.sqrt(a.x*a.x+a.y*a.y+a.z*a.z+a.w*a.w);return 0===b?(a.x=0,a.y=0,a.z=0,a.w=1):(b=1/b,a.x*=b,a.y*=b,a.z*=b,a.w*=b),a},rotateByAxisAngle:function(){var a,b,c=new t.Quaternion,d=new t.Quaternion;return function(e,f,g){return a=(g||0)/2,b=Math.sin(a),d.set((f[0]||0)*b,(f[1]||0)*b,(f[2]||0)*b,Math.cos(a)),c=t.Quaternion.prototype.multiplyQuaternions(e,d),t.Quaternion.prototype.normalize(c)}}()},t.RotationMatrix=function(a,b,c,d,e,f,g,h,i){var k;this.elements=new Float32Array(9),this.identity=function(){return this.set(1,0,0,0,1,0,0,0,1),this},this.set=function(a,b,c,d,e,f,g,h,i){this.elements[0]=a||1,this.elements[1]=b||0,this.elements[2]=c||0,this.elements[3]=d||0,this.elements[4]=e||1,this.elements[5]=f||0,this.elements[6]=g||0,this.elements[7]=h||0,this.elements[8]=i||1},this.copy=function(a){this.elements[0]=a.elements[0],this.elements[1]=a.elements[1],this.elements[2]=a.elements[2],this.elements[3]=a.elements[3],this.elements[4]=a.elements[4],this.elements[5]=a.elements[5],this.elements[6]=a.elements[6],this.elements[7]=a.elements[7],this.elements[8]=a.elements[8]},this.setFromEuler=function(){var a,b,c,d,e,f,g,h,i;return function(k){return k=k||{},c=(k.alpha||0)*j,a=(k.beta||0)*j,b=(k.gamma||0)*j,d=Math.cos(a),e=Math.cos(b),f=Math.cos(c),g=Math.sin(a),h=Math.sin(b),i=Math.sin(c),this.set(f*e-i*g*h,-d*i,e*i*g+f*h,e*i+f*g*h,f*d,i*h-f*e*g,-d*h,g,d*e),this.normalize(),this}}(),this.setFromQuaternion=function(){var a,b,c,d;return function(e){return a=e.w*e.w,b=e.x*e.x,c=e.y*e.y,d=e.z*e.z,this.set(a+b-c-d,2*(e.x*e.y-e.w*e.z),2*(e.x*e.z+e.w*e.y),2*(e.x*e.y+e.w*e.z),a-b+c-d,2*(e.y*e.z-e.w*e.x),2*(e.x*e.z-e.w*e.y),2*(e.y*e.z+e.w*e.x),a-b-c+d),this}}(),this.multiply=function(a){return k=t.RotationMatrix.prototype.multiplyMatrices(this,a),this.copy(k),this},this.rotateX=function(a){return k=t.RotationMatrix.prototype.rotateByAxisAngle(this,[1,0,0],a),this.copy(k),this},this.rotateY=function(a){return k=t.RotationMatrix.prototype.rotateByAxisAngle(this,[0,1,0],a),this.copy(k),this},this.rotateZ=function(a){return k=t.RotationMatrix.prototype.rotateByAxisAngle(this,[0,0,1],a),this.copy(k),this},this.normalize=function(){return t.RotationMatrix.prototype.normalize(this)},this.set(a,b,c,d,e,f,g,h,i)},t.RotationMatrix.prototype={constructor:t.RotationMatrix,multiplyMatrices:function(){var a,b,c=new t.RotationMatrix;return function(d,e){return a=d.elements,b=e.elements,c.set(a[0]*b[0]+a[1]*b[3]+a[2]*b[6],a[0]*b[1]+a[1]*b[4]+a[2]*b[7],a[0]*b[2]+a[1]*b[5]+a[2]*b[8],a[3]*b[0]+a[4]*b[3]+a[5]*b[6],a[3]*b[1]+a[4]*b[4]+a[5]*b[7],a[3]*b[2]+a[4]*b[5]+a[5]*b[8],a[6]*b[0]+a[7]*b[3]+a[8]*b[6],a[6]*b[1]+a[7]*b[4]+a[8]*b[7],a[6]*b[2]+a[7]*b[5]+a[8]*b[8]),c}}(),normalize:function(a){var b=a.elements,c=b[0]*b[4]*b[8]-b[0]*b[5]*b[7]-b[1]*b[3]*b[8]+b[1]*b[5]*b[6]+b[2]*b[3]*b[7]-b[2]*b[4]*b[6];return b[0]/=c,b[1]/=c,b[2]/=c,b[3]/=c,b[4]/=c,b[5]/=c,b[6]/=c,b[7]/=c,b[8]/=c,a.elements=b,a},rotateByAxisAngle:function(){var a,b,c=new t.RotationMatrix,d=new t.RotationMatrix,e=!1;return function(f,g,h){return d.identity(),e=!1,a=Math.sin(h),b=Math.cos(h),1===g[0]&&0===g[1]&&0===g[2]?(e=!0,d.elements[4]=b,d.elements[5]=-a,d.elements[7]=a,d.elements[8]=b):1===g[1]&&0===g[0]&&0===g[2]?(e=!0,d.elements[0]=b,d.elements[2]=a,d.elements[6]=-a,d.elements[8]=b):1===g[2]&&0===g[0]&&0===g[1]&&(e=!0,d.elements[0]=b,d.elements[1]=-a,d.elements[3]=a,d.elements[4]=b),e?(c=t.RotationMatrix.prototype.multiplyMatrices(f,d),c=t.RotationMatrix.prototype.normalize(c)):c=f,c}}()},t.Euler=function(a,b,c){this.set=function(a,b,c){this.alpha=a||0,this.beta=b||0,this.gamma=c||0},this.copy=function(a){this.alpha=a.alpha,this.beta=a.beta,this.gamma=a.gamma},this.setFromRotationMatrix=function(){var a,b,c,d;return function(e){a=e.elements,a[8]>0?(b=Math.atan2(-a[1],a[4]),c=Math.asin(a[7]),d=Math.atan2(-a[6],a[8])):a[8]<0?(b=Math.atan2(a[1],-a[4]),c=-Math.asin(a[7]),c+=c>=0?-g:g,d=Math.atan2(a[6],-a[8])):a[6]>0?(b=Math.atan2(-a[1],a[4]),c=Math.asin(a[7]),d=-h):a[6]<0?(b=Math.atan2(a[1],-a[4]),c=-Math.asin(a[7]),c+=c>=0?-g:g,d=-h):(b=Math.atan2(a[3],a[0]),c=a[7]>0?h:-h,d=0),0>b&&(b+=i),b*=k,c*=k,d*=k,this.set(b,c,d)}}(),this.setFromQuaternion=function(){var a,b,c;return function(d){var e=d.w*d.w,f=d.x*d.x,j=d.y*d.y,l=d.z*d.z,m=e+f+j+l,n=d.w*d.x+d.y*d.z,o=1e-6;if(n>(.5-o)*m)a=2*Math.atan2(d.y,d.w),b=h,c=0;else if((-.5+o)*m>n)a=-2*Math.atan2(d.y,d.w),b=-h,c=0;else{var p=e-f+j-l,q=2*(d.w*d.z-d.x*d.y),r=e-f-j+l,s=2*(d.w*d.y-d.x*d.z);r>0?(a=Math.atan2(q,p),b=Math.asin(2*n/m),c=Math.atan2(s,r)):(a=Math.atan2(-q,-p),b=-Math.asin(2*n/m),b+=0>b?g:-g,c=Math.atan2(-s,-r))}0>a&&(a+=i),a*=k,b*=k,c*=k,this.set(a,b,c)}}(),this.rotateX=function(a){return t.Euler.prototype.rotateByAxisAngle(this,[1,0,0],a),this},this.rotateY=function(a){return t.Euler.prototype.rotateByAxisAngle(this,[0,1,0],a),this},this.rotateZ=function(a){return t.Euler.prototype.rotateByAxisAngle(this,[0,0,1],a),this},this.set(a,b,c)},t.Euler.prototype={constructor:t.Euler,rotateByAxisAngle:function(){var a=new t.RotationMatrix;return function(b,c,d){return a.setFromEuler(b),a=t.RotationMatrix.prototype.rotateByAxisAngle(a,c,d),b.setFromRotationMatrix(a),b}}()},t.DeviceOrientation=function(b){this.options=b||{};var c=0,d=200,e=0,f=10;if(this.alphaOffsetScreen=0,this.alphaOffsetDevice=void 0,"game"===this.options.type){var g=function(b){return null!==b.alpha&&(this.alphaOffsetDevice=new t.Euler(b.alpha,0,0),this.alphaOffsetDevice.rotateZ(-o),++e>=f)?void a.removeEventListener("deviceorientation",g,!1):void(++c>=d&&a.removeEventListener("deviceorientation",g,!1))}.bind(this);a.addEventListener("deviceorientation",g,!1)}else if("world"===this.options.type){var h=function(b){return b.absolute!==!0&&void 0!==b.webkitCompassAccuracy&&null!==b.webkitCompassAccuracy&&+b.webkitCompassAccuracy>=0&&+b.webkitCompassAccuracy<50&&(this.alphaOffsetDevice=new t.Euler(b.webkitCompassHeading,0,0),this.alphaOffsetDevice.rotateZ(o),this.alphaOffsetScreen=o,++e>=f)?void a.removeEventListener("deviceorientation",h,!1):void(++c>=d&&a.removeEventListener("deviceorientation",h,!1))}.bind(this);a.addEventListener("deviceorientation",h,!1)}},t.DeviceOrientation.prototype={constructor:t.DeviceOrientation,start:function(b){b&&"[object Function]"==Object.prototype.toString.call(b)&&l.orientation.callbacks.push(b),m||(n?a.screen.orientation.addEventListener("change",d,!1):a.addEventListener("orientationchange",d,!1)),l.orientation.active||(a.addEventListener("deviceorientation",e,!1),l.orientation.active=!0)},stop:function(){l.orientation.active&&(a.removeEventListener("deviceorientation",e,!1),l.orientation.active=!1)},listen:function(a){this.start(a)},getFixedFrameQuaternion:function(){var a=new t.Euler,b=new t.RotationMatrix,c=new t.Quaternion;return function(){var d=l.orientation.data||{alpha:0,beta:0,gamma:0},e=d.alpha;return this.alphaOffsetDevice&&(b.setFromEuler(this.alphaOffsetDevice),b.rotateZ(-this.alphaOffsetScreen),a.setFromRotationMatrix(b),a.alpha<0&&(a.alpha+=360),a.alpha%=360,e-=a.alpha),a.set(e,d.beta,d.gamma),c.setFromEuler(a),c}}(),getScreenAdjustedQuaternion:function(){var a;return function(){return a=this.getFixedFrameQuaternion(),a.rotateZ(-o),a}}(),getFixedFrameMatrix:function(){var a=new t.Euler,b=new t.RotationMatrix;return function(){var c=l.orientation.data||{alpha:0,beta:0,gamma:0},d=c.alpha;return this.alphaOffsetDevice&&(b.setFromEuler(this.alphaOffsetDevice),b.rotateZ(-this.alphaOffsetScreen),a.setFromRotationMatrix(b),a.alpha<0&&(a.alpha+=360),a.alpha%=360,d-=a.alpha),a.set(d,c.beta,c.gamma),b.setFromEuler(a),b}}(),getScreenAdjustedMatrix:function(){var a;return function(){return a=this.getFixedFrameMatrix(),a.rotateZ(-o),a}}(),getFixedFrameEuler:function(){var a,b=new t.Euler;return function(){return a=this.getFixedFrameMatrix(),b.setFromRotationMatrix(a),b}}(),getScreenAdjustedEuler:function(){var a,b=new t.Euler;return function(){return a=this.getScreenAdjustedMatrix(),b.setFromRotationMatrix(a),b}}(),isAbsolute:function(){return l.orientation.data&&l.orientation.data.absolute===!0?!0:!1},getLastRawEventData:function(){return l.orientation.data||{}},_alphaAvailable:!1,_betaAvailable:!1,_gammaAvailable:!1,isAvailable:function(a){switch(a){case this.ALPHA:return this._alphaAvailable;case this.BETA:return this._betaAvailable;case this.GAMMA:return this._gammaAvailable}},ALPHA:"alpha",BETA:"beta",GAMMA:"gamma"},t.DeviceMotion=function(a){this.options=a||{}},t.DeviceMotion.prototype={constructor:t.DeviceMotion,start:function(b){b&&"[object Function]"==Object.prototype.toString.call(b)&&l.motion.callbacks.push(b),m||(n?a.screen.orientation.addEventListener("change",d,!1):a.addEventListener("orientationchange",d,!1)),l.motion.active||(a.addEventListener("devicemotion",f,!1),l.motion.active=!0)},stop:function(){l.motion.active&&(a.removeEventListener("devicemotion",f,!1),l.motion.active=!1)},listen:function(a){this.start(a)},getScreenAdjustedAcceleration:function(){var a=l.motion.data&&l.motion.data.acceleration?l.motion.data.acceleration:{x:0,y:0,z:0},b={};switch(o){case p:b.x=-a.y,b.y=a.x;break;case q:b.x=-a.x,b.y=-a.y;break;case r:case s:b.x=a.y,b.y=-a.x;break;default:b.x=a.x,b.y=a.y}return b.z=a.z,b},getScreenAdjustedAccelerationIncludingGravity:function(){var a=l.motion.data&&l.motion.data.accelerationIncludingGravity?l.motion.data.accelerationIncludingGravity:{x:0,y:0,z:0},b={};switch(o){case p:b.x=-a.y,b.y=a.x;break;case q:b.x=-a.x,b.y=-a.y;break;case r:case s:b.x=a.y,b.y=-a.x;break;default:b.x=a.x,b.y=a.y}return b.z=a.z,b},getScreenAdjustedRotationRate:function(){var a=l.motion.data&&l.motion.data.rotationRate?l.motion.data.rotationRate:{alpha:0,beta:0,gamma:0},b={};switch(o){case p:b.beta=-a.gamma,b.gamma=a.beta;break;case q:b.beta=-a.beta,b.gamma=-a.gamma;break;case r:case s:b.beta=a.gamma,b.gamma=-a.beta;break;default:b.beta=a.beta,b.gamma=a.gamma}return b.alpha=a.alpha,b},getLastRawEventData:function(){return l.motion.data||{}},_accelerationXAvailable:!1,_accelerationYAvailable:!1,_accelerationZAvailable:!1,_accelerationIncludingGravityXAvailable:!1,_accelerationIncludingGravityYAvailable:!1,_accelerationIncludingGravityZAvailable:!1,_rotationRateAlphaAvailable:!1,_rotationRateBetaAvailable:!1,_rotationRateGammaAvailable:!1,isAvailable:function(a){switch(a){case this.ACCELERATION_X:return this._accelerationXAvailable;case this.ACCELERATION_Y:return this._accelerationYAvailable;case this.ACCELERATION_Z:return this._accelerationZAvailable;case this.ACCELERATION_INCLUDING_GRAVITY_X:return this._accelerationIncludingGravityXAvailable;case this.ACCELERATION_INCLUDING_GRAVITY_Y:return this._accelerationIncludingGravityYAvailable;case this.ACCELERATION_INCLUDING_GRAVITY_Z:return this._accelerationIncludingGravityZAvailable;case this.ROTATION_RATE_ALPHA:return this._rotationRateAlphaAvailable;case this.ROTATION_RATE_BETA:return this._rotationRateBetaAvailable;case this.ROTATION_RATE_GAMMA:return this._rotationRateGammaAvailable}},ACCELERATION_X:"accelerationX",ACCELERATION_Y:"accelerationY",ACCELERATION_Z:"accelerationZ",ACCELERATION_INCLUDING_GRAVITY_X:"accelerationIncludingGravityX",ACCELERATION_INCLUDING_GRAVITY_Y:"accelerationIncludingGravityY",ACCELERATION_INCLUDING_GRAVITY_Z:"accelerationIncludingGravityZ",ROTATION_RATE_ALPHA:"rotationRateAlpha",ROTATION_RATE_BETA:"rotationRateBeta",ROTATION_RATE_GAMMA:"rotationRateGamma"},a.FULLTILT=t}}(window); 3 | -------------------------------------------------------------------------------- /emulator/js/libs/jquery-1.10.2.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license 2 | //@ sourceMappingURL=jquery-1.10.2.min.map 3 | */ 4 | (function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="
    ",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?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)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.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+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,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(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===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]||at.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]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===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===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},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,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.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"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},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"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
    a",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="
    t
    ",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="
    ",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t 5 | }({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/\s*$/g,At={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:x.support.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(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){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?""!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle); 6 | u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("