Explorar o código

添加单兵设备

wenhongquan %!s(int64=3) %!d(string=hai) anos
pai
achega
ec71a057c0
Modificáronse 66 ficheiros con 14615 adicións e 480 borrados
  1. 1 0
      public/imouplayer.js
  2. 6 0
      public/imouplayer.js.LICENSE.txt
  3. 19 19
      public/index.html
  4. 0 0
      public/module/PlayerControl.js
  5. 0 0
      public/module/audioTalkWorker.worker.js
  6. 0 0
      public/module/audioWorker.worker.js
  7. 0 0
      public/module/ffmpegasm.js
  8. BIN=BIN
      public/module/ffmpegasm.js.mem
  9. 0 0
      public/module/videoWorker.worker.js
  10. 0 0
      public/module/videoWorkerTrain.worker.js
  11. 1 0
      public/static/Decode/MjpegDecoder.js
  12. 1 0
      public/static/Decode/audioDecoderG711.js
  13. 0 0
      public/static/Decode/audioDecoderG726x.js
  14. 1 0
      public/static/Decode/h264Decoder.js
  15. 1 0
      public/static/Decode/h265Decoder.js
  16. 0 0
      public/static/Decode/jsFFMPEG.js
  17. 0 0
      public/static/Sylvester.js
  18. 0 0
      public/static/WebGLCanvas.js
  19. 41 0
      public/static/WebsocketServer.js
  20. 1 0
      public/static/aacSession.js
  21. 3480 0
      public/static/adapter.js
  22. 0 0
      public/static/audioPlayer.js
  23. 1 0
      public/static/audioWorker.js
  24. 2039 0
      public/static/bootstrap-datepicker.js
  25. 1 0
      public/static/bootstrap-datepicker.zh-CN.min.js
  26. 1535 0
      public/static/datepicker.js
  27. 19 0
      public/static/datepicker.zh-CN.js
  28. 1 0
      public/static/g711Session.js
  29. 1 0
      public/static/g726Session.js
  30. 0 0
      public/static/h264Session.js
  31. 0 0
      public/static/h265Session.js
  32. 1 0
      public/static/hashMap.js
  33. BIN=BIN
      public/static/images/exitFullScreen.png
  34. BIN=BIN
      public/static/images/fullScreen.png
  35. BIN=BIN
      public/static/images/hd.png
  36. BIN=BIN
      public/static/images/pause.png
  37. BIN=BIN
      public/static/images/play.png
  38. BIN=BIN
      public/static/images/sd.png
  39. BIN=BIN
      public/static/images/soundOff.png
  40. BIN=BIN
      public/static/images/soundOn.png
  41. BIN=BIN
      public/static/images/split_1.png
  42. BIN=BIN
      public/static/images/split_16.png
  43. BIN=BIN
      public/static/images/split_4.png
  44. BIN=BIN
      public/static/images/split_9.png
  45. 0 0
      public/static/ivs.js
  46. 0 0
      public/static/ivsSession.js
  47. 4178 0
      public/static/jquery-min.js
  48. 506 0
      public/static/jquery.i18n.properties.js
  49. 0 0
      public/static/md5.js
  50. 89 0
      public/static/message.js
  51. 0 0
      public/static/mjpegSession.js
  52. 0 0
      public/static/mp4remux.js
  53. 58 0
      public/static/playerControl.js
  54. 0 0
      public/static/public.js
  55. 18 0
      public/static/service.js
  56. 0 0
      public/static/streamDrawer.js
  57. 11 0
      public/static/video.min.js
  58. 0 0
      public/static/videoMediaSource.js
  59. 0 0
      public/static/videoWorker.js
  60. 0 0
      public/static/videojs-contrib-hls.min.js
  61. 1455 0
      public/static/videojs-flash.js
  62. 369 0
      public/static/workerManager.js
  63. 267 0
      public/webLive.html
  64. 96 94
      src/api/qdtl/data.js
  65. 342 291
      src/views/qdtl/video/video.vue
  66. 76 76
      vue.config.js

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
public/imouplayer.js


+ 6 - 0
public/imouplayer.js.LICENSE.txt

@@ -0,0 +1,6 @@
+/*!
+ * Platform.js v1.3.6
+ * Copyright 2014-2020 Benjamin Tan
+ * Copyright 2011-2013 John-David Dalton
+ * Available under MIT license
+ */

+ 19 - 19
public/index.html

@@ -20,14 +20,14 @@
             padding: 0px;
             font-size: 10px;
         }
-
+        
         .chromeframe {
             margin: 0.2em 0;
             background: #ccc;
             color: #000;
             padding: 0.2em 0;
         }
-
+        
         #loader-wrapper {
             position: fixed;
             top: 0;
@@ -36,7 +36,7 @@
             height: 100%;
             z-index: 999999;
         }
-
+        
         #loader {
             display: block;
             position: relative;
@@ -55,7 +55,7 @@
             animation: spin 2s linear infinite;
             z-index: 1001;
         }
-
+        
         #loader:before {
             content: "";
             position: absolute;
@@ -72,7 +72,7 @@
             -ms-animation: spin 3s linear infinite;
             animation: spin 3s linear infinite;
         }
-
+        
         #loader:after {
             content: "";
             position: absolute;
@@ -89,7 +89,7 @@
             -webkit-animation: spin 1.5s linear infinite;
             animation: spin 1.5s linear infinite;
         }
-
+        
         @-webkit-keyframes spin {
             0% {
                 -webkit-transform: rotate(0deg);
@@ -102,7 +102,7 @@
                 transform: rotate(360deg);
             }
         }
-
+        
         @keyframes spin {
             0% {
                 -webkit-transform: rotate(0deg);
@@ -115,7 +115,7 @@
                 transform: rotate(360deg);
             }
         }
-
+        
         #loader-wrapper .loader-section {
             position: fixed;
             top: 0;
@@ -127,15 +127,15 @@
             -ms-transform: translateX(0);
             transform: translateX(0);
         }
-
+        
         #loader-wrapper .loader-section.section-left {
             left: 0;
         }
-
+        
         #loader-wrapper .loader-section.section-right {
             right: 0;
         }
-
+        
         .loaded #loader-wrapper .loader-section.section-left {
             -webkit-transform: translateX(-100%);
             -ms-transform: translateX(-100%);
@@ -143,7 +143,7 @@
             -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
             transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
         }
-
+        
         .loaded #loader-wrapper .loader-section.section-right {
             -webkit-transform: translateX(100%);
             -ms-transform: translateX(100%);
@@ -151,13 +151,13 @@
             -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
             transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
         }
-
+        
         .loaded #loader {
             opacity: 0;
             -webkit-transition: all 0.3s ease-out;
             transition: all 0.3s ease-out;
         }
-
+        
         .loaded #loader-wrapper {
             visibility: hidden;
             -webkit-transform: translateY(-100%);
@@ -166,15 +166,15 @@
             -webkit-transition: all 0.3s 1s ease-out;
             transition: all 0.3s 1s ease-out;
         }
-
+        
         .no-js #loader-wrapper {
             display: none;
         }
-
+        
         .no-js h1 {
             color: #222222;
         }
-
+        
         #loader-wrapper .load_title {
             font-family: 'Open Sans';
             color: #FFF;
@@ -187,7 +187,7 @@
             opacity: 1;
             line-height: 30px;
         }
-
+        
         #loader-wrapper .load_title span {
             font-weight: normal;
             font-style: italic;
@@ -535,4 +535,4 @@
     </div>
 </body>
 
-</html>
+</html>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/module/PlayerControl.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/module/audioTalkWorker.worker.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/module/audioWorker.worker.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/module/ffmpegasm.js


BIN=BIN
public/module/ffmpegasm.js.mem


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/module/videoWorker.worker.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/module/videoWorkerTrain.worker.js


+ 1 - 0
public/static/Decode/MjpegDecoder.js

@@ -0,0 +1 @@
+function MJPEGDecoder(){function a(){debug.log("MJPEG Decoder")}var b,c;return a.prototype={setIsFirstFrame:function(a){isFirstIFrame=a},isFirstFrame:function(){return isFirstIFrame},setResolution:function(a,d){b=a,c=d},decode:function(d){if(!a.prototype.isFirstFrame()){a.prototype.setIsFirstFrame(!0);var e={firstFrame:!0};return e}return{data:d,width:b,height:c,codecType:"mjpeg"}}},new a}

+ 1 - 0
public/static/Decode/audioDecoderG711.js

@@ -0,0 +1 @@
+"use strict";function G711AudioDecoder(a){function b(a){var b=0,c=~a;return b=((c&g)<<3)+e,b<<=(c&i)>>h,c&f?e-b:b-e}function c(a){var b=0,c=0;switch(a^=85,b=(a&g)<<4,c=(a&i)>>h){case 0:b+=8;break;case 1:b+=264;break;default:b+=264,b<<=c-1}return a&f?b:-b}function d(){}var e=132,f=128,g=15,h=4,i=112;return d.prototype={decode:function(d){var e=new Uint8Array(d),f=new Int16Array(e.length),g=0;if("G.711A"==a)for(g=0;g<e.length;g++)f[g]=c(e[g]);else if("G.711Mu"==a)for(g=0;g<e.length;g++)f[g]=b(e[g]);var h=new Float32Array(f.length);for(g=0;g<f.length;g++)h[g]=f[g]/Math.pow(2,15);return h}},new d}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/Decode/audioDecoderG726x.js


+ 1 - 0
public/static/Decode/h264Decoder.js

@@ -0,0 +1 @@
+"use strict";function H264Decoder(){function a(){debug.log("Construct H264 Codec"),b=Module.cwrap("init_jsFFmpeg","void",[]),c=Module.cwrap("context_jsFFmpeg","number",["number"]),d=Module.cwrap("decode_video_jsFFmpeg","number",["number","array","number","number"]),e=Module.cwrap("get_width","number",["number"]),f=Module.cwrap("get_height","number",["number"]),g=Module.cwrap("close_jsFFmpeg","number",["number"]),b(),a.prototype.init(),a.prototype.setIsFirstFrame(!1)}var b=null,c=null,d=null,e=null,f=null,g=null,h=null,i=null,j=264,k=!1;return a.prototype={init:function(){debug.log("H264 Decoder init"),null!==h&&(g(h),h=null),h=c(j)},setOutputSize:function(a){var b=1.5*a,c=Module._malloc(b);i=new Uint8Array(Module.HEAPU8.buffer,c,b)},decode:function(b){var c=null,g=null,j=null,k=null,l=103==b[4]?"I":"P";c=Date.now(),d(h,b,b.length,i.byteOffset),g=Date.now()-c;var m=e(h),n=f(h);if(!a.prototype.isFirstFrame())return a.prototype.setIsFirstFrame(!0),j={firstFrame:!0};if(m>0&&n>0){var o=new Uint8Array(i);return j={data:o,bufferIdx:k,width:m,height:n,codecType:"h264",decodingTime:g,frameType:l}}},setIsFirstFrame:function(a){k=a},isFirstFrame:function(){return k}},new a}

+ 1 - 0
public/static/Decode/h265Decoder.js

@@ -0,0 +1 @@
+"use strict";function H265Decoder(){function a(){debug.log("Construct H265 Codec"),b=Module.cwrap("init_jsFFmpeg","void",[]),c=Module.cwrap("context_jsFFmpeg","number",["number"]),d=Module.cwrap("decode_video_jsFFmpeg","number",["number","array","number","number"]),e=Module.cwrap("get_width","number",["number"]),f=Module.cwrap("get_height","number",["number"]),g=Module.cwrap("close_jsFFmpeg","number",["number"]),b(),a.prototype.init(),a.prototype.setIsFirstFrame(!1)}var b=null,c=null,d=null,e=null,f=null,g=null,h=null,i=new Uint8Array,j=265,k=!1;return a.prototype={init:function(){debug.log("H265 Decoder init"),g(h),h=c(j)},setOutputSize:function(a){var b=1.5*a,c=Module._malloc(b);i=new Uint8Array(Module.HEAPU8.buffer,c,b)},decode:function(b,c){var g=null,j=null,k=null,l=c;g=Date.now(),d(h,b,b.length,i.byteOffset),j=Date.now()-g;var m=e(h),n=f(h);if(!a.prototype.isFirstFrame())return a.prototype.setIsFirstFrame(!0),{firstFrame:!0};if(m>0&&n>0){var o=new Uint8Array(i);return k={data:o,width:m,height:n,codecType:"h265",decodingTime:j,frameType:l}}},setIsFirstFrame:function(a){k=a},isFirstFrame:function(){return k}},new a}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/Decode/jsFFMPEG.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/Sylvester.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/WebGLCanvas.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 41 - 0
public/static/WebsocketServer.js


+ 1 - 0
public/static/aacSession.js

@@ -0,0 +1 @@
+"use strict";var AACSession=function(){function a(a,b){var c=1,e=null,f=null;if("string"!=typeof d)return void debug.log("wrong type of config in SDP");e=parseInt(d.substring(0,2),16),f=parseInt(d.substring(2,4),16);var g=e>>3,h=(7&e)<<1|(128&f)>>7;i[0]=255,i[1]=249,i[2]=g-1<<6,i[2]|=h<<2,i[2]|=c>>2,i[3]=c<<6,i[3]|=(a+7&6144)>>11,i[4]=(a+7&2040)>>3,i[5]=(a+7&7)<<5,i[5]|=1,i[6]=84;var j=new Uint8Array(i.length+b.length);return j.set(i,0),j.set(b,i.length),j}function b(){this.firstTime=0,this.lastMSW=0}var c=7,d=null,e=null,f=null,g=null,h=0,i=new Uint8Array(c),j={seconds:null,useconds:null};return b.prototype={parseRTPData:function(b,c,d){var e=c[22];g=(c[21]<<8)+c[20];var f=c.length-8-(24+e),i=c.subarray(24+e,c.length-8),k=i.subarray(0,2),l={},m=(c[19]<<24)+(c[18]<<16)+(c[17]<<8)+c[16]>>>0,n=Date.UTC("20"+(m>>26),(m>>22&15)-1,m>>17&31,m>>12&31,m>>6&63,63&m)/1e3;if(n-=28800,0==this.firstTime)this.firstTime=n,this.lastMSW=0,h=(c[21]<<8)+c[20],j.seconds=n,j.useconds=0;else{var o,p=(c[21]<<8)+c[20];o=p>h?p-h:p+65535-h,this.lastMSW+=o,n>this.firstTime&&(this.lastMSW-=1e3),this.firstTime=n,j.seconds=n,j.useconds=this.lastMSW,h=p}if(255===k[0]&&240===(240&k[1]))l={codec:"AAC",bufferData:i,rtpTimeStamp:1e3*j.seconds+j.useconds},d===!0&&(l.streamData=i.subarray(7,i.length));else{var q=a(f,i);l={codec:"AAC",bufferData:q,rtpTimeStamp:1e3*j.seconds+j.useconds},d===!0&&(l.streamData=i)}return l},setCodecInfo:function(a){debug.log("Set codec info. for AAC"),d=a.config,f=a.bitrate,e=a.clockFreq},getCodecInfo:function(){return{bitrate:f,clockFreq:e}}},new b};

+ 3480 - 0
public/static/adapter.js

@@ -0,0 +1,3480 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    
+    'use strict';
+    
+    var _adapter_factory = require('./adapter_factory.js');
+    
+    var adapter = (0, _adapter_factory.adapterFactory)({ window: typeof window === 'undefined' ? undefined : window });
+    module.exports = adapter; // this is the difference from adapter_core.
+    
+    },{"./adapter_factory.js":2}],2:[function(require,module,exports){
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    exports.adapterFactory = adapterFactory;
+    
+    var _utils = require('./utils');
+    
+    var utils = _interopRequireWildcard(_utils);
+    
+    var _chrome_shim = require('./chrome/chrome_shim');
+    
+    var chromeShim = _interopRequireWildcard(_chrome_shim);
+    
+    var _firefox_shim = require('./firefox/firefox_shim');
+    
+    var firefoxShim = _interopRequireWildcard(_firefox_shim);
+    
+    var _safari_shim = require('./safari/safari_shim');
+    
+    var safariShim = _interopRequireWildcard(_safari_shim);
+    
+    var _common_shim = require('./common_shim');
+    
+    var commonShim = _interopRequireWildcard(_common_shim);
+    
+    var _sdp = require('sdp');
+    
+    var sdp = _interopRequireWildcard(_sdp);
+    
+    function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+    
+    // Shimming starts here.
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    function adapterFactory() {
+      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
+          window = _ref.window;
+    
+      var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
+        shimChrome: true,
+        shimFirefox: true,
+        shimSafari: true
+      };
+    
+      // Utils.
+      var logging = utils.log;
+      var browserDetails = utils.detectBrowser(window);
+    
+      var adapter = {
+        browserDetails: browserDetails,
+        commonShim: commonShim,
+        extractVersion: utils.extractVersion,
+        disableLog: utils.disableLog,
+        disableWarnings: utils.disableWarnings,
+        // Expose sdp as a convenience. For production apps include directly.
+        sdp: sdp
+      };
+    
+      // Shim browser if found.
+      switch (browserDetails.browser) {
+        case 'chrome':
+          if (!chromeShim || !chromeShim.shimPeerConnection || !options.shimChrome) {
+            logging('Chrome shim is not included in this adapter release.');
+            return adapter;
+          }
+          if (browserDetails.version === null) {
+            logging('Chrome shim can not determine version, not shimming.');
+            return adapter;
+          }
+          logging('adapter.js shimming chrome.');
+          // Export to the adapter global object visible in the browser.
+          adapter.browserShim = chromeShim;
+    
+          // Must be called before shimPeerConnection.
+          commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
+          commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
+    
+          chromeShim.shimGetUserMedia(window, browserDetails);
+          chromeShim.shimMediaStream(window, browserDetails);
+          chromeShim.shimPeerConnection(window, browserDetails);
+          chromeShim.shimOnTrack(window, browserDetails);
+          chromeShim.shimAddTrackRemoveTrack(window, browserDetails);
+          chromeShim.shimGetSendersWithDtmf(window, browserDetails);
+          chromeShim.shimGetStats(window, browserDetails);
+          chromeShim.shimSenderReceiverGetStats(window, browserDetails);
+          chromeShim.fixNegotiationNeeded(window, browserDetails);
+    
+          commonShim.shimRTCIceCandidate(window, browserDetails);
+          commonShim.shimConnectionState(window, browserDetails);
+          commonShim.shimMaxMessageSize(window, browserDetails);
+          commonShim.shimSendThrowTypeError(window, browserDetails);
+          commonShim.removeExtmapAllowMixed(window, browserDetails);
+          break;
+        case 'firefox':
+          if (!firefoxShim || !firefoxShim.shimPeerConnection || !options.shimFirefox) {
+            logging('Firefox shim is not included in this adapter release.');
+            return adapter;
+          }
+          logging('adapter.js shimming firefox.');
+          // Export to the adapter global object visible in the browser.
+          adapter.browserShim = firefoxShim;
+    
+          // Must be called before shimPeerConnection.
+          commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
+          commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
+    
+          firefoxShim.shimGetUserMedia(window, browserDetails);
+          firefoxShim.shimPeerConnection(window, browserDetails);
+          firefoxShim.shimOnTrack(window, browserDetails);
+          firefoxShim.shimRemoveStream(window, browserDetails);
+          firefoxShim.shimSenderGetStats(window, browserDetails);
+          firefoxShim.shimReceiverGetStats(window, browserDetails);
+          firefoxShim.shimRTCDataChannel(window, browserDetails);
+          firefoxShim.shimAddTransceiver(window, browserDetails);
+          firefoxShim.shimGetParameters(window, browserDetails);
+          firefoxShim.shimCreateOffer(window, browserDetails);
+          firefoxShim.shimCreateAnswer(window, browserDetails);
+    
+          commonShim.shimRTCIceCandidate(window, browserDetails);
+          commonShim.shimConnectionState(window, browserDetails);
+          commonShim.shimMaxMessageSize(window, browserDetails);
+          commonShim.shimSendThrowTypeError(window, browserDetails);
+          break;
+        case 'safari':
+          if (!safariShim || !options.shimSafari) {
+            logging('Safari shim is not included in this adapter release.');
+            return adapter;
+          }
+          logging('adapter.js shimming safari.');
+          // Export to the adapter global object visible in the browser.
+          adapter.browserShim = safariShim;
+    
+          // Must be called before shimCallbackAPI.
+          commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails);
+          commonShim.shimParameterlessSetLocalDescription(window, browserDetails);
+    
+          safariShim.shimRTCIceServerUrls(window, browserDetails);
+          safariShim.shimCreateOfferLegacy(window, browserDetails);
+          safariShim.shimCallbacksAPI(window, browserDetails);
+          safariShim.shimLocalStreamsAPI(window, browserDetails);
+          safariShim.shimRemoteStreamsAPI(window, browserDetails);
+          safariShim.shimTrackEventTransceiver(window, browserDetails);
+          safariShim.shimGetUserMedia(window, browserDetails);
+          safariShim.shimAudioContext(window, browserDetails);
+    
+          commonShim.shimRTCIceCandidate(window, browserDetails);
+          commonShim.shimMaxMessageSize(window, browserDetails);
+          commonShim.shimSendThrowTypeError(window, browserDetails);
+          commonShim.removeExtmapAllowMixed(window, browserDetails);
+          break;
+        default:
+          logging('Unsupported browser!');
+          break;
+      }
+    
+      return adapter;
+    }
+    
+    // Browser shims.
+    
+    },{"./chrome/chrome_shim":3,"./common_shim":6,"./firefox/firefox_shim":7,"./safari/safari_shim":10,"./utils":11,"sdp":12}],3:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined;
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    var _getusermedia = require('./getusermedia');
+    
+    Object.defineProperty(exports, 'shimGetUserMedia', {
+      enumerable: true,
+      get: function get() {
+        return _getusermedia.shimGetUserMedia;
+      }
+    });
+    
+    var _getdisplaymedia = require('./getdisplaymedia');
+    
+    Object.defineProperty(exports, 'shimGetDisplayMedia', {
+      enumerable: true,
+      get: function get() {
+        return _getdisplaymedia.shimGetDisplayMedia;
+      }
+    });
+    exports.shimMediaStream = shimMediaStream;
+    exports.shimOnTrack = shimOnTrack;
+    exports.shimGetSendersWithDtmf = shimGetSendersWithDtmf;
+    exports.shimGetStats = shimGetStats;
+    exports.shimSenderReceiverGetStats = shimSenderReceiverGetStats;
+    exports.shimAddTrackRemoveTrackWithNative = shimAddTrackRemoveTrackWithNative;
+    exports.shimAddTrackRemoveTrack = shimAddTrackRemoveTrack;
+    exports.shimPeerConnection = shimPeerConnection;
+    exports.fixNegotiationNeeded = fixNegotiationNeeded;
+    
+    var _utils = require('../utils.js');
+    
+    var utils = _interopRequireWildcard(_utils);
+    
+    function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+    
+    function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+    
+    function shimMediaStream(window) {
+      window.MediaStream = window.MediaStream || window.webkitMediaStream;
+    }
+    
+    function shimOnTrack(window) {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) {
+        Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', {
+          get: function get() {
+            return this._ontrack;
+          },
+          set: function set(f) {
+            if (this._ontrack) {
+              this.removeEventListener('track', this._ontrack);
+            }
+            this.addEventListener('track', this._ontrack = f);
+          },
+    
+          enumerable: true,
+          configurable: true
+        });
+        var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription;
+        window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() {
+          var _this = this;
+    
+          if (!this._ontrackpoly) {
+            this._ontrackpoly = function (e) {
+              // onaddstream does not fire when a track is added to an existing
+              // stream. But stream.onaddtrack is implemented so we use that.
+              e.stream.addEventListener('addtrack', function (te) {
+                var receiver = void 0;
+                if (window.RTCPeerConnection.prototype.getReceivers) {
+                  receiver = _this.getReceivers().find(function (r) {
+                    return r.track && r.track.id === te.track.id;
+                  });
+                } else {
+                  receiver = { track: te.track };
+                }
+    
+                var event = new Event('track');
+                event.track = te.track;
+                event.receiver = receiver;
+                event.transceiver = { receiver: receiver };
+                event.streams = [e.stream];
+                _this.dispatchEvent(event);
+              });
+              e.stream.getTracks().forEach(function (track) {
+                var receiver = void 0;
+                if (window.RTCPeerConnection.prototype.getReceivers) {
+                  receiver = _this.getReceivers().find(function (r) {
+                    return r.track && r.track.id === track.id;
+                  });
+                } else {
+                  receiver = { track: track };
+                }
+                var event = new Event('track');
+                event.track = track;
+                event.receiver = receiver;
+                event.transceiver = { receiver: receiver };
+                event.streams = [e.stream];
+                _this.dispatchEvent(event);
+              });
+            };
+            this.addEventListener('addstream', this._ontrackpoly);
+          }
+          return origSetRemoteDescription.apply(this, arguments);
+        };
+      } else {
+        // even if RTCRtpTransceiver is in window, it is only used and
+        // emitted in unified-plan. Unfortunately this means we need
+        // to unconditionally wrap the event.
+        utils.wrapPeerConnectionEvent(window, 'track', function (e) {
+          if (!e.transceiver) {
+            Object.defineProperty(e, 'transceiver', { value: { receiver: e.receiver } });
+          }
+          return e;
+        });
+      }
+    }
+    
+    function shimGetSendersWithDtmf(window) {
+      // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack.
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) {
+        var shimSenderWithDtmf = function shimSenderWithDtmf(pc, track) {
+          return {
+            track: track,
+            get dtmf() {
+              if (this._dtmf === undefined) {
+                if (track.kind === 'audio') {
+                  this._dtmf = pc.createDTMFSender(track);
+                } else {
+                  this._dtmf = null;
+                }
+              }
+              return this._dtmf;
+            },
+            _pc: pc
+          };
+        };
+    
+        // augment addTrack when getSenders is not available.
+        if (!window.RTCPeerConnection.prototype.getSenders) {
+          window.RTCPeerConnection.prototype.getSenders = function getSenders() {
+            this._senders = this._senders || [];
+            return this._senders.slice(); // return a copy of the internal state.
+          };
+          var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
+          window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) {
+            var sender = origAddTrack.apply(this, arguments);
+            if (!sender) {
+              sender = shimSenderWithDtmf(this, track);
+              this._senders.push(sender);
+            }
+            return sender;
+          };
+    
+          var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;
+          window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) {
+            origRemoveTrack.apply(this, arguments);
+            var idx = this._senders.indexOf(sender);
+            if (idx !== -1) {
+              this._senders.splice(idx, 1);
+            }
+          };
+        }
+        var origAddStream = window.RTCPeerConnection.prototype.addStream;
+        window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
+          var _this2 = this;
+    
+          this._senders = this._senders || [];
+          origAddStream.apply(this, [stream]);
+          stream.getTracks().forEach(function (track) {
+            _this2._senders.push(shimSenderWithDtmf(_this2, track));
+          });
+        };
+    
+        var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
+        window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
+          var _this3 = this;
+    
+          this._senders = this._senders || [];
+          origRemoveStream.apply(this, [stream]);
+    
+          stream.getTracks().forEach(function (track) {
+            var sender = _this3._senders.find(function (s) {
+              return s.track === track;
+            });
+            if (sender) {
+              // remove sender
+              _this3._senders.splice(_this3._senders.indexOf(sender), 1);
+            }
+          });
+        };
+      } else if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) {
+        var origGetSenders = window.RTCPeerConnection.prototype.getSenders;
+        window.RTCPeerConnection.prototype.getSenders = function getSenders() {
+          var _this4 = this;
+    
+          var senders = origGetSenders.apply(this, []);
+          senders.forEach(function (sender) {
+            return sender._pc = _this4;
+          });
+          return senders;
+        };
+    
+        Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {
+          get: function get() {
+            if (this._dtmf === undefined) {
+              if (this.track.kind === 'audio') {
+                this._dtmf = this._pc.createDTMFSender(this.track);
+              } else {
+                this._dtmf = null;
+              }
+            }
+            return this._dtmf;
+          }
+        });
+      }
+    }
+    
+    function shimGetStats(window) {
+      if (!window.RTCPeerConnection) {
+        return;
+      }
+    
+      var origGetStats = window.RTCPeerConnection.prototype.getStats;
+      window.RTCPeerConnection.prototype.getStats = function getStats() {
+        var _this5 = this;
+    
+        var _arguments = Array.prototype.slice.call(arguments),
+            selector = _arguments[0],
+            onSucc = _arguments[1],
+            onErr = _arguments[2];
+    
+        // If selector is a function then we are in the old style stats so just
+        // pass back the original getStats format to avoid breaking old users.
+    
+    
+        if (arguments.length > 0 && typeof selector === 'function') {
+          return origGetStats.apply(this, arguments);
+        }
+    
+        // When spec-style getStats is supported, return those when called with
+        // either no arguments or the selector argument is null.
+        if (origGetStats.length === 0 && (arguments.length === 0 || typeof selector !== 'function')) {
+          return origGetStats.apply(this, []);
+        }
+    
+        var fixChromeStats_ = function fixChromeStats_(response) {
+          var standardReport = {};
+          var reports = response.result();
+          reports.forEach(function (report) {
+            var standardStats = {
+              id: report.id,
+              timestamp: report.timestamp,
+              type: {
+                localcandidate: 'local-candidate',
+                remotecandidate: 'remote-candidate'
+              }[report.type] || report.type
+            };
+            report.names().forEach(function (name) {
+              standardStats[name] = report.stat(name);
+            });
+            standardReport[standardStats.id] = standardStats;
+          });
+    
+          return standardReport;
+        };
+    
+        // shim getStats with maplike support
+        var makeMapStats = function makeMapStats(stats) {
+          return new Map(Object.keys(stats).map(function (key) {
+            return [key, stats[key]];
+          }));
+        };
+    
+        if (arguments.length >= 2) {
+          var successCallbackWrapper_ = function successCallbackWrapper_(response) {
+            onSucc(makeMapStats(fixChromeStats_(response)));
+          };
+    
+          return origGetStats.apply(this, [successCallbackWrapper_, selector]);
+        }
+    
+        // promise-support
+        return new Promise(function (resolve, reject) {
+          origGetStats.apply(_this5, [function (response) {
+            resolve(makeMapStats(fixChromeStats_(response)));
+          }, reject]);
+        }).then(onSucc, onErr);
+      };
+    }
+    
+    function shimSenderReceiverGetStats(window) {
+      if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) {
+        return;
+      }
+    
+      // shim sender stats.
+      if (!('getStats' in window.RTCRtpSender.prototype)) {
+        var origGetSenders = window.RTCPeerConnection.prototype.getSenders;
+        if (origGetSenders) {
+          window.RTCPeerConnection.prototype.getSenders = function getSenders() {
+            var _this6 = this;
+    
+            var senders = origGetSenders.apply(this, []);
+            senders.forEach(function (sender) {
+              return sender._pc = _this6;
+            });
+            return senders;
+          };
+        }
+    
+        var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
+        if (origAddTrack) {
+          window.RTCPeerConnection.prototype.addTrack = function addTrack() {
+            var sender = origAddTrack.apply(this, arguments);
+            sender._pc = this;
+            return sender;
+          };
+        }
+        window.RTCRtpSender.prototype.getStats = function getStats() {
+          var sender = this;
+          return this._pc.getStats().then(function (result) {
+            return (
+              /* Note: this will include stats of all senders that
+               *   send a track with the same id as sender.track as
+               *   it is not possible to identify the RTCRtpSender.
+               */
+              utils.filterStats(result, sender.track, true)
+            );
+          });
+        };
+      }
+    
+      // shim receiver stats.
+      if (!('getStats' in window.RTCRtpReceiver.prototype)) {
+        var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;
+        if (origGetReceivers) {
+          window.RTCPeerConnection.prototype.getReceivers = function getReceivers() {
+            var _this7 = this;
+    
+            var receivers = origGetReceivers.apply(this, []);
+            receivers.forEach(function (receiver) {
+              return receiver._pc = _this7;
+            });
+            return receivers;
+          };
+        }
+        utils.wrapPeerConnectionEvent(window, 'track', function (e) {
+          e.receiver._pc = e.srcElement;
+          return e;
+        });
+        window.RTCRtpReceiver.prototype.getStats = function getStats() {
+          var receiver = this;
+          return this._pc.getStats().then(function (result) {
+            return utils.filterStats(result, receiver.track, false);
+          });
+        };
+      }
+    
+      if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) {
+        return;
+      }
+    
+      // shim RTCPeerConnection.getStats(track).
+      var origGetStats = window.RTCPeerConnection.prototype.getStats;
+      window.RTCPeerConnection.prototype.getStats = function getStats() {
+        if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) {
+          var track = arguments[0];
+          var sender = void 0;
+          var receiver = void 0;
+          var err = void 0;
+          this.getSenders().forEach(function (s) {
+            if (s.track === track) {
+              if (sender) {
+                err = true;
+              } else {
+                sender = s;
+              }
+            }
+          });
+          this.getReceivers().forEach(function (r) {
+            if (r.track === track) {
+              if (receiver) {
+                err = true;
+              } else {
+                receiver = r;
+              }
+            }
+            return r.track === track;
+          });
+          if (err || sender && receiver) {
+            return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError'));
+          } else if (sender) {
+            return sender.getStats();
+          } else if (receiver) {
+            return receiver.getStats();
+          }
+          return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError'));
+        }
+        return origGetStats.apply(this, arguments);
+      };
+    }
+    
+    function shimAddTrackRemoveTrackWithNative(window) {
+      // shim addTrack/removeTrack with native variants in order to make
+      // the interactions with legacy getLocalStreams behave as in other browsers.
+      // Keeps a mapping stream.id => [stream, rtpsenders...]
+      window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() {
+        var _this8 = this;
+    
+        this._shimmedLocalStreams = this._shimmedLocalStreams || {};
+        return Object.keys(this._shimmedLocalStreams).map(function (streamId) {
+          return _this8._shimmedLocalStreams[streamId][0];
+        });
+      };
+    
+      var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
+      window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) {
+        if (!stream) {
+          return origAddTrack.apply(this, arguments);
+        }
+        this._shimmedLocalStreams = this._shimmedLocalStreams || {};
+    
+        var sender = origAddTrack.apply(this, arguments);
+        if (!this._shimmedLocalStreams[stream.id]) {
+          this._shimmedLocalStreams[stream.id] = [stream, sender];
+        } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) {
+          this._shimmedLocalStreams[stream.id].push(sender);
+        }
+        return sender;
+      };
+    
+      var origAddStream = window.RTCPeerConnection.prototype.addStream;
+      window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
+        var _this9 = this;
+    
+        this._shimmedLocalStreams = this._shimmedLocalStreams || {};
+    
+        stream.getTracks().forEach(function (track) {
+          var alreadyExists = _this9.getSenders().find(function (s) {
+            return s.track === track;
+          });
+          if (alreadyExists) {
+            throw new DOMException('Track already exists.', 'InvalidAccessError');
+          }
+        });
+        var existingSenders = this.getSenders();
+        origAddStream.apply(this, arguments);
+        var newSenders = this.getSenders().filter(function (newSender) {
+          return existingSenders.indexOf(newSender) === -1;
+        });
+        this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders);
+      };
+    
+      var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
+      window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
+        this._shimmedLocalStreams = this._shimmedLocalStreams || {};
+        delete this._shimmedLocalStreams[stream.id];
+        return origRemoveStream.apply(this, arguments);
+      };
+    
+      var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack;
+      window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) {
+        var _this10 = this;
+    
+        this._shimmedLocalStreams = this._shimmedLocalStreams || {};
+        if (sender) {
+          Object.keys(this._shimmedLocalStreams).forEach(function (streamId) {
+            var idx = _this10._shimmedLocalStreams[streamId].indexOf(sender);
+            if (idx !== -1) {
+              _this10._shimmedLocalStreams[streamId].splice(idx, 1);
+            }
+            if (_this10._shimmedLocalStreams[streamId].length === 1) {
+              delete _this10._shimmedLocalStreams[streamId];
+            }
+          });
+        }
+        return origRemoveTrack.apply(this, arguments);
+      };
+    }
+    
+    function shimAddTrackRemoveTrack(window, browserDetails) {
+      if (!window.RTCPeerConnection) {
+        return;
+      }
+      // shim addTrack and removeTrack.
+      if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) {
+        return shimAddTrackRemoveTrackWithNative(window);
+      }
+    
+      // also shim pc.getLocalStreams when addTrack is shimmed
+      // to return the original streams.
+      var origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams;
+      window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() {
+        var _this11 = this;
+    
+        var nativeStreams = origGetLocalStreams.apply(this);
+        this._reverseStreams = this._reverseStreams || {};
+        return nativeStreams.map(function (stream) {
+          return _this11._reverseStreams[stream.id];
+        });
+      };
+    
+      var origAddStream = window.RTCPeerConnection.prototype.addStream;
+      window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
+        var _this12 = this;
+    
+        this._streams = this._streams || {};
+        this._reverseStreams = this._reverseStreams || {};
+    
+        stream.getTracks().forEach(function (track) {
+          var alreadyExists = _this12.getSenders().find(function (s) {
+            return s.track === track;
+          });
+          if (alreadyExists) {
+            throw new DOMException('Track already exists.', 'InvalidAccessError');
+          }
+        });
+        // Add identity mapping for consistency with addTrack.
+        // Unless this is being used with a stream from addTrack.
+        if (!this._reverseStreams[stream.id]) {
+          var newStream = new window.MediaStream(stream.getTracks());
+          this._streams[stream.id] = newStream;
+          this._reverseStreams[newStream.id] = stream;
+          stream = newStream;
+        }
+        origAddStream.apply(this, [stream]);
+      };
+    
+      var origRemoveStream = window.RTCPeerConnection.prototype.removeStream;
+      window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
+        this._streams = this._streams || {};
+        this._reverseStreams = this._reverseStreams || {};
+    
+        origRemoveStream.apply(this, [this._streams[stream.id] || stream]);
+        delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id];
+        delete this._streams[stream.id];
+      };
+    
+      window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) {
+        var _this13 = this;
+    
+        if (this.signalingState === 'closed') {
+          throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError');
+        }
+        var streams = [].slice.call(arguments, 1);
+        if (streams.length !== 1 || !streams[0].getTracks().find(function (t) {
+          return t === track;
+        })) {
+          // this is not fully correct but all we can manage without
+          // [[associated MediaStreams]] internal slot.
+          throw new DOMException('The adapter.js addTrack polyfill only supports a single ' + ' stream which is associated with the specified track.', 'NotSupportedError');
+        }
+    
+        var alreadyExists = this.getSenders().find(function (s) {
+          return s.track === track;
+        });
+        if (alreadyExists) {
+          throw new DOMException('Track already exists.', 'InvalidAccessError');
+        }
+    
+        this._streams = this._streams || {};
+        this._reverseStreams = this._reverseStreams || {};
+        var oldStream = this._streams[stream.id];
+        if (oldStream) {
+          // this is using odd Chrome behaviour, use with caution:
+          // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815
+          // Note: we rely on the high-level addTrack/dtmf shim to
+          // create the sender with a dtmf sender.
+          oldStream.addTrack(track);
+    
+          // Trigger ONN async.
+          Promise.resolve().then(function () {
+            _this13.dispatchEvent(new Event('negotiationneeded'));
+          });
+        } else {
+          var newStream = new window.MediaStream([track]);
+          this._streams[stream.id] = newStream;
+          this._reverseStreams[newStream.id] = stream;
+          this.addStream(newStream);
+        }
+        return this.getSenders().find(function (s) {
+          return s.track === track;
+        });
+      };
+    
+      // replace the internal stream id with the external one and
+      // vice versa.
+      function replaceInternalStreamId(pc, description) {
+        var sdp = description.sdp;
+        Object.keys(pc._reverseStreams || []).forEach(function (internalId) {
+          var externalStream = pc._reverseStreams[internalId];
+          var internalStream = pc._streams[externalStream.id];
+          sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id);
+        });
+        return new RTCSessionDescription({
+          type: description.type,
+          sdp: sdp
+        });
+      }
+      function replaceExternalStreamId(pc, description) {
+        var sdp = description.sdp;
+        Object.keys(pc._reverseStreams || []).forEach(function (internalId) {
+          var externalStream = pc._reverseStreams[internalId];
+          var internalStream = pc._streams[externalStream.id];
+          sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id);
+        });
+        return new RTCSessionDescription({
+          type: description.type,
+          sdp: sdp
+        });
+      }
+      ['createOffer', 'createAnswer'].forEach(function (method) {
+        var nativeMethod = window.RTCPeerConnection.prototype[method];
+        var methodObj = _defineProperty({}, method, function () {
+          var _this14 = this;
+    
+          var args = arguments;
+          var isLegacyCall = arguments.length && typeof arguments[0] === 'function';
+          if (isLegacyCall) {
+            return nativeMethod.apply(this, [function (description) {
+              var desc = replaceInternalStreamId(_this14, description);
+              args[0].apply(null, [desc]);
+            }, function (err) {
+              if (args[1]) {
+                args[1].apply(null, err);
+              }
+            }, arguments[2]]);
+          }
+          return nativeMethod.apply(this, arguments).then(function (description) {
+            return replaceInternalStreamId(_this14, description);
+          });
+        });
+        window.RTCPeerConnection.prototype[method] = methodObj[method];
+      });
+    
+      var origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription;
+      window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() {
+        if (!arguments.length || !arguments[0].type) {
+          return origSetLocalDescription.apply(this, arguments);
+        }
+        arguments[0] = replaceExternalStreamId(this, arguments[0]);
+        return origSetLocalDescription.apply(this, arguments);
+      };
+    
+      // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier
+    
+      var origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription');
+      Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', {
+        get: function get() {
+          var description = origLocalDescription.get.apply(this);
+          if (description.type === '') {
+            return description;
+          }
+          return replaceInternalStreamId(this, description);
+        }
+      });
+    
+      window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) {
+        var _this15 = this;
+    
+        if (this.signalingState === 'closed') {
+          throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError');
+        }
+        // We can not yet check for sender instanceof RTCRtpSender
+        // since we shim RTPSender. So we check if sender._pc is set.
+        if (!sender._pc) {
+          throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError');
+        }
+        var isLocal = sender._pc === this;
+        if (!isLocal) {
+          throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError');
+        }
+    
+        // Search for the native stream the senders track belongs to.
+        this._streams = this._streams || {};
+        var stream = void 0;
+        Object.keys(this._streams).forEach(function (streamid) {
+          var hasTrack = _this15._streams[streamid].getTracks().find(function (track) {
+            return sender.track === track;
+          });
+          if (hasTrack) {
+            stream = _this15._streams[streamid];
+          }
+        });
+    
+        if (stream) {
+          if (stream.getTracks().length === 1) {
+            // if this is the last track of the stream, remove the stream. This
+            // takes care of any shimmed _senders.
+            this.removeStream(this._reverseStreams[stream.id]);
+          } else {
+            // relying on the same odd chrome behaviour as above.
+            stream.removeTrack(sender.track);
+          }
+          this.dispatchEvent(new Event('negotiationneeded'));
+        }
+      };
+    }
+    
+    function shimPeerConnection(window, browserDetails) {
+      if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) {
+        // very basic support for old versions.
+        window.RTCPeerConnection = window.webkitRTCPeerConnection;
+      }
+      if (!window.RTCPeerConnection) {
+        return;
+      }
+    
+      // shim implicit creation of RTCSessionDescription/RTCIceCandidate
+      if (browserDetails.version < 53) {
+        ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) {
+          var nativeMethod = window.RTCPeerConnection.prototype[method];
+          var methodObj = _defineProperty({}, method, function () {
+            arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]);
+            return nativeMethod.apply(this, arguments);
+          });
+          window.RTCPeerConnection.prototype[method] = methodObj[method];
+        });
+      }
+    }
+    
+    // Attempt to fix ONN in plan-b mode.
+    function fixNegotiationNeeded(window, browserDetails) {
+      utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) {
+        var pc = e.target;
+        if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') {
+          if (pc.signalingState !== 'stable') {
+            return;
+          }
+        }
+        return e;
+      });
+    }
+    
+    },{"../utils.js":11,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    exports.shimGetDisplayMedia = shimGetDisplayMedia;
+    function shimGetDisplayMedia(window, getSourceId) {
+      if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) {
+        return;
+      }
+      if (!window.navigator.mediaDevices) {
+        return;
+      }
+      // getSourceId is a function that returns a promise resolving with
+      // the sourceId of the screen/window/tab to be shared.
+      if (typeof getSourceId !== 'function') {
+        console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function');
+        return;
+      }
+      window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) {
+        return getSourceId(constraints).then(function (sourceId) {
+          var widthSpecified = constraints.video && constraints.video.width;
+          var heightSpecified = constraints.video && constraints.video.height;
+          var frameRateSpecified = constraints.video && constraints.video.frameRate;
+          constraints.video = {
+            mandatory: {
+              chromeMediaSource: 'desktop',
+              chromeMediaSourceId: sourceId,
+              maxFrameRate: frameRateSpecified || 3
+            }
+          };
+          if (widthSpecified) {
+            constraints.video.mandatory.maxWidth = widthSpecified;
+          }
+          if (heightSpecified) {
+            constraints.video.mandatory.maxHeight = heightSpecified;
+          }
+          return window.navigator.mediaDevices.getUserMedia(constraints);
+        });
+      };
+    }
+    
+    },{}],5:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    exports.shimGetUserMedia = shimGetUserMedia;
+    
+    var _utils = require('../utils.js');
+    
+    var utils = _interopRequireWildcard(_utils);
+    
+    function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+    
+    var logging = utils.log;
+    
+    function shimGetUserMedia(window, browserDetails) {
+      var navigator = window && window.navigator;
+    
+      if (!navigator.mediaDevices) {
+        return;
+      }
+    
+      var constraintsToChrome_ = function constraintsToChrome_(c) {
+        if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) !== 'object' || c.mandatory || c.optional) {
+          return c;
+        }
+        var cc = {};
+        Object.keys(c).forEach(function (key) {
+          if (key === 'require' || key === 'advanced' || key === 'mediaSource') {
+            return;
+          }
+          var r = _typeof(c[key]) === 'object' ? c[key] : { ideal: c[key] };
+          if (r.exact !== undefined && typeof r.exact === 'number') {
+            r.min = r.max = r.exact;
+          }
+          var oldname_ = function oldname_(prefix, name) {
+            if (prefix) {
+              return prefix + name.charAt(0).toUpperCase() + name.slice(1);
+            }
+            return name === 'deviceId' ? 'sourceId' : name;
+          };
+          if (r.ideal !== undefined) {
+            cc.optional = cc.optional || [];
+            var oc = {};
+            if (typeof r.ideal === 'number') {
+              oc[oldname_('min', key)] = r.ideal;
+              cc.optional.push(oc);
+              oc = {};
+              oc[oldname_('max', key)] = r.ideal;
+              cc.optional.push(oc);
+            } else {
+              oc[oldname_('', key)] = r.ideal;
+              cc.optional.push(oc);
+            }
+          }
+          if (r.exact !== undefined && typeof r.exact !== 'number') {
+            cc.mandatory = cc.mandatory || {};
+            cc.mandatory[oldname_('', key)] = r.exact;
+          } else {
+            ['min', 'max'].forEach(function (mix) {
+              if (r[mix] !== undefined) {
+                cc.mandatory = cc.mandatory || {};
+                cc.mandatory[oldname_(mix, key)] = r[mix];
+              }
+            });
+          }
+        });
+        if (c.advanced) {
+          cc.optional = (cc.optional || []).concat(c.advanced);
+        }
+        return cc;
+      };
+    
+      var shimConstraints_ = function shimConstraints_(constraints, func) {
+        if (browserDetails.version >= 61) {
+          return func(constraints);
+        }
+        constraints = JSON.parse(JSON.stringify(constraints));
+        if (constraints && _typeof(constraints.audio) === 'object') {
+          var remap = function remap(obj, a, b) {
+            if (a in obj && !(b in obj)) {
+              obj[b] = obj[a];
+              delete obj[a];
+            }
+          };
+          constraints = JSON.parse(JSON.stringify(constraints));
+          remap(constraints.audio, 'autoGainControl', 'googAutoGainControl');
+          remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression');
+          constraints.audio = constraintsToChrome_(constraints.audio);
+        }
+        if (constraints && _typeof(constraints.video) === 'object') {
+          // Shim facingMode for mobile & surface pro.
+          var face = constraints.video.facingMode;
+          face = face && ((typeof face === 'undefined' ? 'undefined' : _typeof(face)) === 'object' ? face : { ideal: face });
+          var getSupportedFacingModeLies = browserDetails.version < 66;
+    
+          if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) {
+            delete constraints.video.facingMode;
+            var matches = void 0;
+            if (face.exact === 'environment' || face.ideal === 'environment') {
+              matches = ['back', 'rear'];
+            } else if (face.exact === 'user' || face.ideal === 'user') {
+              matches = ['front'];
+            }
+            if (matches) {
+              // Look for matches in label, or use last cam for back (typical).
+              return navigator.mediaDevices.enumerateDevices().then(function (devices) {
+                devices = devices.filter(function (d) {
+                  return d.kind === 'videoinput';
+                });
+                var dev = devices.find(function (d) {
+                  return matches.some(function (match) {
+                    return d.label.toLowerCase().includes(match);
+                  });
+                });
+                if (!dev && devices.length && matches.includes('back')) {
+                  dev = devices[devices.length - 1]; // more likely the back cam
+                }
+                if (dev) {
+                  constraints.video.deviceId = face.exact ? { exact: dev.deviceId } : { ideal: dev.deviceId };
+                }
+                constraints.video = constraintsToChrome_(constraints.video);
+                logging('chrome: ' + JSON.stringify(constraints));
+                return func(constraints);
+              });
+            }
+          }
+          constraints.video = constraintsToChrome_(constraints.video);
+        }
+        logging('chrome: ' + JSON.stringify(constraints));
+        return func(constraints);
+      };
+    
+      var shimError_ = function shimError_(e) {
+        if (browserDetails.version >= 64) {
+          return e;
+        }
+        return {
+          name: {
+            PermissionDeniedError: 'NotAllowedError',
+            PermissionDismissedError: 'NotAllowedError',
+            InvalidStateError: 'NotAllowedError',
+            DevicesNotFoundError: 'NotFoundError',
+            ConstraintNotSatisfiedError: 'OverconstrainedError',
+            TrackStartError: 'NotReadableError',
+            MediaDeviceFailedDueToShutdown: 'NotAllowedError',
+            MediaDeviceKillSwitchOn: 'NotAllowedError',
+            TabCaptureError: 'AbortError',
+            ScreenCaptureError: 'AbortError',
+            DeviceCaptureError: 'AbortError'
+          }[e.name] || e.name,
+          message: e.message,
+          constraint: e.constraint || e.constraintName,
+          toString: function toString() {
+            return this.name + (this.message && ': ') + this.message;
+          }
+        };
+      };
+    
+      var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) {
+        shimConstraints_(constraints, function (c) {
+          navigator.webkitGetUserMedia(c, onSuccess, function (e) {
+            if (onError) {
+              onError(shimError_(e));
+            }
+          });
+        });
+      };
+      navigator.getUserMedia = getUserMedia_.bind(navigator);
+    
+      // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia
+      // function which returns a Promise, it does not accept spec-style
+      // constraints.
+      if (navigator.mediaDevices.getUserMedia) {
+        var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
+        navigator.mediaDevices.getUserMedia = function (cs) {
+          return shimConstraints_(cs, function (c) {
+            return origGetUserMedia(c).then(function (stream) {
+              if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) {
+                stream.getTracks().forEach(function (track) {
+                  track.stop();
+                });
+                throw new DOMException('', 'NotFoundError');
+              }
+              return stream;
+            }, function (e) {
+              return Promise.reject(shimError_(e));
+            });
+          });
+        };
+      }
+    }
+    
+    },{"../utils.js":11}],6:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    exports.shimRTCIceCandidate = shimRTCIceCandidate;
+    exports.shimMaxMessageSize = shimMaxMessageSize;
+    exports.shimSendThrowTypeError = shimSendThrowTypeError;
+    exports.shimConnectionState = shimConnectionState;
+    exports.removeExtmapAllowMixed = removeExtmapAllowMixed;
+    exports.shimAddIceCandidateNullOrEmpty = shimAddIceCandidateNullOrEmpty;
+    exports.shimParameterlessSetLocalDescription = shimParameterlessSetLocalDescription;
+    
+    var _sdp = require('sdp');
+    
+    var _sdp2 = _interopRequireDefault(_sdp);
+    
+    var _utils = require('./utils');
+    
+    var utils = _interopRequireWildcard(_utils);
+    
+    function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+    
+    function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+    
+    function shimRTCIceCandidate(window) {
+      // foundation is arbitrarily chosen as an indicator for full support for
+      // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface
+      if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) {
+        return;
+      }
+    
+      var NativeRTCIceCandidate = window.RTCIceCandidate;
+      window.RTCIceCandidate = function RTCIceCandidate(args) {
+        // Remove the a= which shouldn't be part of the candidate string.
+        if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) {
+          args = JSON.parse(JSON.stringify(args));
+          args.candidate = args.candidate.substr(2);
+        }
+    
+        if (args.candidate && args.candidate.length) {
+          // Augment the native candidate with the parsed fields.
+          var nativeCandidate = new NativeRTCIceCandidate(args);
+          var parsedCandidate = _sdp2.default.parseCandidate(args.candidate);
+          var augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate);
+    
+          // Add a serializer that does not serialize the extra attributes.
+          augmentedCandidate.toJSON = function toJSON() {
+            return {
+              candidate: augmentedCandidate.candidate,
+              sdpMid: augmentedCandidate.sdpMid,
+              sdpMLineIndex: augmentedCandidate.sdpMLineIndex,
+              usernameFragment: augmentedCandidate.usernameFragment
+            };
+          };
+          return augmentedCandidate;
+        }
+        return new NativeRTCIceCandidate(args);
+      };
+      window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype;
+    
+      // Hook up the augmented candidate in onicecandidate and
+      // addEventListener('icecandidate', ...)
+      utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) {
+        if (e.candidate) {
+          Object.defineProperty(e, 'candidate', {
+            value: new window.RTCIceCandidate(e.candidate),
+            writable: 'false'
+          });
+        }
+        return e;
+      });
+    }
+    
+    function shimMaxMessageSize(window, browserDetails) {
+      if (!window.RTCPeerConnection) {
+        return;
+      }
+    
+      if (!('sctp' in window.RTCPeerConnection.prototype)) {
+        Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', {
+          get: function get() {
+            return typeof this._sctp === 'undefined' ? null : this._sctp;
+          }
+        });
+      }
+    
+      var sctpInDescription = function sctpInDescription(description) {
+        if (!description || !description.sdp) {
+          return false;
+        }
+        var sections = _sdp2.default.splitSections(description.sdp);
+        sections.shift();
+        return sections.some(function (mediaSection) {
+          var mLine = _sdp2.default.parseMLine(mediaSection);
+          return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1;
+        });
+      };
+    
+      var getRemoteFirefoxVersion = function getRemoteFirefoxVersion(description) {
+        // TODO: Is there a better solution for detecting Firefox?
+        var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);
+        if (match === null || match.length < 2) {
+          return -1;
+        }
+        var version = parseInt(match[1], 10);
+        // Test for NaN (yes, this is ugly)
+        return version !== version ? -1 : version;
+      };
+    
+      var getCanSendMaxMessageSize = function getCanSendMaxMessageSize(remoteIsFirefox) {
+        // Every implementation we know can send at least 64 KiB.
+        // Note: Although Chrome is technically able to send up to 256 KiB, the
+        //       data does not reach the other peer reliably.
+        //       See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419
+        var canSendMaxMessageSize = 65536;
+        if (browserDetails.browser === 'firefox') {
+          if (browserDetails.version < 57) {
+            if (remoteIsFirefox === -1) {
+              // FF < 57 will send in 16 KiB chunks using the deprecated PPID
+              // fragmentation.
+              canSendMaxMessageSize = 16384;
+            } else {
+              // However, other FF (and RAWRTC) can reassemble PPID-fragmented
+              // messages. Thus, supporting ~2 GiB when sending.
+              canSendMaxMessageSize = 2147483637;
+            }
+          } else if (browserDetails.version < 60) {
+            // Currently, all FF >= 57 will reset the remote maximum message size
+            // to the default value when a data channel is created at a later
+            // stage. :(
+            // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831
+            canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536;
+          } else {
+            // FF >= 60 supports sending ~2 GiB
+            canSendMaxMessageSize = 2147483637;
+          }
+        }
+        return canSendMaxMessageSize;
+      };
+    
+      var getMaxMessageSize = function getMaxMessageSize(description, remoteIsFirefox) {
+        // Note: 65536 bytes is the default value from the SDP spec. Also,
+        //       every implementation we know supports receiving 65536 bytes.
+        var maxMessageSize = 65536;
+    
+        // FF 57 has a slightly incorrect default remote max message size, so
+        // we need to adjust it here to avoid a failure when sending.
+        // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697
+        if (browserDetails.browser === 'firefox' && browserDetails.version === 57) {
+          maxMessageSize = 65535;
+        }
+    
+        var match = _sdp2.default.matchPrefix(description.sdp, 'a=max-message-size:');
+        if (match.length > 0) {
+          maxMessageSize = parseInt(match[0].substr(19), 10);
+        } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) {
+          // If the maximum message size is not present in the remote SDP and
+          // both local and remote are Firefox, the remote peer can receive
+          // ~2 GiB.
+          maxMessageSize = 2147483637;
+        }
+        return maxMessageSize;
+      };
+    
+      var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription;
+      window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() {
+        this._sctp = null;
+        // Chrome decided to not expose .sctp in plan-b mode.
+        // As usual, adapter.js has to do an 'ugly worakaround'
+        // to cover up the mess.
+        if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) {
+          var _getConfiguration = this.getConfiguration(),
+              sdpSemantics = _getConfiguration.sdpSemantics;
+    
+          if (sdpSemantics === 'plan-b') {
+            Object.defineProperty(this, 'sctp', {
+              get: function get() {
+                return typeof this._sctp === 'undefined' ? null : this._sctp;
+              },
+    
+              enumerable: true,
+              configurable: true
+            });
+          }
+        }
+    
+        if (sctpInDescription(arguments[0])) {
+          // Check if the remote is FF.
+          var isFirefox = getRemoteFirefoxVersion(arguments[0]);
+    
+          // Get the maximum message size the local peer is capable of sending
+          var canSendMMS = getCanSendMaxMessageSize(isFirefox);
+    
+          // Get the maximum message size of the remote peer.
+          var remoteMMS = getMaxMessageSize(arguments[0], isFirefox);
+    
+          // Determine final maximum message size
+          var maxMessageSize = void 0;
+          if (canSendMMS === 0 && remoteMMS === 0) {
+            maxMessageSize = Number.POSITIVE_INFINITY;
+          } else if (canSendMMS === 0 || remoteMMS === 0) {
+            maxMessageSize = Math.max(canSendMMS, remoteMMS);
+          } else {
+            maxMessageSize = Math.min(canSendMMS, remoteMMS);
+          }
+    
+          // Create a dummy RTCSctpTransport object and the 'maxMessageSize'
+          // attribute.
+          var sctp = {};
+          Object.defineProperty(sctp, 'maxMessageSize', {
+            get: function get() {
+              return maxMessageSize;
+            }
+          });
+          this._sctp = sctp;
+        }
+    
+        return origSetRemoteDescription.apply(this, arguments);
+      };
+    }
+    
+    function shimSendThrowTypeError(window) {
+      if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) {
+        return;
+      }
+    
+      // Note: Although Firefox >= 57 has a native implementation, the maximum
+      //       message size can be reset for all data channels at a later stage.
+      //       See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831
+    
+      function wrapDcSend(dc, pc) {
+        var origDataChannelSend = dc.send;
+        dc.send = function send() {
+          var data = arguments[0];
+          var length = data.length || data.size || data.byteLength;
+          if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) {
+            throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)');
+          }
+          return origDataChannelSend.apply(dc, arguments);
+        };
+      }
+      var origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel;
+      window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() {
+        var dataChannel = origCreateDataChannel.apply(this, arguments);
+        wrapDcSend(dataChannel, this);
+        return dataChannel;
+      };
+      utils.wrapPeerConnectionEvent(window, 'datachannel', function (e) {
+        wrapDcSend(e.channel, e.target);
+        return e;
+      });
+    }
+    
+    /* shims RTCConnectionState by pretending it is the same as iceConnectionState.
+     * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12
+     * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect
+     * since DTLS failures would be hidden. See
+     * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827
+     * for the Firefox tracking bug.
+     */
+    function shimConnectionState(window) {
+      if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) {
+        return;
+      }
+      var proto = window.RTCPeerConnection.prototype;
+      Object.defineProperty(proto, 'connectionState', {
+        get: function get() {
+          return {
+            completed: 'connected',
+            checking: 'connecting'
+          }[this.iceConnectionState] || this.iceConnectionState;
+        },
+    
+        enumerable: true,
+        configurable: true
+      });
+      Object.defineProperty(proto, 'onconnectionstatechange', {
+        get: function get() {
+          return this._onconnectionstatechange || null;
+        },
+        set: function set(cb) {
+          if (this._onconnectionstatechange) {
+            this.removeEventListener('connectionstatechange', this._onconnectionstatechange);
+            delete this._onconnectionstatechange;
+          }
+          if (cb) {
+            this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb);
+          }
+        },
+    
+        enumerable: true,
+        configurable: true
+      });
+    
+      ['setLocalDescription', 'setRemoteDescription'].forEach(function (method) {
+        var origMethod = proto[method];
+        proto[method] = function () {
+          if (!this._connectionstatechangepoly) {
+            this._connectionstatechangepoly = function (e) {
+              var pc = e.target;
+              if (pc._lastConnectionState !== pc.connectionState) {
+                pc._lastConnectionState = pc.connectionState;
+                var newEvent = new Event('connectionstatechange', e);
+                pc.dispatchEvent(newEvent);
+              }
+              return e;
+            };
+            this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly);
+          }
+          return origMethod.apply(this, arguments);
+        };
+      });
+    }
+    
+    function removeExtmapAllowMixed(window, browserDetails) {
+      /* remove a=extmap-allow-mixed for webrtc.org < M71 */
+      if (!window.RTCPeerConnection) {
+        return;
+      }
+      if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) {
+        return;
+      }
+      if (browserDetails.browser === 'safari' && browserDetails.version >= 605) {
+        return;
+      }
+      var nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription;
+      window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) {
+        if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) {
+          var sdp = desc.sdp.split('\n').filter(function (line) {
+            return line.trim() !== 'a=extmap-allow-mixed';
+          }).join('\n');
+          // Safari enforces read-only-ness of RTCSessionDescription fields.
+          if (window.RTCSessionDescription && desc instanceof window.RTCSessionDescription) {
+            arguments[0] = new window.RTCSessionDescription({
+              type: desc.type,
+              sdp: sdp
+            });
+          } else {
+            desc.sdp = sdp;
+          }
+        }
+        return nativeSRD.apply(this, arguments);
+      };
+    }
+    
+    function shimAddIceCandidateNullOrEmpty(window, browserDetails) {
+      // Support for addIceCandidate(null or undefined)
+      // as well as addIceCandidate({candidate: "", ...})
+      // https://bugs.chromium.org/p/chromium/issues/detail?id=978582
+      // Note: must be called before other polyfills which change the signature.
+      if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) {
+        return;
+      }
+      var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate;
+      if (!nativeAddIceCandidate || nativeAddIceCandidate.length === 0) {
+        return;
+      }
+      window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() {
+        if (!arguments[0]) {
+          if (arguments[1]) {
+            arguments[1].apply(null);
+          }
+          return Promise.resolve();
+        }
+        // Firefox 68+ emits and processes {candidate: "", ...}, ignore
+        // in older versions.
+        // Native support for ignoring exists for Chrome M77+.
+        // Safari ignores as well, exact version unknown but works in the same
+        // version that also ignores addIceCandidate(null).
+        if ((browserDetails.browser === 'chrome' && browserDetails.version < 78 || browserDetails.browser === 'firefox' && browserDetails.version < 68 || browserDetails.browser === 'safari') && arguments[0] && arguments[0].candidate === '') {
+          return Promise.resolve();
+        }
+        return nativeAddIceCandidate.apply(this, arguments);
+      };
+    }
+    
+    // Note: Make sure to call this ahead of APIs that modify
+    // setLocalDescription.length
+    function shimParameterlessSetLocalDescription(window, browserDetails) {
+      if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) {
+        return;
+      }
+      var nativeSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription;
+      if (!nativeSetLocalDescription || nativeSetLocalDescription.length === 0) {
+        return;
+      }
+      window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() {
+        var _this = this;
+    
+        var desc = arguments[0] || {};
+        if ((typeof desc === 'undefined' ? 'undefined' : _typeof(desc)) !== 'object' || desc.type && desc.sdp) {
+          return nativeSetLocalDescription.apply(this, arguments);
+        }
+        // The remaining steps should technically happen when SLD comes off the
+        // RTCPeerConnection's operations chain (not ahead of going on it), but
+        // this is too difficult to shim. Instead, this shim only covers the
+        // common case where the operations chain is empty. This is imperfect, but
+        // should cover many cases. Rationale: Even if we can't reduce the glare
+        // window to zero on imperfect implementations, there's value in tapping
+        // into the perfect negotiation pattern that several browsers support.
+        desc = { type: desc.type, sdp: desc.sdp };
+        if (!desc.type) {
+          switch (this.signalingState) {
+            case 'stable':
+            case 'have-local-offer':
+            case 'have-remote-pranswer':
+              desc.type = 'offer';
+              break;
+            default:
+              desc.type = 'answer';
+              break;
+          }
+        }
+        if (desc.sdp || desc.type !== 'offer' && desc.type !== 'answer') {
+          return nativeSetLocalDescription.apply(this, [desc]);
+        }
+        var func = desc.type === 'offer' ? this.createOffer : this.createAnswer;
+        return func.apply(this).then(function (d) {
+          return nativeSetLocalDescription.apply(_this, [d]);
+        });
+      };
+    }
+    
+    },{"./utils":11,"sdp":12}],7:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined;
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    var _getusermedia = require('./getusermedia');
+    
+    Object.defineProperty(exports, 'shimGetUserMedia', {
+      enumerable: true,
+      get: function get() {
+        return _getusermedia.shimGetUserMedia;
+      }
+    });
+    
+    var _getdisplaymedia = require('./getdisplaymedia');
+    
+    Object.defineProperty(exports, 'shimGetDisplayMedia', {
+      enumerable: true,
+      get: function get() {
+        return _getdisplaymedia.shimGetDisplayMedia;
+      }
+    });
+    exports.shimOnTrack = shimOnTrack;
+    exports.shimPeerConnection = shimPeerConnection;
+    exports.shimSenderGetStats = shimSenderGetStats;
+    exports.shimReceiverGetStats = shimReceiverGetStats;
+    exports.shimRemoveStream = shimRemoveStream;
+    exports.shimRTCDataChannel = shimRTCDataChannel;
+    exports.shimAddTransceiver = shimAddTransceiver;
+    exports.shimGetParameters = shimGetParameters;
+    exports.shimCreateOffer = shimCreateOffer;
+    exports.shimCreateAnswer = shimCreateAnswer;
+    
+    var _utils = require('../utils');
+    
+    var utils = _interopRequireWildcard(_utils);
+    
+    function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+    
+    function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+    
+    function shimOnTrack(window) {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) {
+        Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {
+          get: function get() {
+            return { receiver: this.receiver };
+          }
+        });
+      }
+    }
+    
+    function shimPeerConnection(window, browserDetails) {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) {
+        return; // probably media.peerconnection.enabled=false in about:config
+      }
+      if (!window.RTCPeerConnection && window.mozRTCPeerConnection) {
+        // very basic support for old versions.
+        window.RTCPeerConnection = window.mozRTCPeerConnection;
+      }
+    
+      if (browserDetails.version < 53) {
+        // shim away need for obsolete RTCIceCandidate/RTCSessionDescription.
+        ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) {
+          var nativeMethod = window.RTCPeerConnection.prototype[method];
+          var methodObj = _defineProperty({}, method, function () {
+            arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]);
+            return nativeMethod.apply(this, arguments);
+          });
+          window.RTCPeerConnection.prototype[method] = methodObj[method];
+        });
+      }
+    
+      var modernStatsTypes = {
+        inboundrtp: 'inbound-rtp',
+        outboundrtp: 'outbound-rtp',
+        candidatepair: 'candidate-pair',
+        localcandidate: 'local-candidate',
+        remotecandidate: 'remote-candidate'
+      };
+    
+      var nativeGetStats = window.RTCPeerConnection.prototype.getStats;
+      window.RTCPeerConnection.prototype.getStats = function getStats() {
+        var _arguments = Array.prototype.slice.call(arguments),
+            selector = _arguments[0],
+            onSucc = _arguments[1],
+            onErr = _arguments[2];
+    
+        return nativeGetStats.apply(this, [selector || null]).then(function (stats) {
+          if (browserDetails.version < 53 && !onSucc) {
+            // Shim only promise getStats with spec-hyphens in type names
+            // Leave callback version alone; misc old uses of forEach before Map
+            try {
+              stats.forEach(function (stat) {
+                stat.type = modernStatsTypes[stat.type] || stat.type;
+              });
+            } catch (e) {
+              if (e.name !== 'TypeError') {
+                throw e;
+              }
+              // Avoid TypeError: "type" is read-only, in old versions. 34-43ish
+              stats.forEach(function (stat, i) {
+                stats.set(i, Object.assign({}, stat, {
+                  type: modernStatsTypes[stat.type] || stat.type
+                }));
+              });
+            }
+          }
+          return stats;
+        }).then(onSucc, onErr);
+      };
+    }
+    
+    function shimSenderGetStats(window) {
+      if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) {
+        return;
+      }
+      if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) {
+        return;
+      }
+      var origGetSenders = window.RTCPeerConnection.prototype.getSenders;
+      if (origGetSenders) {
+        window.RTCPeerConnection.prototype.getSenders = function getSenders() {
+          var _this = this;
+    
+          var senders = origGetSenders.apply(this, []);
+          senders.forEach(function (sender) {
+            return sender._pc = _this;
+          });
+          return senders;
+        };
+      }
+    
+      var origAddTrack = window.RTCPeerConnection.prototype.addTrack;
+      if (origAddTrack) {
+        window.RTCPeerConnection.prototype.addTrack = function addTrack() {
+          var sender = origAddTrack.apply(this, arguments);
+          sender._pc = this;
+          return sender;
+        };
+      }
+      window.RTCRtpSender.prototype.getStats = function getStats() {
+        return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map());
+      };
+    }
+    
+    function shimReceiverGetStats(window) {
+      if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) {
+        return;
+      }
+      if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) {
+        return;
+      }
+      var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers;
+      if (origGetReceivers) {
+        window.RTCPeerConnection.prototype.getReceivers = function getReceivers() {
+          var _this2 = this;
+    
+          var receivers = origGetReceivers.apply(this, []);
+          receivers.forEach(function (receiver) {
+            return receiver._pc = _this2;
+          });
+          return receivers;
+        };
+      }
+      utils.wrapPeerConnectionEvent(window, 'track', function (e) {
+        e.receiver._pc = e.srcElement;
+        return e;
+      });
+      window.RTCRtpReceiver.prototype.getStats = function getStats() {
+        return this._pc.getStats(this.track);
+      };
+    }
+    
+    function shimRemoveStream(window) {
+      if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) {
+        return;
+      }
+      window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
+        var _this3 = this;
+    
+        utils.deprecated('removeStream', 'removeTrack');
+        this.getSenders().forEach(function (sender) {
+          if (sender.track && stream.getTracks().includes(sender.track)) {
+            _this3.removeTrack(sender);
+          }
+        });
+      };
+    }
+    
+    function shimRTCDataChannel(window) {
+      // rename DataChannel to RTCDataChannel (native fix in FF60):
+      // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851
+      if (window.DataChannel && !window.RTCDataChannel) {
+        window.RTCDataChannel = window.DataChannel;
+      }
+    }
+    
+    function shimAddTransceiver(window) {
+      // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647
+      // Firefox ignores the init sendEncodings options passed to addTransceiver
+      // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918
+      if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) {
+        return;
+      }
+      var origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver;
+      if (origAddTransceiver) {
+        window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() {
+          this.setParametersPromises = [];
+          var initParameters = arguments[1];
+          var shouldPerformCheck = initParameters && 'sendEncodings' in initParameters;
+          if (shouldPerformCheck) {
+            // If sendEncodings params are provided, validate grammar
+            initParameters.sendEncodings.forEach(function (encodingParam) {
+              if ('rid' in encodingParam) {
+                var ridRegex = /^[a-z0-9]{0,16}$/i;
+                if (!ridRegex.test(encodingParam.rid)) {
+                  throw new TypeError('Invalid RID value provided.');
+                }
+              }
+              if ('scaleResolutionDownBy' in encodingParam) {
+                if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) {
+                  throw new RangeError('scale_resolution_down_by must be >= 1.0');
+                }
+              }
+              if ('maxFramerate' in encodingParam) {
+                if (!(parseFloat(encodingParam.maxFramerate) >= 0)) {
+                  throw new RangeError('max_framerate must be >= 0.0');
+                }
+              }
+            });
+          }
+          var transceiver = origAddTransceiver.apply(this, arguments);
+          if (shouldPerformCheck) {
+            // Check if the init options were applied. If not we do this in an
+            // asynchronous way and save the promise reference in a global object.
+            // This is an ugly hack, but at the same time is way more robust than
+            // checking the sender parameters before and after the createOffer
+            // Also note that after the createoffer we are not 100% sure that
+            // the params were asynchronously applied so we might miss the
+            // opportunity to recreate offer.
+            var sender = transceiver.sender;
+    
+            var params = sender.getParameters();
+            if (!('encodings' in params) ||
+            // Avoid being fooled by patched getParameters() below.
+            params.encodings.length === 1 && Object.keys(params.encodings[0]).length === 0) {
+              params.encodings = initParameters.sendEncodings;
+              sender.sendEncodings = initParameters.sendEncodings;
+              this.setParametersPromises.push(sender.setParameters(params).then(function () {
+                delete sender.sendEncodings;
+              }).catch(function () {
+                delete sender.sendEncodings;
+              }));
+            }
+          }
+          return transceiver;
+        };
+      }
+    }
+    
+    function shimGetParameters(window) {
+      if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCRtpSender)) {
+        return;
+      }
+      var origGetParameters = window.RTCRtpSender.prototype.getParameters;
+      if (origGetParameters) {
+        window.RTCRtpSender.prototype.getParameters = function getParameters() {
+          var params = origGetParameters.apply(this, arguments);
+          if (!('encodings' in params)) {
+            params.encodings = [].concat(this.sendEncodings || [{}]);
+          }
+          return params;
+        };
+      }
+    }
+    
+    function shimCreateOffer(window) {
+      // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647
+      // Firefox ignores the init sendEncodings options passed to addTransceiver
+      // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918
+      if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) {
+        return;
+      }
+      var origCreateOffer = window.RTCPeerConnection.prototype.createOffer;
+      window.RTCPeerConnection.prototype.createOffer = function createOffer() {
+        var _this4 = this,
+            _arguments2 = arguments;
+    
+        if (this.setParametersPromises && this.setParametersPromises.length) {
+          return Promise.all(this.setParametersPromises).then(function () {
+            return origCreateOffer.apply(_this4, _arguments2);
+          }).finally(function () {
+            _this4.setParametersPromises = [];
+          });
+        }
+        return origCreateOffer.apply(this, arguments);
+      };
+    }
+    
+    function shimCreateAnswer(window) {
+      // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647
+      // Firefox ignores the init sendEncodings options passed to addTransceiver
+      // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918
+      if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) {
+        return;
+      }
+      var origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer;
+      window.RTCPeerConnection.prototype.createAnswer = function createAnswer() {
+        var _this5 = this,
+            _arguments3 = arguments;
+    
+        if (this.setParametersPromises && this.setParametersPromises.length) {
+          return Promise.all(this.setParametersPromises).then(function () {
+            return origCreateAnswer.apply(_this5, _arguments3);
+          }).finally(function () {
+            _this5.setParametersPromises = [];
+          });
+        }
+        return origCreateAnswer.apply(this, arguments);
+      };
+    }
+    
+    },{"../utils":11,"./getdisplaymedia":8,"./getusermedia":9}],8:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2018 The adapter.js project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    exports.shimGetDisplayMedia = shimGetDisplayMedia;
+    function shimGetDisplayMedia(window, preferredMediaSource) {
+      if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) {
+        return;
+      }
+      if (!window.navigator.mediaDevices) {
+        return;
+      }
+      window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) {
+        if (!(constraints && constraints.video)) {
+          var err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined');
+          err.name = 'NotFoundError';
+          // from https://heycam.github.io/webidl/#idl-DOMException-error-names
+          err.code = 8;
+          return Promise.reject(err);
+        }
+        if (constraints.video === true) {
+          constraints.video = { mediaSource: preferredMediaSource };
+        } else {
+          constraints.video.mediaSource = preferredMediaSource;
+        }
+        return window.navigator.mediaDevices.getUserMedia(constraints);
+      };
+    }
+    
+    },{}],9:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    exports.shimGetUserMedia = shimGetUserMedia;
+    
+    var _utils = require('../utils');
+    
+    var utils = _interopRequireWildcard(_utils);
+    
+    function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+    
+    function shimGetUserMedia(window, browserDetails) {
+      var navigator = window && window.navigator;
+      var MediaStreamTrack = window && window.MediaStreamTrack;
+    
+      navigator.getUserMedia = function (constraints, onSuccess, onError) {
+        // Replace Firefox 44+'s deprecation warning with unprefixed version.
+        utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia');
+        navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
+      };
+    
+      if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) {
+        var remap = function remap(obj, a, b) {
+          if (a in obj && !(b in obj)) {
+            obj[b] = obj[a];
+            delete obj[a];
+          }
+        };
+    
+        var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
+        navigator.mediaDevices.getUserMedia = function (c) {
+          if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object' && _typeof(c.audio) === 'object') {
+            c = JSON.parse(JSON.stringify(c));
+            remap(c.audio, 'autoGainControl', 'mozAutoGainControl');
+            remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression');
+          }
+          return nativeGetUserMedia(c);
+        };
+    
+        if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) {
+          var nativeGetSettings = MediaStreamTrack.prototype.getSettings;
+          MediaStreamTrack.prototype.getSettings = function () {
+            var obj = nativeGetSettings.apply(this, arguments);
+            remap(obj, 'mozAutoGainControl', 'autoGainControl');
+            remap(obj, 'mozNoiseSuppression', 'noiseSuppression');
+            return obj;
+          };
+        }
+    
+        if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) {
+          var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints;
+          MediaStreamTrack.prototype.applyConstraints = function (c) {
+            if (this.kind === 'audio' && (typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object') {
+              c = JSON.parse(JSON.stringify(c));
+              remap(c, 'autoGainControl', 'mozAutoGainControl');
+              remap(c, 'noiseSuppression', 'mozNoiseSuppression');
+            }
+            return nativeApplyConstraints.apply(this, [c]);
+          };
+        }
+      }
+    }
+    
+    },{"../utils":11}],10:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    exports.shimLocalStreamsAPI = shimLocalStreamsAPI;
+    exports.shimRemoteStreamsAPI = shimRemoteStreamsAPI;
+    exports.shimCallbacksAPI = shimCallbacksAPI;
+    exports.shimGetUserMedia = shimGetUserMedia;
+    exports.shimConstraints = shimConstraints;
+    exports.shimRTCIceServerUrls = shimRTCIceServerUrls;
+    exports.shimTrackEventTransceiver = shimTrackEventTransceiver;
+    exports.shimCreateOfferLegacy = shimCreateOfferLegacy;
+    exports.shimAudioContext = shimAudioContext;
+    
+    var _utils = require('../utils');
+    
+    var utils = _interopRequireWildcard(_utils);
+    
+    function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+    
+    function shimLocalStreamsAPI(window) {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) {
+        return;
+      }
+      if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) {
+        window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() {
+          if (!this._localStreams) {
+            this._localStreams = [];
+          }
+          return this._localStreams;
+        };
+      }
+      if (!('addStream' in window.RTCPeerConnection.prototype)) {
+        var _addTrack = window.RTCPeerConnection.prototype.addTrack;
+        window.RTCPeerConnection.prototype.addStream = function addStream(stream) {
+          var _this = this;
+    
+          if (!this._localStreams) {
+            this._localStreams = [];
+          }
+          if (!this._localStreams.includes(stream)) {
+            this._localStreams.push(stream);
+          }
+          // Try to emulate Chrome's behaviour of adding in audio-video order.
+          // Safari orders by track id.
+          stream.getAudioTracks().forEach(function (track) {
+            return _addTrack.call(_this, track, stream);
+          });
+          stream.getVideoTracks().forEach(function (track) {
+            return _addTrack.call(_this, track, stream);
+          });
+        };
+    
+        window.RTCPeerConnection.prototype.addTrack = function addTrack(track) {
+          var _this2 = this;
+    
+          for (var _len = arguments.length, streams = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+            streams[_key - 1] = arguments[_key];
+          }
+    
+          if (streams) {
+            streams.forEach(function (stream) {
+              if (!_this2._localStreams) {
+                _this2._localStreams = [stream];
+              } else if (!_this2._localStreams.includes(stream)) {
+                _this2._localStreams.push(stream);
+              }
+            });
+          }
+          return _addTrack.apply(this, arguments);
+        };
+      }
+      if (!('removeStream' in window.RTCPeerConnection.prototype)) {
+        window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
+          var _this3 = this;
+    
+          if (!this._localStreams) {
+            this._localStreams = [];
+          }
+          var index = this._localStreams.indexOf(stream);
+          if (index === -1) {
+            return;
+          }
+          this._localStreams.splice(index, 1);
+          var tracks = stream.getTracks();
+          this.getSenders().forEach(function (sender) {
+            if (tracks.includes(sender.track)) {
+              _this3.removeTrack(sender);
+            }
+          });
+        };
+      }
+    }
+    
+    function shimRemoteStreamsAPI(window) {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) {
+        return;
+      }
+      if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) {
+        window.RTCPeerConnection.prototype.getRemoteStreams = function getRemoteStreams() {
+          return this._remoteStreams ? this._remoteStreams : [];
+        };
+      }
+      if (!('onaddstream' in window.RTCPeerConnection.prototype)) {
+        Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', {
+          get: function get() {
+            return this._onaddstream;
+          },
+          set: function set(f) {
+            var _this4 = this;
+    
+            if (this._onaddstream) {
+              this.removeEventListener('addstream', this._onaddstream);
+              this.removeEventListener('track', this._onaddstreampoly);
+            }
+            this.addEventListener('addstream', this._onaddstream = f);
+            this.addEventListener('track', this._onaddstreampoly = function (e) {
+              e.streams.forEach(function (stream) {
+                if (!_this4._remoteStreams) {
+                  _this4._remoteStreams = [];
+                }
+                if (_this4._remoteStreams.includes(stream)) {
+                  return;
+                }
+                _this4._remoteStreams.push(stream);
+                var event = new Event('addstream');
+                event.stream = stream;
+                _this4.dispatchEvent(event);
+              });
+            });
+          }
+        });
+        var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription;
+        window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() {
+          var pc = this;
+          if (!this._onaddstreampoly) {
+            this.addEventListener('track', this._onaddstreampoly = function (e) {
+              e.streams.forEach(function (stream) {
+                if (!pc._remoteStreams) {
+                  pc._remoteStreams = [];
+                }
+                if (pc._remoteStreams.indexOf(stream) >= 0) {
+                  return;
+                }
+                pc._remoteStreams.push(stream);
+                var event = new Event('addstream');
+                event.stream = stream;
+                pc.dispatchEvent(event);
+              });
+            });
+          }
+          return origSetRemoteDescription.apply(pc, arguments);
+        };
+      }
+    }
+    
+    function shimCallbacksAPI(window) {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) {
+        return;
+      }
+      var prototype = window.RTCPeerConnection.prototype;
+      var origCreateOffer = prototype.createOffer;
+      var origCreateAnswer = prototype.createAnswer;
+      var setLocalDescription = prototype.setLocalDescription;
+      var setRemoteDescription = prototype.setRemoteDescription;
+      var addIceCandidate = prototype.addIceCandidate;
+    
+      prototype.createOffer = function createOffer(successCallback, failureCallback) {
+        var options = arguments.length >= 2 ? arguments[2] : arguments[0];
+        var promise = origCreateOffer.apply(this, [options]);
+        if (!failureCallback) {
+          return promise;
+        }
+        promise.then(successCallback, failureCallback);
+        return Promise.resolve();
+      };
+    
+      prototype.createAnswer = function createAnswer(successCallback, failureCallback) {
+        var options = arguments.length >= 2 ? arguments[2] : arguments[0];
+        var promise = origCreateAnswer.apply(this, [options]);
+        if (!failureCallback) {
+          return promise;
+        }
+        promise.then(successCallback, failureCallback);
+        return Promise.resolve();
+      };
+    
+      var withCallback = function withCallback(description, successCallback, failureCallback) {
+        var promise = setLocalDescription.apply(this, [description]);
+        if (!failureCallback) {
+          return promise;
+        }
+        promise.then(successCallback, failureCallback);
+        return Promise.resolve();
+      };
+      prototype.setLocalDescription = withCallback;
+    
+      withCallback = function withCallback(description, successCallback, failureCallback) {
+        var promise = setRemoteDescription.apply(this, [description]);
+        if (!failureCallback) {
+          return promise;
+        }
+        promise.then(successCallback, failureCallback);
+        return Promise.resolve();
+      };
+      prototype.setRemoteDescription = withCallback;
+    
+      withCallback = function withCallback(candidate, successCallback, failureCallback) {
+        var promise = addIceCandidate.apply(this, [candidate]);
+        if (!failureCallback) {
+          return promise;
+        }
+        promise.then(successCallback, failureCallback);
+        return Promise.resolve();
+      };
+      prototype.addIceCandidate = withCallback;
+    }
+    
+    function shimGetUserMedia(window) {
+      var navigator = window && window.navigator;
+    
+      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
+        // shim not needed in Safari 12.1
+        var mediaDevices = navigator.mediaDevices;
+        var _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices);
+        navigator.mediaDevices.getUserMedia = function (constraints) {
+          return _getUserMedia(shimConstraints(constraints));
+        };
+      }
+    
+      if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
+        navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) {
+          navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb);
+        }.bind(navigator);
+      }
+    }
+    
+    function shimConstraints(constraints) {
+      if (constraints && constraints.video !== undefined) {
+        return Object.assign({}, constraints, { video: utils.compactObject(constraints.video) });
+      }
+    
+      return constraints;
+    }
+    
+    function shimRTCIceServerUrls(window) {
+      if (!window.RTCPeerConnection) {
+        return;
+      }
+      // migrate from non-spec RTCIceServer.url to RTCIceServer.urls
+      var OrigPeerConnection = window.RTCPeerConnection;
+      window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) {
+        if (pcConfig && pcConfig.iceServers) {
+          var newIceServers = [];
+          for (var i = 0; i < pcConfig.iceServers.length; i++) {
+            var server = pcConfig.iceServers[i];
+            if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) {
+              utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls');
+              server = JSON.parse(JSON.stringify(server));
+              server.urls = server.url;
+              delete server.url;
+              newIceServers.push(server);
+            } else {
+              newIceServers.push(pcConfig.iceServers[i]);
+            }
+          }
+          pcConfig.iceServers = newIceServers;
+        }
+        return new OrigPeerConnection(pcConfig, pcConstraints);
+      };
+      window.RTCPeerConnection.prototype = OrigPeerConnection.prototype;
+      // wrap static methods. Currently just generateCertificate.
+      if ('generateCertificate' in OrigPeerConnection) {
+        Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', {
+          get: function get() {
+            return OrigPeerConnection.generateCertificate;
+          }
+        });
+      }
+    }
+    
+    function shimTrackEventTransceiver(window) {
+      // Add event.transceiver member over deprecated event.receiver
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) {
+        Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', {
+          get: function get() {
+            return { receiver: this.receiver };
+          }
+        });
+      }
+    }
+    
+    function shimCreateOfferLegacy(window) {
+      var origCreateOffer = window.RTCPeerConnection.prototype.createOffer;
+      window.RTCPeerConnection.prototype.createOffer = function createOffer(offerOptions) {
+        if (offerOptions) {
+          if (typeof offerOptions.offerToReceiveAudio !== 'undefined') {
+            // support bit values
+            offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio;
+          }
+          var audioTransceiver = this.getTransceivers().find(function (transceiver) {
+            return transceiver.receiver.track.kind === 'audio';
+          });
+          if (offerOptions.offerToReceiveAudio === false && audioTransceiver) {
+            if (audioTransceiver.direction === 'sendrecv') {
+              if (audioTransceiver.setDirection) {
+                audioTransceiver.setDirection('sendonly');
+              } else {
+                audioTransceiver.direction = 'sendonly';
+              }
+            } else if (audioTransceiver.direction === 'recvonly') {
+              if (audioTransceiver.setDirection) {
+                audioTransceiver.setDirection('inactive');
+              } else {
+                audioTransceiver.direction = 'inactive';
+              }
+            }
+          } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) {
+            this.addTransceiver('audio');
+          }
+    
+          if (typeof offerOptions.offerToReceiveVideo !== 'undefined') {
+            // support bit values
+            offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo;
+          }
+          var videoTransceiver = this.getTransceivers().find(function (transceiver) {
+            return transceiver.receiver.track.kind === 'video';
+          });
+          if (offerOptions.offerToReceiveVideo === false && videoTransceiver) {
+            if (videoTransceiver.direction === 'sendrecv') {
+              if (videoTransceiver.setDirection) {
+                videoTransceiver.setDirection('sendonly');
+              } else {
+                videoTransceiver.direction = 'sendonly';
+              }
+            } else if (videoTransceiver.direction === 'recvonly') {
+              if (videoTransceiver.setDirection) {
+                videoTransceiver.setDirection('inactive');
+              } else {
+                videoTransceiver.direction = 'inactive';
+              }
+            }
+          } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) {
+            this.addTransceiver('video');
+          }
+        }
+        return origCreateOffer.apply(this, arguments);
+      };
+    }
+    
+    function shimAudioContext(window) {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || window.AudioContext) {
+        return;
+      }
+      window.AudioContext = window.webkitAudioContext;
+    }
+    
+    },{"../utils":11}],11:[function(require,module,exports){
+    /*
+     *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+     *
+     *  Use of this source code is governed by a BSD-style license
+     *  that can be found in the LICENSE file in the root of the source
+     *  tree.
+     */
+    /* eslint-env node */
+    'use strict';
+    
+    Object.defineProperty(exports, "__esModule", {
+      value: true
+    });
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    exports.extractVersion = extractVersion;
+    exports.wrapPeerConnectionEvent = wrapPeerConnectionEvent;
+    exports.disableLog = disableLog;
+    exports.disableWarnings = disableWarnings;
+    exports.log = log;
+    exports.deprecated = deprecated;
+    exports.detectBrowser = detectBrowser;
+    exports.compactObject = compactObject;
+    exports.walkStats = walkStats;
+    exports.filterStats = filterStats;
+    
+    function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+    
+    var logDisabled_ = true;
+    var deprecationWarnings_ = true;
+    
+    /**
+     * Extract browser version out of the provided user agent string.
+     *
+     * @param {!string} uastring userAgent string.
+     * @param {!string} expr Regular expression used as match criteria.
+     * @param {!number} pos position in the version string to be returned.
+     * @return {!number} browser version.
+     */
+    function extractVersion(uastring, expr, pos) {
+      var match = uastring.match(expr);
+      return match && match.length >= pos && parseInt(match[pos], 10);
+    }
+    
+    // Wraps the peerconnection event eventNameToWrap in a function
+    // which returns the modified event object (or false to prevent
+    // the event).
+    function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) {
+      if (!window.RTCPeerConnection) {
+        return;
+      }
+      var proto = window.RTCPeerConnection.prototype;
+      var nativeAddEventListener = proto.addEventListener;
+      proto.addEventListener = function (nativeEventName, cb) {
+        if (nativeEventName !== eventNameToWrap) {
+          return nativeAddEventListener.apply(this, arguments);
+        }
+        var wrappedCallback = function wrappedCallback(e) {
+          var modifiedEvent = wrapper(e);
+          if (modifiedEvent) {
+            if (cb.handleEvent) {
+              cb.handleEvent(modifiedEvent);
+            } else {
+              cb(modifiedEvent);
+            }
+          }
+        };
+        this._eventMap = this._eventMap || {};
+        if (!this._eventMap[eventNameToWrap]) {
+          this._eventMap[eventNameToWrap] = new Map();
+        }
+        this._eventMap[eventNameToWrap].set(cb, wrappedCallback);
+        return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]);
+      };
+    
+      var nativeRemoveEventListener = proto.removeEventListener;
+      proto.removeEventListener = function (nativeEventName, cb) {
+        if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[eventNameToWrap]) {
+          return nativeRemoveEventListener.apply(this, arguments);
+        }
+        if (!this._eventMap[eventNameToWrap].has(cb)) {
+          return nativeRemoveEventListener.apply(this, arguments);
+        }
+        var unwrappedCb = this._eventMap[eventNameToWrap].get(cb);
+        this._eventMap[eventNameToWrap].delete(cb);
+        if (this._eventMap[eventNameToWrap].size === 0) {
+          delete this._eventMap[eventNameToWrap];
+        }
+        if (Object.keys(this._eventMap).length === 0) {
+          delete this._eventMap;
+        }
+        return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]);
+      };
+    
+      Object.defineProperty(proto, 'on' + eventNameToWrap, {
+        get: function get() {
+          return this['_on' + eventNameToWrap];
+        },
+        set: function set(cb) {
+          if (this['_on' + eventNameToWrap]) {
+            this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]);
+            delete this['_on' + eventNameToWrap];
+          }
+          if (cb) {
+            this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb);
+          }
+        },
+    
+        enumerable: true,
+        configurable: true
+      });
+    }
+    
+    function disableLog(bool) {
+      if (typeof bool !== 'boolean') {
+        return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.');
+      }
+      logDisabled_ = bool;
+      return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled';
+    }
+    
+    /**
+     * Disable or enable deprecation warnings
+     * @param {!boolean} bool set to true to disable warnings.
+     */
+    function disableWarnings(bool) {
+      if (typeof bool !== 'boolean') {
+        return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.');
+      }
+      deprecationWarnings_ = !bool;
+      return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled');
+    }
+    
+    function log() {
+      if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') {
+        if (logDisabled_) {
+          return;
+        }
+        if (typeof console !== 'undefined' && typeof console.log === 'function') {
+          console.log.apply(console, arguments);
+        }
+      }
+    }
+    
+    /**
+     * Shows a deprecation warning suggesting the modern and spec-compatible API.
+     */
+    function deprecated(oldMethod, newMethod) {
+      if (!deprecationWarnings_) {
+        return;
+      }
+      console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.');
+    }
+    
+    /**
+     * Browser detector.
+     *
+     * @return {object} result containing browser and version
+     *     properties.
+     */
+    function detectBrowser(window) {
+      // Returned result object.
+      var result = { browser: null, version: null };
+    
+      // Fail early if it's not a browser
+      if (typeof window === 'undefined' || !window.navigator) {
+        result.browser = 'Not a browser.';
+        return result;
+      }
+    
+      var navigator = window.navigator;
+    
+    
+      if (navigator.mozGetUserMedia) {
+        // Firefox.
+        result.browser = 'firefox';
+        result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1);
+      } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection && !window.RTCIceGatherer) {
+        // Chrome, Chromium, Webview, Opera.
+        // Version matches Chrome/WebRTC version.
+        // Chrome 74 removed webkitGetUserMedia on http as well so we need the
+        // more complicated fallback to webkitRTCPeerConnection.
+        result.browser = 'chrome';
+        result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2);
+      } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) {
+        // Safari.
+        result.browser = 'safari';
+        result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1);
+        result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype;
+      } else {
+        // Default fallthrough: not supported.
+        result.browser = 'Not a supported browser.';
+        return result;
+      }
+    
+      return result;
+    }
+    
+    /**
+     * Checks if something is an object.
+     *
+     * @param {*} val The something you want to check.
+     * @return true if val is an object, false otherwise.
+     */
+    function isObject(val) {
+      return Object.prototype.toString.call(val) === '[object Object]';
+    }
+    
+    /**
+     * Remove all empty objects and undefined values
+     * from a nested object -- an enhanced and vanilla version
+     * of Lodash's `compact`.
+     */
+    function compactObject(data) {
+      if (!isObject(data)) {
+        return data;
+      }
+    
+      return Object.keys(data).reduce(function (accumulator, key) {
+        var isObj = isObject(data[key]);
+        var value = isObj ? compactObject(data[key]) : data[key];
+        var isEmptyObject = isObj && !Object.keys(value).length;
+        if (value === undefined || isEmptyObject) {
+          return accumulator;
+        }
+        return Object.assign(accumulator, _defineProperty({}, key, value));
+      }, {});
+    }
+    
+    /* iterates the stats graph recursively. */
+    function walkStats(stats, base, resultSet) {
+      if (!base || resultSet.has(base.id)) {
+        return;
+      }
+      resultSet.set(base.id, base);
+      Object.keys(base).forEach(function (name) {
+        if (name.endsWith('Id')) {
+          walkStats(stats, stats.get(base[name]), resultSet);
+        } else if (name.endsWith('Ids')) {
+          base[name].forEach(function (id) {
+            walkStats(stats, stats.get(id), resultSet);
+          });
+        }
+      });
+    }
+    
+    /* filter getStats for a sender/receiver track. */
+    function filterStats(result, track, outbound) {
+      var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp';
+      var filteredResult = new Map();
+      if (track === null) {
+        return filteredResult;
+      }
+      var trackStats = [];
+      result.forEach(function (value) {
+        if (value.type === 'track' && value.trackIdentifier === track.id) {
+          trackStats.push(value);
+        }
+      });
+      trackStats.forEach(function (trackStat) {
+        result.forEach(function (stats) {
+          if (stats.type === streamStatsType && stats.trackId === trackStat.id) {
+            walkStats(result, stats, filteredResult);
+          }
+        });
+      });
+      return filteredResult;
+    }
+    
+    },{}],12:[function(require,module,exports){
+    /* eslint-env node */
+    'use strict';
+    
+    // SDP helpers.
+    
+    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
+    
+    var SDPUtils = {};
+    
+    // Generate an alphanumeric identifier for cname or mids.
+    // TODO: use UUIDs instead? https://gist.github.com/jed/982883
+    SDPUtils.generateIdentifier = function () {
+      return Math.random().toString(36).substr(2, 10);
+    };
+    
+    // The RTCP CNAME used by all peerconnections from the same JS.
+    SDPUtils.localCName = SDPUtils.generateIdentifier();
+    
+    // Splits SDP into lines, dealing with both CRLF and LF.
+    SDPUtils.splitLines = function (blob) {
+      return blob.trim().split('\n').map(function (line) {
+        return line.trim();
+      });
+    };
+    // Splits SDP into sessionpart and mediasections. Ensures CRLF.
+    SDPUtils.splitSections = function (blob) {
+      var parts = blob.split('\nm=');
+      return parts.map(function (part, index) {
+        return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
+      });
+    };
+    
+    // Returns the session description.
+    SDPUtils.getDescription = function (blob) {
+      var sections = SDPUtils.splitSections(blob);
+      return sections && sections[0];
+    };
+    
+    // Returns the individual media sections.
+    SDPUtils.getMediaSections = function (blob) {
+      var sections = SDPUtils.splitSections(blob);
+      sections.shift();
+      return sections;
+    };
+    
+    // Returns lines that start with a certain prefix.
+    SDPUtils.matchPrefix = function (blob, prefix) {
+      return SDPUtils.splitLines(blob).filter(function (line) {
+        return line.indexOf(prefix) === 0;
+      });
+    };
+    
+    // Parses an ICE candidate line. Sample input:
+    // candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
+    // rport 55996"
+    // Input can be prefixed with a=.
+    SDPUtils.parseCandidate = function (line) {
+      var parts = void 0;
+      // Parse both variants.
+      if (line.indexOf('a=candidate:') === 0) {
+        parts = line.substring(12).split(' ');
+      } else {
+        parts = line.substring(10).split(' ');
+      }
+    
+      var candidate = {
+        foundation: parts[0],
+        component: { 1: 'rtp', 2: 'rtcp' }[parts[1]] || parts[1],
+        protocol: parts[2].toLowerCase(),
+        priority: parseInt(parts[3], 10),
+        ip: parts[4],
+        address: parts[4], // address is an alias for ip.
+        port: parseInt(parts[5], 10),
+        // skip parts[6] == 'typ'
+        type: parts[7]
+      };
+    
+      for (var i = 8; i < parts.length; i += 2) {
+        switch (parts[i]) {
+          case 'raddr':
+            candidate.relatedAddress = parts[i + 1];
+            break;
+          case 'rport':
+            candidate.relatedPort = parseInt(parts[i + 1], 10);
+            break;
+          case 'tcptype':
+            candidate.tcpType = parts[i + 1];
+            break;
+          case 'ufrag':
+            candidate.ufrag = parts[i + 1]; // for backward compatibility.
+            candidate.usernameFragment = parts[i + 1];
+            break;
+          default:
+            // extension handling, in particular ufrag. Don't overwrite.
+            if (candidate[parts[i]] === undefined) {
+              candidate[parts[i]] = parts[i + 1];
+            }
+            break;
+        }
+      }
+      return candidate;
+    };
+    
+    // Translates a candidate object into SDP candidate attribute.
+    // This does not include the a= prefix!
+    SDPUtils.writeCandidate = function (candidate) {
+      var sdp = [];
+      sdp.push(candidate.foundation);
+    
+      var component = candidate.component;
+      if (component === 'rtp') {
+        sdp.push(1);
+      } else if (component === 'rtcp') {
+        sdp.push(2);
+      } else {
+        sdp.push(component);
+      }
+      sdp.push(candidate.protocol.toUpperCase());
+      sdp.push(candidate.priority);
+      sdp.push(candidate.address || candidate.ip);
+      sdp.push(candidate.port);
+    
+      var type = candidate.type;
+      sdp.push('typ');
+      sdp.push(type);
+      if (type !== 'host' && candidate.relatedAddress && candidate.relatedPort) {
+        sdp.push('raddr');
+        sdp.push(candidate.relatedAddress);
+        sdp.push('rport');
+        sdp.push(candidate.relatedPort);
+      }
+      if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
+        sdp.push('tcptype');
+        sdp.push(candidate.tcpType);
+      }
+      if (candidate.usernameFragment || candidate.ufrag) {
+        sdp.push('ufrag');
+        sdp.push(candidate.usernameFragment || candidate.ufrag);
+      }
+      return 'candidate:' + sdp.join(' ');
+    };
+    
+    // Parses an ice-options line, returns an array of option tags.
+    // Sample input:
+    // a=ice-options:foo bar
+    SDPUtils.parseIceOptions = function (line) {
+      return line.substr(14).split(' ');
+    };
+    
+    // Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input:
+    // a=rtpmap:111 opus/48000/2
+    SDPUtils.parseRtpMap = function (line) {
+      var parts = line.substr(9).split(' ');
+      var parsed = {
+        payloadType: parseInt(parts.shift(), 10) // was: id
+      };
+    
+      parts = parts[0].split('/');
+    
+      parsed.name = parts[0];
+      parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
+      parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1;
+      // legacy alias, got renamed back to channels in ORTC.
+      parsed.numChannels = parsed.channels;
+      return parsed;
+    };
+    
+    // Generates a rtpmap line from RTCRtpCodecCapability or
+    // RTCRtpCodecParameters.
+    SDPUtils.writeRtpMap = function (codec) {
+      var pt = codec.payloadType;
+      if (codec.preferredPayloadType !== undefined) {
+        pt = codec.preferredPayloadType;
+      }
+      var channels = codec.channels || codec.numChannels || 1;
+      return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + (channels !== 1 ? '/' + channels : '') + '\r\n';
+    };
+    
+    // Parses a extmap line (headerextension from RFC 5285). Sample input:
+    // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+    // a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset
+    SDPUtils.parseExtmap = function (line) {
+      var parts = line.substr(9).split(' ');
+      return {
+        id: parseInt(parts[0], 10),
+        direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',
+        uri: parts[1]
+      };
+    };
+    
+    // Generates an extmap line from RTCRtpHeaderExtensionParameters or
+    // RTCRtpHeaderExtension.
+    SDPUtils.writeExtmap = function (headerExtension) {
+      return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + (headerExtension.direction && headerExtension.direction !== 'sendrecv' ? '/' + headerExtension.direction : '') + ' ' + headerExtension.uri + '\r\n';
+    };
+    
+    // Parses a fmtp line, returns dictionary. Sample input:
+    // a=fmtp:96 vbr=on;cng=on
+    // Also deals with vbr=on; cng=on
+    SDPUtils.parseFmtp = function (line) {
+      var parsed = {};
+      var kv = void 0;
+      var parts = line.substr(line.indexOf(' ') + 1).split(';');
+      for (var j = 0; j < parts.length; j++) {
+        kv = parts[j].trim().split('=');
+        parsed[kv[0].trim()] = kv[1];
+      }
+      return parsed;
+    };
+    
+    // Generates a fmtp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
+    SDPUtils.writeFmtp = function (codec) {
+      var line = '';
+      var pt = codec.payloadType;
+      if (codec.preferredPayloadType !== undefined) {
+        pt = codec.preferredPayloadType;
+      }
+      if (codec.parameters && Object.keys(codec.parameters).length) {
+        var params = [];
+        Object.keys(codec.parameters).forEach(function (param) {
+          if (codec.parameters[param] !== undefined) {
+            params.push(param + '=' + codec.parameters[param]);
+          } else {
+            params.push(param);
+          }
+        });
+        line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
+      }
+      return line;
+    };
+    
+    // Parses a rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
+    // a=rtcp-fb:98 nack rpsi
+    SDPUtils.parseRtcpFb = function (line) {
+      var parts = line.substr(line.indexOf(' ') + 1).split(' ');
+      return {
+        type: parts.shift(),
+        parameter: parts.join(' ')
+      };
+    };
+    
+    // Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
+    SDPUtils.writeRtcpFb = function (codec) {
+      var lines = '';
+      var pt = codec.payloadType;
+      if (codec.preferredPayloadType !== undefined) {
+        pt = codec.preferredPayloadType;
+      }
+      if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
+        // FIXME: special handling for trr-int?
+        codec.rtcpFeedback.forEach(function (fb) {
+          lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + '\r\n';
+        });
+      }
+      return lines;
+    };
+    
+    // Parses a RFC 5576 ssrc media attribute. Sample input:
+    // a=ssrc:3735928559 cname:something
+    SDPUtils.parseSsrcMedia = function (line) {
+      var sp = line.indexOf(' ');
+      var parts = {
+        ssrc: parseInt(line.substr(7, sp - 7), 10)
+      };
+      var colon = line.indexOf(':', sp);
+      if (colon > -1) {
+        parts.attribute = line.substr(sp + 1, colon - sp - 1);
+        parts.value = line.substr(colon + 1);
+      } else {
+        parts.attribute = line.substr(sp + 1);
+      }
+      return parts;
+    };
+    
+    // Parse a ssrc-group line (see RFC 5576). Sample input:
+    // a=ssrc-group:semantics 12 34
+    SDPUtils.parseSsrcGroup = function (line) {
+      var parts = line.substr(13).split(' ');
+      return {
+        semantics: parts.shift(),
+        ssrcs: parts.map(function (ssrc) {
+          return parseInt(ssrc, 10);
+        })
+      };
+    };
+    
+    // Extracts the MID (RFC 5888) from a media section.
+    // Returns the MID or undefined if no mid line was found.
+    SDPUtils.getMid = function (mediaSection) {
+      var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];
+      if (mid) {
+        return mid.substr(6);
+      }
+    };
+    
+    // Parses a fingerprint line for DTLS-SRTP.
+    SDPUtils.parseFingerprint = function (line) {
+      var parts = line.substr(14).split(' ');
+      return {
+        algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.
+        value: parts[1].toUpperCase() // the definition is upper-case in RFC 4572.
+      };
+    };
+    
+    // Extracts DTLS parameters from SDP media section or sessionpart.
+    // FIXME: for consistency with other functions this should only
+    //   get the fingerprint line as input. See also getIceParameters.
+    SDPUtils.getDtlsParameters = function (mediaSection, sessionpart) {
+      var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=fingerprint:');
+      // Note: a=setup line is ignored since we use the 'auto' role in Edge.
+      return {
+        role: 'auto',
+        fingerprints: lines.map(SDPUtils.parseFingerprint)
+      };
+    };
+    
+    // Serializes DTLS parameters to SDP.
+    SDPUtils.writeDtlsParameters = function (params, setupType) {
+      var sdp = 'a=setup:' + setupType + '\r\n';
+      params.fingerprints.forEach(function (fp) {
+        sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
+      });
+      return sdp;
+    };
+    
+    // Parses a=crypto lines into
+    //   https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members
+    SDPUtils.parseCryptoLine = function (line) {
+      var parts = line.substr(9).split(' ');
+      return {
+        tag: parseInt(parts[0], 10),
+        cryptoSuite: parts[1],
+        keyParams: parts[2],
+        sessionParams: parts.slice(3)
+      };
+    };
+    
+    SDPUtils.writeCryptoLine = function (parameters) {
+      return 'a=crypto:' + parameters.tag + ' ' + parameters.cryptoSuite + ' ' + (_typeof(parameters.keyParams) === 'object' ? SDPUtils.writeCryptoKeyParams(parameters.keyParams) : parameters.keyParams) + (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') + '\r\n';
+    };
+    
+    // Parses the crypto key parameters into
+    //   https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam*
+    SDPUtils.parseCryptoKeyParams = function (keyParams) {
+      if (keyParams.indexOf('inline:') !== 0) {
+        return null;
+      }
+      var parts = keyParams.substr(7).split('|');
+      return {
+        keyMethod: 'inline',
+        keySalt: parts[0],
+        lifeTime: parts[1],
+        mkiValue: parts[2] ? parts[2].split(':')[0] : undefined,
+        mkiLength: parts[2] ? parts[2].split(':')[1] : undefined
+      };
+    };
+    
+    SDPUtils.writeCryptoKeyParams = function (keyParams) {
+      return keyParams.keyMethod + ':' + keyParams.keySalt + (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') + (keyParams.mkiValue && keyParams.mkiLength ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength : '');
+    };
+    
+    // Extracts all SDES parameters.
+    SDPUtils.getCryptoParameters = function (mediaSection, sessionpart) {
+      var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=crypto:');
+      return lines.map(SDPUtils.parseCryptoLine);
+    };
+    
+    // Parses ICE information from SDP media section or sessionpart.
+    // FIXME: for consistency with other functions this should only
+    //   get the ice-ufrag and ice-pwd lines as input.
+    SDPUtils.getIceParameters = function (mediaSection, sessionpart) {
+      var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-ufrag:')[0];
+      var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-pwd:')[0];
+      if (!(ufrag && pwd)) {
+        return null;
+      }
+      return {
+        usernameFragment: ufrag.substr(12),
+        password: pwd.substr(10)
+      };
+    };
+    
+    // Serializes ICE parameters to SDP.
+    SDPUtils.writeIceParameters = function (params) {
+      var sdp = 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + 'a=ice-pwd:' + params.password + '\r\n';
+      if (params.iceLite) {
+        sdp += 'a=ice-lite\r\n';
+      }
+      return sdp;
+    };
+    
+    // Parses the SDP media section and returns RTCRtpParameters.
+    SDPUtils.parseRtpParameters = function (mediaSection) {
+      var description = {
+        codecs: [],
+        headerExtensions: [],
+        fecMechanisms: [],
+        rtcp: []
+      };
+      var lines = SDPUtils.splitLines(mediaSection);
+      var mline = lines[0].split(' ');
+      for (var i = 3; i < mline.length; i++) {
+        // find all codecs from mline[3..]
+        var pt = mline[i];
+        var rtpmapline = SDPUtils.matchPrefix(mediaSection, 'a=rtpmap:' + pt + ' ')[0];
+        if (rtpmapline) {
+          var codec = SDPUtils.parseRtpMap(rtpmapline);
+          var fmtps = SDPUtils.matchPrefix(mediaSection, 'a=fmtp:' + pt + ' ');
+          // Only the first a=fmtp:<pt> is considered.
+          codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
+          codec.rtcpFeedback = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:' + pt + ' ').map(SDPUtils.parseRtcpFb);
+          description.codecs.push(codec);
+          // parse FEC mechanisms from rtpmap lines.
+          switch (codec.name.toUpperCase()) {
+            case 'RED':
+            case 'ULPFEC':
+              description.fecMechanisms.push(codec.name.toUpperCase());
+              break;
+            default:
+              // only RED and ULPFEC are recognized as FEC mechanisms.
+              break;
+          }
+        }
+      }
+      SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function (line) {
+        description.headerExtensions.push(SDPUtils.parseExtmap(line));
+      });
+      // FIXME: parse rtcp.
+      return description;
+    };
+    
+    // Generates parts of the SDP media section describing the capabilities /
+    // parameters.
+    SDPUtils.writeRtpDescription = function (kind, caps) {
+      var sdp = '';
+    
+      // Build the mline.
+      sdp += 'm=' + kind + ' ';
+      sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
+      sdp += ' UDP/TLS/RTP/SAVPF ';
+      sdp += caps.codecs.map(function (codec) {
+        if (codec.preferredPayloadType !== undefined) {
+          return codec.preferredPayloadType;
+        }
+        return codec.payloadType;
+      }).join(' ') + '\r\n';
+    
+      sdp += 'c=IN IP4 0.0.0.0\r\n';
+      sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';
+    
+      // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
+      caps.codecs.forEach(function (codec) {
+        sdp += SDPUtils.writeRtpMap(codec);
+        sdp += SDPUtils.writeFmtp(codec);
+        sdp += SDPUtils.writeRtcpFb(codec);
+      });
+      var maxptime = 0;
+      caps.codecs.forEach(function (codec) {
+        if (codec.maxptime > maxptime) {
+          maxptime = codec.maxptime;
+        }
+      });
+      if (maxptime > 0) {
+        sdp += 'a=maxptime:' + maxptime + '\r\n';
+      }
+    
+      if (caps.headerExtensions) {
+        caps.headerExtensions.forEach(function (extension) {
+          sdp += SDPUtils.writeExtmap(extension);
+        });
+      }
+      // FIXME: write fecMechanisms.
+      return sdp;
+    };
+    
+    // Parses the SDP media section and returns an array of
+    // RTCRtpEncodingParameters.
+    SDPUtils.parseRtpEncodingParameters = function (mediaSection) {
+      var encodingParameters = [];
+      var description = SDPUtils.parseRtpParameters(mediaSection);
+      var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
+      var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;
+    
+      // filter a=ssrc:... cname:, ignore PlanB-msid
+      var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(function (line) {
+        return SDPUtils.parseSsrcMedia(line);
+      }).filter(function (parts) {
+        return parts.attribute === 'cname';
+      });
+      var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
+      var secondarySsrc = void 0;
+    
+      var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID').map(function (line) {
+        var parts = line.substr(17).split(' ');
+        return parts.map(function (part) {
+          return parseInt(part, 10);
+        });
+      });
+      if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
+        secondarySsrc = flows[0][1];
+      }
+    
+      description.codecs.forEach(function (codec) {
+        if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
+          var encParam = {
+            ssrc: primarySsrc,
+            codecPayloadType: parseInt(codec.parameters.apt, 10)
+          };
+          if (primarySsrc && secondarySsrc) {
+            encParam.rtx = { ssrc: secondarySsrc };
+          }
+          encodingParameters.push(encParam);
+          if (hasRed) {
+            encParam = JSON.parse(JSON.stringify(encParam));
+            encParam.fec = {
+              ssrc: primarySsrc,
+              mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
+            };
+            encodingParameters.push(encParam);
+          }
+        }
+      });
+      if (encodingParameters.length === 0 && primarySsrc) {
+        encodingParameters.push({
+          ssrc: primarySsrc
+        });
+      }
+    
+      // we support both b=AS and b=TIAS but interpret AS as TIAS.
+      var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
+      if (bandwidth.length) {
+        if (bandwidth[0].indexOf('b=TIAS:') === 0) {
+          bandwidth = parseInt(bandwidth[0].substr(7), 10);
+        } else if (bandwidth[0].indexOf('b=AS:') === 0) {
+          // use formula from JSEP to convert b=AS to TIAS value.
+          bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - 50 * 40 * 8;
+        } else {
+          bandwidth = undefined;
+        }
+        encodingParameters.forEach(function (params) {
+          params.maxBitrate = bandwidth;
+        });
+      }
+      return encodingParameters;
+    };
+    
+    // parses http://draft.ortc.org/#rtcrtcpparameters*
+    SDPUtils.parseRtcpParameters = function (mediaSection) {
+      var rtcpParameters = {};
+    
+      // Gets the first SSRC. Note that with RTX there might be multiple
+      // SSRCs.
+      var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(function (line) {
+        return SDPUtils.parseSsrcMedia(line);
+      }).filter(function (obj) {
+        return obj.attribute === 'cname';
+      })[0];
+      if (remoteSsrc) {
+        rtcpParameters.cname = remoteSsrc.value;
+        rtcpParameters.ssrc = remoteSsrc.ssrc;
+      }
+    
+      // Edge uses the compound attribute instead of reducedSize
+      // compound is !reducedSize
+      var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');
+      rtcpParameters.reducedSize = rsize.length > 0;
+      rtcpParameters.compound = rsize.length === 0;
+    
+      // parses the rtcp-mux attrіbute.
+      // Note that Edge does not support unmuxed RTCP.
+      var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');
+      rtcpParameters.mux = mux.length > 0;
+    
+      return rtcpParameters;
+    };
+    
+    SDPUtils.writeRtcpParameters = function (rtcpParameters) {
+      var sdp = '';
+      if (rtcpParameters.reducedSize) {
+        sdp += 'a=rtcp-rsize\r\n';
+      }
+      if (rtcpParameters.mux) {
+        sdp += 'a=rtcp-mux\r\n';
+      }
+      if (rtcpParameters.ssrc !== undefined && rtcpParameters.cname) {
+        sdp += 'a=ssrc:' + rtcpParameters.ssrc + ' cname:' + rtcpParameters.cname + '\r\n';
+      }
+      return sdp;
+    };
+    
+    // parses either a=msid: or a=ssrc:... msid lines and returns
+    // the id of the MediaStream and MediaStreamTrack.
+    SDPUtils.parseMsid = function (mediaSection) {
+      var parts = void 0;
+      var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');
+      if (spec.length === 1) {
+        parts = spec[0].substr(7).split(' ');
+        return { stream: parts[0], track: parts[1] };
+      }
+      var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(function (line) {
+        return SDPUtils.parseSsrcMedia(line);
+      }).filter(function (msidParts) {
+        return msidParts.attribute === 'msid';
+      });
+      if (planB.length > 0) {
+        parts = planB[0].value.split(' ');
+        return { stream: parts[0], track: parts[1] };
+      }
+    };
+    
+    // SCTP
+    // parses draft-ietf-mmusic-sctp-sdp-26 first and falls back
+    // to draft-ietf-mmusic-sctp-sdp-05
+    SDPUtils.parseSctpDescription = function (mediaSection) {
+      var mline = SDPUtils.parseMLine(mediaSection);
+      var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:');
+      var maxMessageSize = void 0;
+      if (maxSizeLine.length > 0) {
+        maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10);
+      }
+      if (isNaN(maxMessageSize)) {
+        maxMessageSize = 65536;
+      }
+      var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:');
+      if (sctpPort.length > 0) {
+        return {
+          port: parseInt(sctpPort[0].substr(12), 10),
+          protocol: mline.fmt,
+          maxMessageSize: maxMessageSize
+        };
+      }
+      var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:');
+      if (sctpMapLines.length > 0) {
+        var parts = sctpMapLines[0].substr(10).split(' ');
+        return {
+          port: parseInt(parts[0], 10),
+          protocol: parts[1],
+          maxMessageSize: maxMessageSize
+        };
+      }
+    };
+    
+    // SCTP
+    // outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers
+    // support by now receiving in this format, unless we originally parsed
+    // as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line
+    // protocol of DTLS/SCTP -- without UDP/ or TCP/)
+    SDPUtils.writeSctpDescription = function (media, sctp) {
+      var output = [];
+      if (media.protocol !== 'DTLS/SCTP') {
+        output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctp-port:' + sctp.port + '\r\n'];
+      } else {
+        output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n'];
+      }
+      if (sctp.maxMessageSize !== undefined) {
+        output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n');
+      }
+      return output.join('');
+    };
+    
+    // Generate a session ID for SDP.
+    // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1
+    // recommends using a cryptographically random +ve 64-bit value
+    // but right now this should be acceptable and within the right range
+    SDPUtils.generateSessionId = function () {
+      return Math.random().toString().substr(2, 21);
+    };
+    
+    // Write boiler plate for start of SDP
+    // sessId argument is optional - if not supplied it will
+    // be generated randomly
+    // sessVersion is optional and defaults to 2
+    // sessUser is optional and defaults to 'thisisadapterortc'
+    SDPUtils.writeSessionBoilerplate = function (sessId, sessVer, sessUser) {
+      var sessionId = void 0;
+      var version = sessVer !== undefined ? sessVer : 2;
+      if (sessId) {
+        sessionId = sessId;
+      } else {
+        sessionId = SDPUtils.generateSessionId();
+      }
+      var user = sessUser || 'thisisadapterortc';
+      // FIXME: sess-id should be an NTP timestamp.
+      return 'v=0\r\n' + 'o=' + user + ' ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + 's=-\r\n' + 't=0 0\r\n';
+    };
+    
+    // Gets the direction from the mediaSection or the sessionpart.
+    SDPUtils.getDirection = function (mediaSection, sessionpart) {
+      // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
+      var lines = SDPUtils.splitLines(mediaSection);
+      for (var i = 0; i < lines.length; i++) {
+        switch (lines[i]) {
+          case 'a=sendrecv':
+          case 'a=sendonly':
+          case 'a=recvonly':
+          case 'a=inactive':
+            return lines[i].substr(2);
+          default:
+          // FIXME: What should happen here?
+        }
+      }
+      if (sessionpart) {
+        return SDPUtils.getDirection(sessionpart);
+      }
+      return 'sendrecv';
+    };
+    
+    SDPUtils.getKind = function (mediaSection) {
+      var lines = SDPUtils.splitLines(mediaSection);
+      var mline = lines[0].split(' ');
+      return mline[0].substr(2);
+    };
+    
+    SDPUtils.isRejected = function (mediaSection) {
+      return mediaSection.split(' ', 2)[1] === '0';
+    };
+    
+    SDPUtils.parseMLine = function (mediaSection) {
+      var lines = SDPUtils.splitLines(mediaSection);
+      var parts = lines[0].substr(2).split(' ');
+      return {
+        kind: parts[0],
+        port: parseInt(parts[1], 10),
+        protocol: parts[2],
+        fmt: parts.slice(3).join(' ')
+      };
+    };
+    
+    SDPUtils.parseOLine = function (mediaSection) {
+      var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0];
+      var parts = line.substr(2).split(' ');
+      return {
+        username: parts[0],
+        sessionId: parts[1],
+        sessionVersion: parseInt(parts[2], 10),
+        netType: parts[3],
+        addressType: parts[4],
+        address: parts[5]
+      };
+    };
+    
+    // a very naive interpretation of a valid SDP.
+    SDPUtils.isValidSDP = function (blob) {
+      if (typeof blob !== 'string' || blob.length === 0) {
+        return false;
+      }
+      var lines = SDPUtils.splitLines(blob);
+      for (var i = 0; i < lines.length; i++) {
+        if (lines[i].length < 2 || lines[i].charAt(1) !== '=') {
+          return false;
+        }
+        // TODO: check the modifier a bit more.
+      }
+      return true;
+    };
+    
+    // Expose public methods.
+    if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') {
+      module.exports = SDPUtils;
+    }
+    },{}]},{},[1])(1)
+    });

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/audioPlayer.js


+ 1 - 0
public/static/audioWorker.js

@@ -0,0 +1 @@
+"use strict";function receiveMessage(a){var b=a.data;switch(b.type){case"sdpInfo":sdpInfo=b.data.sdpInfo;var c=b.data.aacCodecInfo;setAudioRtpSession(sdpInfo,c);break;case"MediaData":var d=b.data.rtspInterleave[1];if("undefined"!=typeof audioRtpSessionsArray[d]){var e=b.data,f=audioRtpSessionsArray[d].parseRTPData(e.rtspInterleave,e.payload,isBackupCommand,b.info);null!==f&&"undefined"!=typeof f&&null!==f.streamData&&"undefined"!=typeof f.streamData&&(f.streamData=null),sendMessage("render",f)}}}function setAudioRtpSession(a,b){for(var c=a,d=0;d<a.length;d++)if(-1===c[d].trackID.search("trackID=t")){switch(rtpSession=null,c[d].codecName){case"G.711A":case"G.711Mu":rtpSession=new G711Session(c[d].codecName),rtpSession.setCodecInfo(c[d]);break;case"G.726-16":case"G.726-24":case"G.726-32":case"G.726-40":var e=parseInt(c[d].codecName.substr(6,2));debug.log(e),rtpSession=new G726Session(e);break;case"mpeg4-generic":rtpSession=new AACSession,debug.log("aacCodecInfo:  "+JSON.stringify(b)),rtpSession.setCodecInfo(b)}var f=c[d].RtpInterlevedID;if(audioRtpSessionsArray[f]=rtpSession,null!=rtpSession)return}}function sendMessage(a,b){var c={type:a,codec:b.codec,data:b.bufferData,rtpTimeStamp:b.rtpTimeStamp,samplingRate:b.samplingRate||8e3};if("render"===a)postMessage(c,[b.bufferData.buffer]);else if("backup"===a){var d={type:a,data:b};postMessage(d)}else postMessage(c)}importScripts("./public.js","./g711Session.js","./g726Session.js","./aacSession.js","./Decode/audioDecoderG711.js","./Decode/audioDecoderG726x.js"),addEventListener("message",receiveMessage,!1);var audioRtpSessionsArray=[],sdpInfo=null,rtpSession=null,isBackupCommand=!1;

+ 2039 - 0
public/static/bootstrap-datepicker.js

@@ -0,0 +1,2039 @@
+/*!
+ * Datepicker for Bootstrap v1.9.0 (https://github.com/uxsolutions/bootstrap-datepicker)
+ *
+ * Licensed under the Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+(function(factory){
+    if (typeof define === 'function' && define.amd) {
+        define(['jquery'], factory);
+    } else if (typeof exports === 'object') {
+        factory(require('jquery'));
+    } else {
+        factory(jQuery);
+    }
+}(function($, undefined){
+	function UTCDate(){
+		return new Date(Date.UTC.apply(Date, arguments));
+	}
+	function UTCToday(){
+		var today = new Date();
+		return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
+	}
+	function isUTCEquals(date1, date2) {
+		return (
+			date1.getUTCFullYear() === date2.getUTCFullYear() &&
+			date1.getUTCMonth() === date2.getUTCMonth() &&
+			date1.getUTCDate() === date2.getUTCDate()
+		);
+	}
+	function alias(method, deprecationMsg){
+		return function(){
+			if (deprecationMsg !== undefined) {
+				$.fn.datepicker.deprecated(deprecationMsg);
+			}
+
+			return this[method].apply(this, arguments);
+		};
+	}
+	function isValidDate(d) {
+		return d && !isNaN(d.getTime());
+	}
+
+	var DateArray = (function(){
+		var extras = {
+			get: function(i){
+				return this.slice(i)[0];
+			},
+			contains: function(d){
+				// Array.indexOf is not cross-browser;
+				// $.inArray doesn't work with Dates
+				var val = d && d.valueOf();
+				for (var i=0, l=this.length; i < l; i++)
+          // Use date arithmetic to allow dates with different times to match
+          if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000*60*60*24)
+						return i;
+				return -1;
+			},
+			remove: function(i){
+				this.splice(i,1);
+			},
+			replace: function(new_array){
+				if (!new_array)
+					return;
+				if (!$.isArray(new_array))
+					new_array = [new_array];
+				this.clear();
+				this.push.apply(this, new_array);
+			},
+			clear: function(){
+				this.length = 0;
+			},
+			copy: function(){
+				var a = new DateArray();
+				a.replace(this);
+				return a;
+			}
+		};
+
+		return function(){
+			var a = [];
+			a.push.apply(a, arguments);
+			$.extend(a, extras);
+			return a;
+		};
+	})();
+
+
+	// Picker object
+
+	var Datepicker = function(element, options){
+		$.data(element, 'datepicker', this);
+
+		this._events = [];
+		this._secondaryEvents = [];
+
+		this._process_options(options);
+
+		this.dates = new DateArray();
+		this.viewDate = this.o.defaultViewDate;
+		this.focusDate = null;
+
+		this.element = $(element);
+		this.isInput = this.element.is('input');
+		this.inputField = this.isInput ? this.element : this.element.find('input');
+		this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .input-group-append, .input-group-prepend, .btn') : false;
+		if (this.component && this.component.length === 0)
+			this.component = false;
+		this.isInline = !this.component && this.element.is('div');
+
+		this.picker = $(DPGlobal.template);
+
+		// Checking templates and inserting
+		if (this._check_template(this.o.templates.leftArrow)) {
+			this.picker.find('.prev').html(this.o.templates.leftArrow);
+		}
+
+		if (this._check_template(this.o.templates.rightArrow)) {
+			this.picker.find('.next').html(this.o.templates.rightArrow);
+		}
+
+		this._buildEvents();
+		this._attachEvents();
+
+		if (this.isInline){
+			this.picker.addClass('datepicker-inline').appendTo(this.element);
+		}
+		else {
+			this.picker.addClass('datepicker-dropdown dropdown-menu');
+		}
+
+		if (this.o.rtl){
+			this.picker.addClass('datepicker-rtl');
+		}
+
+		if (this.o.calendarWeeks) {
+			this.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear')
+				.attr('colspan', function(i, val){
+					return Number(val) + 1;
+				});
+		}
+
+		this._process_options({
+			startDate: this._o.startDate,
+			endDate: this._o.endDate,
+			daysOfWeekDisabled: this.o.daysOfWeekDisabled,
+			daysOfWeekHighlighted: this.o.daysOfWeekHighlighted,
+			datesDisabled: this.o.datesDisabled
+		});
+
+		this._allow_update = false;
+		this.setViewMode(this.o.startView);
+		this._allow_update = true;
+
+		this.fillDow();
+		this.fillMonths();
+
+		this.update();
+
+		if (this.isInline){
+			this.show();
+		}
+	};
+
+	Datepicker.prototype = {
+		constructor: Datepicker,
+
+		_resolveViewName: function(view){
+			$.each(DPGlobal.viewModes, function(i, viewMode){
+				if (view === i || $.inArray(view, viewMode.names) !== -1){
+					view = i;
+					return false;
+				}
+			});
+
+			return view;
+		},
+
+		_resolveDaysOfWeek: function(daysOfWeek){
+			if (!$.isArray(daysOfWeek))
+				daysOfWeek = daysOfWeek.split(/[,\s]*/);
+			return $.map(daysOfWeek, Number);
+		},
+
+		_check_template: function(tmp){
+			try {
+				// If empty
+				if (tmp === undefined || tmp === "") {
+					return false;
+				}
+				// If no html, everything ok
+				if ((tmp.match(/[<>]/g) || []).length <= 0) {
+					return true;
+				}
+				// Checking if html is fine
+				var jDom = $(tmp);
+				return jDom.length > 0;
+			}
+			catch (ex) {
+				return false;
+			}
+		},
+
+		_process_options: function(opts){
+			// Store raw options for reference
+			this._o = $.extend({}, this._o, opts);
+			// Processed options
+			var o = this.o = $.extend({}, this._o);
+
+			// Check if "de-DE" style date is available, if not language should
+			// fallback to 2 letter code eg "de"
+			var lang = o.language;
+			if (!dates[lang]){
+				lang = lang.split('-')[0];
+				if (!dates[lang])
+					lang = defaults.language;
+			}
+			o.language = lang;
+
+			// Retrieve view index from any aliases
+			o.startView = this._resolveViewName(o.startView);
+			o.minViewMode = this._resolveViewName(o.minViewMode);
+			o.maxViewMode = this._resolveViewName(o.maxViewMode);
+
+			// Check view is between min and max
+			o.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));
+
+			// true, false, or Number > 0
+			if (o.multidate !== true){
+				o.multidate = Number(o.multidate) || false;
+				if (o.multidate !== false)
+					o.multidate = Math.max(0, o.multidate);
+			}
+			o.multidateSeparator = String(o.multidateSeparator);
+
+			o.weekStart %= 7;
+			o.weekEnd = (o.weekStart + 6) % 7;
+
+			var format = DPGlobal.parseFormat(o.format);
+			if (o.startDate !== -Infinity){
+				if (!!o.startDate){
+					if (o.startDate instanceof Date)
+						o.startDate = this._local_to_utc(this._zero_time(o.startDate));
+					else
+						o.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);
+				}
+				else {
+					o.startDate = -Infinity;
+				}
+			}
+			if (o.endDate !== Infinity){
+				if (!!o.endDate){
+					if (o.endDate instanceof Date)
+						o.endDate = this._local_to_utc(this._zero_time(o.endDate));
+					else
+						o.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);
+				}
+				else {
+					o.endDate = Infinity;
+				}
+			}
+
+			o.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled||[]);
+			o.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted||[]);
+
+			o.datesDisabled = o.datesDisabled||[];
+			if (!$.isArray(o.datesDisabled)) {
+				o.datesDisabled = o.datesDisabled.split(',');
+			}
+			o.datesDisabled = $.map(o.datesDisabled, function(d){
+				return DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);
+			});
+
+			var plc = String(o.orientation).toLowerCase().split(/\s+/g),
+				_plc = o.orientation.toLowerCase();
+			plc = $.grep(plc, function(word){
+				return /^auto|left|right|top|bottom$/.test(word);
+			});
+			o.orientation = {x: 'auto', y: 'auto'};
+			if (!_plc || _plc === 'auto')
+				; // no action
+			else if (plc.length === 1){
+				switch (plc[0]){
+					case 'top':
+					case 'bottom':
+						o.orientation.y = plc[0];
+						break;
+					case 'left':
+					case 'right':
+						o.orientation.x = plc[0];
+						break;
+				}
+			}
+			else {
+				_plc = $.grep(plc, function(word){
+					return /^left|right$/.test(word);
+				});
+				o.orientation.x = _plc[0] || 'auto';
+
+				_plc = $.grep(plc, function(word){
+					return /^top|bottom$/.test(word);
+				});
+				o.orientation.y = _plc[0] || 'auto';
+			}
+			if (o.defaultViewDate instanceof Date || typeof o.defaultViewDate === 'string') {
+				o.defaultViewDate = DPGlobal.parseDate(o.defaultViewDate, format, o.language, o.assumeNearbyYear);
+			} else if (o.defaultViewDate) {
+				var year = o.defaultViewDate.year || new Date().getFullYear();
+				var month = o.defaultViewDate.month || 0;
+				var day = o.defaultViewDate.day || 1;
+				o.defaultViewDate = UTCDate(year, month, day);
+			} else {
+				o.defaultViewDate = UTCToday();
+			}
+		},
+		_applyEvents: function(evs){
+			for (var i=0, el, ch, ev; i < evs.length; i++){
+				el = evs[i][0];
+				if (evs[i].length === 2){
+					ch = undefined;
+					ev = evs[i][1];
+				} else if (evs[i].length === 3){
+					ch = evs[i][1];
+					ev = evs[i][2];
+				}
+				el.on(ev, ch);
+			}
+		},
+		_unapplyEvents: function(evs){
+			for (var i=0, el, ev, ch; i < evs.length; i++){
+				el = evs[i][0];
+				if (evs[i].length === 2){
+					ch = undefined;
+					ev = evs[i][1];
+				} else if (evs[i].length === 3){
+					ch = evs[i][1];
+					ev = evs[i][2];
+				}
+				el.off(ev, ch);
+			}
+		},
+		_buildEvents: function(){
+            var events = {
+                keyup: $.proxy(function(e){
+                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
+                        this.update();
+                }, this),
+                keydown: $.proxy(this.keydown, this),
+                paste: $.proxy(this.paste, this)
+            };
+
+            if (this.o.showOnFocus === true) {
+                events.focus = $.proxy(this.show, this);
+            }
+
+            if (this.isInput) { // single input
+                this._events = [
+                    [this.element, events]
+                ];
+            }
+            // component: input + button
+            else if (this.component && this.inputField.length) {
+                this._events = [
+                    // For components that are not readonly, allow keyboard nav
+                    [this.inputField, events],
+                    [this.component, {
+                        click: $.proxy(this.show, this)
+                    }]
+                ];
+            }
+			else {
+				this._events = [
+					[this.element, {
+						click: $.proxy(this.show, this),
+						keydown: $.proxy(this.keydown, this)
+					}]
+				];
+			}
+			this._events.push(
+				// Component: listen for blur on element descendants
+				[this.element, '*', {
+					blur: $.proxy(function(e){
+						this._focused_from = e.target;
+					}, this)
+				}],
+				// Input: listen for blur on element
+				[this.element, {
+					blur: $.proxy(function(e){
+						this._focused_from = e.target;
+					}, this)
+				}]
+			);
+
+			if (this.o.immediateUpdates) {
+				// Trigger input updates immediately on changed year/month
+				this._events.push([this.element, {
+					'changeYear changeMonth': $.proxy(function(e){
+						this.update(e.date);
+					}, this)
+				}]);
+			}
+
+			this._secondaryEvents = [
+				[this.picker, {
+					click: $.proxy(this.click, this)
+				}],
+				[this.picker, '.prev, .next', {
+					click: $.proxy(this.navArrowsClick, this)
+				}],
+				[this.picker, '.day:not(.disabled)', {
+					click: $.proxy(this.dayCellClick, this)
+				}],
+				[$(window), {
+					resize: $.proxy(this.place, this)
+				}],
+				[$(document), {
+					'mousedown touchstart': $.proxy(function(e){
+						// Clicked outside the datepicker, hide it
+						if (!(
+							this.element.is(e.target) ||
+							this.element.find(e.target).length ||
+							this.picker.is(e.target) ||
+							this.picker.find(e.target).length ||
+							this.isInline
+						)){
+							this.hide();
+						}
+					}, this)
+				}]
+			];
+		},
+		_attachEvents: function(){
+			this._detachEvents();
+			this._applyEvents(this._events);
+		},
+		_detachEvents: function(){
+			this._unapplyEvents(this._events);
+		},
+		_attachSecondaryEvents: function(){
+			this._detachSecondaryEvents();
+			this._applyEvents(this._secondaryEvents);
+		},
+		_detachSecondaryEvents: function(){
+			this._unapplyEvents(this._secondaryEvents);
+		},
+		_trigger: function(event, altdate){
+			var date = altdate || this.dates.get(-1),
+				local_date = this._utc_to_local(date);
+
+			this.element.trigger({
+				type: event,
+				date: local_date,
+				viewMode: this.viewMode,
+				dates: $.map(this.dates, this._utc_to_local),
+				format: $.proxy(function(ix, format){
+					if (arguments.length === 0){
+						ix = this.dates.length - 1;
+						format = this.o.format;
+					} else if (typeof ix === 'string'){
+						format = ix;
+						ix = this.dates.length - 1;
+					}
+					format = format || this.o.format;
+					var date = this.dates.get(ix);
+					return DPGlobal.formatDate(date, format, this.o.language);
+				}, this)
+			});
+		},
+
+		show: function(){
+			if (this.inputField.is(':disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))
+				return;
+			if (!this.isInline)
+				this.picker.appendTo(this.o.container);
+			this.place();
+			this.picker.show();
+			this._attachSecondaryEvents();
+			this._trigger('show');
+			if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
+				$(this.element).blur();
+			}
+			return this;
+		},
+
+		hide: function(){
+			if (this.isInline || !this.picker.is(':visible'))
+				return this;
+			this.focusDate = null;
+			this.picker.hide().detach();
+			this._detachSecondaryEvents();
+			this.setViewMode(this.o.startView);
+
+			if (this.o.forceParse && this.inputField.val())
+				this.setValue();
+			this._trigger('hide');
+			return this;
+		},
+
+		destroy: function(){
+			this.hide();
+			this._detachEvents();
+			this._detachSecondaryEvents();
+			this.picker.remove();
+			delete this.element.data().datepicker;
+			if (!this.isInput){
+				delete this.element.data().date;
+			}
+			return this;
+		},
+
+		paste: function(e){
+			var dateString;
+			if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types
+				&& $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {
+				dateString = e.originalEvent.clipboardData.getData('text/plain');
+			} else if (window.clipboardData) {
+				dateString = window.clipboardData.getData('Text');
+			} else {
+				return;
+			}
+			this.setDate(dateString);
+			this.update();
+			e.preventDefault();
+		},
+
+		_utc_to_local: function(utc){
+			if (!utc) {
+				return utc;
+			}
+
+			var local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
+
+			if (local.getTimezoneOffset() !== utc.getTimezoneOffset()) {
+				local = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000));
+			}
+
+			return local;
+		},
+		_local_to_utc: function(local){
+			return local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));
+		},
+		_zero_time: function(local){
+			return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
+		},
+		_zero_utc_time: function(utc){
+			return utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
+		},
+
+		getDates: function(){
+			return $.map(this.dates, this._utc_to_local);
+		},
+
+		getUTCDates: function(){
+			return $.map(this.dates, function(d){
+				return new Date(d);
+			});
+		},
+
+		getDate: function(){
+			return this._utc_to_local(this.getUTCDate());
+		},
+
+		getUTCDate: function(){
+			var selected_date = this.dates.get(-1);
+			if (selected_date !== undefined) {
+				return new Date(selected_date);
+			} else {
+				return null;
+			}
+		},
+
+		clearDates: function(){
+			this.inputField.val('');
+			this.update();
+			this._trigger('changeDate');
+
+			if (this.o.autoclose) {
+				this.hide();
+			}
+		},
+
+		setDates: function(){
+			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
+			this.update.apply(this, args);
+			this._trigger('changeDate');
+			this.setValue();
+			return this;
+		},
+
+		setUTCDates: function(){
+			var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
+			this.setDates.apply(this, $.map(args, this._utc_to_local));
+			return this;
+		},
+
+		setDate: alias('setDates'),
+		setUTCDate: alias('setUTCDates'),
+		remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead'),
+
+		setValue: function(){
+			var formatted = this.getFormattedDate();
+			this.inputField.val(formatted);
+			return this;
+		},
+
+		getFormattedDate: function(format){
+			if (format === undefined)
+				format = this.o.format;
+
+			var lang = this.o.language;
+			return $.map(this.dates, function(d){
+				return DPGlobal.formatDate(d, format, lang);
+			}).join(this.o.multidateSeparator);
+		},
+
+		getStartDate: function(){
+			return this.o.startDate;
+		},
+
+		setStartDate: function(startDate){
+			this._process_options({startDate: startDate});
+			this.update();
+			this.updateNavArrows();
+			return this;
+		},
+
+		getEndDate: function(){
+			return this.o.endDate;
+		},
+
+		setEndDate: function(endDate){
+			this._process_options({endDate: endDate});
+			this.update();
+			this.updateNavArrows();
+			return this;
+		},
+
+		setDaysOfWeekDisabled: function(daysOfWeekDisabled){
+			this._process_options({daysOfWeekDisabled: daysOfWeekDisabled});
+			this.update();
+			return this;
+		},
+
+		setDaysOfWeekHighlighted: function(daysOfWeekHighlighted){
+			this._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});
+			this.update();
+			return this;
+		},
+
+		setDatesDisabled: function(datesDisabled){
+			this._process_options({datesDisabled: datesDisabled});
+			this.update();
+			return this;
+		},
+
+		place: function(){
+			if (this.isInline)
+				return this;
+			var calendarWidth = this.picker.outerWidth(),
+				calendarHeight = this.picker.outerHeight(),
+				visualPadding = 10,
+				container = $(this.o.container),
+				windowWidth = container.width(),
+				scrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),
+				appendOffset = container.offset();
+
+			var parentsZindex = [0];
+			this.element.parents().each(function(){
+				var itemZIndex = $(this).css('z-index');
+				if (itemZIndex !== 'auto' && Number(itemZIndex) !== 0) parentsZindex.push(Number(itemZIndex));
+			});
+			var zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;
+			var offset = this.component ? this.component.parent().offset() : this.element.offset();
+			var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
+			var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
+			var left = offset.left - appendOffset.left;
+			var top = offset.top - appendOffset.top;
+
+			if (this.o.container !== 'body') {
+				top += scrollTop;
+			}
+
+			this.picker.removeClass(
+				'datepicker-orient-top datepicker-orient-bottom '+
+				'datepicker-orient-right datepicker-orient-left'
+			);
+
+			if (this.o.orientation.x !== 'auto'){
+				this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
+				if (this.o.orientation.x === 'right')
+					left -= calendarWidth - width;
+			}
+			// auto x orientation is best-placement: if it crosses a window
+			// edge, fudge it sideways
+			else {
+				if (offset.left < 0) {
+					// component is outside the window on the left side. Move it into visible range
+					this.picker.addClass('datepicker-orient-left');
+					left -= offset.left - visualPadding;
+				} else if (left + calendarWidth > windowWidth) {
+					// the calendar passes the widow right edge. Align it to component right side
+					this.picker.addClass('datepicker-orient-right');
+					left += width - calendarWidth;
+				} else {
+					if (this.o.rtl) {
+						// Default to right
+						this.picker.addClass('datepicker-orient-right');
+					} else {
+						// Default to left
+						this.picker.addClass('datepicker-orient-left');
+					}
+				}
+			}
+
+			// auto y orientation is best-situation: top or bottom, no fudging,
+			// decision based on which shows more of the calendar
+			var yorient = this.o.orientation.y,
+				top_overflow;
+			if (yorient === 'auto'){
+				top_overflow = -scrollTop + top - calendarHeight;
+				yorient = top_overflow < 0 ? 'bottom' : 'top';
+			}
+
+			this.picker.addClass('datepicker-orient-' + yorient);
+			if (yorient === 'top')
+				top -= calendarHeight + parseInt(this.picker.css('padding-top'));
+			else
+				top += height;
+
+			if (this.o.rtl) {
+				var right = windowWidth - (left + width);
+				this.picker.css({
+					top: top,
+					right: right,
+					zIndex: zIndex
+				});
+			} else {
+				this.picker.css({
+					top: top,
+					left: left,
+					zIndex: zIndex
+				});
+			}
+			return this;
+		},
+
+		_allow_update: true,
+		update: function(){
+			if (!this._allow_update)
+				return this;
+
+			var oldDates = this.dates.copy(),
+				dates = [],
+				fromArgs = false;
+			if (arguments.length){
+				$.each(arguments, $.proxy(function(i, date){
+					if (date instanceof Date)
+						date = this._local_to_utc(date);
+					dates.push(date);
+				}, this));
+				fromArgs = true;
+			} else {
+				dates = this.isInput
+						? this.element.val()
+						: this.element.data('date') || this.inputField.val();
+				if (dates && this.o.multidate)
+					dates = dates.split(this.o.multidateSeparator);
+				else
+					dates = [dates];
+				delete this.element.data().date;
+			}
+
+			dates = $.map(dates, $.proxy(function(date){
+				return DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);
+			}, this));
+			dates = $.grep(dates, $.proxy(function(date){
+				return (
+					!this.dateWithinRange(date) ||
+					!date
+				);
+			}, this), true);
+			this.dates.replace(dates);
+
+			if (this.o.updateViewDate) {
+				if (this.dates.length)
+					this.viewDate = new Date(this.dates.get(-1));
+				else if (this.viewDate < this.o.startDate)
+					this.viewDate = new Date(this.o.startDate);
+				else if (this.viewDate > this.o.endDate)
+					this.viewDate = new Date(this.o.endDate);
+				else
+					this.viewDate = this.o.defaultViewDate;
+			}
+
+			if (fromArgs){
+				// setting date by clicking
+				this.setValue();
+				this.element.change();
+			}
+			else if (this.dates.length){
+				// setting date by typing
+				if (String(oldDates) !== String(this.dates) && fromArgs) {
+					this._trigger('changeDate');
+					this.element.change();
+				}
+			}
+			if (!this.dates.length && oldDates.length) {
+				this._trigger('clearDate');
+				this.element.change();
+			}
+
+			this.fill();
+			return this;
+		},
+
+		fillDow: function(){
+      if (this.o.showWeekDays) {
+			var dowCnt = this.o.weekStart,
+				html = '<tr>';
+			if (this.o.calendarWeeks){
+				html += '<th class="cw">&#160;</th>';
+			}
+			while (dowCnt < this.o.weekStart + 7){
+				html += '<th class="dow';
+        if ($.inArray(dowCnt, this.o.daysOfWeekDisabled) !== -1)
+          html += ' disabled';
+        html += '">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>';
+			}
+			html += '</tr>';
+			this.picker.find('.datepicker-days thead').append(html);
+      }
+		},
+
+		fillMonths: function(){
+      var localDate = this._utc_to_local(this.viewDate);
+			var html = '';
+			var focused;
+			for (var i = 0; i < 12; i++){
+				focused = localDate && localDate.getMonth() === i ? ' focused' : '';
+				html += '<span class="month' + focused + '">' + dates[this.o.language].monthsShort[i] + '</span>';
+			}
+			this.picker.find('.datepicker-months td').html(html);
+		},
+
+		setRange: function(range){
+			if (!range || !range.length)
+				delete this.range;
+			else
+				this.range = $.map(range, function(d){
+					return d.valueOf();
+				});
+			this.fill();
+		},
+
+		getClassNames: function(date){
+			var cls = [],
+				year = this.viewDate.getUTCFullYear(),
+				month = this.viewDate.getUTCMonth(),
+				today = UTCToday();
+			if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){
+				cls.push('old');
+			} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){
+				cls.push('new');
+			}
+			if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
+				cls.push('focused');
+			// Compare internal UTC date with UTC today, not local today
+			if (this.o.todayHighlight && isUTCEquals(date, today)) {
+				cls.push('today');
+			}
+			if (this.dates.contains(date) !== -1)
+				cls.push('active');
+			if (!this.dateWithinRange(date)){
+				cls.push('disabled');
+			}
+			if (this.dateIsDisabled(date)){
+				cls.push('disabled', 'disabled-date');
+			}
+			if ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){
+				cls.push('highlighted');
+			}
+
+			if (this.range){
+				if (date > this.range[0] && date < this.range[this.range.length-1]){
+					cls.push('range');
+				}
+				if ($.inArray(date.valueOf(), this.range) !== -1){
+					cls.push('selected');
+				}
+				if (date.valueOf() === this.range[0]){
+          cls.push('range-start');
+        }
+        if (date.valueOf() === this.range[this.range.length-1]){
+          cls.push('range-end');
+        }
+			}
+			return cls;
+		},
+
+		_fill_yearsView: function(selector, cssClass, factor, year, startYear, endYear, beforeFn){
+			var html = '';
+			var step = factor / 10;
+			var view = this.picker.find(selector);
+			var startVal = Math.floor(year / factor) * factor;
+			var endVal = startVal + step * 9;
+			var focusedVal = Math.floor(this.viewDate.getFullYear() / step) * step;
+			var selected = $.map(this.dates, function(d){
+				return Math.floor(d.getUTCFullYear() / step) * step;
+			});
+
+			var classes, tooltip, before;
+			for (var currVal = startVal - step; currVal <= endVal + step; currVal += step) {
+				classes = [cssClass];
+				tooltip = null;
+
+				if (currVal === startVal - step) {
+					classes.push('old');
+				} else if (currVal === endVal + step) {
+					classes.push('new');
+				}
+				if ($.inArray(currVal, selected) !== -1) {
+					classes.push('active');
+				}
+				if (currVal < startYear || currVal > endYear) {
+					classes.push('disabled');
+				}
+				if (currVal === focusedVal) {
+				  classes.push('focused');
+        }
+
+				if (beforeFn !== $.noop) {
+					before = beforeFn(new Date(currVal, 0, 1));
+					if (before === undefined) {
+						before = {};
+					} else if (typeof before === 'boolean') {
+						before = {enabled: before};
+					} else if (typeof before === 'string') {
+						before = {classes: before};
+					}
+					if (before.enabled === false) {
+						classes.push('disabled');
+					}
+					if (before.classes) {
+						classes = classes.concat(before.classes.split(/\s+/));
+					}
+					if (before.tooltip) {
+						tooltip = before.tooltip;
+					}
+				}
+
+				html += '<span class="' + classes.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + currVal + '</span>';
+			}
+
+			view.find('.datepicker-switch').text(startVal + '-' + endVal);
+			view.find('td').html(html);
+		},
+
+		fill: function(){
+			var d = new Date(this.viewDate),
+				year = d.getUTCFullYear(),
+				month = d.getUTCMonth(),
+				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
+				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
+				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
+				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
+				todaytxt = dates[this.o.language].today || dates['en'].today || '',
+				cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
+        titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,
+        todayDate = UTCToday(),
+        titleBtnVisible = (this.o.todayBtn === true || this.o.todayBtn === 'linked') && todayDate >= this.o.startDate && todayDate <= this.o.endDate && !this.weekOfDateIsDisabled(todayDate),
+				tooltip,
+				before;
+			if (isNaN(year) || isNaN(month))
+				return;
+			this.picker.find('.datepicker-days .datepicker-switch')
+						.text(DPGlobal.formatDate(d, titleFormat, this.o.language));
+			this.picker.find('tfoot .today')
+						.text(todaytxt)
+            .css('display', titleBtnVisible ? 'table-cell' : 'none');
+			this.picker.find('tfoot .clear')
+						.text(cleartxt)
+						.css('display', this.o.clearBtn === true ? 'table-cell' : 'none');
+			this.picker.find('thead .datepicker-title')
+						.text(this.o.title)
+						.css('display', typeof this.o.title === 'string' && this.o.title !== '' ? 'table-cell' : 'none');
+			this.updateNavArrows();
+			this.fillMonths();
+			var prevMonth = UTCDate(year, month, 0),
+				day = prevMonth.getUTCDate();
+			prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);
+			var nextMonth = new Date(prevMonth);
+			if (prevMonth.getUTCFullYear() < 100){
+        nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());
+      }
+			nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
+			nextMonth = nextMonth.valueOf();
+			var html = [];
+			var weekDay, clsName;
+			while (prevMonth.valueOf() < nextMonth){
+				weekDay = prevMonth.getUTCDay();
+				if (weekDay === this.o.weekStart){
+					html.push('<tr>');
+					if (this.o.calendarWeeks){
+						// ISO 8601: First week contains first thursday.
+						// ISO also states week starts on Monday, but we can be more abstract here.
+						var
+							// Start of current week: based on weekstart/current date
+							ws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),
+							// Thursday of this week
+							th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
+							// First Thursday of year, year from thursday
+							yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
+							// Calendar week: ms between thursdays, div ms per day, div 7 days
+							calWeek = (th - yth) / 864e5 / 7 + 1;
+						html.push('<td class="cw">'+ calWeek +'</td>');
+					}
+				}
+				clsName = this.getClassNames(prevMonth);
+				clsName.push('day');
+
+				var content = prevMonth.getUTCDate();
+
+				if (this.o.beforeShowDay !== $.noop){
+					before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
+					if (before === undefined)
+						before = {};
+					else if (typeof before === 'boolean')
+						before = {enabled: before};
+					else if (typeof before === 'string')
+						before = {classes: before};
+					if (before.enabled === false)
+						clsName.push('disabled');
+					if (before.classes)
+						clsName = clsName.concat(before.classes.split(/\s+/));
+					if (before.tooltip)
+						tooltip = before.tooltip;
+					if (before.content)
+						content = before.content;
+				}
+
+				//Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2)
+				//Fallback to unique function for older jquery versions
+				if ($.isFunction($.uniqueSort)) {
+					clsName = $.uniqueSort(clsName);
+				} else {
+					clsName = $.unique(clsName);
+				}
+
+				html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + ' data-date="' + prevMonth.getTime().toString() + '">' + content + '</td>');
+				tooltip = null;
+				if (weekDay === this.o.weekEnd){
+					html.push('</tr>');
+				}
+				prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
+			}
+			this.picker.find('.datepicker-days tbody').html(html.join(''));
+
+			var monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';
+			var months = this.picker.find('.datepicker-months')
+						.find('.datepicker-switch')
+							.text(this.o.maxViewMode < 2 ? monthsTitle : year)
+							.end()
+						.find('tbody span').removeClass('active');
+
+			$.each(this.dates, function(i, d){
+				if (d.getUTCFullYear() === year)
+					months.eq(d.getUTCMonth()).addClass('active');
+			});
+
+			if (year < startYear || year > endYear){
+				months.addClass('disabled');
+			}
+			if (year === startYear){
+				months.slice(0, startMonth).addClass('disabled');
+			}
+			if (year === endYear){
+				months.slice(endMonth+1).addClass('disabled');
+			}
+
+			if (this.o.beforeShowMonth !== $.noop){
+				var that = this;
+				$.each(months, function(i, month){
+          var moDate = new Date(year, i, 1);
+          var before = that.o.beforeShowMonth(moDate);
+					if (before === undefined)
+						before = {};
+					else if (typeof before === 'boolean')
+						before = {enabled: before};
+					else if (typeof before === 'string')
+						before = {classes: before};
+					if (before.enabled === false && !$(month).hasClass('disabled'))
+					    $(month).addClass('disabled');
+					if (before.classes)
+					    $(month).addClass(before.classes);
+					if (before.tooltip)
+					    $(month).prop('title', before.tooltip);
+				});
+			}
+
+			// Generating decade/years picker
+			this._fill_yearsView(
+				'.datepicker-years',
+				'year',
+				10,
+				year,
+				startYear,
+				endYear,
+				this.o.beforeShowYear
+			);
+
+			// Generating century/decades picker
+			this._fill_yearsView(
+				'.datepicker-decades',
+				'decade',
+				100,
+				year,
+				startYear,
+				endYear,
+				this.o.beforeShowDecade
+			);
+
+			// Generating millennium/centuries picker
+			this._fill_yearsView(
+				'.datepicker-centuries',
+				'century',
+				1000,
+				year,
+				startYear,
+				endYear,
+				this.o.beforeShowCentury
+			);
+		},
+
+		updateNavArrows: function(){
+			if (!this._allow_update)
+				return;
+
+			var d = new Date(this.viewDate),
+				year = d.getUTCFullYear(),
+				month = d.getUTCMonth(),
+				startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
+				startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
+				endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
+				endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
+				prevIsDisabled,
+				nextIsDisabled,
+				factor = 1;
+			switch (this.viewMode){
+				case 4:
+					factor *= 10;
+					/* falls through */
+				case 3:
+					factor *= 10;
+					/* falls through */
+				case 2:
+					factor *= 10;
+					/* falls through */
+				case 1:
+					prevIsDisabled = Math.floor(year / factor) * factor <= startYear;
+					nextIsDisabled = Math.floor(year / factor) * factor + factor > endYear;
+					break;
+				case 0:
+					prevIsDisabled = year <= startYear && month <= startMonth;
+					nextIsDisabled = year >= endYear && month >= endMonth;
+					break;
+			}
+
+			this.picker.find('.prev').toggleClass('disabled', prevIsDisabled);
+			this.picker.find('.next').toggleClass('disabled', nextIsDisabled);
+		},
+
+		click: function(e){
+			e.preventDefault();
+			e.stopPropagation();
+
+			var target, dir, day, year, month;
+			target = $(e.target);
+
+			// Clicked on the switch
+			if (target.hasClass('datepicker-switch') && this.viewMode !== this.o.maxViewMode){
+				this.setViewMode(this.viewMode + 1);
+			}
+
+			// Clicked on today button
+			if (target.hasClass('today') && !target.hasClass('day')){
+				this.setViewMode(0);
+				this._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');
+			}
+
+			// Clicked on clear button
+			if (target.hasClass('clear')){
+				this.clearDates();
+			}
+
+			if (!target.hasClass('disabled')){
+				// Clicked on a month, year, decade, century
+				if (target.hasClass('month')
+						|| target.hasClass('year')
+						|| target.hasClass('decade')
+						|| target.hasClass('century')) {
+					this.viewDate.setUTCDate(1);
+
+					day = 1;
+					if (this.viewMode === 1){
+						month = target.parent().find('span').index(target);
+						year = this.viewDate.getUTCFullYear();
+						this.viewDate.setUTCMonth(month);
+					} else {
+						month = 0;
+						year = Number(target.text());
+						this.viewDate.setUTCFullYear(year);
+					}
+
+					this._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);
+
+					if (this.viewMode === this.o.minViewMode){
+						this._setDate(UTCDate(year, month, day));
+					} else {
+						this.setViewMode(this.viewMode - 1);
+						this.fill();
+					}
+				}
+			}
+
+			if (this.picker.is(':visible') && this._focused_from){
+				this._focused_from.focus();
+			}
+			delete this._focused_from;
+		},
+
+		dayCellClick: function(e){
+			var $target = $(e.currentTarget);
+			var timestamp = $target.data('date');
+			var date = new Date(timestamp);
+
+			if (this.o.updateViewDate) {
+				if (date.getUTCFullYear() !== this.viewDate.getUTCFullYear()) {
+					this._trigger('changeYear', this.viewDate);
+				}
+
+				if (date.getUTCMonth() !== this.viewDate.getUTCMonth()) {
+					this._trigger('changeMonth', this.viewDate);
+				}
+			}
+			this._setDate(date);
+		},
+
+		// Clicked on prev or next
+		navArrowsClick: function(e){
+			var $target = $(e.currentTarget);
+			var dir = $target.hasClass('prev') ? -1 : 1;
+			if (this.viewMode !== 0){
+				dir *= DPGlobal.viewModes[this.viewMode].navStep * 12;
+			}
+			this.viewDate = this.moveMonth(this.viewDate, dir);
+			this._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate);
+			this.fill();
+		},
+
+		_toggle_multidate: function(date){
+			var ix = this.dates.contains(date);
+			if (!date){
+				this.dates.clear();
+			}
+
+			if (ix !== -1){
+				if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){
+					this.dates.remove(ix);
+				}
+			} else if (this.o.multidate === false) {
+				this.dates.clear();
+				this.dates.push(date);
+			}
+			else {
+				this.dates.push(date);
+			}
+
+			if (typeof this.o.multidate === 'number')
+				while (this.dates.length > this.o.multidate)
+					this.dates.remove(0);
+		},
+
+		_setDate: function(date, which){
+			if (!which || which === 'date')
+				this._toggle_multidate(date && new Date(date));
+			if ((!which && this.o.updateViewDate) || which === 'view')
+				this.viewDate = date && new Date(date);
+
+			this.fill();
+			this.setValue();
+			if (!which || which !== 'view') {
+				this._trigger('changeDate');
+			}
+			this.inputField.trigger('change');
+			if (this.o.autoclose && (!which || which === 'date')){
+				this.hide();
+			}
+		},
+
+		moveDay: function(date, dir){
+			var newDate = new Date(date);
+			newDate.setUTCDate(date.getUTCDate() + dir);
+
+			return newDate;
+		},
+
+		moveWeek: function(date, dir){
+			return this.moveDay(date, dir * 7);
+		},
+
+		moveMonth: function(date, dir){
+			if (!isValidDate(date))
+				return this.o.defaultViewDate;
+			if (!dir)
+				return date;
+			var new_date = new Date(date.valueOf()),
+				day = new_date.getUTCDate(),
+				month = new_date.getUTCMonth(),
+				mag = Math.abs(dir),
+				new_month, test;
+			dir = dir > 0 ? 1 : -1;
+			if (mag === 1){
+				test = dir === -1
+					// If going back one month, make sure month is not current month
+					// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
+					? function(){
+						return new_date.getUTCMonth() === month;
+					}
+					// If going forward one month, make sure month is as expected
+					// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
+					: function(){
+						return new_date.getUTCMonth() !== new_month;
+					};
+				new_month = month + dir;
+				new_date.setUTCMonth(new_month);
+				// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
+				new_month = (new_month + 12) % 12;
+			}
+			else {
+				// For magnitudes >1, move one month at a time...
+				for (var i=0; i < mag; i++)
+					// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
+					new_date = this.moveMonth(new_date, dir);
+				// ...then reset the day, keeping it in the new month
+				new_month = new_date.getUTCMonth();
+				new_date.setUTCDate(day);
+				test = function(){
+					return new_month !== new_date.getUTCMonth();
+				};
+			}
+			// Common date-resetting loop -- if date is beyond end of month, make it
+			// end of month
+			while (test()){
+				new_date.setUTCDate(--day);
+				new_date.setUTCMonth(new_month);
+			}
+			return new_date;
+		},
+
+		moveYear: function(date, dir){
+			return this.moveMonth(date, dir*12);
+		},
+
+		moveAvailableDate: function(date, dir, fn){
+			do {
+				date = this[fn](date, dir);
+
+				if (!this.dateWithinRange(date))
+					return false;
+
+				fn = 'moveDay';
+			}
+			while (this.dateIsDisabled(date));
+
+			return date;
+		},
+
+		weekOfDateIsDisabled: function(date){
+			return $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;
+		},
+
+		dateIsDisabled: function(date){
+			return (
+				this.weekOfDateIsDisabled(date) ||
+				$.grep(this.o.datesDisabled, function(d){
+					return isUTCEquals(date, d);
+				}).length > 0
+			);
+		},
+
+		dateWithinRange: function(date){
+			return date >= this.o.startDate && date <= this.o.endDate;
+		},
+
+		keydown: function(e){
+			if (!this.picker.is(':visible')){
+				if (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker
+					this.show();
+					e.stopPropagation();
+        }
+				return;
+			}
+			var dateChanged = false,
+				dir, newViewDate,
+				focusDate = this.focusDate || this.viewDate;
+			switch (e.keyCode){
+				case 27: // escape
+					if (this.focusDate){
+						this.focusDate = null;
+						this.viewDate = this.dates.get(-1) || this.viewDate;
+						this.fill();
+					}
+					else
+						this.hide();
+					e.preventDefault();
+					e.stopPropagation();
+					break;
+				case 37: // left
+				case 38: // up
+				case 39: // right
+				case 40: // down
+					if (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)
+						break;
+					dir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;
+          if (this.viewMode === 0) {
+  					if (e.ctrlKey){
+  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
+
+  						if (newViewDate)
+  							this._trigger('changeYear', this.viewDate);
+  					} else if (e.shiftKey){
+  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
+
+  						if (newViewDate)
+  							this._trigger('changeMonth', this.viewDate);
+  					} else if (e.keyCode === 37 || e.keyCode === 39){
+  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');
+  					} else if (!this.weekOfDateIsDisabled(focusDate)){
+  						newViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');
+  					}
+          } else if (this.viewMode === 1) {
+            if (e.keyCode === 38 || e.keyCode === 40) {
+              dir = dir * 4;
+            }
+            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');
+          } else if (this.viewMode === 2) {
+            if (e.keyCode === 38 || e.keyCode === 40) {
+              dir = dir * 4;
+            }
+            newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');
+          }
+					if (newViewDate){
+						this.focusDate = this.viewDate = newViewDate;
+						this.setValue();
+						this.fill();
+						e.preventDefault();
+					}
+					break;
+				case 13: // enter
+					if (!this.o.forceParse)
+						break;
+					focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
+					if (this.o.keyboardNavigation) {
+						this._toggle_multidate(focusDate);
+						dateChanged = true;
+					}
+					this.focusDate = null;
+					this.viewDate = this.dates.get(-1) || this.viewDate;
+					this.setValue();
+					this.fill();
+					if (this.picker.is(':visible')){
+						e.preventDefault();
+						e.stopPropagation();
+						if (this.o.autoclose)
+							this.hide();
+					}
+					break;
+				case 9: // tab
+					this.focusDate = null;
+					this.viewDate = this.dates.get(-1) || this.viewDate;
+					this.fill();
+					this.hide();
+					break;
+			}
+			if (dateChanged){
+				if (this.dates.length)
+					this._trigger('changeDate');
+				else
+					this._trigger('clearDate');
+				this.inputField.trigger('change');
+			}
+		},
+
+		setViewMode: function(viewMode){
+			this.viewMode = viewMode;
+			this.picker
+				.children('div')
+				.hide()
+				.filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName)
+					.show();
+			this.updateNavArrows();
+      this._trigger('changeViewMode', new Date(this.viewDate));
+		}
+	};
+
+	var DateRangePicker = function(element, options){
+		$.data(element, 'datepicker', this);
+		this.element = $(element);
+		this.inputs = $.map(options.inputs, function(i){
+			return i.jquery ? i[0] : i;
+		});
+		delete options.inputs;
+
+		this.keepEmptyValues = options.keepEmptyValues;
+		delete options.keepEmptyValues;
+
+		datepickerPlugin.call($(this.inputs), options)
+			.on('changeDate', $.proxy(this.dateUpdated, this));
+
+		this.pickers = $.map(this.inputs, function(i){
+			return $.data(i, 'datepicker');
+		});
+		this.updateDates();
+	};
+	DateRangePicker.prototype = {
+		updateDates: function(){
+			this.dates = $.map(this.pickers, function(i){
+				return i.getUTCDate();
+			});
+			this.updateRanges();
+		},
+		updateRanges: function(){
+			var range = $.map(this.dates, function(d){
+				return d.valueOf();
+			});
+			$.each(this.pickers, function(i, p){
+				p.setRange(range);
+			});
+		},
+		clearDates: function(){
+			$.each(this.pickers, function(i, p){
+				p.clearDates();
+			});
+		},
+		dateUpdated: function(e){
+			// `this.updating` is a workaround for preventing infinite recursion
+			// between `changeDate` triggering and `setUTCDate` calling.  Until
+			// there is a better mechanism.
+			if (this.updating)
+				return;
+			this.updating = true;
+
+			var dp = $.data(e.target, 'datepicker');
+
+			if (dp === undefined) {
+				return;
+			}
+
+			var new_date = dp.getUTCDate(),
+				keep_empty_values = this.keepEmptyValues,
+				i = $.inArray(e.target, this.inputs),
+				j = i - 1,
+				k = i + 1,
+				l = this.inputs.length;
+			if (i === -1)
+				return;
+
+			$.each(this.pickers, function(i, p){
+				if (!p.getUTCDate() && (p === dp || !keep_empty_values))
+					p.setUTCDate(new_date);
+			});
+
+			if (new_date < this.dates[j]){
+				// Date being moved earlier/left
+				while (j >= 0 && new_date < this.dates[j]){
+					this.pickers[j--].setUTCDate(new_date);
+				}
+			} else if (new_date > this.dates[k]){
+				// Date being moved later/right
+				while (k < l && new_date > this.dates[k]){
+					this.pickers[k++].setUTCDate(new_date);
+				}
+			}
+			this.updateDates();
+
+			delete this.updating;
+		},
+		destroy: function(){
+			$.map(this.pickers, function(p){ p.destroy(); });
+			$(this.inputs).off('changeDate', this.dateUpdated);
+			delete this.element.data().datepicker;
+		},
+		remove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead')
+	};
+
+	function opts_from_el(el, prefix){
+		// Derive options from element data-attrs
+		var data = $(el).data(),
+			out = {}, inkey,
+			replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
+		prefix = new RegExp('^' + prefix.toLowerCase());
+		function re_lower(_,a){
+			return a.toLowerCase();
+		}
+		for (var key in data)
+			if (prefix.test(key)){
+				inkey = key.replace(replace, re_lower);
+				out[inkey] = data[key];
+			}
+		return out;
+	}
+
+	function opts_from_locale(lang){
+		// Derive options from locale plugins
+		var out = {};
+		// Check if "de-DE" style date is available, if not language should
+		// fallback to 2 letter code eg "de"
+		if (!dates[lang]){
+			lang = lang.split('-')[0];
+			if (!dates[lang])
+				return;
+		}
+		var d = dates[lang];
+		$.each(locale_opts, function(i,k){
+			if (k in d)
+				out[k] = d[k];
+		});
+		return out;
+	}
+
+	var old = $.fn.datepicker;
+	var datepickerPlugin = function(option){
+		var args = Array.apply(null, arguments);
+		args.shift();
+		var internal_return;
+		this.each(function(){
+			var $this = $(this),
+				data = $this.data('datepicker'),
+				options = typeof option === 'object' && option;
+			if (!data){
+				var elopts = opts_from_el(this, 'date'),
+					// Preliminary otions
+					xopts = $.extend({}, defaults, elopts, options),
+					locopts = opts_from_locale(xopts.language),
+					// Options priority: js args, data-attrs, locales, defaults
+					opts = $.extend({}, defaults, locopts, elopts, options);
+				if ($this.hasClass('input-daterange') || opts.inputs){
+					$.extend(opts, {
+						inputs: opts.inputs || $this.find('input').toArray()
+					});
+					data = new DateRangePicker(this, opts);
+				}
+				else {
+					data = new Datepicker(this, opts);
+				}
+				$this.data('datepicker', data);
+			}
+			if (typeof option === 'string' && typeof data[option] === 'function'){
+				internal_return = data[option].apply(data, args);
+			}
+		});
+
+		if (
+			internal_return === undefined ||
+			internal_return instanceof Datepicker ||
+			internal_return instanceof DateRangePicker
+		)
+			return this;
+
+		if (this.length > 1)
+			throw new Error('Using only allowed for the collection of a single element (' + option + ' function)');
+		else
+			return internal_return;
+	};
+	$.fn.datepicker = datepickerPlugin;
+
+	var defaults = $.fn.datepicker.defaults = {
+		assumeNearbyYear: false,
+		autoclose: false,
+		beforeShowDay: $.noop,
+		beforeShowMonth: $.noop,
+		beforeShowYear: $.noop,
+		beforeShowDecade: $.noop,
+		beforeShowCentury: $.noop,
+		calendarWeeks: false,
+		clearBtn: false,
+		toggleActive: false,
+		daysOfWeekDisabled: [],
+		daysOfWeekHighlighted: [],
+		datesDisabled: [],
+		endDate: Infinity,
+		forceParse: true,
+		format: 'mm/dd/yyyy',
+		keepEmptyValues: false,
+		keyboardNavigation: true,
+		language: 'en',
+		minViewMode: 0,
+		maxViewMode: 4,
+		multidate: false,
+		multidateSeparator: ',',
+		orientation: "auto",
+		rtl: false,
+		startDate: -Infinity,
+		startView: 0,
+		todayBtn: false,
+		todayHighlight: false,
+		updateViewDate: true,
+		weekStart: 0,
+		disableTouchKeyboard: false,
+		enableOnReadonly: true,
+		showOnFocus: true,
+		zIndexOffset: 10,
+		container: 'body',
+		immediateUpdates: false,
+		title: '',
+		templates: {
+			leftArrow: '&#x00AB;',
+			rightArrow: '&#x00BB;'
+		},
+    showWeekDays: true
+	};
+	var locale_opts = $.fn.datepicker.locale_opts = [
+		'format',
+		'rtl',
+		'weekStart'
+	];
+	$.fn.datepicker.Constructor = Datepicker;
+	var dates = $.fn.datepicker.dates = {
+		en: {
+			days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+			daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+			daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+			months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+			monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+			today: "Today",
+			clear: "Clear",
+			titleFormat: "MM yyyy"
+		}
+	};
+
+	var DPGlobal = {
+		viewModes: [
+			{
+				names: ['days', 'month'],
+				clsName: 'days',
+				e: 'changeMonth'
+			},
+			{
+				names: ['months', 'year'],
+				clsName: 'months',
+				e: 'changeYear',
+				navStep: 1
+			},
+			{
+				names: ['years', 'decade'],
+				clsName: 'years',
+				e: 'changeDecade',
+				navStep: 10
+			},
+			{
+				names: ['decades', 'century'],
+				clsName: 'decades',
+				e: 'changeCentury',
+				navStep: 100
+			},
+			{
+				names: ['centuries', 'millennium'],
+				clsName: 'centuries',
+				e: 'changeMillennium',
+				navStep: 1000
+			}
+		],
+		validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
+		nonpunctuation: /[^ -\/:-@\u5e74\u6708\u65e5\[-`{-~\t\n\r]+/g,
+		parseFormat: function(format){
+			if (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')
+                return format;
+            // IE treats \0 as a string end in inputs (truncating the value),
+			// so it's a bad format delimiter, anyway
+			var separators = format.replace(this.validParts, '\0').split('\0'),
+				parts = format.match(this.validParts);
+			if (!separators || !separators.length || !parts || parts.length === 0){
+				throw new Error("Invalid date format.");
+			}
+			return {separators: separators, parts: parts};
+		},
+		parseDate: function(date, format, language, assumeNearby){
+			if (!date)
+				return undefined;
+			if (date instanceof Date)
+				return date;
+			if (typeof format === 'string')
+				format = DPGlobal.parseFormat(format);
+			if (format.toValue)
+				return format.toValue(date, format, language);
+			var fn_map = {
+					d: 'moveDay',
+					m: 'moveMonth',
+					w: 'moveWeek',
+					y: 'moveYear'
+				},
+				dateAliases = {
+					yesterday: '-1d',
+					today: '+0d',
+					tomorrow: '+1d'
+				},
+				parts, part, dir, i, fn;
+			if (date in dateAliases){
+				date = dateAliases[date];
+			}
+			if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/i.test(date)){
+				parts = date.match(/([\-+]\d+)([dmwy])/gi);
+				date = new Date();
+				for (i=0; i < parts.length; i++){
+					part = parts[i].match(/([\-+]\d+)([dmwy])/i);
+					dir = Number(part[1]);
+					fn = fn_map[part[2].toLowerCase()];
+					date = Datepicker.prototype[fn](date, dir);
+				}
+				return Datepicker.prototype._zero_utc_time(date);
+			}
+
+			parts = date && date.match(this.nonpunctuation) || [];
+
+			function applyNearbyYear(year, threshold){
+				if (threshold === true)
+					threshold = 10;
+
+				// if year is 2 digits or less, than the user most likely is trying to get a recent century
+				if (year < 100){
+					year += 2000;
+					// if the new year is more than threshold years in advance, use last century
+					if (year > ((new Date()).getFullYear()+threshold)){
+						year -= 100;
+					}
+				}
+
+				return year;
+			}
+
+			var parsed = {},
+				setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
+				setters_map = {
+					yyyy: function(d,v){
+						return d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);
+					},
+					m: function(d,v){
+						if (isNaN(d))
+							return d;
+						v -= 1;
+						while (v < 0) v += 12;
+						v %= 12;
+						d.setUTCMonth(v);
+						while (d.getUTCMonth() !== v)
+							d.setUTCDate(d.getUTCDate()-1);
+						return d;
+					},
+					d: function(d,v){
+						return d.setUTCDate(v);
+					}
+				},
+				val, filtered;
+			setters_map['yy'] = setters_map['yyyy'];
+			setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
+			setters_map['dd'] = setters_map['d'];
+			date = UTCToday();
+			var fparts = format.parts.slice();
+			// Remove noop parts
+			if (parts.length !== fparts.length){
+				fparts = $(fparts).filter(function(i,p){
+					return $.inArray(p, setters_order) !== -1;
+				}).toArray();
+			}
+			// Process remainder
+			function match_part(){
+				var m = this.slice(0, parts[i].length),
+					p = parts[i].slice(0, m.length);
+				return m.toLowerCase() === p.toLowerCase();
+			}
+			if (parts.length === fparts.length){
+				var cnt;
+				for (i=0, cnt = fparts.length; i < cnt; i++){
+					val = parseInt(parts[i], 10);
+					part = fparts[i];
+					if (isNaN(val)){
+						switch (part){
+							case 'MM':
+								filtered = $(dates[language].months).filter(match_part);
+								val = $.inArray(filtered[0], dates[language].months) + 1;
+								break;
+							case 'M':
+								filtered = $(dates[language].monthsShort).filter(match_part);
+								val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
+								break;
+						}
+					}
+					parsed[part] = val;
+				}
+				var _date, s;
+				for (i=0; i < setters_order.length; i++){
+					s = setters_order[i];
+					if (s in parsed && !isNaN(parsed[s])){
+						_date = new Date(date);
+						setters_map[s](_date, parsed[s]);
+						if (!isNaN(_date))
+							date = _date;
+					}
+				}
+			}
+			return date;
+		},
+		formatDate: function(date, format, language){
+			if (!date)
+				return '';
+			if (typeof format === 'string')
+				format = DPGlobal.parseFormat(format);
+			if (format.toDisplay)
+                return format.toDisplay(date, format, language);
+            var val = {
+				d: date.getUTCDate(),
+				D: dates[language].daysShort[date.getUTCDay()],
+				DD: dates[language].days[date.getUTCDay()],
+				m: date.getUTCMonth() + 1,
+				M: dates[language].monthsShort[date.getUTCMonth()],
+				MM: dates[language].months[date.getUTCMonth()],
+				yy: date.getUTCFullYear().toString().substring(2),
+				yyyy: date.getUTCFullYear()
+			};
+			val.dd = (val.d < 10 ? '0' : '') + val.d;
+			val.mm = (val.m < 10 ? '0' : '') + val.m;
+			date = [];
+			var seps = $.extend([], format.separators);
+			for (var i=0, cnt = format.parts.length; i <= cnt; i++){
+				if (seps.length)
+					date.push(seps.shift());
+				date.push(val[format.parts[i]]);
+			}
+			return date.join('');
+		},
+		headTemplate: '<thead>'+
+			              '<tr>'+
+			                '<th colspan="7" class="datepicker-title"></th>'+
+			              '</tr>'+
+							'<tr>'+
+								'<th class="prev">'+defaults.templates.leftArrow+'</th>'+
+								'<th colspan="5" class="datepicker-switch"></th>'+
+								'<th class="next">'+defaults.templates.rightArrow+'</th>'+
+							'</tr>'+
+						'</thead>',
+		contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
+		footTemplate: '<tfoot>'+
+							'<tr>'+
+								'<th colspan="7" class="today"></th>'+
+							'</tr>'+
+							'<tr>'+
+								'<th colspan="7" class="clear"></th>'+
+							'</tr>'+
+						'</tfoot>'
+	};
+	DPGlobal.template = '<div class="datepicker">'+
+							'<div class="datepicker-days">'+
+								'<table class="table-condensed">'+
+									DPGlobal.headTemplate+
+									'<tbody></tbody>'+
+									DPGlobal.footTemplate+
+								'</table>'+
+							'</div>'+
+							'<div class="datepicker-months">'+
+								'<table class="table-condensed">'+
+									DPGlobal.headTemplate+
+									DPGlobal.contTemplate+
+									DPGlobal.footTemplate+
+								'</table>'+
+							'</div>'+
+							'<div class="datepicker-years">'+
+								'<table class="table-condensed">'+
+									DPGlobal.headTemplate+
+									DPGlobal.contTemplate+
+									DPGlobal.footTemplate+
+								'</table>'+
+							'</div>'+
+							'<div class="datepicker-decades">'+
+								'<table class="table-condensed">'+
+									DPGlobal.headTemplate+
+									DPGlobal.contTemplate+
+									DPGlobal.footTemplate+
+								'</table>'+
+							'</div>'+
+							'<div class="datepicker-centuries">'+
+								'<table class="table-condensed">'+
+									DPGlobal.headTemplate+
+									DPGlobal.contTemplate+
+									DPGlobal.footTemplate+
+								'</table>'+
+							'</div>'+
+						'</div>';
+
+	$.fn.datepicker.DPGlobal = DPGlobal;
+
+
+	/* DATEPICKER NO CONFLICT
+	* =================== */
+
+	$.fn.datepicker.noConflict = function(){
+		$.fn.datepicker = old;
+		return this;
+	};
+
+	/* DATEPICKER VERSION
+	 * =================== */
+	$.fn.datepicker.version = '1.9.0';
+
+	$.fn.datepicker.deprecated = function(msg){
+		var console = window.console;
+		if (console && console.warn) {
+			console.warn('DEPRECATED: ' + msg);
+		}
+	};
+
+
+	/* DATEPICKER DATA-API
+	* ================== */
+
+	$(document).on(
+		'focus.datepicker.data-api click.datepicker.data-api',
+		'[data-provide="datepicker"]',
+		function(e){
+			var $this = $(this);
+			if ($this.data('datepicker'))
+				return;
+			e.preventDefault();
+			// component click requires us to explicitly show it
+			datepickerPlugin.call($this, 'show');
+		}
+	);
+	$(function(){
+		datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
+	});
+
+}));

+ 1 - 0
public/static/bootstrap-datepicker.zh-CN.min.js

@@ -0,0 +1 @@
+!function(a){a.fn.datepicker.dates["zh-CN"]={days:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],daysShort:["周日","周一","周二","周三","周四","周五","周六"],daysMin:["日","一","二","三","四","五","六"],months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今天",monthsTitle:"选择月份",clear:"清除",format:"yyyy-mm-dd",titleFormat:"yyyy年mm月",weekStart:1}}(jQuery);

+ 1535 - 0
public/static/datepicker.js

@@ -0,0 +1,1535 @@
+/*!
+ * Datepicker v1.0.10
+ * https://fengyuanchen.github.io/datepicker
+ *
+ * Copyright 2014-present Chen Fengyuan
+ * Released under the MIT license
+ *
+ * Date: 2020-09-29T14:46:10.983Z
+ */
+
+(function(global, factory) {
+    typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) :
+        typeof define === 'function' && define.amd ? define(['jquery'], factory) :
+        (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jQuery));
+}(this, (function($) {
+    'use strict';
+
+    $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
+
+    function _classCallCheck(instance, Constructor) {
+        if (!(instance instanceof Constructor)) {
+            throw new TypeError("Cannot call a class as a function");
+        }
+    }
+
+    function _defineProperties(target, props) {
+        for (var i = 0; i < props.length; i++) {
+            var descriptor = props[i];
+            descriptor.enumerable = descriptor.enumerable || false;
+            descriptor.configurable = true;
+            if ("value" in descriptor) descriptor.writable = true;
+            Object.defineProperty(target, descriptor.key, descriptor);
+        }
+    }
+
+    function _createClass(Constructor, protoProps, staticProps) {
+        if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+        if (staticProps) _defineProperties(Constructor, staticProps);
+        return Constructor;
+    }
+
+    var DEFAULTS = {
+        // Show the datepicker automatically when initialized
+        autoShow: false,
+        // Hide the datepicker automatically when picked
+        autoHide: false,
+        // Pick the initial date automatically when initialized
+        autoPick: false,
+        // Enable inline mode
+        inline: false,
+        // A element (or selector) for putting the datepicker
+        container: null,
+        // A element (or selector) for triggering the datepicker
+        trigger: null,
+        // The ISO language code (built-in: en-US)
+        language: '',
+        // The date string format
+        format: 'mm/dd/yyyy',
+        // The initial date
+        date: null,
+        // The start view date
+        startDate: null,
+        // The end view date
+        endDate: null,
+        // The start view when initialized
+        startView: 0,
+        // 0 for days, 1 for months, 2 for years
+        // The start day of the week
+        // 0 for Sunday, 1 for Monday, 2 for Tuesday, 3 for Wednesday,
+        // 4 for Thursday, 5 for Friday, 6 for Saturday
+        weekStart: 0,
+        // Show year before month on the datepicker header
+        yearFirst: false,
+        // A string suffix to the year number.
+        yearSuffix: '',
+        // Days' name of the week.
+        days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+        // Shorter days' name
+        daysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
+        // Shortest days' name
+        daysMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
+        // Months' name
+        months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+        // Shorter months' name
+        monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+        // A element tag for each item of years, months and days
+        itemTag: 'li',
+        // A class (CSS) for muted date item
+        mutedClass: 'muted',
+        // A class (CSS) for picked date item
+        pickedClass: 'picked',
+        // A class (CSS) for disabled date item
+        disabledClass: 'disabled',
+        // A class (CSS) for highlight date item
+        highlightedClass: 'highlighted',
+        // The template of the datepicker
+        template: '<div class="datepicker-container">' + '<div class="datepicker-panel" data-view="years picker">' + '<ul>' + '<li data-view="years prev">&lsaquo;</li>' + '<li data-view="years current"></li>' + '<li data-view="years next">&rsaquo;</li>' + '</ul>' + '<ul data-view="years"></ul>' + '</div>' + '<div class="datepicker-panel" data-view="months picker">' + '<ul>' + '<li data-view="year prev">&lsaquo;</li>' + '<li data-view="year current"></li>' + '<li data-view="year next">&rsaquo;</li>' + '</ul>' + '<ul data-view="months"></ul>' + '</div>' + '<div class="datepicker-panel" data-view="days picker">' + '<ul>' + '<li data-view="month prev">&lsaquo;</li>' + '<li data-view="month current"></li>' + '<li data-view="month next">&rsaquo;</li>' + '</ul>' + '<ul data-view="week"></ul>' + '<ul data-view="days"></ul>' + '</div>' + '</div>',
+        // The offset top or bottom of the datepicker from the element
+        offset: 10,
+        // The `z-index` of the datepicker
+        zIndex: 1000000,
+        // Filter each date item (return `false` to disable a date item)
+        filter: null,
+        // Event shortcuts
+        show: null,
+        hide: null,
+        pick: null
+    };
+
+    var IS_BROWSER = typeof window !== 'undefined';
+    var WINDOW = IS_BROWSER ? window : {};
+    var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
+    var NAMESPACE = 'datepicker';
+    var EVENT_CLICK = "click.".concat(NAMESPACE);
+    var EVENT_FOCUS = "focus.".concat(NAMESPACE);
+    var EVENT_HIDE = "hide.".concat(NAMESPACE);
+    var EVENT_KEYUP = "keyup.".concat(NAMESPACE);
+    var EVENT_PICK = "pick.".concat(NAMESPACE);
+    var EVENT_RESIZE = "resize.".concat(NAMESPACE);
+    var EVENT_SCROLL = "scroll.".concat(NAMESPACE);
+    var EVENT_SHOW = "show.".concat(NAMESPACE);
+    var EVENT_TOUCH_START = "touchstart.".concat(NAMESPACE);
+    var CLASS_HIDE = "".concat(NAMESPACE, "-hide");
+    var LANGUAGES = {};
+    var VIEWS = {
+        DAYS: 0,
+        MONTHS: 1,
+        YEARS: 2
+    };
+
+    var toString = Object.prototype.toString;
+
+    function typeOf(obj) {
+        return toString.call(obj).slice(8, -1).toLowerCase();
+    }
+
+    function isString(value) {
+        return typeof value === 'string';
+    }
+    var isNaN = Number.isNaN || WINDOW.isNaN;
+
+    function isNumber(value) {
+        return typeof value === 'number' && !isNaN(value);
+    }
+
+    function isUndefined(value) {
+        return typeof value === 'undefined';
+    }
+
+    function isDate(value) {
+        return typeOf(value) === 'date' && !isNaN(value.getTime());
+    }
+
+    function proxy(fn, context) {
+        for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
+            args[_key - 2] = arguments[_key];
+        }
+
+        return function() {
+            for (var _len2 = arguments.length, args2 = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+                args2[_key2] = arguments[_key2];
+            }
+
+            return fn.apply(context, args.concat(args2));
+        };
+    }
+
+    function selectorOf(view) {
+        return "[data-view=\"".concat(view, "\"]");
+    }
+
+    function isLeapYear(year) {
+        return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
+    }
+
+    function getDaysInMonth(year, month) {
+        return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
+    }
+
+    function getMinDay(year, month, day) {
+        return Math.min(day, getDaysInMonth(year, month));
+    }
+    var formatParts = /(y|m|d)+/g;
+
+    function parseFormat(format) {
+        var source = String(format).toLowerCase();
+        var parts = source.match(formatParts);
+
+        if (!parts || parts.length === 0) {
+            throw new Error('Invalid date format.');
+        }
+
+        format = {
+            source: source,
+            parts: parts
+        };
+        $.each(parts, function(i, part) {
+            switch (part) {
+                case 'dd':
+                case 'd':
+                    format.hasDay = true;
+                    break;
+
+                case 'mm':
+                case 'm':
+                    format.hasMonth = true;
+                    break;
+
+                case 'yyyy':
+                case 'yy':
+                    format.hasYear = true;
+                    break;
+            }
+        });
+        return format;
+    }
+
+    function getScrollParent(element) {
+        var includeHidden = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+        var $element = $(element);
+        var position = $element.css('position');
+        var excludeStaticParent = position === 'absolute';
+        var overflowRegex = includeHidden ? /auto|scroll|hidden/ : /auto|scroll/;
+        var scrollParent = $element.parents().filter(function(index, parent) {
+            var $parent = $(parent);
+
+            if (excludeStaticParent && $parent.css('position') === 'static') {
+                return false;
+            }
+
+            return overflowRegex.test($parent.css('overflow') + $parent.css('overflow-y') + $parent.css('overflow-x'));
+        }).eq(0);
+        return position === 'fixed' || !scrollParent.length ? $(element.ownerDocument || document) : scrollParent;
+    }
+    /**
+     * Add leading zeroes to the given value
+     * @param {number} value - The value to add.
+     * @param {number} [length=1] - The expected value length.
+     * @returns {string} Returns converted value.
+     */
+
+    function addLeadingZero(value) {
+        var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
+        var str = String(Math.abs(value));
+        var i = str.length;
+        var result = '';
+
+        if (value < 0) {
+            result += '-';
+        }
+
+        while (i < length) {
+            i += 1;
+            result += '0';
+        }
+
+        return result + str;
+    }
+
+    var REGEXP_DIGITS = /\d+/g;
+    var methods = {
+        // Show the datepicker
+        show: function show() {
+            if (!this.built) {
+                this.build();
+            }
+
+            if (this.shown) {
+                return;
+            }
+
+            if (this.trigger(EVENT_SHOW).isDefaultPrevented()) {
+                return;
+            }
+
+            this.shown = true;
+            this.$picker.removeClass(CLASS_HIDE).on(EVENT_CLICK, $.proxy(this.click, this));
+            this.showView(this.options.startView);
+
+            if (!this.inline) {
+                this.$scrollParent.on(EVENT_SCROLL, $.proxy(this.place, this));
+                $(window).on(EVENT_RESIZE, this.onResize = proxy(this.place, this));
+                $(document).on(EVENT_CLICK, this.onGlobalClick = proxy(this.globalClick, this));
+                $(document).on(EVENT_KEYUP, this.onGlobalKeyup = proxy(this.globalKeyup, this));
+
+                if (IS_TOUCH_DEVICE) {
+                    $(document).on(EVENT_TOUCH_START, this.onTouchStart = proxy(this.touchstart, this));
+                }
+
+                this.place();
+            }
+        },
+        // Hide the datepicker
+        hide: function hide() {
+            if (!this.shown) {
+                return;
+            }
+
+            if (this.trigger(EVENT_HIDE).isDefaultPrevented()) {
+                return;
+            }
+
+            this.shown = false;
+            this.$picker.addClass(CLASS_HIDE).off(EVENT_CLICK, this.click);
+
+            if (!this.inline) {
+                this.$scrollParent.off(EVENT_SCROLL, this.place);
+                $(window).off(EVENT_RESIZE, this.onResize);
+                $(document).off(EVENT_CLICK, this.onGlobalClick);
+                $(document).off(EVENT_KEYUP, this.onGlobalKeyup);
+
+                if (IS_TOUCH_DEVICE) {
+                    $(document).off(EVENT_TOUCH_START, this.onTouchStart);
+                }
+            }
+        },
+        toggle: function toggle() {
+            if (this.shown) {
+                this.hide();
+            } else {
+                this.show();
+            }
+        },
+        // Update the datepicker with the current input value
+        update: function update() {
+            var value = this.getValue();
+
+            if (value === this.oldValue) {
+                return;
+            }
+
+            this.setDate(value, true);
+            this.oldValue = value;
+        },
+
+        /**
+         * Pick the current date to the element
+         *
+         * @param {String} _view (private)
+         */
+        pick: function pick(_view) {
+            var $this = this.$element;
+            var date = this.date;
+
+            if (this.trigger(EVENT_PICK, {
+                    view: _view || '',
+                    date: date
+                }).isDefaultPrevented()) {
+                return;
+            }
+
+            date = this.formatDate(this.date);
+            this.setValue(date);
+
+            if (this.isInput) {
+                $this.trigger('input');
+                $this.trigger('change');
+            }
+        },
+        // Reset the datepicker
+        reset: function reset() {
+            this.setDate(this.initialDate, true);
+            this.setValue(this.initialValue);
+
+            if (this.shown) {
+                this.showView(this.options.startView);
+            }
+        },
+
+        /**
+         * Get the month name with given argument or the current date
+         *
+         * @param {Number} month (optional)
+         * @param {Boolean} shortForm (optional)
+         * @return {String} (month name)
+         */
+        getMonthName: function getMonthName(month, shortForm) {
+            var options = this.options;
+            var monthsShort = options.monthsShort;
+            var months = options.months;
+
+            if ($.isNumeric(month)) {
+                month = Number(month);
+            } else if (isUndefined(shortForm)) {
+                shortForm = month;
+            }
+
+            if (shortForm === true) {
+                months = monthsShort;
+            }
+
+            return months[isNumber(month) ? month : this.date.getMonth()];
+        },
+
+        /**
+         * Get the day name with given argument or the current date
+         *
+         * @param {Number} day (optional)
+         * @param {Boolean} shortForm (optional)
+         * @param {Boolean} min (optional)
+         * @return {String} (day name)
+         */
+        getDayName: function getDayName(day, shortForm, min) {
+            var options = this.options;
+            var days = options.days;
+
+            if ($.isNumeric(day)) {
+                day = Number(day);
+            } else {
+                if (isUndefined(min)) {
+                    min = shortForm;
+                }
+
+                if (isUndefined(shortForm)) {
+                    shortForm = day;
+                }
+            }
+
+            if (min) {
+                days = options.daysMin;
+            } else if (shortForm) {
+                days = options.daysShort;
+            }
+
+            return days[isNumber(day) ? day : this.date.getDay()];
+        },
+
+        /**
+         * Get the current date
+         *
+         * @param {Boolean} formatted (optional)
+         * @return {Date|String} (date)
+         */
+        getDate: function getDate(formatted) {
+            var date = this.date;
+            return formatted ? this.formatDate(date) : new Date(date);
+        },
+
+        /**
+         * Set the current date with a new date
+         *
+         * @param {Date} date
+         * @param {Boolean} _updated (private)
+         */
+        setDate: function setDate(date, _updated) {
+            var filter = this.options.filter;
+
+            if (isDate(date) || isString(date)) {
+                date = this.parseDate(date);
+
+                if ($.isFunction(filter) && filter.call(this.$element, date, 'day') === false) {
+                    return;
+                }
+
+                this.date = date;
+                this.viewDate = new Date(date);
+
+                if (!_updated) {
+                    this.pick();
+                }
+
+                if (this.built) {
+                    this.render();
+                }
+            }
+        },
+
+        /**
+         * Set the start view date with a new date
+         *
+         * @param {Date|string|null} date
+         */
+        setStartDate: function setStartDate(date) {
+            if (isDate(date) || isString(date)) {
+                this.startDate = this.parseDate(date);
+            } else {
+                this.startDate = null;
+            }
+
+            if (this.built) {
+                this.render();
+            }
+        },
+
+        /**
+         * Set the end view date with a new date
+         *
+         * @param {Date|string|null} date
+         */
+        setEndDate: function setEndDate(date) {
+            if (isDate(date) || isString(date)) {
+                this.endDate = this.parseDate(date);
+            } else {
+                this.endDate = null;
+            }
+
+            if (this.built) {
+                this.render();
+            }
+        },
+
+        /**
+         * Parse a date string with the set date format
+         *
+         * @param {String} date
+         * @return {Date} (parsed date)
+         */
+        parseDate: function parseDate(date) {
+            var format = this.format;
+            var parts = [];
+
+            if (!isDate(date)) {
+                if (isString(date)) {
+                    parts = date.match(REGEXP_DIGITS) || [];
+                }
+
+                date = date ? new Date(date) : new Date();
+
+                if (!isDate(date)) {
+                    date = new Date();
+                }
+
+                if (parts.length === format.parts.length) {
+                    // Set year and month first
+                    $.each(parts, function(i, part) {
+                        var value = parseInt(part, 10);
+
+                        switch (format.parts[i]) {
+                            case 'yy':
+                                date.setFullYear(2000 + value);
+                                break;
+
+                            case 'yyyy':
+                                // Converts 2-digit year to 2000+
+                                date.setFullYear(part.length === 2 ? 2000 + value : value);
+                                break;
+
+                            case 'mm':
+                            case 'm':
+                                date.setMonth(value - 1);
+                                break;
+                        }
+                    }); // Set day in the last to avoid converting `31/10/2019` to `01/10/2019`
+
+                    $.each(parts, function(i, part) {
+                        var value = parseInt(part, 10);
+
+                        switch (format.parts[i]) {
+                            case 'dd':
+                            case 'd':
+                                date.setDate(value);
+                                break;
+                        }
+                    });
+                }
+            } // Ignore hours, minutes, seconds and milliseconds to avoid side effect (#192)
+
+
+            return new Date(date.getFullYear(), date.getMonth(), date.getDate());
+        },
+
+        /**
+         * Format a date object to a string with the set date format
+         *
+         * @param {Date} date
+         * @return {String} (formatted date)
+         */
+        formatDate: function formatDate(date) {
+            var format = this.format;
+            var formatted = '';
+
+            if (isDate(date)) {
+                var year = date.getFullYear();
+                var month = date.getMonth();
+                var day = date.getDate();
+                var values = {
+                    d: day,
+                    dd: addLeadingZero(day, 2),
+                    m: month + 1,
+                    mm: addLeadingZero(month + 1, 2),
+                    yy: String(year).substring(2),
+                    yyyy: addLeadingZero(year, 4)
+                };
+                formatted = format.source;
+                $.each(format.parts, function(i, part) {
+                    formatted = formatted.replace(part, values[part]);
+                });
+            }
+
+            return formatted;
+        },
+        // Destroy the datepicker and remove the instance from the target element
+        destroy: function destroy() {
+            this.unbind();
+            this.unbuild();
+            this.$element.removeData(NAMESPACE);
+        }
+    };
+
+    var handlers = {
+        click: function click(e) {
+            var $target = $(e.target);
+            var options = this.options,
+                date = this.date,
+                viewDate = this.viewDate,
+                format = this.format;
+            e.stopPropagation();
+            e.preventDefault();
+
+            if ($target.hasClass('disabled')) {
+                return;
+            }
+
+            var view = $target.data('view');
+            var viewYear = viewDate.getFullYear();
+            var viewMonth = viewDate.getMonth();
+            var viewDay = viewDate.getDate();
+
+            switch (view) {
+                case 'years prev':
+                case 'years next':
+                    {
+                        viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10;
+                        viewDate.setFullYear(viewYear);
+                        viewDate.setDate(getMinDay(viewYear, viewMonth, viewDay));
+                        this.renderYears();
+                        break;
+                    }
+
+                case 'year prev':
+                case 'year next':
+                    viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1;
+                    viewDate.setFullYear(viewYear);
+                    viewDate.setDate(getMinDay(viewYear, viewMonth, viewDay));
+                    this.renderMonths();
+                    break;
+
+                case 'year current':
+                    if (format.hasYear) {
+                        this.showView(VIEWS.YEARS);
+                    }
+
+                    break;
+
+                case 'year picked':
+                    if (format.hasMonth) {
+                        this.showView(VIEWS.MONTHS);
+                    } else {
+                        $target.siblings(".".concat(options.pickedClass)).removeClass(options.pickedClass).data('view', 'year');
+                        this.hideView();
+                    }
+
+                    this.pick('year');
+                    break;
+
+                case 'year':
+                    viewYear = parseInt($target.text(), 10); // Set date first to avoid month changing (#195)
+
+                    date.setDate(getMinDay(viewYear, viewMonth, viewDay));
+                    date.setFullYear(viewYear);
+                    viewDate.setDate(getMinDay(viewYear, viewMonth, viewDay));
+                    viewDate.setFullYear(viewYear);
+
+                    if (format.hasMonth) {
+                        this.showView(VIEWS.MONTHS);
+                    } else {
+                        $target.addClass(options.pickedClass).data('view', 'year picked').siblings(".".concat(options.pickedClass)).removeClass(options.pickedClass).data('view', 'year');
+                        this.hideView();
+                    }
+
+                    this.pick('year');
+                    break;
+
+                case 'month prev':
+                case 'month next':
+                    viewMonth = view === 'month prev' ? viewMonth - 1 : viewMonth + 1;
+
+                    if (viewMonth < 0) {
+                        viewYear -= 1;
+                        viewMonth += 12;
+                    } else if (viewMonth > 11) {
+                        viewYear += 1;
+                        viewMonth -= 12;
+                    }
+
+                    viewDate.setFullYear(viewYear);
+                    viewDate.setDate(getMinDay(viewYear, viewMonth, viewDay));
+                    viewDate.setMonth(viewMonth);
+                    this.renderDays();
+                    break;
+
+                case 'month current':
+                    if (format.hasMonth) {
+                        this.showView(VIEWS.MONTHS);
+                    }
+
+                    break;
+
+                case 'month picked':
+                    if (format.hasDay) {
+                        this.showView(VIEWS.DAYS);
+                    } else {
+                        $target.siblings(".".concat(options.pickedClass)).removeClass(options.pickedClass).data('view', 'month');
+                        this.hideView();
+                    }
+
+                    this.pick('month');
+                    break;
+
+                case 'month':
+                    viewMonth = $.inArray($target.text(), options.monthsShort);
+                    date.setFullYear(viewYear); // Set date before month to avoid month changing (#195)
+
+                    date.setDate(getMinDay(viewYear, viewMonth, viewDay));
+                    date.setMonth(viewMonth);
+                    viewDate.setFullYear(viewYear);
+                    viewDate.setDate(getMinDay(viewYear, viewMonth, viewDay));
+                    viewDate.setMonth(viewMonth);
+
+                    if (format.hasDay) {
+                        this.showView(VIEWS.DAYS);
+                    } else {
+                        $target.addClass(options.pickedClass).data('view', 'month picked').siblings(".".concat(options.pickedClass)).removeClass(options.pickedClass).data('view', 'month');
+                        this.hideView();
+                    }
+
+                    this.pick('month');
+                    break;
+
+                case 'day prev':
+                case 'day next':
+                case 'day':
+                    if (view === 'day prev') {
+                        viewMonth -= 1;
+                    } else if (view === 'day next') {
+                        viewMonth += 1;
+                    }
+
+                    viewDay = parseInt($target.text(), 10); // Set date to 1 to avoid month changing (#195)
+
+                    date.setDate(1);
+                    date.setFullYear(viewYear);
+                    date.setMonth(viewMonth);
+                    date.setDate(viewDay);
+                    viewDate.setDate(1);
+                    viewDate.setFullYear(viewYear);
+                    viewDate.setMonth(viewMonth);
+                    viewDate.setDate(viewDay);
+                    this.renderDays();
+
+                    if (view === 'day') {
+                        this.hideView();
+                    }
+
+                    this.pick('day');
+                    break;
+
+                case 'day picked':
+                    this.hideView();
+                    this.pick('day');
+                    break;
+            }
+        },
+        globalClick: function globalClick(_ref) {
+            var target = _ref.target;
+            var element = this.element,
+                $trigger = this.$trigger;
+            var trigger = $trigger[0];
+            var hidden = true;
+
+            while (target !== document) {
+                if (target === trigger || target === element) {
+                    hidden = false;
+                    break;
+                }
+
+                target = target.parentNode;
+            }
+
+            if (hidden) {
+                this.hide();
+            }
+        },
+        keyup: function keyup() {
+            this.update();
+        },
+        globalKeyup: function globalKeyup(_ref2) {
+            var target = _ref2.target,
+                key = _ref2.key,
+                keyCode = _ref2.keyCode;
+
+            if (this.isInput && target !== this.element && this.shown && (key === 'Tab' || keyCode === 9)) {
+                this.hide();
+            }
+        },
+        touchstart: function touchstart(_ref3) {
+            var target = _ref3.target;
+
+            // Emulate click in touch devices to support hiding the picker automatically (#197).
+            if (this.isInput && target !== this.element && !$.contains(this.$picker[0], target)) {
+                this.hide();
+                this.element.blur();
+            }
+        }
+    };
+
+    var render = {
+        render: function render() {
+            this.renderYears();
+            this.renderMonths();
+            this.renderDays();
+        },
+        renderWeek: function renderWeek() {
+            var _this = this;
+
+            var items = [];
+            var _this$options = this.options,
+                weekStart = _this$options.weekStart,
+                daysMin = _this$options.daysMin;
+            weekStart = parseInt(weekStart, 10) % 7;
+            daysMin = daysMin.slice(weekStart).concat(daysMin.slice(0, weekStart));
+            $.each(daysMin, function(i, day) {
+                items.push(_this.createItem({
+                    text: day
+                }));
+            });
+            this.$week.html(items.join(''));
+        },
+        renderYears: function renderYears() {
+            var options = this.options,
+                startDate = this.startDate,
+                endDate = this.endDate;
+            var disabledClass = options.disabledClass,
+                filter = options.filter,
+                yearSuffix = options.yearSuffix;
+            var viewYear = this.viewDate.getFullYear();
+            var now = new Date();
+            var thisYear = now.getFullYear();
+            var year = this.date.getFullYear();
+            var start = -5;
+            var end = 6;
+            var items = [];
+            var prevDisabled = false;
+            var nextDisabled = false;
+            var i;
+
+            for (i = start; i <= end; i += 1) {
+                var date = new Date(viewYear + i, 1, 1);
+                var disabled = false;
+
+                if (startDate) {
+                    disabled = date.getFullYear() < startDate.getFullYear();
+
+                    if (i === start) {
+                        prevDisabled = disabled;
+                    }
+                }
+
+                if (!disabled && endDate) {
+                    disabled = date.getFullYear() > endDate.getFullYear();
+
+                    if (i === end) {
+                        nextDisabled = disabled;
+                    }
+                }
+
+                if (!disabled && filter) {
+                    disabled = filter.call(this.$element, date, 'year') === false;
+                }
+
+                var picked = viewYear + i === year;
+                var view = picked ? 'year picked' : 'year';
+                items.push(this.createItem({
+                    picked: picked,
+                    disabled: disabled,
+                    text: viewYear + i,
+                    view: disabled ? 'year disabled' : view,
+                    highlighted: date.getFullYear() === thisYear
+                }));
+            }
+
+            this.$yearsPrev.toggleClass(disabledClass, prevDisabled);
+            this.$yearsNext.toggleClass(disabledClass, nextDisabled);
+            this.$yearsCurrent.toggleClass(disabledClass, true).html("".concat(viewYear + start + yearSuffix, " - ").concat(viewYear + end).concat(yearSuffix));
+            this.$years.html(items.join(''));
+        },
+        renderMonths: function renderMonths() {
+            var options = this.options,
+                startDate = this.startDate,
+                endDate = this.endDate,
+                viewDate = this.viewDate;
+            var disabledClass = options.disabledClass || '';
+            var months = options.monthsShort;
+            var filter = $.isFunction(options.filter) && options.filter;
+            var viewYear = viewDate.getFullYear();
+            var now = new Date();
+            var thisYear = now.getFullYear();
+            var thisMonth = now.getMonth();
+            var year = this.date.getFullYear();
+            var month = this.date.getMonth();
+            var items = [];
+            var prevDisabled = false;
+            var nextDisabled = false;
+            var i;
+
+            for (i = 0; i <= 11; i += 1) {
+                var date = new Date(viewYear, i, 1);
+                var disabled = false;
+
+                if (startDate) {
+                    prevDisabled = date.getFullYear() === startDate.getFullYear();
+                    disabled = prevDisabled && date.getMonth() < startDate.getMonth();
+                }
+
+                if (!disabled && endDate) {
+                    nextDisabled = date.getFullYear() === endDate.getFullYear();
+                    disabled = nextDisabled && date.getMonth() > endDate.getMonth();
+                }
+
+                if (!disabled && filter) {
+                    disabled = filter.call(this.$element, date, 'month') === false;
+                }
+
+                var picked = viewYear === year && i === month;
+                var view = picked ? 'month picked' : 'month';
+                items.push(this.createItem({
+                    disabled: disabled,
+                    picked: picked,
+                    highlighted: viewYear === thisYear && date.getMonth() === thisMonth,
+                    index: i,
+                    text: months[i],
+                    view: disabled ? 'month disabled' : view
+                }));
+            }
+
+            this.$yearPrev.toggleClass(disabledClass, prevDisabled);
+            this.$yearNext.toggleClass(disabledClass, nextDisabled);
+            this.$yearCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(viewYear + options.yearSuffix || '');
+            this.$months.html(items.join(''));
+        },
+        renderDays: function renderDays() {
+            var $element = this.$element,
+                options = this.options,
+                startDate = this.startDate,
+                endDate = this.endDate,
+                viewDate = this.viewDate,
+                currentDate = this.date;
+            var disabledClass = options.disabledClass,
+                filter = options.filter,
+                months = options.months,
+                weekStart = options.weekStart,
+                yearSuffix = options.yearSuffix;
+            var viewYear = viewDate.getFullYear();
+            var viewMonth = viewDate.getMonth();
+            var now = new Date();
+            var thisYear = now.getFullYear();
+            var thisMonth = now.getMonth();
+            var thisDay = now.getDate();
+            var year = currentDate.getFullYear();
+            var month = currentDate.getMonth();
+            var day = currentDate.getDate();
+            var length;
+            var i;
+            var n; // Days of prev month
+            // -----------------------------------------------------------------------
+
+            var prevItems = [];
+            var prevViewYear = viewYear;
+            var prevViewMonth = viewMonth;
+            var prevDisabled = false;
+
+            if (viewMonth === 0) {
+                prevViewYear -= 1;
+                prevViewMonth = 11;
+            } else {
+                prevViewMonth -= 1;
+            } // The length of the days of prev month
+
+
+            length = getDaysInMonth(prevViewYear, prevViewMonth); // The first day of current month
+
+            var firstDay = new Date(viewYear, viewMonth, 1); // The visible length of the days of prev month
+            // [0,1,2,3,4,5,6] - [0,1,2,3,4,5,6] => [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6]
+
+            n = firstDay.getDay() - parseInt(weekStart, 10) % 7; // [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] => [1,2,3,4,5,6,7]
+
+            if (n <= 0) {
+                n += 7;
+            }
+
+            if (startDate) {
+                prevDisabled = firstDay.getTime() <= startDate.getTime();
+            }
+
+            for (i = length - (n - 1); i <= length; i += 1) {
+                var prevViewDate = new Date(prevViewYear, prevViewMonth, i);
+                var disabled = false;
+
+                if (startDate) {
+                    disabled = prevViewDate.getTime() < startDate.getTime();
+                }
+
+                if (!disabled && filter) {
+                    disabled = filter.call($element, prevViewDate, 'day') === false;
+                }
+
+                prevItems.push(this.createItem({
+                    disabled: disabled,
+                    highlighted: prevViewYear === thisYear && prevViewMonth === thisMonth && prevViewDate.getDate() === thisDay,
+                    muted: true,
+                    picked: prevViewYear === year && prevViewMonth === month && i === day,
+                    text: i,
+                    view: 'day prev'
+                }));
+            } // Days of next month
+            // -----------------------------------------------------------------------
+
+
+            var nextItems = [];
+            var nextViewYear = viewYear;
+            var nextViewMonth = viewMonth;
+            var nextDisabled = false;
+
+            if (viewMonth === 11) {
+                nextViewYear += 1;
+                nextViewMonth = 0;
+            } else {
+                nextViewMonth += 1;
+            } // The length of the days of current month
+
+
+            length = getDaysInMonth(viewYear, viewMonth); // The visible length of next month (42 means 6 rows and 7 columns)
+
+            n = 42 - (prevItems.length + length); // The last day of current month
+
+            var lastDate = new Date(viewYear, viewMonth, length);
+
+            if (endDate) {
+                nextDisabled = lastDate.getTime() >= endDate.getTime();
+            }
+
+            for (i = 1; i <= n; i += 1) {
+                var date = new Date(nextViewYear, nextViewMonth, i);
+                var picked = nextViewYear === year && nextViewMonth === month && i === day;
+                var _disabled = false;
+
+                if (endDate) {
+                    _disabled = date.getTime() > endDate.getTime();
+                }
+
+                if (!_disabled && filter) {
+                    _disabled = filter.call($element, date, 'day') === false;
+                }
+
+                nextItems.push(this.createItem({
+                    disabled: _disabled,
+                    picked: picked,
+                    highlighted: nextViewYear === thisYear && nextViewMonth === thisMonth && date.getDate() === thisDay,
+                    muted: true,
+                    text: i,
+                    view: 'day next'
+                }));
+            } // Days of current month
+            // -----------------------------------------------------------------------
+
+
+            var items = [];
+
+            for (i = 1; i <= length; i += 1) {
+                var _date = new Date(viewYear, viewMonth, i);
+
+                var _disabled2 = false;
+
+                if (startDate) {
+                    _disabled2 = _date.getTime() < startDate.getTime();
+                }
+
+                if (!_disabled2 && endDate) {
+                    _disabled2 = _date.getTime() > endDate.getTime();
+                }
+
+                if (!_disabled2 && filter) {
+                    _disabled2 = filter.call($element, _date, 'day') === false;
+                }
+
+                var _picked = viewYear === year && viewMonth === month && i === day;
+
+                var view = _picked ? 'day picked' : 'day';
+                items.push(this.createItem({
+                    disabled: _disabled2,
+                    picked: _picked,
+                    highlighted: viewYear === thisYear && viewMonth === thisMonth && _date.getDate() === thisDay,
+                    text: i,
+                    view: _disabled2 ? 'day disabled' : view
+                }));
+            } // Render days picker
+            // -----------------------------------------------------------------------
+
+
+            this.$monthPrev.toggleClass(disabledClass, prevDisabled);
+            this.$monthNext.toggleClass(disabledClass, nextDisabled);
+            this.$monthCurrent.toggleClass(disabledClass, prevDisabled && nextDisabled).html(options.yearFirst ? "".concat(viewYear + yearSuffix, " ").concat(months[viewMonth]) : "".concat(months[viewMonth], " ").concat(viewYear).concat(yearSuffix));
+            this.$days.html(prevItems.join('') + items.join('') + nextItems.join(''));
+        }
+    };
+
+    var CLASS_TOP_LEFT = "".concat(NAMESPACE, "-top-left");
+    var CLASS_TOP_RIGHT = "".concat(NAMESPACE, "-top-right");
+    var CLASS_BOTTOM_LEFT = "".concat(NAMESPACE, "-bottom-left");
+    var CLASS_BOTTOM_RIGHT = "".concat(NAMESPACE, "-bottom-right");
+    var CLASS_PLACEMENTS = [CLASS_TOP_LEFT, CLASS_TOP_RIGHT, CLASS_BOTTOM_LEFT, CLASS_BOTTOM_RIGHT].join(' ');
+
+    var Datepicker = /*#__PURE__*/ function() {
+        function Datepicker(element) {
+            var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+            _classCallCheck(this, Datepicker);
+
+            this.$element = $(element);
+            this.element = element;
+            this.options = $.extend({}, DEFAULTS, LANGUAGES[options.language], $.isPlainObject(options) && options);
+            this.$scrollParent = getScrollParent(element, true);
+            this.built = false;
+            this.shown = false;
+            this.isInput = false;
+            this.inline = false;
+            this.initialValue = '';
+            this.initialDate = null;
+            this.startDate = null;
+            this.endDate = null;
+            this.init();
+        }
+
+        _createClass(Datepicker, [{
+            key: "init",
+            value: function init() {
+                var $this = this.$element,
+                    options = this.options;
+                var startDate = options.startDate,
+                    endDate = options.endDate,
+                    date = options.date;
+                this.$trigger = $(options.trigger);
+                this.isInput = $this.is('input') || $this.is('textarea');
+                this.inline = options.inline && (options.container || !this.isInput);
+                this.format = parseFormat(options.format);
+                var initialValue = this.getValue();
+                this.initialValue = initialValue;
+                this.oldValue = initialValue;
+                date = this.parseDate(date || initialValue);
+
+                if (startDate) {
+                    startDate = this.parseDate(startDate);
+
+                    if (date.getTime() < startDate.getTime()) {
+                        date = new Date(startDate);
+                    }
+
+                    this.startDate = startDate;
+                }
+
+                if (endDate) {
+                    endDate = this.parseDate(endDate);
+
+                    if (startDate && endDate.getTime() < startDate.getTime()) {
+                        endDate = new Date(startDate);
+                    }
+
+                    if (date.getTime() > endDate.getTime()) {
+                        date = new Date(endDate);
+                    }
+
+                    this.endDate = endDate;
+                }
+
+                this.date = date;
+                this.viewDate = new Date(date);
+                this.initialDate = new Date(this.date);
+                this.bind();
+
+                if (options.autoShow || this.inline) {
+                    this.show();
+                }
+
+                if (options.autoPick) {
+                    this.pick();
+                }
+            }
+        }, {
+            key: "build",
+            value: function build() {
+                if (this.built) {
+                    return;
+                }
+
+                this.built = true;
+                var $this = this.$element,
+                    options = this.options;
+                var $picker = $(options.template);
+                this.$picker = $picker;
+                this.$week = $picker.find(selectorOf('week')); // Years view
+
+                this.$yearsPicker = $picker.find(selectorOf('years picker'));
+                this.$yearsPrev = $picker.find(selectorOf('years prev'));
+                this.$yearsNext = $picker.find(selectorOf('years next'));
+                this.$yearsCurrent = $picker.find(selectorOf('years current'));
+                this.$years = $picker.find(selectorOf('years')); // Months view
+
+                this.$monthsPicker = $picker.find(selectorOf('months picker'));
+                this.$yearPrev = $picker.find(selectorOf('year prev'));
+                this.$yearNext = $picker.find(selectorOf('year next'));
+                this.$yearCurrent = $picker.find(selectorOf('year current'));
+                this.$months = $picker.find(selectorOf('months')); // Days view
+
+                this.$daysPicker = $picker.find(selectorOf('days picker'));
+                this.$monthPrev = $picker.find(selectorOf('month prev'));
+                this.$monthNext = $picker.find(selectorOf('month next'));
+                this.$monthCurrent = $picker.find(selectorOf('month current'));
+                this.$days = $picker.find(selectorOf('days'));
+
+                if (this.inline) {
+                    $(options.container || $this).append($picker.addClass("".concat(NAMESPACE, "-inline")));
+                } else {
+                    $(document.body).append($picker.addClass("".concat(NAMESPACE, "-dropdown")));
+                    $picker.addClass(CLASS_HIDE).css({
+                        zIndex: parseInt(options.zIndex, 10)
+                    });
+                }
+
+                this.renderWeek();
+            }
+        }, {
+            key: "unbuild",
+            value: function unbuild() {
+                if (!this.built) {
+                    return;
+                }
+
+                this.built = false;
+                this.$picker.remove();
+            }
+        }, {
+            key: "bind",
+            value: function bind() {
+                var options = this.options,
+                    $this = this.$element;
+
+                if ($.isFunction(options.show)) {
+                    $this.on(EVENT_SHOW, options.show);
+                }
+
+                if ($.isFunction(options.hide)) {
+                    $this.on(EVENT_HIDE, options.hide);
+                }
+
+                if ($.isFunction(options.pick)) {
+                    $this.on(EVENT_PICK, options.pick);
+                }
+
+                if (this.isInput) {
+                    $this.on(EVENT_KEYUP, $.proxy(this.keyup, this));
+                }
+
+                if (!this.inline) {
+                    if (options.trigger) {
+                        this.$trigger.on(EVENT_CLICK, $.proxy(this.toggle, this));
+                    } else if (this.isInput) {
+                        $this.on(EVENT_FOCUS, $.proxy(this.show, this));
+                    } else {
+                        $this.on(EVENT_CLICK, $.proxy(this.show, this));
+                    }
+                }
+            }
+        }, {
+            key: "unbind",
+            value: function unbind() {
+                var $this = this.$element,
+                    options = this.options;
+
+                if ($.isFunction(options.show)) {
+                    $this.off(EVENT_SHOW, options.show);
+                }
+
+                if ($.isFunction(options.hide)) {
+                    $this.off(EVENT_HIDE, options.hide);
+                }
+
+                if ($.isFunction(options.pick)) {
+                    $this.off(EVENT_PICK, options.pick);
+                }
+
+                if (this.isInput) {
+                    $this.off(EVENT_KEYUP, this.keyup);
+                }
+
+                if (!this.inline) {
+                    if (options.trigger) {
+                        this.$trigger.off(EVENT_CLICK, this.toggle);
+                    } else if (this.isInput) {
+                        $this.off(EVENT_FOCUS, this.show);
+                    } else {
+                        $this.off(EVENT_CLICK, this.show);
+                    }
+                }
+            }
+        }, {
+            key: "showView",
+            value: function showView(view) {
+                var $yearsPicker = this.$yearsPicker,
+                    $monthsPicker = this.$monthsPicker,
+                    $daysPicker = this.$daysPicker,
+                    format = this.format;
+
+                if (format.hasYear || format.hasMonth || format.hasDay) {
+                    switch (Number(view)) {
+                        case VIEWS.YEARS:
+                            $monthsPicker.addClass(CLASS_HIDE);
+                            $daysPicker.addClass(CLASS_HIDE);
+
+                            if (format.hasYear) {
+                                this.renderYears();
+                                $yearsPicker.removeClass(CLASS_HIDE);
+                                this.place();
+                            } else {
+                                this.showView(VIEWS.DAYS);
+                            }
+
+                            break;
+
+                        case VIEWS.MONTHS:
+                            $yearsPicker.addClass(CLASS_HIDE);
+                            $daysPicker.addClass(CLASS_HIDE);
+
+                            if (format.hasMonth) {
+                                this.renderMonths();
+                                $monthsPicker.removeClass(CLASS_HIDE);
+                                this.place();
+                            } else {
+                                this.showView(VIEWS.YEARS);
+                            }
+
+                            break;
+                            // case VIEWS.DAYS:
+
+                        default:
+                            $yearsPicker.addClass(CLASS_HIDE);
+                            $monthsPicker.addClass(CLASS_HIDE);
+
+                            if (format.hasDay) {
+                                this.renderDays();
+                                $daysPicker.removeClass(CLASS_HIDE);
+                                this.place();
+                            } else {
+                                this.showView(VIEWS.MONTHS);
+                            }
+
+                    }
+                }
+            }
+        }, {
+            key: "hideView",
+            value: function hideView() {
+                if (!this.inline && this.options.autoHide) {
+                    this.hide();
+                }
+            }
+        }, {
+            key: "place",
+            value: function place() {
+                    if (this.inline) {
+                        return;
+                    }
+
+                    var $this = this.$element,
+                        options = this.options,
+                        $picker = this.$picker;
+                    var containerWidth = $(document).outerWidth();
+                    var containerHeight = $(document).outerHeight();
+                    var elementWidth = $this.outerWidth();
+                    var elementHeight = $this.outerHeight();
+                    var width = $picker.width();
+                    var height = $picker.height();
+
+                    var _$this$offset = $this.offset(),
+                        left = _$this$offset.left,
+                        top = _$this$offset.top;
+
+                    var offset = parseFloat(options.offset);
+                    var placement = CLASS_TOP_LEFT;
+
+                    if (isNaN(offset)) {
+                        offset = 10;
+                    }
+
+                    if (top > height && top + elementHeight + height > containerHeight) {
+                        top -= height + offset;
+                        placement = CLASS_BOTTOM_LEFT;
+                    } else {
+                        top += elementHeight + offset;
+                    }
+
+                    if (left + width > containerWidth) {
+                        left += elementWidth - width;
+                        placement = placement.replace('left', 'right');
+                    }
+
+                    $picker.removeClass(CLASS_PLACEMENTS).addClass(placement).css({
+                        top: top,
+                        left: left
+                    });
+                } // A shortcut for triggering custom events
+
+        }, {
+            key: "trigger",
+            value: function trigger(type, data) {
+                var e = $.Event(type, data);
+                this.$element.trigger(e);
+                return e;
+            }
+        }, {
+            key: "createItem",
+            value: function createItem(data) {
+                var options = this.options;
+                var itemTag = options.itemTag;
+                var item = {
+                    text: '',
+                    view: '',
+                    muted: false,
+                    picked: false,
+                    disabled: false,
+                    highlighted: false
+                };
+                var classes = [];
+                $.extend(item, data);
+
+                if (item.muted) {
+                    classes.push(options.mutedClass);
+                }
+
+                if (item.highlighted) {
+                    classes.push(options.highlightedClass);
+                }
+
+                if (item.picked) {
+                    classes.push(options.pickedClass);
+                }
+
+                if (item.disabled) {
+                    classes.push(options.disabledClass);
+                }
+
+                return "<".concat(itemTag, " class=\"").concat(classes.join(' '), "\" data-view=\"").concat(item.view, "\">").concat(item.text, "</").concat(itemTag, ">");
+            }
+        }, {
+            key: "getValue",
+            value: function getValue() {
+                var $this = this.$element;
+                return this.isInput ? $this.val() : $this.text();
+            }
+        }, {
+            key: "setValue",
+            value: function setValue() {
+                var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
+                var $this = this.$element;
+
+                if (this.isInput) {
+                    $this.val(value);
+                } else if (!this.inline || this.options.container) {
+                    $this.text(value);
+                }
+            }
+        }], [{
+            key: "setDefaults",
+            value: function setDefaults() {
+                var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+                $.extend(DEFAULTS, LANGUAGES[options.language], $.isPlainObject(options) && options);
+            }
+        }]);
+
+        return Datepicker;
+    }();
+
+    if ($.extend) {
+        $.extend(Datepicker.prototype, render, handlers, methods);
+    }
+
+    if ($.fn) {
+        var AnotherDatepicker = $.fn.datepicker;
+
+        $.fn.datepicker = function jQueryDatepicker(option) {
+            for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+                args[_key - 1] = arguments[_key];
+            }
+
+            var result;
+            this.each(function(i, element) {
+                var $element = $(element);
+                var isDestroy = option === 'destroy';
+                var datepicker = $element.data(NAMESPACE);
+
+                if (!datepicker) {
+                    if (isDestroy) {
+                        return;
+                    }
+
+                    var options = $.extend({}, $element.data(), $.isPlainObject(option) && option);
+                    datepicker = new Datepicker(element, options);
+                    $element.data(NAMESPACE, datepicker);
+                }
+
+                if (isString(option)) {
+                    var fn = datepicker[option];
+
+                    if ($.isFunction(fn)) {
+                        result = fn.apply(datepicker, args);
+
+                        if (isDestroy) {
+                            $element.removeData(NAMESPACE);
+                        }
+                    }
+                }
+            });
+            return !isUndefined(result) ? result : this;
+        };
+
+        $.fn.datepicker.Constructor = Datepicker;
+        $.fn.datepicker.languages = LANGUAGES;
+        $.fn.datepicker.setDefaults = Datepicker.setDefaults;
+
+        $.fn.datepicker.noConflict = function noConflict() {
+            $.fn.datepicker = AnotherDatepicker;
+            return this;
+        };
+    }
+
+})));

+ 19 - 0
public/static/datepicker.zh-CN.js

@@ -0,0 +1,19 @@
+(function(global, factory) {
+    typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) :
+        typeof define === 'function' && define.amd ? define(['jquery'], factory) :
+        (factory(global.jQuery));
+}(this, (function($) {
+    'use strict';
+
+    $.fn.datepicker.languages['zh-CN'] = {
+        format: 'yyyy年mm月dd日',
+        days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
+        daysShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
+        daysMin: ['日', '一', '二', '三', '四', '五', '六'],
+        months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
+        monthsShort: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+        weekStart: 1,
+        yearFirst: true,
+        yearSuffix: '年'
+    };
+})));

+ 1 - 0
public/static/g711Session.js

@@ -0,0 +1 @@
+"use strict";var G711Session=function(a){function b(){d=new G711AudioDecoder(a),this.firstTime=0,this.lastMSW=0}var c=0,d=null,e=null,f=0,g={seconds:null,useconds:null};return b.prototype={parseRTPData:function(a,b,h){var i=b[22],j=b.subarray(24+i,b.length-8);c=(b[21]<<8)+b[20];var k=(b[19]<<24)+(b[18]<<16)+(b[17]<<8)+b[16]>>>0,l=Date.UTC("20"+(k>>26),(k>>22&15)-1,k>>17&31,k>>12&31,k>>6&63,63&k)/1e3;if(l-=28800,0==this.firstTime)this.firstTime=l,this.lastMSW=0,f=(b[21]<<8)+b[20],g.seconds=l,g.useconds=0;else{var m,n=(b[21]<<8)+b[20];m=n>f?n-f:n+65535-f,this.lastMSW+=m,l>this.firstTime&&(this.lastMSW-=1e3),this.firstTime=l,g.seconds=l,g.useconds=this.lastMSW,f=n}var o=d.decode(j),p={codec:"G711",bufferData:o,rtpTimeStamp:1e3*g.seconds+g.useconds,samplingRate:e};return h===!0&&(p.streamData=j),p},setCodecInfo:function(a){debug.log("Set codec info. for G711"),e=a.ClockFreq-0}},new b};

+ 1 - 0
public/static/g726Session.js

@@ -0,0 +1 @@
+"use strict";var G726Session=function(a){function b(){e=new G726xAudioDecoder(f),this.firstTime=0,this.lastMSW=0}var c=0,d=0,e=null,f=a,g={seconds:null,useconds:null};return b.prototype={parseRTPData:function(a,b,h){var i=b[22],j=b.subarray(24+i,b.length-8);c=(b[21]<<8)+b[20];var k=(b[19]<<24)+(b[18]<<16)+(b[17]<<8)+b[16]>>>0,l=Date.UTC("20"+(k>>26),(k>>22&15)-1,k>>17&31,k>>12&31,k>>6&63,63&k)/1e3;if(l-=28800,0==this.firstTime)this.firstTime=l,this.lastMSW=0,d=(b[21]<<8)+b[20],g.seconds=l,g.useconds=0;else{var m,n=(b[21]<<8)+b[20];m=n>d?n-d:n+65535-d,this.lastMSW+=m,l>this.firstTime&&(this.lastMSW-=1e3),this.firstTime=l,g.seconds=l,g.useconds=this.lastMSW,d=n}for(var o=e.decode(j),p=new Float32Array(o.length),q=0;q<o.length;q++)p[q]=o[q]/Math.pow(2,15);var r={codec:"G726",bufferData:p,rtpTimeStamp:1e3*g.seconds+g.useconds};return h===!0&&(r.bitrate=f,r.streamData=j),r},setCodecInfo:function(){debug.log("Set codec info. for G726")}},new b};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/h264Session.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/h265Session.js


+ 1 - 0
public/static/hashMap.js

@@ -0,0 +1 @@
+var Map=function(){this.map={}};Map.prototype={put:function(a,b){this.map[a]=b},get:function(a){return this.map[a]},containsKey:function(a){return a in this.map},containsValue:function(a){for(var b in this.map)if(this.map[b]===a)return!0;return!1},isEmpty:function(){return 0===this.size()},clear:function(){for(var a in this.map)delete this.map[a]},remove:function(a){delete this.map[a]},keys:function(){var a=new Array;for(var b in this.map)a.push(b);return a},values:function(){var a=new Array;for(var b in this.map)a.push(this.map[b]);return a},size:function(){var a=0;for(var b in this.map)a++;return a}};

BIN=BIN
public/static/images/exitFullScreen.png


BIN=BIN
public/static/images/fullScreen.png


BIN=BIN
public/static/images/hd.png


BIN=BIN
public/static/images/pause.png


BIN=BIN
public/static/images/play.png


BIN=BIN
public/static/images/sd.png


BIN=BIN
public/static/images/soundOff.png


BIN=BIN
public/static/images/soundOn.png


BIN=BIN
public/static/images/split_1.png


BIN=BIN
public/static/images/split_16.png


BIN=BIN
public/static/images/split_4.png


BIN=BIN
public/static/images/split_9.png


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/ivs.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/ivsSession.js


+ 4178 - 0
public/static/jquery-min.js

@@ -0,0 +1,4178 @@
+/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(e, t) {
+    "use strict";
+    "object" == typeof module && "object" == typeof module.exports ? module.exports = e.document ? t(e, !0) : function(e) {
+        if (!e.document)
+            throw new Error("jQuery requires a window with a document");
+        return t(e)
+    }
+    : t(e)
+}("undefined" != typeof window ? window : this, function(e, t) {
+    "use strict";
+    var n = []
+      , r = e.document
+      , i = Object.getPrototypeOf
+      , o = n.slice
+      , a = n.concat
+      , s = n.push
+      , u = n.indexOf
+      , l = {}
+      , c = l.toString
+      , f = l.hasOwnProperty
+      , p = f.toString
+      , d = p.call(Object)
+      , h = {}
+      , g = function e(t) {
+        return "function" == typeof t && "number" != typeof t.nodeType
+    }
+      , y = function e(t) {
+        return null != t && t === t.window
+    }
+      , v = {
+        type: !0,
+        src: !0,
+        noModule: !0
+    };
+    function m(e, t, n) {
+        var i, o = (t = t || r).createElement("script");
+        if (o.text = e,
+        n)
+            for (i in v)
+                n[i] && (o[i] = n[i]);
+        t.head.appendChild(o).parentNode.removeChild(o)
+    }
+    function x(e) {
+        return null == e ? e + "" : "object" == typeof e || "function" == typeof e ? l[c.call(e)] || "object" : typeof e
+    }
+    var b = "3.3.1"
+      , w = function(e, t) {
+        return new w.fn.init(e,t)
+    }
+      , T = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
+    w.fn = w.prototype = {
+        jquery: "3.3.1",
+        constructor: w,
+        length: 0,
+        toArray: function() {
+            return o.call(this)
+        },
+        get: function(e) {
+            return null == e ? o.call(this) : e < 0 ? this[e + this.length] : this[e]
+        },
+        pushStack: function(e) {
+            var t = w.merge(this.constructor(), e);
+            return t.prevObject = this,
+            t
+        },
+        each: function(e) {
+            return w.each(this, e)
+        },
+        map: function(e) {
+            return this.pushStack(w.map(this, function(t, n) {
+                return e.call(t, n, t)
+            }))
+        },
+        slice: function() {
+            return this.pushStack(o.apply(this, arguments))
+        },
+        first: function() {
+            return this.eq(0)
+        },
+        last: function() {
+            return this.eq(-1)
+        },
+        eq: function(e) {
+            var t = this.length
+              , n = +e + (e < 0 ? t : 0);
+            return this.pushStack(n >= 0 && n < t ? [this[n]] : [])
+        },
+        end: function() {
+            return this.prevObject || this.constructor()
+        },
+        push: s,
+        sort: n.sort,
+        splice: n.splice
+    },
+    w.extend = w.fn.extend = function() {
+        var e, t, n, r, i, o, a = arguments[0] || {}, s = 1, u = arguments.length, l = !1;
+        for ("boolean" == typeof a && (l = a,
+        a = arguments[s] || {},
+        s++),
+        "object" == typeof a || g(a) || (a = {}),
+        s === u && (a = this,
+        s--); s < u; s++)
+            if (null != (e = arguments[s]))
+                for (t in e)
+                    n = a[t],
+                    a !== (r = e[t]) && (l && r && (w.isPlainObject(r) || (i = Array.isArray(r))) ? (i ? (i = !1,
+                    o = n && Array.isArray(n) ? n : []) : o = n && w.isPlainObject(n) ? n : {},
+                    a[t] = w.extend(l, o, r)) : void 0 !== r && (a[t] = r));
+        return a
+    }
+    ,
+    w.extend({
+        expando: "jQuery" + ("3.3.1" + Math.random()).replace(/\D/g, ""),
+        isReady: !0,
+        error: function(e) {
+            throw new Error(e)
+        },
+        noop: function() {},
+        isPlainObject: function(e) {
+            var t, n;
+            return !(!e || "[object Object]" !== c.call(e)) && (!(t = i(e)) || "function" == typeof (n = f.call(t, "constructor") && t.constructor) && p.call(n) === d)
+        },
+        isEmptyObject: function(e) {
+            var t;
+            for (t in e)
+                return !1;
+            return !0
+        },
+        globalEval: function(e) {
+            m(e)
+        },
+        each: function(e, t) {
+            var n, r = 0;
+            if (C(e)) {
+                for (n = e.length; r < n; r++)
+                    if (!1 === t.call(e[r], r, e[r]))
+                        break
+            } else
+                for (r in e)
+                    if (!1 === t.call(e[r], r, e[r]))
+                        break;
+            return e
+        },
+        trim: function(e) {
+            return null == e ? "" : (e + "").replace(T, "")
+        },
+        makeArray: function(e, t) {
+            var n = t || [];
+            return null != e && (C(Object(e)) ? w.merge(n, "string" == typeof e ? [e] : e) : s.call(n, e)),
+            n
+        },
+        inArray: function(e, t, n) {
+            return null == t ? -1 : u.call(t, e, n)
+        },
+        merge: function(e, t) {
+            for (var n = +t.length, r = 0, i = e.length; r < n; r++)
+                e[i++] = t[r];
+            return e.length = i,
+            e
+        },
+        grep: function(e, t, n) {
+            for (var r, i = [], o = 0, a = e.length, s = !n; o < a; o++)
+                (r = !t(e[o], o)) !== s && i.push(e[o]);
+            return i
+        },
+        map: function(e, t, n) {
+            var r, i, o = 0, s = [];
+            if (C(e))
+                for (r = e.length; o < r; o++)
+                    null != (i = t(e[o], o, n)) && s.push(i);
+            else
+                for (o in e)
+                    null != (i = t(e[o], o, n)) && s.push(i);
+            return a.apply([], s)
+        },
+        guid: 1,
+        support: h
+    }),
+    "function" == typeof Symbol && (w.fn[Symbol.iterator] = n[Symbol.iterator]),
+    w.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "), function(e, t) {
+        l["[object " + t + "]"] = t.toLowerCase()
+    });
+    function C(e) {
+        var t = !!e && "length"in e && e.length
+          , n = x(e);
+        return !g(e) && !y(e) && ("array" === n || 0 === t || "number" == typeof t && t > 0 && t - 1 in e)
+    }
+    var E = function(e) {
+        var t, n, r, i, o, a, s, u, l, c, f, p, d, h, g, y, v, m, x, b = "sizzle" + 1 * new Date, w = e.document, T = 0, C = 0, E = ae(), k = ae(), S = ae(), D = function(e, t) {
+            return e === t && (f = !0),
+            0
+        }, N = {}.hasOwnProperty, A = [], j = A.pop, q = A.push, L = A.push, H = A.slice, O = function(e, t) {
+            for (var n = 0, r = e.length; n < r; n++)
+                if (e[n] === t)
+                    return n;
+            return -1
+        }, P = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", M = "[\\x20\\t\\r\\n\\f]", R = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", I = "\\[" + M + "*(" + R + ")(?:" + M + "*([*^$|!~]?=)" + M + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + R + "))|)" + M + "*\\]", W = ":(" + R + ")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|" + I + ")*)|.*)\\)|)", $ = new RegExp(M + "+","g"), B = new RegExp("^" + M + "+|((?:^|[^\\\\])(?:\\\\.)*)" + M + "+$","g"), F = new RegExp("^" + M + "*," + M + "*"), _ = new RegExp("^" + M + "*([>+~]|" + M + ")" + M + "*"), z = new RegExp("=" + M + "*([^\\]'\"]*?)" + M + "*\\]","g"), X = new RegExp(W), U = new RegExp("^" + R + "$"), V = {
+            ID: new RegExp("^#(" + R + ")"),
+            CLASS: new RegExp("^\\.(" + R + ")"),
+            TAG: new RegExp("^(" + R + "|[*])"),
+            ATTR: new RegExp("^" + I),
+            PSEUDO: new RegExp("^" + W),
+            CHILD: new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + M + "*(even|odd|(([+-]|)(\\d*)n|)" + M + "*(?:([+-]|)" + M + "*(\\d+)|))" + M + "*\\)|)","i"),
+            bool: new RegExp("^(?:" + P + ")$","i"),
+            needsContext: new RegExp("^" + M + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + M + "*((?:-\\d)?\\d*)" + M + "*\\)|)(?=[^-]|$)","i")
+        }, G = /^(?:input|select|textarea|button)$/i, Y = /^h\d$/i, Q = /^[^{]+\{\s*\[native \w/, J = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, K = /[+~]/, Z = new RegExp("\\\\([\\da-f]{1,6}" + M + "?|(" + M + ")|.)","ig"), ee = function(e, t, n) {
+            var r = "0x" + t - 65536;
+            return r !== r || n ? t : r < 0 ? String.fromCharCode(r + 65536) : String.fromCharCode(r >> 10 | 55296, 1023 & r | 56320)
+        }, te = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, ne = function(e, t) {
+            return t ? "\0" === e ? "\ufffd" : e.slice(0, -1) + "\\" + e.charCodeAt(e.length - 1).toString(16) + " " : "\\" + e
+        }, re = function() {
+            p()
+        }, ie = me(function(e) {
+            return !0 === e.disabled && ("form"in e || "label"in e)
+        }, {
+            dir: "parentNode",
+            next: "legend"
+        });
+        try {
+            L.apply(A = H.call(w.childNodes), w.childNodes),
+            A[w.childNodes.length].nodeType
+        } catch (e) {
+            L = {
+                apply: A.length ? function(e, t) {
+                    q.apply(e, H.call(t))
+                }
+                : function(e, t) {
+                    var n = e.length
+                      , r = 0;
+                    while (e[n++] = t[r++])
+                        ;
+                    e.length = n - 1
+                }
+            }
+        }
+        function oe(e, t, r, i) {
+            var o, s, l, c, f, h, v, m = t && t.ownerDocument, T = t ? t.nodeType : 9;
+            if (r = r || [],
+            "string" != typeof e || !e || 1 !== T && 9 !== T && 11 !== T)
+                return r;
+            if (!i && ((t ? t.ownerDocument || t : w) !== d && p(t),
+            t = t || d,
+            g)) {
+                if (11 !== T && (f = J.exec(e)))
+                    if (o = f[1]) {
+                        if (9 === T) {
+                            if (!(l = t.getElementById(o)))
+                                return r;
+                            if (l.id === o)
+                                return r.push(l),
+                                r
+                        } else if (m && (l = m.getElementById(o)) && x(t, l) && l.id === o)
+                            return r.push(l),
+                            r
+                    } else {
+                        if (f[2])
+                            return L.apply(r, t.getElementsByTagName(e)),
+                            r;
+                        if ((o = f[3]) && n.getElementsByClassName && t.getElementsByClassName)
+                            return L.apply(r, t.getElementsByClassName(o)),
+                            r
+                    }
+                if (n.qsa && !S[e + " "] && (!y || !y.test(e))) {
+                    if (1 !== T)
+                        m = t,
+                        v = e;
+                    else if ("object" !== t.nodeName.toLowerCase()) {
+                        (c = t.getAttribute("id")) ? c = c.replace(te, ne) : t.setAttribute("id", c = b),
+                        s = (h = a(e)).length;
+                        while (s--)
+                            h[s] = "#" + c + " " + ve(h[s]);
+                        v = h.join(","),
+                        m = K.test(e) && ge(t.parentNode) || t
+                    }
+                    if (v)
+                        try {
+                            return L.apply(r, m.querySelectorAll(v)),
+                            r
+                        } catch (e) {} finally {
+                            c === b && t.removeAttribute("id")
+                        }
+                }
+            }
+            return u(e.replace(B, "$1"), t, r, i)
+        }
+        function ae() {
+            var e = [];
+            function t(n, i) {
+                return e.push(n + " ") > r.cacheLength && delete t[e.shift()],
+                t[n + " "] = i
+            }
+            return t
+        }
+        function se(e) {
+            return e[b] = !0,
+            e
+        }
+        function ue(e) {
+            var t = d.createElement("fieldset");
+            try {
+                return !!e(t)
+            } catch (e) {
+                return !1
+            } finally {
+                t.parentNode && t.parentNode.removeChild(t),
+                t = null
+            }
+        }
+        function le(e, t) {
+            var n = e.split("|")
+              , i = n.length;
+            while (i--)
+                r.attrHandle[n[i]] = t
+        }
+        function ce(e, t) {
+            var n = t && e
+              , r = n && 1 === e.nodeType && 1 === t.nodeType && e.sourceIndex - t.sourceIndex;
+            if (r)
+                return r;
+            if (n)
+                while (n = n.nextSibling)
+                    if (n === t)
+                        return -1;
+            return e ? 1 : -1
+        }
+        function fe(e) {
+            return function(t) {
+                return "input" === t.nodeName.toLowerCase() && t.type === e
+            }
+        }
+        function pe(e) {
+            return function(t) {
+                var n = t.nodeName.toLowerCase();
+                return ("input" === n || "button" === n) && t.type === e
+            }
+        }
+        function de(e) {
+            return function(t) {
+                return "form"in t ? t.parentNode && !1 === t.disabled ? "label"in t ? "label"in t.parentNode ? t.parentNode.disabled === e : t.disabled === e : t.isDisabled === e || t.isDisabled !== !e && ie(t) === e : t.disabled === e : "label"in t && t.disabled === e
+            }
+        }
+        function he(e) {
+            return se(function(t) {
+                return t = +t,
+                se(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]))
+                })
+            })
+        }
+        function ge(e) {
+            return e && "undefined" != typeof e.getElementsByTagName && e
+        }
+        n = oe.support = {},
+        o = oe.isXML = function(e) {
+            var t = e && (e.ownerDocument || e).documentElement;
+            return !!t && "HTML" !== t.nodeName
+        }
+        ,
+        p = oe.setDocument = function(e) {
+            var t, i, a = e ? e.ownerDocument || e : w;
+            return a !== d && 9 === a.nodeType && a.documentElement ? (d = a,
+            h = d.documentElement,
+            g = !o(d),
+            w !== d && (i = d.defaultView) && i.top !== i && (i.addEventListener ? i.addEventListener("unload", re, !1) : i.attachEvent && i.attachEvent("onunload", re)),
+            n.attributes = ue(function(e) {
+                return e.className = "i",
+                !e.getAttribute("className")
+            }),
+            n.getElementsByTagName = ue(function(e) {
+                return e.appendChild(d.createComment("")),
+                !e.getElementsByTagName("*").length
+            }),
+            n.getElementsByClassName = Q.test(d.getElementsByClassName),
+            n.getById = ue(function(e) {
+                return h.appendChild(e).id = b,
+                !d.getElementsByName || !d.getElementsByName(b).length
+            }),
+            n.getById ? (r.filter.ID = function(e) {
+                var t = e.replace(Z, ee);
+                return function(e) {
+                    return e.getAttribute("id") === t
+                }
+            }
+            ,
+            r.find.ID = function(e, t) {
+                if ("undefined" != typeof t.getElementById && g) {
+                    var n = t.getElementById(e);
+                    return n ? [n] : []
+                }
+            }
+            ) : (r.filter.ID = function(e) {
+                var t = e.replace(Z, ee);
+                return function(e) {
+                    var n = "undefined" != typeof e.getAttributeNode && e.getAttributeNode("id");
+                    return n && n.value === t
+                }
+            }
+            ,
+            r.find.ID = function(e, t) {
+                if ("undefined" != typeof t.getElementById && g) {
+                    var n, r, i, o = t.getElementById(e);
+                    if (o) {
+                        if ((n = o.getAttributeNode("id")) && n.value === e)
+                            return [o];
+                        i = t.getElementsByName(e),
+                        r = 0;
+                        while (o = i[r++])
+                            if ((n = o.getAttributeNode("id")) && n.value === e)
+                                return [o]
+                    }
+                    return []
+                }
+            }
+            ),
+            r.find.TAG = n.getElementsByTagName ? function(e, t) {
+                return "undefined" != typeof t.getElementsByTagName ? t.getElementsByTagName(e) : n.qsa ? t.querySelectorAll(e) : void 0
+            }
+            : 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
+            }
+            ,
+            r.find.CLASS = n.getElementsByClassName && function(e, t) {
+                if ("undefined" != typeof t.getElementsByClassName && g)
+                    return t.getElementsByClassName(e)
+            }
+            ,
+            v = [],
+            y = [],
+            (n.qsa = Q.test(d.querySelectorAll)) && (ue(function(e) {
+                h.appendChild(e).innerHTML = "<a id='" + b + "'></a><select id='" + b + "-\r\\' msallowcapture=''><option selected=''></option></select>",
+                e.querySelectorAll("[msallowcapture^='']").length && y.push("[*^$]=" + M + "*(?:''|\"\")"),
+                e.querySelectorAll("[selected]").length || y.push("\\[" + M + "*(?:value|" + P + ")"),
+                e.querySelectorAll("[id~=" + b + "-]").length || y.push("~="),
+                e.querySelectorAll(":checked").length || y.push(":checked"),
+                e.querySelectorAll("a#" + b + "+*").length || y.push(".#.+[+~]")
+            }),
+            ue(function(e) {
+                e.innerHTML = "<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";
+                var t = d.createElement("input");
+                t.setAttribute("type", "hidden"),
+                e.appendChild(t).setAttribute("name", "D"),
+                e.querySelectorAll("[name=d]").length && y.push("name" + M + "*[*^$|!~]?="),
+                2 !== e.querySelectorAll(":enabled").length && y.push(":enabled", ":disabled"),
+                h.appendChild(e).disabled = !0,
+                2 !== e.querySelectorAll(":disabled").length && y.push(":enabled", ":disabled"),
+                e.querySelectorAll("*,:x"),
+                y.push(",.*:")
+            })),
+            (n.matchesSelector = Q.test(m = h.matches || h.webkitMatchesSelector || h.mozMatchesSelector || h.oMatchesSelector || h.msMatchesSelector)) && ue(function(e) {
+                n.disconnectedMatch = m.call(e, "*"),
+                m.call(e, "[s!='']:x"),
+                v.push("!=", W)
+            }),
+            y = y.length && new RegExp(y.join("|")),
+            v = v.length && new RegExp(v.join("|")),
+            t = Q.test(h.compareDocumentPosition),
+            x = t || Q.test(h.contains) ? function(e, t) {
+                var n = 9 === e.nodeType ? e.documentElement : e
+                  , r = t && t.parentNode;
+                return e === r || !(!r || 1 !== r.nodeType || !(n.contains ? n.contains(r) : e.compareDocumentPosition && 16 & e.compareDocumentPosition(r)))
+            }
+            : function(e, t) {
+                if (t)
+                    while (t = t.parentNode)
+                        if (t === e)
+                            return !0;
+                return !1
+            }
+            ,
+            D = t ? function(e, t) {
+                if (e === t)
+                    return f = !0,
+                    0;
+                var r = !e.compareDocumentPosition - !t.compareDocumentPosition;
+                return r || (1 & (r = (e.ownerDocument || e) === (t.ownerDocument || t) ? e.compareDocumentPosition(t) : 1) || !n.sortDetached && t.compareDocumentPosition(e) === r ? e === d || e.ownerDocument === w && x(w, e) ? -1 : t === d || t.ownerDocument === w && x(w, t) ? 1 : c ? O(c, e) - O(c, t) : 0 : 4 & r ? -1 : 1)
+            }
+            : function(e, t) {
+                if (e === t)
+                    return f = !0,
+                    0;
+                var n, r = 0, i = e.parentNode, o = t.parentNode, a = [e], s = [t];
+                if (!i || !o)
+                    return e === d ? -1 : t === d ? 1 : i ? -1 : o ? 1 : c ? O(c, e) - O(c, t) : 0;
+                if (i === o)
+                    return ce(e, t);
+                n = e;
+                while (n = n.parentNode)
+                    a.unshift(n);
+                n = t;
+                while (n = n.parentNode)
+                    s.unshift(n);
+                while (a[r] === s[r])
+                    r++;
+                return r ? ce(a[r], s[r]) : a[r] === w ? -1 : s[r] === w ? 1 : 0
+            }
+            ,
+            d) : d
+        }
+        ,
+        oe.matches = function(e, t) {
+            return oe(e, null, null, t)
+        }
+        ,
+        oe.matchesSelector = function(e, t) {
+            if ((e.ownerDocument || e) !== d && p(e),
+            t = t.replace(z, "='$1']"),
+            n.matchesSelector && g && !S[t + " "] && (!v || !v.test(t)) && (!y || !y.test(t)))
+                try {
+                    var r = m.call(e, t);
+                    if (r || n.disconnectedMatch || e.document && 11 !== e.document.nodeType)
+                        return r
+                } catch (e) {}
+            return oe(t, d, null, [e]).length > 0
+        }
+        ,
+        oe.contains = function(e, t) {
+            return (e.ownerDocument || e) !== d && p(e),
+            x(e, t)
+        }
+        ,
+        oe.attr = function(e, t) {
+            (e.ownerDocument || e) !== d && p(e);
+            var i = r.attrHandle[t.toLowerCase()]
+              , o = i && N.call(r.attrHandle, t.toLowerCase()) ? i(e, t, !g) : void 0;
+            return void 0 !== o ? o : n.attributes || !g ? e.getAttribute(t) : (o = e.getAttributeNode(t)) && o.specified ? o.value : null
+        }
+        ,
+        oe.escape = function(e) {
+            return (e + "").replace(te, ne)
+        }
+        ,
+        oe.error = function(e) {
+            throw new Error("Syntax error, unrecognized expression: " + e)
+        }
+        ,
+        oe.uniqueSort = function(e) {
+            var t, r = [], i = 0, o = 0;
+            if (f = !n.detectDuplicates,
+            c = !n.sortStable && e.slice(0),
+            e.sort(D),
+            f) {
+                while (t = e[o++])
+                    t === e[o] && (i = r.push(o));
+                while (i--)
+                    e.splice(r[i], 1)
+            }
+            return c = null,
+            e
+        }
+        ,
+        i = oe.getText = function(e) {
+            var t, n = "", r = 0, o = e.nodeType;
+            if (o) {
+                if (1 === o || 9 === o || 11 === o) {
+                    if ("string" == typeof e.textContent)
+                        return e.textContent;
+                    for (e = e.firstChild; e; e = e.nextSibling)
+                        n += i(e)
+                } else if (3 === o || 4 === o)
+                    return e.nodeValue
+            } else
+                while (t = e[r++])
+                    n += i(t);
+            return n
+        }
+        ,
+        (r = oe.selectors = {
+            cacheLength: 50,
+            createPseudo: se,
+            match: V,
+            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(Z, ee),
+                    e[3] = (e[3] || e[4] || e[5] || "").replace(Z, ee),
+                    "~=" === 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] || oe.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] && oe.error(e[0]),
+                    e
+                },
+                PSEUDO: function(e) {
+                    var t, n = !e[6] && e[2];
+                    return V.CHILD.test(e[0]) ? null : (e[3] ? e[2] = e[4] || e[5] || "" : n && X.test(n) && (t = a(n, !0)) && (t = n.indexOf(")", n.length - t) - n.length) && (e[0] = e[0].slice(0, t),
+                    e[2] = n.slice(0, t)),
+                    e.slice(0, 3))
+                }
+            },
+            filter: {
+                TAG: function(e) {
+                    var t = e.replace(Z, ee).toLowerCase();
+                    return "*" === e ? function() {
+                        return !0
+                    }
+                    : function(e) {
+                        return e.nodeName && e.nodeName.toLowerCase() === t
+                    }
+                },
+                CLASS: function(e) {
+                    var t = E[e + " "];
+                    return t || (t = new RegExp("(^|" + M + ")" + e + "(" + M + "|$)")) && E(e, function(e) {
+                        return t.test("string" == typeof e.className && e.className || "undefined" != typeof e.getAttribute && e.getAttribute("class") || "")
+                    })
+                },
+                ATTR: function(e, t, n) {
+                    return function(r) {
+                        var i = oe.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.replace($, " ") + " ").indexOf(n) > -1 : "|=" === t && (i === n || i.slice(0, n.length + 1) === n + "-"))
+                    }
+                },
+                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, u) {
+                        var l, c, f, p, d, h, g = o !== a ? "nextSibling" : "previousSibling", y = t.parentNode, v = s && t.nodeName.toLowerCase(), m = !u && !s, x = !1;
+                        if (y) {
+                            if (o) {
+                                while (g) {
+                                    p = t;
+                                    while (p = p[g])
+                                        if (s ? p.nodeName.toLowerCase() === v : 1 === p.nodeType)
+                                            return !1;
+                                    h = g = "only" === e && !h && "nextSibling"
+                                }
+                                return !0
+                            }
+                            if (h = [a ? y.firstChild : y.lastChild],
+                            a && m) {
+                                x = (d = (l = (c = (f = (p = y)[b] || (p[b] = {}))[p.uniqueID] || (f[p.uniqueID] = {}))[e] || [])[0] === T && l[1]) && l[2],
+                                p = d && y.childNodes[d];
+                                while (p = ++d && p && p[g] || (x = d = 0) || h.pop())
+                                    if (1 === p.nodeType && ++x && p === t) {
+                                        c[e] = [T, d, x];
+                                        break
+                                    }
+                            } else if (m && (x = d = (l = (c = (f = (p = t)[b] || (p[b] = {}))[p.uniqueID] || (f[p.uniqueID] = {}))[e] || [])[0] === T && l[1]),
+                            !1 === x)
+                                while (p = ++d && p && p[g] || (x = d = 0) || h.pop())
+                                    if ((s ? p.nodeName.toLowerCase() === v : 1 === p.nodeType) && ++x && (m && ((c = (f = p[b] || (p[b] = {}))[p.uniqueID] || (f[p.uniqueID] = {}))[e] = [T, x]),
+                                    p === t))
+                                        break;
+                            return (x -= i) === r || x % r == 0 && x / r >= 0
+                        }
+                    }
+                },
+                PSEUDO: function(e, t) {
+                    var n, i = r.pseudos[e] || r.setFilters[e.toLowerCase()] || oe.error("unsupported pseudo: " + e);
+                    return i[b] ? i(t) : i.length > 1 ? (n = [e, e, "", t],
+                    r.setFilters.hasOwnProperty(e.toLowerCase()) ? se(function(e, n) {
+                        var r, o = i(e, t), a = o.length;
+                        while (a--)
+                            e[r = O(e, o[a])] = !(n[r] = o[a])
+                    }) : function(e) {
+                        return i(e, 0, n)
+                    }
+                    ) : i
+                }
+            },
+            pseudos: {
+                not: se(function(e) {
+                    var t = []
+                      , n = []
+                      , r = s(e.replace(B, "$1"));
+                    return r[b] ? se(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),
+                        t[0] = null,
+                        !n.pop()
+                    }
+                }),
+                has: se(function(e) {
+                    return function(t) {
+                        return oe(e, t).length > 0
+                    }
+                }),
+                contains: se(function(e) {
+                    return e = e.replace(Z, ee),
+                    function(t) {
+                        return (t.textContent || t.innerText || i(t)).indexOf(e) > -1
+                    }
+                }),
+                lang: se(function(e) {
+                    return U.test(e || "") || oe.error("unsupported lang: " + e),
+                    e = e.replace(Z, ee).toLowerCase(),
+                    function(t) {
+                        var n;
+                        do {
+                            if (n = g ? t.lang : t.getAttribute("xml:lang") || t.getAttribute("lang"))
+                                return (n = n.toLowerCase()) === e || 0 === n.indexOf(e + "-")
+                        } while ((t = t.parentNode) && 1 === t.nodeType);
+                        return !1
+                    }
+                }),
+                target: function(t) {
+                    var n = e.location && e.location.hash;
+                    return n && n.slice(1) === t.id
+                },
+                root: function(e) {
+                    return e === h
+                },
+                focus: function(e) {
+                    return e === d.activeElement && (!d.hasFocus || d.hasFocus()) && !!(e.type || e.href || ~e.tabIndex)
+                },
+                enabled: de(!1),
+                disabled: de(!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,
+                    !0 === e.selected
+                },
+                empty: function(e) {
+                    for (e = e.firstChild; e; e = e.nextSibling)
+                        if (e.nodeType < 6)
+                            return !1;
+                    return !0
+                },
+                parent: function(e) {
+                    return !r.pseudos.empty(e)
+                },
+                header: function(e) {
+                    return Y.test(e.nodeName)
+                },
+                input: function(e) {
+                    return G.test(e.nodeName)
+                },
+                button: function(e) {
+                    var t = e.nodeName.toLowerCase();
+                    return "input" === t && "button" === e.type || "button" === t
+                },
+                text: function(e) {
+                    var t;
+                    return "input" === e.nodeName.toLowerCase() && "text" === e.type && (null == (t = e.getAttribute("type")) || "text" === t.toLowerCase())
+                },
+                first: he(function() {
+                    return [0]
+                }),
+                last: he(function(e, t) {
+                    return [t - 1]
+                }),
+                eq: he(function(e, t, n) {
+                    return [n < 0 ? n + t : n]
+                }),
+                even: he(function(e, t) {
+                    for (var n = 0; n < t; n += 2)
+                        e.push(n);
+                    return e
+                }),
+                odd: he(function(e, t) {
+                    for (var n = 1; n < t; n += 2)
+                        e.push(n);
+                    return e
+                }),
+                lt: he(function(e, t, n) {
+                    for (var r = n < 0 ? n + t : n; --r >= 0; )
+                        e.push(r);
+                    return e
+                }),
+                gt: he(function(e, t, n) {
+                    for (var r = n < 0 ? n + t : n; ++r < t; )
+                        e.push(r);
+                    return e
+                })
+            }
+        }).pseudos.nth = r.pseudos.eq;
+        for (t in {
+            radio: !0,
+            checkbox: !0,
+            file: !0,
+            password: !0,
+            image: !0
+        })
+            r.pseudos[t] = fe(t);
+        for (t in {
+            submit: !0,
+            reset: !0
+        })
+            r.pseudos[t] = pe(t);
+        function ye() {}
+        ye.prototype = r.filters = r.pseudos,
+        r.setFilters = new ye,
+        a = oe.tokenize = function(e, t) {
+            var n, i, o, a, s, u, l, c = k[e + " "];
+            if (c)
+                return t ? 0 : c.slice(0);
+            s = e,
+            u = [],
+            l = r.preFilter;
+            while (s) {
+                n && !(i = F.exec(s)) || (i && (s = s.slice(i[0].length) || s),
+                u.push(o = [])),
+                n = !1,
+                (i = _.exec(s)) && (n = i.shift(),
+                o.push({
+                    value: n,
+                    type: i[0].replace(B, " ")
+                }),
+                s = s.slice(n.length));
+                for (a in r.filter)
+                    !(i = V[a].exec(s)) || l[a] && !(i = l[a](i)) || (n = i.shift(),
+                    o.push({
+                        value: n,
+                        type: a,
+                        matches: i
+                    }),
+                    s = s.slice(n.length));
+                if (!n)
+                    break
+            }
+            return t ? s.length : s ? oe.error(e) : k(e, u).slice(0)
+        }
+        ;
+        function ve(e) {
+            for (var t = 0, n = e.length, r = ""; t < n; t++)
+                r += e[t].value;
+            return r
+        }
+        function me(e, t, n) {
+            var r = t.dir
+              , i = t.next
+              , o = i || r
+              , a = n && "parentNode" === o
+              , s = C++;
+            return t.first ? function(t, n, i) {
+                while (t = t[r])
+                    if (1 === t.nodeType || a)
+                        return e(t, n, i);
+                return !1
+            }
+            : function(t, n, u) {
+                var l, c, f, p = [T, s];
+                if (u) {
+                    while (t = t[r])
+                        if ((1 === t.nodeType || a) && e(t, n, u))
+                            return !0
+                } else
+                    while (t = t[r])
+                        if (1 === t.nodeType || a)
+                            if (f = t[b] || (t[b] = {}),
+                            c = f[t.uniqueID] || (f[t.uniqueID] = {}),
+                            i && i === t.nodeName.toLowerCase())
+                                t = t[r] || t;
+                            else {
+                                if ((l = c[o]) && l[0] === T && l[1] === s)
+                                    return p[2] = l[2];
+                                if (c[o] = p,
+                                p[2] = e(t, n, u))
+                                    return !0
+                            }
+                return !1
+            }
+        }
+        function xe(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 be(e, t, n) {
+            for (var r = 0, i = t.length; r < i; r++)
+                oe(e, t[r], n);
+            return n
+        }
+        function we(e, t, n, r, i) {
+            for (var o, a = [], s = 0, u = e.length, l = null != t; s < u; s++)
+                (o = e[s]) && (n && !n(o, r, i) || (a.push(o),
+                l && t.push(s)));
+            return a
+        }
+        function Te(e, t, n, r, i, o) {
+            return r && !r[b] && (r = Te(r)),
+            i && !i[b] && (i = Te(i, o)),
+            se(function(o, a, s, u) {
+                var l, c, f, p = [], d = [], h = a.length, g = o || be(t || "*", s.nodeType ? [s] : s, []), y = !e || !o && t ? g : we(g, p, e, s, u), v = n ? i || (o ? e : h || r) ? [] : a : y;
+                if (n && n(y, v, s, u),
+                r) {
+                    l = we(v, d),
+                    r(l, [], s, u),
+                    c = l.length;
+                    while (c--)
+                        (f = l[c]) && (v[d[c]] = !(y[d[c]] = f))
+                }
+                if (o) {
+                    if (i || e) {
+                        if (i) {
+                            l = [],
+                            c = v.length;
+                            while (c--)
+                                (f = v[c]) && l.push(y[c] = f);
+                            i(null, v = [], l, u)
+                        }
+                        c = v.length;
+                        while (c--)
+                            (f = v[c]) && (l = i ? O(o, f) : p[c]) > -1 && (o[l] = !(a[l] = f))
+                    }
+                } else
+                    v = we(v === a ? v.splice(h, v.length) : v),
+                    i ? i(null, a, v, u) : L.apply(a, v)
+            })
+        }
+        function Ce(e) {
+            for (var t, n, i, o = e.length, a = r.relative[e[0].type], s = a || r.relative[" "], u = a ? 1 : 0, c = me(function(e) {
+                return e === t
+            }, s, !0), f = me(function(e) {
+                return O(t, e) > -1
+            }, s, !0), p = [function(e, n, r) {
+                var i = !a && (r || n !== l) || ((t = n).nodeType ? c(e, n, r) : f(e, n, r));
+                return t = null,
+                i
+            }
+            ]; u < o; u++)
+                if (n = r.relative[e[u].type])
+                    p = [me(xe(p), n)];
+                else {
+                    if ((n = r.filter[e[u].type].apply(null, e[u].matches))[b]) {
+                        for (i = ++u; i < o; i++)
+                            if (r.relative[e[i].type])
+                                break;
+                        return Te(u > 1 && xe(p), u > 1 && ve(e.slice(0, u - 1).concat({
+                            value: " " === e[u - 2].type ? "*" : ""
+                        })).replace(B, "$1"), n, u < i && Ce(e.slice(u, i)), i < o && Ce(e = e.slice(i)), i < o && ve(e))
+                    }
+                    p.push(n)
+                }
+            return xe(p)
+        }
+        function Ee(e, t) {
+            var n = t.length > 0
+              , i = e.length > 0
+              , o = function(o, a, s, u, c) {
+                var f, h, y, v = 0, m = "0", x = o && [], b = [], w = l, C = o || i && r.find.TAG("*", c), E = T += null == w ? 1 : Math.random() || .1, k = C.length;
+                for (c && (l = a === d || a || c); m !== k && null != (f = C[m]); m++) {
+                    if (i && f) {
+                        h = 0,
+                        a || f.ownerDocument === d || (p(f),
+                        s = !g);
+                        while (y = e[h++])
+                            if (y(f, a || d, s)) {
+                                u.push(f);
+                                break
+                            }
+                        c && (T = E)
+                    }
+                    n && ((f = !y && f) && v--,
+                    o && x.push(f))
+                }
+                if (v += m,
+                n && m !== v) {
+                    h = 0;
+                    while (y = t[h++])
+                        y(x, b, a, s);
+                    if (o) {
+                        if (v > 0)
+                            while (m--)
+                                x[m] || b[m] || (b[m] = j.call(u));
+                        b = we(b)
+                    }
+                    L.apply(u, b),
+                    c && !o && b.length > 0 && v + t.length > 1 && oe.uniqueSort(u)
+                }
+                return c && (T = E,
+                l = w),
+                x
+            };
+            return n ? se(o) : o
+        }
+        return s = oe.compile = function(e, t) {
+            var n, r = [], i = [], o = S[e + " "];
+            if (!o) {
+                t || (t = a(e)),
+                n = t.length;
+                while (n--)
+                    (o = Ce(t[n]))[b] ? r.push(o) : i.push(o);
+                (o = S(e, Ee(i, r))).selector = e
+            }
+            return o
+        }
+        ,
+        u = oe.select = function(e, t, n, i) {
+            var o, u, l, c, f, p = "function" == typeof e && e, d = !i && a(e = p.selector || e);
+            if (n = n || [],
+            1 === d.length) {
+                if ((u = d[0] = d[0].slice(0)).length > 2 && "ID" === (l = u[0]).type && 9 === t.nodeType && g && r.relative[u[1].type]) {
+                    if (!(t = (r.find.ID(l.matches[0].replace(Z, ee), t) || [])[0]))
+                        return n;
+                    p && (t = t.parentNode),
+                    e = e.slice(u.shift().value.length)
+                }
+                o = V.needsContext.test(e) ? 0 : u.length;
+                while (o--) {
+                    if (l = u[o],
+                    r.relative[c = l.type])
+                        break;
+                    if ((f = r.find[c]) && (i = f(l.matches[0].replace(Z, ee), K.test(u[0].type) && ge(t.parentNode) || t))) {
+                        if (u.splice(o, 1),
+                        !(e = i.length && ve(u)))
+                            return L.apply(n, i),
+                            n;
+                        break
+                    }
+                }
+            }
+            return (p || s(e, d))(i, t, !g, n, !t || K.test(e) && ge(t.parentNode) || t),
+            n
+        }
+        ,
+        n.sortStable = b.split("").sort(D).join("") === b,
+        n.detectDuplicates = !!f,
+        p(),
+        n.sortDetached = ue(function(e) {
+            return 1 & e.compareDocumentPosition(d.createElement("fieldset"))
+        }),
+        ue(function(e) {
+            return e.innerHTML = "<a href='#'></a>",
+            "#" === e.firstChild.getAttribute("href")
+        }) || le("type|href|height|width", function(e, t, n) {
+            if (!n)
+                return e.getAttribute(t, "type" === t.toLowerCase() ? 1 : 2)
+        }),
+        n.attributes && ue(function(e) {
+            return e.innerHTML = "<input/>",
+            e.firstChild.setAttribute("value", ""),
+            "" === e.firstChild.getAttribute("value")
+        }) || le("value", function(e, t, n) {
+            if (!n && "input" === e.nodeName.toLowerCase())
+                return e.defaultValue
+        }),
+        ue(function(e) {
+            return null == e.getAttribute("disabled")
+        }) || le(P, function(e, t, n) {
+            var r;
+            if (!n)
+                return !0 === e[t] ? t.toLowerCase() : (r = e.getAttributeNode(t)) && r.specified ? r.value : null
+        }),
+        oe
+    }(e);
+    w.find = E,
+    w.expr = E.selectors,
+    w.expr[":"] = w.expr.pseudos,
+    w.uniqueSort = w.unique = E.uniqueSort,
+    w.text = E.getText,
+    w.isXMLDoc = E.isXML,
+    w.contains = E.contains,
+    w.escapeSelector = E.escape;
+    var k = function(e, t, n) {
+        var r = []
+          , i = void 0 !== n;
+        while ((e = e[t]) && 9 !== e.nodeType)
+            if (1 === e.nodeType) {
+                if (i && w(e).is(n))
+                    break;
+                r.push(e)
+            }
+        return r
+    }
+      , S = function(e, t) {
+        for (var n = []; e; e = e.nextSibling)
+            1 === e.nodeType && e !== t && n.push(e);
+        return n
+    }
+      , D = w.expr.match.needsContext;
+    function N(e, t) {
+        return e.nodeName && e.nodeName.toLowerCase() === t.toLowerCase()
+    }
+    var A = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;
+    function j(e, t, n) {
+        return g(t) ? w.grep(e, function(e, r) {
+            return !!t.call(e, r, e) !== n
+        }) : t.nodeType ? w.grep(e, function(e) {
+            return e === t !== n
+        }) : "string" != typeof t ? w.grep(e, function(e) {
+            return u.call(t, e) > -1 !== n
+        }) : w.filter(t, e, n)
+    }
+    w.filter = function(e, t, n) {
+        var r = t[0];
+        return n && (e = ":not(" + e + ")"),
+        1 === t.length && 1 === r.nodeType ? w.find.matchesSelector(r, e) ? [r] : [] : w.find.matches(e, w.grep(t, function(e) {
+            return 1 === e.nodeType
+        }))
+    }
+    ,
+    w.fn.extend({
+        find: function(e) {
+            var t, n, r = this.length, i = this;
+            if ("string" != typeof e)
+                return this.pushStack(w(e).filter(function() {
+                    for (t = 0; t < r; t++)
+                        if (w.contains(i[t], this))
+                            return !0
+                }));
+            for (n = this.pushStack([]),
+            t = 0; t < r; t++)
+                w.find(e, i[t], n);
+            return r > 1 ? w.uniqueSort(n) : n
+        },
+        filter: function(e) {
+            return this.pushStack(j(this, e || [], !1))
+        },
+        not: function(e) {
+            return this.pushStack(j(this, e || [], !0))
+        },
+        is: function(e) {
+            return !!j(this, "string" == typeof e && D.test(e) ? w(e) : e || [], !1).length
+        }
+    });
+    var q, L = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;
+    (w.fn.init = function(e, t, n) {
+        var i, o;
+        if (!e)
+            return this;
+        if (n = n || q,
+        "string" == typeof e) {
+            if (!(i = "<" === e[0] && ">" === e[e.length - 1] && e.length >= 3 ? [null, e, null] : L.exec(e)) || !i[1] && t)
+                return !t || t.jquery ? (t || n).find(e) : this.constructor(t).find(e);
+            if (i[1]) {
+                if (t = t instanceof w ? t[0] : t,
+                w.merge(this, w.parseHTML(i[1], t && t.nodeType ? t.ownerDocument || t : r, !0)),
+                A.test(i[1]) && w.isPlainObject(t))
+                    for (i in t)
+                        g(this[i]) ? this[i](t[i]) : this.attr(i, t[i]);
+                return this
+            }
+            return (o = r.getElementById(i[2])) && (this[0] = o,
+            this.length = 1),
+            this
+        }
+        return e.nodeType ? (this[0] = e,
+        this.length = 1,
+        this) : g(e) ? void 0 !== n.ready ? n.ready(e) : e(w) : w.makeArray(e, this)
+    }
+    ).prototype = w.fn,
+    q = w(r);
+    var H = /^(?:parents|prev(?:Until|All))/
+      , O = {
+        children: !0,
+        contents: !0,
+        next: !0,
+        prev: !0
+    };
+    w.fn.extend({
+        has: function(e) {
+            var t = w(e, this)
+              , n = t.length;
+            return this.filter(function() {
+                for (var e = 0; e < n; e++)
+                    if (w.contains(this, t[e]))
+                        return !0
+            })
+        },
+        closest: function(e, t) {
+            var n, r = 0, i = this.length, o = [], a = "string" != typeof e && w(e);
+            if (!D.test(e))
+                for (; r < i; r++)
+                    for (n = this[r]; n && n !== t; n = n.parentNode)
+                        if (n.nodeType < 11 && (a ? a.index(n) > -1 : 1 === n.nodeType && w.find.matchesSelector(n, e))) {
+                            o.push(n);
+                            break
+                        }
+            return this.pushStack(o.length > 1 ? w.uniqueSort(o) : o)
+        },
+        index: function(e) {
+            return e ? "string" == typeof e ? u.call(w(e), this[0]) : u.call(this, e.jquery ? e[0] : e) : this[0] && this[0].parentNode ? this.first().prevAll().length : -1
+        },
+        add: function(e, t) {
+            return this.pushStack(w.uniqueSort(w.merge(this.get(), w(e, t))))
+        },
+        addBack: function(e) {
+            return this.add(null == e ? this.prevObject : this.prevObject.filter(e))
+        }
+    });
+    function P(e, t) {
+        while ((e = e[t]) && 1 !== e.nodeType)
+            ;
+        return e
+    }
+    w.each({
+        parent: function(e) {
+            var t = e.parentNode;
+            return t && 11 !== t.nodeType ? t : null
+        },
+        parents: function(e) {
+            return k(e, "parentNode")
+        },
+        parentsUntil: function(e, t, n) {
+            return k(e, "parentNode", n)
+        },
+        next: function(e) {
+            return P(e, "nextSibling")
+        },
+        prev: function(e) {
+            return P(e, "previousSibling")
+        },
+        nextAll: function(e) {
+            return k(e, "nextSibling")
+        },
+        prevAll: function(e) {
+            return k(e, "previousSibling")
+        },
+        nextUntil: function(e, t, n) {
+            return k(e, "nextSibling", n)
+        },
+        prevUntil: function(e, t, n) {
+            return k(e, "previousSibling", n)
+        },
+        siblings: function(e) {
+            return S((e.parentNode || {}).firstChild, e)
+        },
+        children: function(e) {
+            return S(e.firstChild)
+        },
+        contents: function(e) {
+            return N(e, "iframe") ? e.contentDocument : (N(e, "template") && (e = e.content || e),
+            w.merge([], e.childNodes))
+        }
+    }, function(e, t) {
+        w.fn[e] = function(n, r) {
+            var i = w.map(this, t, n);
+            return "Until" !== e.slice(-5) && (r = n),
+            r && "string" == typeof r && (i = w.filter(r, i)),
+            this.length > 1 && (O[e] || w.uniqueSort(i),
+            H.test(e) && i.reverse()),
+            this.pushStack(i)
+        }
+    });
+    var M = /[^\x20\t\r\n\f]+/g;
+    function R(e) {
+        var t = {};
+        return w.each(e.match(M) || [], function(e, n) {
+            t[n] = !0
+        }),
+        t
+    }
+    w.Callbacks = function(e) {
+        e = "string" == typeof e ? R(e) : w.extend({}, e);
+        var t, n, r, i, o = [], a = [], s = -1, u = function() {
+            for (i = i || e.once,
+            r = t = !0; a.length; s = -1) {
+                n = a.shift();
+                while (++s < o.length)
+                    !1 === o[s].apply(n[0], n[1]) && e.stopOnFalse && (s = o.length,
+                    n = !1)
+            }
+            e.memory || (n = !1),
+            t = !1,
+            i && (o = n ? [] : "")
+        }, l = {
+            add: function() {
+                return o && (n && !t && (s = o.length - 1,
+                a.push(n)),
+                function t(n) {
+                    w.each(n, function(n, r) {
+                        g(r) ? e.unique && l.has(r) || o.push(r) : r && r.length && "string" !== x(r) && t(r)
+                    })
+                }(arguments),
+                n && !t && u()),
+                this
+            },
+            remove: function() {
+                return w.each(arguments, function(e, t) {
+                    var n;
+                    while ((n = w.inArray(t, o, n)) > -1)
+                        o.splice(n, 1),
+                        n <= s && s--
+                }),
+                this
+            },
+            has: function(e) {
+                return e ? w.inArray(e, o) > -1 : o.length > 0
+            },
+            empty: function() {
+                return o && (o = []),
+                this
+            },
+            disable: function() {
+                return i = a = [],
+                o = n = "",
+                this
+            },
+            disabled: function() {
+                return !o
+            },
+            lock: function() {
+                return i = a = [],
+                n || t || (o = n = ""),
+                this
+            },
+            locked: function() {
+                return !!i
+            },
+            fireWith: function(e, n) {
+                return i || (n = [e, (n = n || []).slice ? n.slice() : n],
+                a.push(n),
+                t || u()),
+                this
+            },
+            fire: function() {
+                return l.fireWith(this, arguments),
+                this
+            },
+            fired: function() {
+                return !!r
+            }
+        };
+        return l
+    }
+    ;
+    function I(e) {
+        return e
+    }
+    function W(e) {
+        throw e
+    }
+    function $(e, t, n, r) {
+        var i;
+        try {
+            e && g(i = e.promise) ? i.call(e).done(t).fail(n) : e && g(i = e.then) ? i.call(e, t, n) : t.apply(void 0, [e].slice(r))
+        } catch (e) {
+            n.apply(void 0, [e])
+        }
+    }
+    w.extend({
+        Deferred: function(t) {
+            var n = [["notify", "progress", w.Callbacks("memory"), w.Callbacks("memory"), 2], ["resolve", "done", w.Callbacks("once memory"), w.Callbacks("once memory"), 0, "resolved"], ["reject", "fail", w.Callbacks("once memory"), w.Callbacks("once memory"), 1, "rejected"]]
+              , r = "pending"
+              , i = {
+                state: function() {
+                    return r
+                },
+                always: function() {
+                    return o.done(arguments).fail(arguments),
+                    this
+                },
+                "catch": function(e) {
+                    return i.then(null, e)
+                },
+                pipe: function() {
+                    var e = arguments;
+                    return w.Deferred(function(t) {
+                        w.each(n, function(n, r) {
+                            var i = g(e[r[4]]) && e[r[4]];
+                            o[r[1]](function() {
+                                var e = i && i.apply(this, arguments);
+                                e && g(e.promise) ? e.promise().progress(t.notify).done(t.resolve).fail(t.reject) : t[r[0] + "With"](this, i ? [e] : arguments)
+                            })
+                        }),
+                        e = null
+                    }).promise()
+                },
+                then: function(t, r, i) {
+                    var o = 0;
+                    function a(t, n, r, i) {
+                        return function() {
+                            var s = this
+                              , u = arguments
+                              , l = function() {
+                                var e, l;
+                                if (!(t < o)) {
+                                    if ((e = r.apply(s, u)) === n.promise())
+                                        throw new TypeError("Thenable self-resolution");
+                                    l = e && ("object" == typeof e || "function" == typeof e) && e.then,
+                                    g(l) ? i ? l.call(e, a(o, n, I, i), a(o, n, W, i)) : (o++,
+                                    l.call(e, a(o, n, I, i), a(o, n, W, i), a(o, n, I, n.notifyWith))) : (r !== I && (s = void 0,
+                                    u = [e]),
+                                    (i || n.resolveWith)(s, u))
+                                }
+                            }
+                              , c = i ? l : function() {
+                                try {
+                                    l()
+                                } catch (e) {
+                                    w.Deferred.exceptionHook && w.Deferred.exceptionHook(e, c.stackTrace),
+                                    t + 1 >= o && (r !== W && (s = void 0,
+                                    u = [e]),
+                                    n.rejectWith(s, u))
+                                }
+                            }
+                            ;
+                            t ? c() : (w.Deferred.getStackHook && (c.stackTrace = w.Deferred.getStackHook()),
+                            e.setTimeout(c))
+                        }
+                    }
+                    return w.Deferred(function(e) {
+                        n[0][3].add(a(0, e, g(i) ? i : I, e.notifyWith)),
+                        n[1][3].add(a(0, e, g(t) ? t : I)),
+                        n[2][3].add(a(0, e, g(r) ? r : W))
+                    }).promise()
+                },
+                promise: function(e) {
+                    return null != e ? w.extend(e, i) : i
+                }
+            }
+              , o = {};
+            return w.each(n, function(e, t) {
+                var a = t[2]
+                  , s = t[5];
+                i[t[1]] = a.add,
+                s && a.add(function() {
+                    r = s
+                }, n[3 - e][2].disable, n[3 - e][3].disable, n[0][2].lock, n[0][3].lock),
+                a.add(t[3].fire),
+                o[t[0]] = function() {
+                    return o[t[0] + "With"](this === o ? void 0 : this, arguments),
+                    this
+                }
+                ,
+                o[t[0] + "With"] = a.fireWith
+            }),
+            i.promise(o),
+            t && t.call(o, o),
+            o
+        },
+        when: function(e) {
+            var t = arguments.length
+              , n = t
+              , r = Array(n)
+              , i = o.call(arguments)
+              , a = w.Deferred()
+              , s = function(e) {
+                return function(n) {
+                    r[e] = this,
+                    i[e] = arguments.length > 1 ? o.call(arguments) : n,
+                    --t || a.resolveWith(r, i)
+                }
+            };
+            if (t <= 1 && ($(e, a.done(s(n)).resolve, a.reject, !t),
+            "pending" === a.state() || g(i[n] && i[n].then)))
+                return a.then();
+            while (n--)
+                $(i[n], s(n), a.reject);
+            return a.promise()
+        }
+    });
+    var B = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
+    w.Deferred.exceptionHook = function(t, n) {
+        e.console && e.console.warn && t && B.test(t.name) && e.console.warn("jQuery.Deferred exception: " + t.message, t.stack, n)
+    }
+    ,
+    w.readyException = function(t) {
+        e.setTimeout(function() {
+            throw t
+        })
+    }
+    ;
+    var F = w.Deferred();
+    w.fn.ready = function(e) {
+        return F.then(e)["catch"](function(e) {
+            w.readyException(e)
+        }),
+        this
+    }
+    ,
+    w.extend({
+        isReady: !1,
+        readyWait: 1,
+        ready: function(e) {
+            (!0 === e ? --w.readyWait : w.isReady) || (w.isReady = !0,
+            !0 !== e && --w.readyWait > 0 || F.resolveWith(r, [w]))
+        }
+    }),
+    w.ready.then = F.then;
+    function _() {
+        r.removeEventListener("DOMContentLoaded", _),
+        e.removeEventListener("load", _),
+        w.ready()
+    }
+    "complete" === r.readyState || "loading" !== r.readyState && !r.documentElement.doScroll ? e.setTimeout(w.ready) : (r.addEventListener("DOMContentLoaded", _),
+    e.addEventListener("load", _));
+    var z = function(e, t, n, r, i, o, a) {
+        var s = 0
+          , u = e.length
+          , l = null == n;
+        if ("object" === x(n)) {
+            i = !0;
+            for (s in n)
+                z(e, t, s, n[s], !0, o, a)
+        } else if (void 0 !== r && (i = !0,
+        g(r) || (a = !0),
+        l && (a ? (t.call(e, r),
+        t = null) : (l = t,
+        t = function(e, t, n) {
+            return l.call(w(e), n)
+        }
+        )),
+        t))
+            for (; s < u; s++)
+                t(e[s], n, a ? r : r.call(e[s], s, t(e[s], n)));
+        return i ? e : l ? t.call(e) : u ? t(e[0], n) : o
+    }
+      , X = /^-ms-/
+      , U = /-([a-z])/g;
+    function V(e, t) {
+        return t.toUpperCase()
+    }
+    function G(e) {
+        return e.replace(X, "ms-").replace(U, V)
+    }
+    var Y = function(e) {
+        return 1 === e.nodeType || 9 === e.nodeType || !+e.nodeType
+    };
+    function Q() {
+        this.expando = w.expando + Q.uid++
+    }
+    Q.uid = 1,
+    Q.prototype = {
+        cache: function(e) {
+            var t = e[this.expando];
+            return t || (t = {},
+            Y(e) && (e.nodeType ? e[this.expando] = t : Object.defineProperty(e, this.expando, {
+                value: t,
+                configurable: !0
+            }))),
+            t
+        },
+        set: function(e, t, n) {
+            var r, i = this.cache(e);
+            if ("string" == typeof t)
+                i[G(t)] = n;
+            else
+                for (r in t)
+                    i[G(r)] = t[r];
+            return i
+        },
+        get: function(e, t) {
+            return void 0 === t ? this.cache(e) : e[this.expando] && e[this.expando][G(t)]
+        },
+        access: function(e, t, n) {
+            return void 0 === t || t && "string" == typeof t && void 0 === n ? this.get(e, t) : (this.set(e, t, n),
+            void 0 !== n ? n : t)
+        },
+        remove: function(e, t) {
+            var n, r = e[this.expando];
+            if (void 0 !== r) {
+                if (void 0 !== t) {
+                    n = (t = Array.isArray(t) ? t.map(G) : (t = G(t))in r ? [t] : t.match(M) || []).length;
+                    while (n--)
+                        delete r[t[n]]
+                }
+                (void 0 === t || w.isEmptyObject(r)) && (e.nodeType ? e[this.expando] = void 0 : delete e[this.expando])
+            }
+        },
+        hasData: function(e) {
+            var t = e[this.expando];
+            return void 0 !== t && !w.isEmptyObject(t)
+        }
+    };
+    var J = new Q
+      , K = new Q
+      , Z = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/
+      , ee = /[A-Z]/g;
+    function te(e) {
+        return "true" === e || "false" !== e && ("null" === e ? null : e === +e + "" ? +e : Z.test(e) ? JSON.parse(e) : e)
+    }
+    function ne(e, t, n) {
+        var r;
+        if (void 0 === n && 1 === e.nodeType)
+            if (r = "data-" + t.replace(ee, "-$&").toLowerCase(),
+            "string" == typeof (n = e.getAttribute(r))) {
+                try {
+                    n = te(n)
+                } catch (e) {}
+                K.set(e, t, n)
+            } else
+                n = void 0;
+        return n
+    }
+    w.extend({
+        hasData: function(e) {
+            return K.hasData(e) || J.hasData(e)
+        },
+        data: function(e, t, n) {
+            return K.access(e, t, n)
+        },
+        removeData: function(e, t) {
+            K.remove(e, t)
+        },
+        _data: function(e, t, n) {
+            return J.access(e, t, n)
+        },
+        _removeData: function(e, t) {
+            J.remove(e, t)
+        }
+    }),
+    w.fn.extend({
+        data: function(e, t) {
+            var n, r, i, o = this[0], a = o && o.attributes;
+            if (void 0 === e) {
+                if (this.length && (i = K.get(o),
+                1 === o.nodeType && !J.get(o, "hasDataAttrs"))) {
+                    n = a.length;
+                    while (n--)
+                        a[n] && 0 === (r = a[n].name).indexOf("data-") && (r = G(r.slice(5)),
+                        ne(o, r, i[r]));
+                    J.set(o, "hasDataAttrs", !0)
+                }
+                return i
+            }
+            return "object" == typeof e ? this.each(function() {
+                K.set(this, e)
+            }) : z(this, function(t) {
+                var n;
+                if (o && void 0 === t) {
+                    if (void 0 !== (n = K.get(o, e)))
+                        return n;
+                    if (void 0 !== (n = ne(o, e)))
+                        return n
+                } else
+                    this.each(function() {
+                        K.set(this, e, t)
+                    })
+            }, null, t, arguments.length > 1, null, !0)
+        },
+        removeData: function(e) {
+            return this.each(function() {
+                K.remove(this, e)
+            })
+        }
+    }),
+    w.extend({
+        queue: function(e, t, n) {
+            var r;
+            if (e)
+                return t = (t || "fx") + "queue",
+                r = J.get(e, t),
+                n && (!r || Array.isArray(n) ? r = J.access(e, t, w.makeArray(n)) : r.push(n)),
+                r || []
+        },
+        dequeue: function(e, t) {
+            t = t || "fx";
+            var n = w.queue(e, t)
+              , r = n.length
+              , i = n.shift()
+              , o = w._queueHooks(e, t)
+              , a = function() {
+                w.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 J.get(e, n) || J.access(e, n, {
+                empty: w.Callbacks("once memory").add(function() {
+                    J.remove(e, [t + "queue", n])
+                })
+            })
+        }
+    }),
+    w.fn.extend({
+        queue: function(e, t) {
+            var n = 2;
+            return "string" != typeof e && (t = e,
+            e = "fx",
+            n--),
+            arguments.length < n ? w.queue(this[0], e) : void 0 === t ? this : this.each(function() {
+                var n = w.queue(this, e, t);
+                w._queueHooks(this, e),
+                "fx" === e && "inprogress" !== n[0] && w.dequeue(this, e)
+            })
+        },
+        dequeue: function(e) {
+            return this.each(function() {
+                w.dequeue(this, e)
+            })
+        },
+        clearQueue: function(e) {
+            return this.queue(e || "fx", [])
+        },
+        promise: function(e, t) {
+            var n, r = 1, i = w.Deferred(), o = this, a = this.length, s = function() {
+                --r || i.resolveWith(o, [o])
+            };
+            "string" != typeof e && (t = e,
+            e = void 0),
+            e = e || "fx";
+            while (a--)
+                (n = J.get(o[a], e + "queueHooks")) && n.empty && (r++,
+                n.empty.add(s));
+            return s(),
+            i.promise(t)
+        }
+    });
+    var re = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source
+      , ie = new RegExp("^(?:([+-])=|)(" + re + ")([a-z%]*)$","i")
+      , oe = ["Top", "Right", "Bottom", "Left"]
+      , ae = function(e, t) {
+        return "none" === (e = t || e).style.display || "" === e.style.display && w.contains(e.ownerDocument, e) && "none" === w.css(e, "display")
+    }
+      , se = 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
+    };
+    function ue(e, t, n, r) {
+        var i, o, a = 20, s = r ? function() {
+            return r.cur()
+        }
+        : function() {
+            return w.css(e, t, "")
+        }
+        , u = s(), l = n && n[3] || (w.cssNumber[t] ? "" : "px"), c = (w.cssNumber[t] || "px" !== l && +u) && ie.exec(w.css(e, t));
+        if (c && c[3] !== l) {
+            u /= 2,
+            l = l || c[3],
+            c = +u || 1;
+            while (a--)
+                w.style(e, t, c + l),
+                (1 - o) * (1 - (o = s() / u || .5)) <= 0 && (a = 0),
+                c /= o;
+            c *= 2,
+            w.style(e, t, c + l),
+            n = n || []
+        }
+        return n && (c = +c || +u || 0,
+        i = n[1] ? c + (n[1] + 1) * n[2] : +n[2],
+        r && (r.unit = l,
+        r.start = c,
+        r.end = i)),
+        i
+    }
+    var le = {};
+    function ce(e) {
+        var t, n = e.ownerDocument, r = e.nodeName, i = le[r];
+        return i || (t = n.body.appendChild(n.createElement(r)),
+        i = w.css(t, "display"),
+        t.parentNode.removeChild(t),
+        "none" === i && (i = "block"),
+        le[r] = i,
+        i)
+    }
+    function fe(e, t) {
+        for (var n, r, i = [], o = 0, a = e.length; o < a; o++)
+            (r = e[o]).style && (n = r.style.display,
+            t ? ("none" === n && (i[o] = J.get(r, "display") || null,
+            i[o] || (r.style.display = "")),
+            "" === r.style.display && ae(r) && (i[o] = ce(r))) : "none" !== n && (i[o] = "none",
+            J.set(r, "display", n)));
+        for (o = 0; o < a; o++)
+            null != i[o] && (e[o].style.display = i[o]);
+        return e
+    }
+    w.fn.extend({
+        show: function() {
+            return fe(this, !0)
+        },
+        hide: function() {
+            return fe(this)
+        },
+        toggle: function(e) {
+            return "boolean" == typeof e ? e ? this.show() : this.hide() : this.each(function() {
+                ae(this) ? w(this).show() : w(this).hide()
+            })
+        }
+    });
+    var pe = /^(?:checkbox|radio)$/i
+      , de = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i
+      , he = /^$|^module$|\/(?:java|ecma)script/i
+      , ge = {
+        option: [1, "<select multiple='multiple'>", "</select>"],
+        thead: [1, "<table>", "</table>"],
+        col: [2, "<table><colgroup>", "</colgroup></table>"],
+        tr: [2, "<table><tbody>", "</tbody></table>"],
+        td: [3, "<table><tbody><tr>", "</tr></tbody></table>"],
+        _default: [0, "", ""]
+    };
+    ge.optgroup = ge.option,
+    ge.tbody = ge.tfoot = ge.colgroup = ge.caption = ge.thead,
+    ge.th = ge.td;
+    function ye(e, t) {
+        var n;
+        return n = "undefined" != typeof e.getElementsByTagName ? e.getElementsByTagName(t || "*") : "undefined" != typeof e.querySelectorAll ? e.querySelectorAll(t || "*") : [],
+        void 0 === t || t && N(e, t) ? w.merge([e], n) : n
+    }
+    function ve(e, t) {
+        for (var n = 0, r = e.length; n < r; n++)
+            J.set(e[n], "globalEval", !t || J.get(t[n], "globalEval"))
+    }
+    var me = /<|&#?\w+;/;
+    function xe(e, t, n, r, i) {
+        for (var o, a, s, u, l, c, f = t.createDocumentFragment(), p = [], d = 0, h = e.length; d < h; d++)
+            if ((o = e[d]) || 0 === o)
+                if ("object" === x(o))
+                    w.merge(p, o.nodeType ? [o] : o);
+                else if (me.test(o)) {
+                    a = a || f.appendChild(t.createElement("div")),
+                    s = (de.exec(o) || ["", ""])[1].toLowerCase(),
+                    u = ge[s] || ge._default,
+                    a.innerHTML = u[1] + w.htmlPrefilter(o) + u[2],
+                    c = u[0];
+                    while (c--)
+                        a = a.lastChild;
+                    w.merge(p, a.childNodes),
+                    (a = f.firstChild).textContent = ""
+                } else
+                    p.push(t.createTextNode(o));
+        f.textContent = "",
+        d = 0;
+        while (o = p[d++])
+            if (r && w.inArray(o, r) > -1)
+                i && i.push(o);
+            else if (l = w.contains(o.ownerDocument, o),
+            a = ye(f.appendChild(o), "script"),
+            l && ve(a),
+            n) {
+                c = 0;
+                while (o = a[c++])
+                    he.test(o.type || "") && n.push(o)
+            }
+        return f
+    }
+    !function() {
+        var e = r.createDocumentFragment().appendChild(r.createElement("div"))
+          , t = r.createElement("input");
+        t.setAttribute("type", "radio"),
+        t.setAttribute("checked", "checked"),
+        t.setAttribute("name", "t"),
+        e.appendChild(t),
+        h.checkClone = e.cloneNode(!0).cloneNode(!0).lastChild.checked,
+        e.innerHTML = "<textarea>x</textarea>",
+        h.noCloneChecked = !!e.cloneNode(!0).lastChild.defaultValue
+    }();
+    var be = r.documentElement
+      , we = /^key/
+      , Te = /^(?:mouse|pointer|contextmenu|drag|drop)|click/
+      , Ce = /^([^.]*)(?:\.(.+)|)/;
+    function Ee() {
+        return !0
+    }
+    function ke() {
+        return !1
+    }
+    function Se() {
+        try {
+            return r.activeElement
+        } catch (e) {}
+    }
+    function De(e, t, n, r, i, o) {
+        var a, s;
+        if ("object" == typeof t) {
+            "string" != typeof n && (r = r || n,
+            n = void 0);
+            for (s in t)
+                De(e, s, n, r, t[s], o);
+            return e
+        }
+        if (null == r && null == i ? (i = n,
+        r = n = void 0) : null == i && ("string" == typeof n ? (i = r,
+        r = void 0) : (i = r,
+        r = n,
+        n = void 0)),
+        !1 === i)
+            i = ke;
+        else if (!i)
+            return e;
+        return 1 === o && (a = i,
+        (i = function(e) {
+            return w().off(e),
+            a.apply(this, arguments)
+        }
+        ).guid = a.guid || (a.guid = w.guid++)),
+        e.each(function() {
+            w.event.add(this, t, i, r, n)
+        })
+    }
+    w.event = {
+        global: {},
+        add: function(e, t, n, r, i) {
+            var o, a, s, u, l, c, f, p, d, h, g, y = J.get(e);
+            if (y) {
+                n.handler && (n = (o = n).handler,
+                i = o.selector),
+                i && w.find.matchesSelector(be, i),
+                n.guid || (n.guid = w.guid++),
+                (u = y.events) || (u = y.events = {}),
+                (a = y.handle) || (a = y.handle = function(t) {
+                    return "undefined" != typeof w && w.event.triggered !== t.type ? w.event.dispatch.apply(e, arguments) : void 0
+                }
+                ),
+                l = (t = (t || "").match(M) || [""]).length;
+                while (l--)
+                    d = g = (s = Ce.exec(t[l]) || [])[1],
+                    h = (s[2] || "").split(".").sort(),
+                    d && (f = w.event.special[d] || {},
+                    d = (i ? f.delegateType : f.bindType) || d,
+                    f = w.event.special[d] || {},
+                    c = w.extend({
+                        type: d,
+                        origType: g,
+                        data: r,
+                        handler: n,
+                        guid: n.guid,
+                        selector: i,
+                        needsContext: i && w.expr.match.needsContext.test(i),
+                        namespace: h.join(".")
+                    }, o),
+                    (p = u[d]) || ((p = u[d] = []).delegateCount = 0,
+                    f.setup && !1 !== f.setup.call(e, r, h, a) || e.addEventListener && e.addEventListener(d, a)),
+                    f.add && (f.add.call(e, c),
+                    c.handler.guid || (c.handler.guid = n.guid)),
+                    i ? p.splice(p.delegateCount++, 0, c) : p.push(c),
+                    w.event.global[d] = !0)
+            }
+        },
+        remove: function(e, t, n, r, i) {
+            var o, a, s, u, l, c, f, p, d, h, g, y = J.hasData(e) && J.get(e);
+            if (y && (u = y.events)) {
+                l = (t = (t || "").match(M) || [""]).length;
+                while (l--)
+                    if (s = Ce.exec(t[l]) || [],
+                    d = g = s[1],
+                    h = (s[2] || "").split(".").sort(),
+                    d) {
+                        f = w.event.special[d] || {},
+                        p = u[d = (r ? f.delegateType : f.bindType) || d] || [],
+                        s = s[2] && new RegExp("(^|\\.)" + h.join("\\.(?:.*\\.|)") + "(\\.|$)"),
+                        a = o = p.length;
+                        while (o--)
+                            c = p[o],
+                            !i && g !== c.origType || n && n.guid !== c.guid || s && !s.test(c.namespace) || r && r !== c.selector && ("**" !== r || !c.selector) || (p.splice(o, 1),
+                            c.selector && p.delegateCount--,
+                            f.remove && f.remove.call(e, c));
+                        a && !p.length && (f.teardown && !1 !== f.teardown.call(e, h, y.handle) || w.removeEvent(e, d, y.handle),
+                        delete u[d])
+                    } else
+                        for (d in u)
+                            w.event.remove(e, d + t[l], n, r, !0);
+                w.isEmptyObject(u) && J.remove(e, "handle events")
+            }
+        },
+        dispatch: function(e) {
+            var t = w.event.fix(e), n, r, i, o, a, s, u = new Array(arguments.length), l = (J.get(this, "events") || {})[t.type] || [], c = w.event.special[t.type] || {};
+            for (u[0] = t,
+            n = 1; n < arguments.length; n++)
+                u[n] = arguments[n];
+            if (t.delegateTarget = this,
+            !c.preDispatch || !1 !== c.preDispatch.call(this, t)) {
+                s = w.event.handlers.call(this, t, l),
+                n = 0;
+                while ((o = s[n++]) && !t.isPropagationStopped()) {
+                    t.currentTarget = o.elem,
+                    r = 0;
+                    while ((a = o.handlers[r++]) && !t.isImmediatePropagationStopped())
+                        t.rnamespace && !t.rnamespace.test(a.namespace) || (t.handleObj = a,
+                        t.data = a.data,
+                        void 0 !== (i = ((w.event.special[a.origType] || {}).handle || a.handler).apply(o.elem, u)) && !1 === (t.result = i) && (t.preventDefault(),
+                        t.stopPropagation()))
+                }
+                return c.postDispatch && c.postDispatch.call(this, t),
+                t.result
+            }
+        },
+        handlers: function(e, t) {
+            var n, r, i, o, a, s = [], u = t.delegateCount, l = e.target;
+            if (u && l.nodeType && !("click" === e.type && e.button >= 1))
+                for (; l !== this; l = l.parentNode || this)
+                    if (1 === l.nodeType && ("click" !== e.type || !0 !== l.disabled)) {
+                        for (o = [],
+                        a = {},
+                        n = 0; n < u; n++)
+                            void 0 === a[i = (r = t[n]).selector + " "] && (a[i] = r.needsContext ? w(i, this).index(l) > -1 : w.find(i, this, null, [l]).length),
+                            a[i] && o.push(r);
+                        o.length && s.push({
+                            elem: l,
+                            handlers: o
+                        })
+                    }
+            return l = this,
+            u < t.length && s.push({
+                elem: l,
+                handlers: t.slice(u)
+            }),
+            s
+        },
+        addProp: function(e, t) {
+            Object.defineProperty(w.Event.prototype, e, {
+                enumerable: !0,
+                configurable: !0,
+                get: g(t) ? function() {
+                    if (this.originalEvent)
+                        return t(this.originalEvent)
+                }
+                : function() {
+                    if (this.originalEvent)
+                        return this.originalEvent[e]
+                }
+                ,
+                set: function(t) {
+                    Object.defineProperty(this, e, {
+                        enumerable: !0,
+                        configurable: !0,
+                        writable: !0,
+                        value: t
+                    })
+                }
+            })
+        },
+        fix: function(e) {
+            return e[w.expando] ? e : new w.Event(e)
+        },
+        special: {
+            load: {
+                noBubble: !0
+            },
+            focus: {
+                trigger: function() {
+                    if (this !== Se() && this.focus)
+                        return this.focus(),
+                        !1
+                },
+                delegateType: "focusin"
+            },
+            blur: {
+                trigger: function() {
+                    if (this === Se() && this.blur)
+                        return this.blur(),
+                        !1
+                },
+                delegateType: "focusout"
+            },
+            click: {
+                trigger: function() {
+                    if ("checkbox" === this.type && this.click && N(this, "input"))
+                        return this.click(),
+                        !1
+                },
+                _default: function(e) {
+                    return N(e.target, "a")
+                }
+            },
+            beforeunload: {
+                postDispatch: function(e) {
+                    void 0 !== e.result && e.originalEvent && (e.originalEvent.returnValue = e.result)
+                }
+            }
+        }
+    },
+    w.removeEvent = function(e, t, n) {
+        e.removeEventListener && e.removeEventListener(t, n)
+    }
+    ,
+    w.Event = function(e, t) {
+        if (!(this instanceof w.Event))
+            return new w.Event(e,t);
+        e && e.type ? (this.originalEvent = e,
+        this.type = e.type,
+        this.isDefaultPrevented = e.defaultPrevented || void 0 === e.defaultPrevented && !1 === e.returnValue ? Ee : ke,
+        this.target = e.target && 3 === e.target.nodeType ? e.target.parentNode : e.target,
+        this.currentTarget = e.currentTarget,
+        this.relatedTarget = e.relatedTarget) : this.type = e,
+        t && w.extend(this, t),
+        this.timeStamp = e && e.timeStamp || Date.now(),
+        this[w.expando] = !0
+    }
+    ,
+    w.Event.prototype = {
+        constructor: w.Event,
+        isDefaultPrevented: ke,
+        isPropagationStopped: ke,
+        isImmediatePropagationStopped: ke,
+        isSimulated: !1,
+        preventDefault: function() {
+            var e = this.originalEvent;
+            this.isDefaultPrevented = Ee,
+            e && !this.isSimulated && e.preventDefault()
+        },
+        stopPropagation: function() {
+            var e = this.originalEvent;
+            this.isPropagationStopped = Ee,
+            e && !this.isSimulated && e.stopPropagation()
+        },
+        stopImmediatePropagation: function() {
+            var e = this.originalEvent;
+            this.isImmediatePropagationStopped = Ee,
+            e && !this.isSimulated && e.stopImmediatePropagation(),
+            this.stopPropagation()
+        }
+    },
+    w.each({
+        altKey: !0,
+        bubbles: !0,
+        cancelable: !0,
+        changedTouches: !0,
+        ctrlKey: !0,
+        detail: !0,
+        eventPhase: !0,
+        metaKey: !0,
+        pageX: !0,
+        pageY: !0,
+        shiftKey: !0,
+        view: !0,
+        "char": !0,
+        charCode: !0,
+        key: !0,
+        keyCode: !0,
+        button: !0,
+        buttons: !0,
+        clientX: !0,
+        clientY: !0,
+        offsetX: !0,
+        offsetY: !0,
+        pointerId: !0,
+        pointerType: !0,
+        screenX: !0,
+        screenY: !0,
+        targetTouches: !0,
+        toElement: !0,
+        touches: !0,
+        which: function(e) {
+            var t = e.button;
+            return null == e.which && we.test(e.type) ? null != e.charCode ? e.charCode : e.keyCode : !e.which && void 0 !== t && Te.test(e.type) ? 1 & t ? 1 : 2 & t ? 3 : 4 & t ? 2 : 0 : e.which
+        }
+    }, w.event.addProp),
+    w.each({
+        mouseenter: "mouseover",
+        mouseleave: "mouseout",
+        pointerenter: "pointerover",
+        pointerleave: "pointerout"
+    }, function(e, t) {
+        w.event.special[e] = {
+            delegateType: t,
+            bindType: t,
+            handle: function(e) {
+                var n, r = this, i = e.relatedTarget, o = e.handleObj;
+                return i && (i === r || w.contains(r, i)) || (e.type = o.origType,
+                n = o.handler.apply(this, arguments),
+                e.type = t),
+                n
+            }
+        }
+    }),
+    w.fn.extend({
+        on: function(e, t, n, r) {
+            return De(this, e, t, n, r)
+        },
+        one: function(e, t, n, r) {
+            return De(this, e, t, n, r, 1)
+        },
+        off: function(e, t, n) {
+            var r, i;
+            if (e && e.preventDefault && e.handleObj)
+                return r = e.handleObj,
+                w(e.delegateTarget).off(r.namespace ? r.origType + "." + r.namespace : r.origType, r.selector, r.handler),
+                this;
+            if ("object" == typeof e) {
+                for (i in e)
+                    this.off(i, t, e[i]);
+                return this
+            }
+            return !1 !== t && "function" != typeof t || (n = t,
+            t = void 0),
+            !1 === n && (n = ke),
+            this.each(function() {
+                w.event.remove(this, e, n, t)
+            })
+        }
+    });
+    var Ne = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi
+      , Ae = /<script|<style|<link/i
+      , je = /checked\s*(?:[^=]|=\s*.checked.)/i
+      , qe = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
+    function Le(e, t) {
+        return N(e, "table") && N(11 !== t.nodeType ? t : t.firstChild, "tr") ? w(e).children("tbody")[0] || e : e
+    }
+    function He(e) {
+        return e.type = (null !== e.getAttribute("type")) + "/" + e.type,
+        e
+    }
+    function Oe(e) {
+        return "true/" === (e.type || "").slice(0, 5) ? e.type = e.type.slice(5) : e.removeAttribute("type"),
+        e
+    }
+    function Pe(e, t) {
+        var n, r, i, o, a, s, u, l;
+        if (1 === t.nodeType) {
+            if (J.hasData(e) && (o = J.access(e),
+            a = J.set(t, o),
+            l = o.events)) {
+                delete a.handle,
+                a.events = {};
+                for (i in l)
+                    for (n = 0,
+                    r = l[i].length; n < r; n++)
+                        w.event.add(t, i, l[i][n])
+            }
+            K.hasData(e) && (s = K.access(e),
+            u = w.extend({}, s),
+            K.set(t, u))
+        }
+    }
+    function Me(e, t) {
+        var n = t.nodeName.toLowerCase();
+        "input" === n && pe.test(e.type) ? t.checked = e.checked : "input" !== n && "textarea" !== n || (t.defaultValue = e.defaultValue)
+    }
+    function Re(e, t, n, r) {
+        t = a.apply([], t);
+        var i, o, s, u, l, c, f = 0, p = e.length, d = p - 1, y = t[0], v = g(y);
+        if (v || p > 1 && "string" == typeof y && !h.checkClone && je.test(y))
+            return e.each(function(i) {
+                var o = e.eq(i);
+                v && (t[0] = y.call(this, i, o.html())),
+                Re(o, t, n, r)
+            });
+        if (p && (i = xe(t, e[0].ownerDocument, !1, e, r),
+        o = i.firstChild,
+        1 === i.childNodes.length && (i = o),
+        o || r)) {
+            for (u = (s = w.map(ye(i, "script"), He)).length; f < p; f++)
+                l = i,
+                f !== d && (l = w.clone(l, !0, !0),
+                u && w.merge(s, ye(l, "script"))),
+                n.call(e[f], l, f);
+            if (u)
+                for (c = s[s.length - 1].ownerDocument,
+                w.map(s, Oe),
+                f = 0; f < u; f++)
+                    l = s[f],
+                    he.test(l.type || "") && !J.access(l, "globalEval") && w.contains(c, l) && (l.src && "module" !== (l.type || "").toLowerCase() ? w._evalUrl && w._evalUrl(l.src) : m(l.textContent.replace(qe, ""), c, l))
+        }
+        return e
+    }
+    function Ie(e, t, n) {
+        for (var r, i = t ? w.filter(t, e) : e, o = 0; null != (r = i[o]); o++)
+            n || 1 !== r.nodeType || w.cleanData(ye(r)),
+            r.parentNode && (n && w.contains(r.ownerDocument, r) && ve(ye(r, "script")),
+            r.parentNode.removeChild(r));
+        return e
+    }
+    w.extend({
+        htmlPrefilter: function(e) {
+            return e.replace(Ne, "<$1></$2>")
+        },
+        clone: function(e, t, n) {
+            var r, i, o, a, s = e.cloneNode(!0), u = w.contains(e.ownerDocument, e);
+            if (!(h.noCloneChecked || 1 !== e.nodeType && 11 !== e.nodeType || w.isXMLDoc(e)))
+                for (a = ye(s),
+                r = 0,
+                i = (o = ye(e)).length; r < i; r++)
+                    Me(o[r], a[r]);
+            if (t)
+                if (n)
+                    for (o = o || ye(e),
+                    a = a || ye(s),
+                    r = 0,
+                    i = o.length; r < i; r++)
+                        Pe(o[r], a[r]);
+                else
+                    Pe(e, s);
+            return (a = ye(s, "script")).length > 0 && ve(a, !u && ye(e, "script")),
+            s
+        },
+        cleanData: function(e) {
+            for (var t, n, r, i = w.event.special, o = 0; void 0 !== (n = e[o]); o++)
+                if (Y(n)) {
+                    if (t = n[J.expando]) {
+                        if (t.events)
+                            for (r in t.events)
+                                i[r] ? w.event.remove(n, r) : w.removeEvent(n, r, t.handle);
+                        n[J.expando] = void 0
+                    }
+                    n[K.expando] && (n[K.expando] = void 0)
+                }
+        }
+    }),
+    w.fn.extend({
+        detach: function(e) {
+            return Ie(this, e, !0)
+        },
+        remove: function(e) {
+            return Ie(this, e)
+        },
+        text: function(e) {
+            return z(this, function(e) {
+                return void 0 === e ? w.text(this) : this.empty().each(function() {
+                    1 !== this.nodeType && 11 !== this.nodeType && 9 !== this.nodeType || (this.textContent = e)
+                })
+            }, null, e, arguments.length)
+        },
+        append: function() {
+            return Re(this, arguments, function(e) {
+                1 !== this.nodeType && 11 !== this.nodeType && 9 !== this.nodeType || Le(this, e).appendChild(e)
+            })
+        },
+        prepend: function() {
+            return Re(this, arguments, function(e) {
+                if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) {
+                    var t = Le(this, e);
+                    t.insertBefore(e, t.firstChild)
+                }
+            })
+        },
+        before: function() {
+            return Re(this, arguments, function(e) {
+                this.parentNode && this.parentNode.insertBefore(e, this)
+            })
+        },
+        after: function() {
+            return Re(this, arguments, function(e) {
+                this.parentNode && this.parentNode.insertBefore(e, this.nextSibling)
+            })
+        },
+        empty: function() {
+            for (var e, t = 0; null != (e = this[t]); t++)
+                1 === e.nodeType && (w.cleanData(ye(e, !1)),
+                e.textContent = "");
+            return this
+        },
+        clone: function(e, t) {
+            return e = null != e && e,
+            t = null == t ? e : t,
+            this.map(function() {
+                return w.clone(this, e, t)
+            })
+        },
+        html: function(e) {
+            return z(this, function(e) {
+                var t = this[0] || {}
+                  , n = 0
+                  , r = this.length;
+                if (void 0 === e && 1 === t.nodeType)
+                    return t.innerHTML;
+                if ("string" == typeof e && !Ae.test(e) && !ge[(de.exec(e) || ["", ""])[1].toLowerCase()]) {
+                    e = w.htmlPrefilter(e);
+                    try {
+                        for (; n < r; n++)
+                            1 === (t = this[n] || {}).nodeType && (w.cleanData(ye(t, !1)),
+                            t.innerHTML = e);
+                        t = 0
+                    } catch (e) {}
+                }
+                t && this.empty().append(e)
+            }, null, e, arguments.length)
+        },
+        replaceWith: function() {
+            var e = [];
+            return Re(this, arguments, function(t) {
+                var n = this.parentNode;
+                w.inArray(this, e) < 0 && (w.cleanData(ye(this)),
+                n && n.replaceChild(t, this))
+            }, e)
+        }
+    }),
+    w.each({
+        appendTo: "append",
+        prependTo: "prepend",
+        insertBefore: "before",
+        insertAfter: "after",
+        replaceAll: "replaceWith"
+    }, function(e, t) {
+        w.fn[e] = function(e) {
+            for (var n, r = [], i = w(e), o = i.length - 1, a = 0; a <= o; a++)
+                n = a === o ? this : this.clone(!0),
+                w(i[a])[t](n),
+                s.apply(r, n.get());
+            return this.pushStack(r)
+        }
+    });
+    var We = new RegExp("^(" + re + ")(?!px)[a-z%]+$","i")
+      , $e = function(t) {
+        var n = t.ownerDocument.defaultView;
+        return n && n.opener || (n = e),
+        n.getComputedStyle(t)
+    }
+      , Be = new RegExp(oe.join("|"),"i");
+    !function() {
+        function t() {
+            if (c) {
+                l.style.cssText = "position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",
+                c.style.cssText = "position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",
+                be.appendChild(l).appendChild(c);
+                var t = e.getComputedStyle(c);
+                i = "1%" !== t.top,
+                u = 12 === n(t.marginLeft),
+                c.style.right = "60%",
+                s = 36 === n(t.right),
+                o = 36 === n(t.width),
+                c.style.position = "absolute",
+                a = 36 === c.offsetWidth || "absolute",
+                be.removeChild(l),
+                c = null
+            }
+        }
+        function n(e) {
+            return Math.round(parseFloat(e))
+        }
+        var i, o, a, s, u, l = r.createElement("div"), c = r.createElement("div");
+        c.style && (c.style.backgroundClip = "content-box",
+        c.cloneNode(!0).style.backgroundClip = "",
+        h.clearCloneStyle = "content-box" === c.style.backgroundClip,
+        w.extend(h, {
+            boxSizingReliable: function() {
+                return t(),
+                o
+            },
+            pixelBoxStyles: function() {
+                return t(),
+                s
+            },
+            pixelPosition: function() {
+                return t(),
+                i
+            },
+            reliableMarginLeft: function() {
+                return t(),
+                u
+            },
+            scrollboxSize: function() {
+                return t(),
+                a
+            }
+        }))
+    }();
+    function Fe(e, t, n) {
+        var r, i, o, a, s = e.style;
+        return (n = n || $e(e)) && ("" !== (a = n.getPropertyValue(t) || n[t]) || w.contains(e.ownerDocument, e) || (a = w.style(e, t)),
+        !h.pixelBoxStyles() && We.test(a) && Be.test(t) && (r = s.width,
+        i = s.minWidth,
+        o = s.maxWidth,
+        s.minWidth = s.maxWidth = s.width = a,
+        a = n.width,
+        s.width = r,
+        s.minWidth = i,
+        s.maxWidth = o)),
+        void 0 !== a ? a + "" : a
+    }
+    function _e(e, t) {
+        return {
+            get: function() {
+                if (!e())
+                    return (this.get = t).apply(this, arguments);
+                delete this.get
+            }
+        }
+    }
+    var ze = /^(none|table(?!-c[ea]).+)/
+      , Xe = /^--/
+      , Ue = {
+        position: "absolute",
+        visibility: "hidden",
+        display: "block"
+    }
+      , Ve = {
+        letterSpacing: "0",
+        fontWeight: "400"
+    }
+      , Ge = ["Webkit", "Moz", "ms"]
+      , Ye = r.createElement("div").style;
+    function Qe(e) {
+        if (e in Ye)
+            return e;
+        var t = e[0].toUpperCase() + e.slice(1)
+          , n = Ge.length;
+        while (n--)
+            if ((e = Ge[n] + t)in Ye)
+                return e
+    }
+    function Je(e) {
+        var t = w.cssProps[e];
+        return t || (t = w.cssProps[e] = Qe(e) || e),
+        t
+    }
+    function Ke(e, t, n) {
+        var r = ie.exec(t);
+        return r ? Math.max(0, r[2] - (n || 0)) + (r[3] || "px") : t
+    }
+    function Ze(e, t, n, r, i, o) {
+        var a = "width" === t ? 1 : 0
+          , s = 0
+          , u = 0;
+        if (n === (r ? "border" : "content"))
+            return 0;
+        for (; a < 4; a += 2)
+            "margin" === n && (u += w.css(e, n + oe[a], !0, i)),
+            r ? ("content" === n && (u -= w.css(e, "padding" + oe[a], !0, i)),
+            "margin" !== n && (u -= w.css(e, "border" + oe[a] + "Width", !0, i))) : (u += w.css(e, "padding" + oe[a], !0, i),
+            "padding" !== n ? u += w.css(e, "border" + oe[a] + "Width", !0, i) : s += w.css(e, "border" + oe[a] + "Width", !0, i));
+        return !r && o >= 0 && (u += Math.max(0, Math.ceil(e["offset" + t[0].toUpperCase() + t.slice(1)] - o - u - s - .5))),
+        u
+    }
+    function et(e, t, n) {
+        var r = $e(e)
+          , i = Fe(e, t, r)
+          , o = "border-box" === w.css(e, "boxSizing", !1, r)
+          , a = o;
+        if (We.test(i)) {
+            if (!n)
+                return i;
+            i = "auto"
+        }
+        return a = a && (h.boxSizingReliable() || i === e.style[t]),
+        ("auto" === i || !parseFloat(i) && "inline" === w.css(e, "display", !1, r)) && (i = e["offset" + t[0].toUpperCase() + t.slice(1)],
+        a = !0),
+        (i = parseFloat(i) || 0) + Ze(e, t, n || (o ? "border" : "content"), a, r, i) + "px"
+    }
+    w.extend({
+        cssHooks: {
+            opacity: {
+                get: function(e, t) {
+                    if (t) {
+                        var n = Fe(e, "opacity");
+                        return "" === n ? "1" : n
+                    }
+                }
+            }
+        },
+        cssNumber: {
+            animationIterationCount: !0,
+            columnCount: !0,
+            fillOpacity: !0,
+            flexGrow: !0,
+            flexShrink: !0,
+            fontWeight: !0,
+            lineHeight: !0,
+            opacity: !0,
+            order: !0,
+            orphans: !0,
+            widows: !0,
+            zIndex: !0,
+            zoom: !0
+        },
+        cssProps: {},
+        style: function(e, t, n, r) {
+            if (e && 3 !== e.nodeType && 8 !== e.nodeType && e.style) {
+                var i, o, a, s = G(t), u = Xe.test(t), l = e.style;
+                if (u || (t = Je(s)),
+                a = w.cssHooks[t] || w.cssHooks[s],
+                void 0 === n)
+                    return a && "get"in a && void 0 !== (i = a.get(e, !1, r)) ? i : l[t];
+                "string" == (o = typeof n) && (i = ie.exec(n)) && i[1] && (n = ue(e, t, i),
+                o = "number"),
+                null != n && n === n && ("number" === o && (n += i && i[3] || (w.cssNumber[s] ? "" : "px")),
+                h.clearCloneStyle || "" !== n || 0 !== t.indexOf("background") || (l[t] = "inherit"),
+                a && "set"in a && void 0 === (n = a.set(e, n, r)) || (u ? l.setProperty(t, n) : l[t] = n))
+            }
+        },
+        css: function(e, t, n, r) {
+            var i, o, a, s = G(t);
+            return Xe.test(t) || (t = Je(s)),
+            (a = w.cssHooks[t] || w.cssHooks[s]) && "get"in a && (i = a.get(e, !0, n)),
+            void 0 === i && (i = Fe(e, t, r)),
+            "normal" === i && t in Ve && (i = Ve[t]),
+            "" === n || n ? (o = parseFloat(i),
+            !0 === n || isFinite(o) ? o || 0 : i) : i
+        }
+    }),
+    w.each(["height", "width"], function(e, t) {
+        w.cssHooks[t] = {
+            get: function(e, n, r) {
+                if (n)
+                    return !ze.test(w.css(e, "display")) || e.getClientRects().length && e.getBoundingClientRect().width ? et(e, t, r) : se(e, Ue, function() {
+                        return et(e, t, r)
+                    })
+            },
+            set: function(e, n, r) {
+                var i, o = $e(e), a = "border-box" === w.css(e, "boxSizing", !1, o), s = r && Ze(e, t, r, a, o);
+                return a && h.scrollboxSize() === o.position && (s -= Math.ceil(e["offset" + t[0].toUpperCase() + t.slice(1)] - parseFloat(o[t]) - Ze(e, t, "border", !1, o) - .5)),
+                s && (i = ie.exec(n)) && "px" !== (i[3] || "px") && (e.style[t] = n,
+                n = w.css(e, t)),
+                Ke(e, n, s)
+            }
+        }
+    }),
+    w.cssHooks.marginLeft = _e(h.reliableMarginLeft, function(e, t) {
+        if (t)
+            return (parseFloat(Fe(e, "marginLeft")) || e.getBoundingClientRect().left - se(e, {
+                marginLeft: 0
+            }, function() {
+                return e.getBoundingClientRect().left
+            })) + "px"
+    }),
+    w.each({
+        margin: "",
+        padding: "",
+        border: "Width"
+    }, function(e, t) {
+        w.cssHooks[e + t] = {
+            expand: function(n) {
+                for (var r = 0, i = {}, o = "string" == typeof n ? n.split(" ") : [n]; r < 4; r++)
+                    i[e + oe[r] + t] = o[r] || o[r - 2] || o[0];
+                return i
+            }
+        },
+        "margin" !== e && (w.cssHooks[e + t].set = Ke)
+    }),
+    w.fn.extend({
+        css: function(e, t) {
+            return z(this, function(e, t, n) {
+                var r, i, o = {}, a = 0;
+                if (Array.isArray(t)) {
+                    for (r = $e(e),
+                    i = t.length; a < i; a++)
+                        o[t[a]] = w.css(e, t[a], !1, r);
+                    return o
+                }
+                return void 0 !== n ? w.style(e, t, n) : w.css(e, t)
+            }, e, t, arguments.length > 1)
+        }
+    });
+    function tt(e, t, n, r, i) {
+        return new tt.prototype.init(e,t,n,r,i)
+    }
+    w.Tween = tt,
+    tt.prototype = {
+        constructor: tt,
+        init: function(e, t, n, r, i, o) {
+            this.elem = e,
+            this.prop = n,
+            this.easing = i || w.easing._default,
+            this.options = t,
+            this.start = this.now = this.cur(),
+            this.end = r,
+            this.unit = o || (w.cssNumber[n] ? "" : "px")
+        },
+        cur: function() {
+            var e = tt.propHooks[this.prop];
+            return e && e.get ? e.get(this) : tt.propHooks._default.get(this)
+        },
+        run: function(e) {
+            var t, n = tt.propHooks[this.prop];
+            return this.options.duration ? this.pos = t = w.easing[this.easing](e, this.options.duration * e, 0, 1, this.options.duration) : this.pos = t = e,
+            this.now = (this.end - this.start) * t + this.start,
+            this.options.step && this.options.step.call(this.elem, this.now, this),
+            n && n.set ? n.set(this) : tt.propHooks._default.set(this),
+            this
+        }
+    },
+    tt.prototype.init.prototype = tt.prototype,
+    tt.propHooks = {
+        _default: {
+            get: function(e) {
+                var t;
+                return 1 !== e.elem.nodeType || null != e.elem[e.prop] && null == e.elem.style[e.prop] ? e.elem[e.prop] : (t = w.css(e.elem, e.prop, "")) && "auto" !== t ? t : 0
+            },
+            set: function(e) {
+                w.fx.step[e.prop] ? w.fx.step[e.prop](e) : 1 !== e.elem.nodeType || null == e.elem.style[w.cssProps[e.prop]] && !w.cssHooks[e.prop] ? e.elem[e.prop] = e.now : w.style(e.elem, e.prop, e.now + e.unit)
+            }
+        }
+    },
+    tt.propHooks.scrollTop = tt.propHooks.scrollLeft = {
+        set: function(e) {
+            e.elem.nodeType && e.elem.parentNode && (e.elem[e.prop] = e.now)
+        }
+    },
+    w.easing = {
+        linear: function(e) {
+            return e
+        },
+        swing: function(e) {
+            return .5 - Math.cos(e * Math.PI) / 2
+        },
+        _default: "swing"
+    },
+    w.fx = tt.prototype.init,
+    w.fx.step = {};
+    var nt, rt, it = /^(?:toggle|show|hide)$/, ot = /queueHooks$/;
+    function at() {
+        rt && (!1 === r.hidden && e.requestAnimationFrame ? e.requestAnimationFrame(at) : e.setTimeout(at, w.fx.interval),
+        w.fx.tick())
+    }
+    function st() {
+        return e.setTimeout(function() {
+            nt = void 0
+        }),
+        nt = Date.now()
+    }
+    function ut(e, t) {
+        var n, r = 0, i = {
+            height: e
+        };
+        for (t = t ? 1 : 0; r < 4; r += 2 - t)
+            i["margin" + (n = oe[r])] = i["padding" + n] = e;
+        return t && (i.opacity = i.width = e),
+        i
+    }
+    function lt(e, t, n) {
+        for (var r, i = (pt.tweeners[t] || []).concat(pt.tweeners["*"]), o = 0, a = i.length; o < a; o++)
+            if (r = i[o].call(n, t, e))
+                return r
+    }
+    function ct(e, t, n) {
+        var r, i, o, a, s, u, l, c, f = "width"in t || "height"in t, p = this, d = {}, h = e.style, g = e.nodeType && ae(e), y = J.get(e, "fxshow");
+        n.queue || (null == (a = w._queueHooks(e, "fx")).unqueued && (a.unqueued = 0,
+        s = a.empty.fire,
+        a.empty.fire = function() {
+            a.unqueued || s()
+        }
+        ),
+        a.unqueued++,
+        p.always(function() {
+            p.always(function() {
+                a.unqueued--,
+                w.queue(e, "fx").length || a.empty.fire()
+            })
+        }));
+        for (r in t)
+            if (i = t[r],
+            it.test(i)) {
+                if (delete t[r],
+                o = o || "toggle" === i,
+                i === (g ? "hide" : "show")) {
+                    if ("show" !== i || !y || void 0 === y[r])
+                        continue;
+                    g = !0
+                }
+                d[r] = y && y[r] || w.style(e, r)
+            }
+        if ((u = !w.isEmptyObject(t)) || !w.isEmptyObject(d)) {
+            f && 1 === e.nodeType && (n.overflow = [h.overflow, h.overflowX, h.overflowY],
+            null == (l = y && y.display) && (l = J.get(e, "display")),
+            "none" === (c = w.css(e, "display")) && (l ? c = l : (fe([e], !0),
+            l = e.style.display || l,
+            c = w.css(e, "display"),
+            fe([e]))),
+            ("inline" === c || "inline-block" === c && null != l) && "none" === w.css(e, "float") && (u || (p.done(function() {
+                h.display = l
+            }),
+            null == l && (c = h.display,
+            l = "none" === c ? "" : c)),
+            h.display = "inline-block")),
+            n.overflow && (h.overflow = "hidden",
+            p.always(function() {
+                h.overflow = n.overflow[0],
+                h.overflowX = n.overflow[1],
+                h.overflowY = n.overflow[2]
+            })),
+            u = !1;
+            for (r in d)
+                u || (y ? "hidden"in y && (g = y.hidden) : y = J.access(e, "fxshow", {
+                    display: l
+                }),
+                o && (y.hidden = !g),
+                g && fe([e], !0),
+                p.done(function() {
+                    g || fe([e]),
+                    J.remove(e, "fxshow");
+                    for (r in d)
+                        w.style(e, r, d[r])
+                })),
+                u = lt(g ? y[r] : 0, r, p),
+                r in y || (y[r] = u.start,
+                g && (u.end = u.start,
+                u.start = 0))
+        }
+    }
+    function ft(e, t) {
+        var n, r, i, o, a;
+        for (n in e)
+            if (r = G(n),
+            i = t[r],
+            o = e[n],
+            Array.isArray(o) && (i = o[1],
+            o = e[n] = o[0]),
+            n !== r && (e[r] = o,
+            delete e[n]),
+            (a = w.cssHooks[r]) && "expand"in a) {
+                o = a.expand(o),
+                delete e[r];
+                for (n in o)
+                    n in e || (e[n] = o[n],
+                    t[n] = i)
+            } else
+                t[r] = i
+    }
+    function pt(e, t, n) {
+        var r, i, o = 0, a = pt.prefilters.length, s = w.Deferred().always(function() {
+            delete u.elem
+        }), u = function() {
+            if (i)
+                return !1;
+            for (var t = nt || st(), n = Math.max(0, l.startTime + l.duration - t), r = 1 - (n / l.duration || 0), o = 0, a = l.tweens.length; o < a; o++)
+                l.tweens[o].run(r);
+            return s.notifyWith(e, [l, r, n]),
+            r < 1 && a ? n : (a || s.notifyWith(e, [l, 1, 0]),
+            s.resolveWith(e, [l]),
+            !1)
+        }, l = s.promise({
+            elem: e,
+            props: w.extend({}, t),
+            opts: w.extend(!0, {
+                specialEasing: {},
+                easing: w.easing._default
+            }, n),
+            originalProperties: t,
+            originalOptions: n,
+            startTime: nt || st(),
+            duration: n.duration,
+            tweens: [],
+            createTween: function(t, n) {
+                var r = w.Tween(e, l.opts, t, n, l.opts.specialEasing[t] || l.opts.easing);
+                return l.tweens.push(r),
+                r
+            },
+            stop: function(t) {
+                var n = 0
+                  , r = t ? l.tweens.length : 0;
+                if (i)
+                    return this;
+                for (i = !0; n < r; n++)
+                    l.tweens[n].run(1);
+                return t ? (s.notifyWith(e, [l, 1, 0]),
+                s.resolveWith(e, [l, t])) : s.rejectWith(e, [l, t]),
+                this
+            }
+        }), c = l.props;
+        for (ft(c, l.opts.specialEasing); o < a; o++)
+            if (r = pt.prefilters[o].call(l, e, c, l.opts))
+                return g(r.stop) && (w._queueHooks(l.elem, l.opts.queue).stop = r.stop.bind(r)),
+                r;
+        return w.map(c, lt, l),
+        g(l.opts.start) && l.opts.start.call(e, l),
+        l.progress(l.opts.progress).done(l.opts.done, l.opts.complete).fail(l.opts.fail).always(l.opts.always),
+        w.fx.timer(w.extend(u, {
+            elem: e,
+            anim: l,
+            queue: l.opts.queue
+        })),
+        l
+    }
+    w.Animation = w.extend(pt, {
+        tweeners: {
+            "*": [function(e, t) {
+                var n = this.createTween(e, t);
+                return ue(n.elem, e, ie.exec(t), n),
+                n
+            }
+            ]
+        },
+        tweener: function(e, t) {
+            g(e) ? (t = e,
+            e = ["*"]) : e = e.match(M);
+            for (var n, r = 0, i = e.length; r < i; r++)
+                n = e[r],
+                pt.tweeners[n] = pt.tweeners[n] || [],
+                pt.tweeners[n].unshift(t)
+        },
+        prefilters: [ct],
+        prefilter: function(e, t) {
+            t ? pt.prefilters.unshift(e) : pt.prefilters.push(e)
+        }
+    }),
+    w.speed = function(e, t, n) {
+        var r = e && "object" == typeof e ? w.extend({}, e) : {
+            complete: n || !n && t || g(e) && e,
+            duration: e,
+            easing: n && t || t && !g(t) && t
+        };
+        return w.fx.off ? r.duration = 0 : "number" != typeof r.duration && (r.duration in w.fx.speeds ? r.duration = w.fx.speeds[r.duration] : r.duration = w.fx.speeds._default),
+        null != r.queue && !0 !== r.queue || (r.queue = "fx"),
+        r.old = r.complete,
+        r.complete = function() {
+            g(r.old) && r.old.call(this),
+            r.queue && w.dequeue(this, r.queue)
+        }
+        ,
+        r
+    }
+    ,
+    w.fn.extend({
+        fadeTo: function(e, t, n, r) {
+            return this.filter(ae).css("opacity", 0).show().end().animate({
+                opacity: t
+            }, e, n, r)
+        },
+        animate: function(e, t, n, r) {
+            var i = w.isEmptyObject(e)
+              , o = w.speed(t, n, r)
+              , a = function() {
+                var t = pt(this, w.extend({}, e), o);
+                (i || J.get(this, "finish")) && t.stop(!0)
+            };
+            return a.finish = a,
+            i || !1 === o.queue ? this.each(a) : this.queue(o.queue, a)
+        },
+        stop: function(e, t, n) {
+            var r = function(e) {
+                var t = e.stop;
+                delete e.stop,
+                t(n)
+            };
+            return "string" != typeof e && (n = t,
+            t = e,
+            e = void 0),
+            t && !1 !== e && this.queue(e || "fx", []),
+            this.each(function() {
+                var t = !0
+                  , i = null != e && e + "queueHooks"
+                  , o = w.timers
+                  , a = J.get(this);
+                if (i)
+                    a[i] && a[i].stop && r(a[i]);
+                else
+                    for (i in a)
+                        a[i] && a[i].stop && ot.test(i) && r(a[i]);
+                for (i = o.length; i--; )
+                    o[i].elem !== this || null != e && o[i].queue !== e || (o[i].anim.stop(n),
+                    t = !1,
+                    o.splice(i, 1));
+                !t && n || w.dequeue(this, e)
+            })
+        },
+        finish: function(e) {
+            return !1 !== e && (e = e || "fx"),
+            this.each(function() {
+                var t, n = J.get(this), r = n[e + "queue"], i = n[e + "queueHooks"], o = w.timers, a = r ? r.length : 0;
+                for (n.finish = !0,
+                w.queue(this, e, []),
+                i && i.stop && i.stop.call(this, !0),
+                t = o.length; t--; )
+                    o[t].elem === this && o[t].queue === e && (o[t].anim.stop(!0),
+                    o.splice(t, 1));
+                for (t = 0; t < a; t++)
+                    r[t] && r[t].finish && r[t].finish.call(this);
+                delete n.finish
+            })
+        }
+    }),
+    w.each(["toggle", "show", "hide"], function(e, t) {
+        var n = w.fn[t];
+        w.fn[t] = function(e, r, i) {
+            return null == e || "boolean" == typeof e ? n.apply(this, arguments) : this.animate(ut(t, !0), e, r, i)
+        }
+    }),
+    w.each({
+        slideDown: ut("show"),
+        slideUp: ut("hide"),
+        slideToggle: ut("toggle"),
+        fadeIn: {
+            opacity: "show"
+        },
+        fadeOut: {
+            opacity: "hide"
+        },
+        fadeToggle: {
+            opacity: "toggle"
+        }
+    }, function(e, t) {
+        w.fn[e] = function(e, n, r) {
+            return this.animate(t, e, n, r)
+        }
+    }),
+    w.timers = [],
+    w.fx.tick = function() {
+        var e, t = 0, n = w.timers;
+        for (nt = Date.now(); t < n.length; t++)
+            (e = n[t])() || n[t] !== e || n.splice(t--, 1);
+        n.length || w.fx.stop(),
+        nt = void 0
+    }
+    ,
+    w.fx.timer = function(e) {
+        w.timers.push(e),
+        w.fx.start()
+    }
+    ,
+    w.fx.interval = 13,
+    w.fx.start = function() {
+        rt || (rt = !0,
+        at())
+    }
+    ,
+    w.fx.stop = function() {
+        rt = null
+    }
+    ,
+    w.fx.speeds = {
+        slow: 600,
+        fast: 200,
+        _default: 400
+    },
+    w.fn.delay = function(t, n) {
+        return t = w.fx ? w.fx.speeds[t] || t : t,
+        n = n || "fx",
+        this.queue(n, function(n, r) {
+            var i = e.setTimeout(n, t);
+            r.stop = function() {
+                e.clearTimeout(i)
+            }
+        })
+    }
+    ,
+    function() {
+        var e = r.createElement("input")
+          , t = r.createElement("select").appendChild(r.createElement("option"));
+        e.type = "checkbox",
+        h.checkOn = "" !== e.value,
+        h.optSelected = t.selected,
+        (e = r.createElement("input")).value = "t",
+        e.type = "radio",
+        h.radioValue = "t" === e.value
+    }();
+    var dt, ht = w.expr.attrHandle;
+    w.fn.extend({
+        attr: function(e, t) {
+            return z(this, w.attr, e, t, arguments.length > 1)
+        },
+        removeAttr: function(e) {
+            return this.each(function() {
+                w.removeAttr(this, e)
+            })
+        }
+    }),
+    w.extend({
+        attr: function(e, t, n) {
+            var r, i, o = e.nodeType;
+            if (3 !== o && 8 !== o && 2 !== o)
+                return "undefined" == typeof e.getAttribute ? w.prop(e, t, n) : (1 === o && w.isXMLDoc(e) || (i = w.attrHooks[t.toLowerCase()] || (w.expr.match.bool.test(t) ? dt : void 0)),
+                void 0 !== n ? null === n ? void w.removeAttr(e, t) : i && "set"in i && void 0 !== (r = i.set(e, n, t)) ? r : (e.setAttribute(t, n + ""),
+                n) : i && "get"in i && null !== (r = i.get(e, t)) ? r : null == (r = w.find.attr(e, t)) ? void 0 : r)
+        },
+        attrHooks: {
+            type: {
+                set: function(e, t) {
+                    if (!h.radioValue && "radio" === t && N(e, "input")) {
+                        var n = e.value;
+                        return e.setAttribute("type", t),
+                        n && (e.value = n),
+                        t
+                    }
+                }
+            }
+        },
+        removeAttr: function(e, t) {
+            var n, r = 0, i = t && t.match(M);
+            if (i && 1 === e.nodeType)
+                while (n = i[r++])
+                    e.removeAttribute(n)
+        }
+    }),
+    dt = {
+        set: function(e, t, n) {
+            return !1 === t ? w.removeAttr(e, n) : e.setAttribute(n, n),
+            n
+        }
+    },
+    w.each(w.expr.match.bool.source.match(/\w+/g), function(e, t) {
+        var n = ht[t] || w.find.attr;
+        ht[t] = function(e, t, r) {
+            var i, o, a = t.toLowerCase();
+            return r || (o = ht[a],
+            ht[a] = i,
+            i = null != n(e, t, r) ? a : null,
+            ht[a] = o),
+            i
+        }
+    });
+    var gt = /^(?:input|select|textarea|button)$/i
+      , yt = /^(?:a|area)$/i;
+    w.fn.extend({
+        prop: function(e, t) {
+            return z(this, w.prop, e, t, arguments.length > 1)
+        },
+        removeProp: function(e) {
+            return this.each(function() {
+                delete this[w.propFix[e] || e]
+            })
+        }
+    }),
+    w.extend({
+        prop: function(e, t, n) {
+            var r, i, o = e.nodeType;
+            if (3 !== o && 8 !== o && 2 !== o)
+                return 1 === o && w.isXMLDoc(e) || (t = w.propFix[t] || t,
+                i = w.propHooks[t]),
+                void 0 !== n ? i && "set"in i && void 0 !== (r = i.set(e, n, t)) ? r : e[t] = n : i && "get"in i && null !== (r = i.get(e, t)) ? r : e[t]
+        },
+        propHooks: {
+            tabIndex: {
+                get: function(e) {
+                    var t = w.find.attr(e, "tabindex");
+                    return t ? parseInt(t, 10) : gt.test(e.nodeName) || yt.test(e.nodeName) && e.href ? 0 : -1
+                }
+            }
+        },
+        propFix: {
+            "for": "htmlFor",
+            "class": "className"
+        }
+    }),
+    h.optSelected || (w.propHooks.selected = {
+        get: function(e) {
+            var t = e.parentNode;
+            return t && t.parentNode && t.parentNode.selectedIndex,
+            null
+        },
+        set: function(e) {
+            var t = e.parentNode;
+            t && (t.selectedIndex,
+            t.parentNode && t.parentNode.selectedIndex)
+        }
+    }),
+    w.each(["tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable"], function() {
+        w.propFix[this.toLowerCase()] = this
+    });
+    function vt(e) {
+        return (e.match(M) || []).join(" ")
+    }
+    function mt(e) {
+        return e.getAttribute && e.getAttribute("class") || ""
+    }
+    function xt(e) {
+        return Array.isArray(e) ? e : "string" == typeof e ? e.match(M) || [] : []
+    }
+    w.fn.extend({
+        addClass: function(e) {
+            var t, n, r, i, o, a, s, u = 0;
+            if (g(e))
+                return this.each(function(t) {
+                    w(this).addClass(e.call(this, t, mt(this)))
+                });
+            if ((t = xt(e)).length)
+                while (n = this[u++])
+                    if (i = mt(n),
+                    r = 1 === n.nodeType && " " + vt(i) + " ") {
+                        a = 0;
+                        while (o = t[a++])
+                            r.indexOf(" " + o + " ") < 0 && (r += o + " ");
+                        i !== (s = vt(r)) && n.setAttribute("class", s)
+                    }
+            return this
+        },
+        removeClass: function(e) {
+            var t, n, r, i, o, a, s, u = 0;
+            if (g(e))
+                return this.each(function(t) {
+                    w(this).removeClass(e.call(this, t, mt(this)))
+                });
+            if (!arguments.length)
+                return this.attr("class", "");
+            if ((t = xt(e)).length)
+                while (n = this[u++])
+                    if (i = mt(n),
+                    r = 1 === n.nodeType && " " + vt(i) + " ") {
+                        a = 0;
+                        while (o = t[a++])
+                            while (r.indexOf(" " + o + " ") > -1)
+                                r = r.replace(" " + o + " ", " ");
+                        i !== (s = vt(r)) && n.setAttribute("class", s)
+                    }
+            return this
+        },
+        toggleClass: function(e, t) {
+            var n = typeof e
+              , r = "string" === n || Array.isArray(e);
+            return "boolean" == typeof t && r ? t ? this.addClass(e) : this.removeClass(e) : g(e) ? this.each(function(n) {
+                w(this).toggleClass(e.call(this, n, mt(this), t), t)
+            }) : this.each(function() {
+                var t, i, o, a;
+                if (r) {
+                    i = 0,
+                    o = w(this),
+                    a = xt(e);
+                    while (t = a[i++])
+                        o.hasClass(t) ? o.removeClass(t) : o.addClass(t)
+                } else
+                    void 0 !== e && "boolean" !== n || ((t = mt(this)) && J.set(this, "__className__", t),
+                    this.setAttribute && this.setAttribute("class", t || !1 === e ? "" : J.get(this, "__className__") || ""))
+            })
+        },
+        hasClass: function(e) {
+            var t, n, r = 0;
+            t = " " + e + " ";
+            while (n = this[r++])
+                if (1 === n.nodeType && (" " + vt(mt(n)) + " ").indexOf(t) > -1)
+                    return !0;
+            return !1
+        }
+    });
+    var bt = /\r/g;
+    w.fn.extend({
+        val: function(e) {
+            var t, n, r, i = this[0];
+            {
+                if (arguments.length)
+                    return r = g(e),
+                    this.each(function(n) {
+                        var i;
+                        1 === this.nodeType && (null == (i = r ? e.call(this, n, w(this).val()) : e) ? i = "" : "number" == typeof i ? i += "" : Array.isArray(i) && (i = w.map(i, function(e) {
+                            return null == e ? "" : e + ""
+                        })),
+                        (t = w.valHooks[this.type] || w.valHooks[this.nodeName.toLowerCase()]) && "set"in t && void 0 !== t.set(this, i, "value") || (this.value = i))
+                    });
+                if (i)
+                    return (t = w.valHooks[i.type] || w.valHooks[i.nodeName.toLowerCase()]) && "get"in t && void 0 !== (n = t.get(i, "value")) ? n : "string" == typeof (n = i.value) ? n.replace(bt, "") : null == n ? "" : n
+            }
+        }
+    }),
+    w.extend({
+        valHooks: {
+            option: {
+                get: function(e) {
+                    var t = w.find.attr(e, "value");
+                    return null != t ? t : vt(w.text(e))
+                }
+            },
+            select: {
+                get: function(e) {
+                    var t, n, r, i = e.options, o = e.selectedIndex, a = "select-one" === e.type, s = a ? null : [], u = a ? o + 1 : i.length;
+                    for (r = o < 0 ? u : a ? o : 0; r < u; r++)
+                        if (((n = i[r]).selected || r === o) && !n.disabled && (!n.parentNode.disabled || !N(n.parentNode, "optgroup"))) {
+                            if (t = w(n).val(),
+                            a)
+                                return t;
+                            s.push(t)
+                        }
+                    return s
+                },
+                set: function(e, t) {
+                    var n, r, i = e.options, o = w.makeArray(t), a = i.length;
+                    while (a--)
+                        ((r = i[a]).selected = w.inArray(w.valHooks.option.get(r), o) > -1) && (n = !0);
+                    return n || (e.selectedIndex = -1),
+                    o
+                }
+            }
+        }
+    }),
+    w.each(["radio", "checkbox"], function() {
+        w.valHooks[this] = {
+            set: function(e, t) {
+                if (Array.isArray(t))
+                    return e.checked = w.inArray(w(e).val(), t) > -1
+            }
+        },
+        h.checkOn || (w.valHooks[this].get = function(e) {
+            return null === e.getAttribute("value") ? "on" : e.value
+        }
+        )
+    }),
+    h.focusin = "onfocusin"in e;
+    var wt = /^(?:focusinfocus|focusoutblur)$/
+      , Tt = function(e) {
+        e.stopPropagation()
+    };
+    w.extend(w.event, {
+        trigger: function(t, n, i, o) {
+            var a, s, u, l, c, p, d, h, v = [i || r], m = f.call(t, "type") ? t.type : t, x = f.call(t, "namespace") ? t.namespace.split(".") : [];
+            if (s = h = u = i = i || r,
+            3 !== i.nodeType && 8 !== i.nodeType && !wt.test(m + w.event.triggered) && (m.indexOf(".") > -1 && (m = (x = m.split(".")).shift(),
+            x.sort()),
+            c = m.indexOf(":") < 0 && "on" + m,
+            t = t[w.expando] ? t : new w.Event(m,"object" == typeof t && t),
+            t.isTrigger = o ? 2 : 3,
+            t.namespace = x.join("."),
+            t.rnamespace = t.namespace ? new RegExp("(^|\\.)" + x.join("\\.(?:.*\\.|)") + "(\\.|$)") : null,
+            t.result = void 0,
+            t.target || (t.target = i),
+            n = null == n ? [t] : w.makeArray(n, [t]),
+            d = w.event.special[m] || {},
+            o || !d.trigger || !1 !== d.trigger.apply(i, n))) {
+                if (!o && !d.noBubble && !y(i)) {
+                    for (l = d.delegateType || m,
+                    wt.test(l + m) || (s = s.parentNode); s; s = s.parentNode)
+                        v.push(s),
+                        u = s;
+                    u === (i.ownerDocument || r) && v.push(u.defaultView || u.parentWindow || e)
+                }
+                a = 0;
+                while ((s = v[a++]) && !t.isPropagationStopped())
+                    h = s,
+                    t.type = a > 1 ? l : d.bindType || m,
+                    (p = (J.get(s, "events") || {})[t.type] && J.get(s, "handle")) && p.apply(s, n),
+                    (p = c && s[c]) && p.apply && Y(s) && (t.result = p.apply(s, n),
+                    !1 === t.result && t.preventDefault());
+                return t.type = m,
+                o || t.isDefaultPrevented() || d._default && !1 !== d._default.apply(v.pop(), n) || !Y(i) || c && g(i[m]) && !y(i) && ((u = i[c]) && (i[c] = null),
+                w.event.triggered = m,
+                t.isPropagationStopped() && h.addEventListener(m, Tt),
+                i[m](),
+                t.isPropagationStopped() && h.removeEventListener(m, Tt),
+                w.event.triggered = void 0,
+                u && (i[c] = u)),
+                t.result
+            }
+        },
+        simulate: function(e, t, n) {
+            var r = w.extend(new w.Event, n, {
+                type: e,
+                isSimulated: !0
+            });
+            w.event.trigger(r, null, t)
+        }
+    }),
+    w.fn.extend({
+        trigger: function(e, t) {
+            return this.each(function() {
+                w.event.trigger(e, t, this)
+            })
+        },
+        triggerHandler: function(e, t) {
+            var n = this[0];
+            if (n)
+                return w.event.trigger(e, t, n, !0)
+        }
+    }),
+    h.focusin || w.each({
+        focus: "focusin",
+        blur: "focusout"
+    }, function(e, t) {
+        var n = function(e) {
+            w.event.simulate(t, e.target, w.event.fix(e))
+        };
+        w.event.special[t] = {
+            setup: function() {
+                var r = this.ownerDocument || this
+                  , i = J.access(r, t);
+                i || r.addEventListener(e, n, !0),
+                J.access(r, t, (i || 0) + 1)
+            },
+            teardown: function() {
+                var r = this.ownerDocument || this
+                  , i = J.access(r, t) - 1;
+                i ? J.access(r, t, i) : (r.removeEventListener(e, n, !0),
+                J.remove(r, t))
+            }
+        }
+    });
+    var Ct = e.location
+      , Et = Date.now()
+      , kt = /\?/;
+    w.parseXML = function(t) {
+        var n;
+        if (!t || "string" != typeof t)
+            return null;
+        try {
+            n = (new e.DOMParser).parseFromString(t, "text/xml")
+        } catch (e) {
+            n = void 0
+        }
+        return n && !n.getElementsByTagName("parsererror").length || w.error("Invalid XML: " + t),
+        n
+    }
+    ;
+    var St = /\[\]$/
+      , Dt = /\r?\n/g
+      , Nt = /^(?:submit|button|image|reset|file)$/i
+      , At = /^(?:input|select|textarea|keygen)/i;
+    function jt(e, t, n, r) {
+        var i;
+        if (Array.isArray(t))
+            w.each(t, function(t, i) {
+                n || St.test(e) ? r(e, i) : jt(e + "[" + ("object" == typeof i && null != i ? t : "") + "]", i, n, r)
+            });
+        else if (n || "object" !== x(t))
+            r(e, t);
+        else
+            for (i in t)
+                jt(e + "[" + i + "]", t[i], n, r)
+    }
+    w.param = function(e, t) {
+        var n, r = [], i = function(e, t) {
+            var n = g(t) ? t() : t;
+            r[r.length] = encodeURIComponent(e) + "=" + encodeURIComponent(null == n ? "" : n)
+        };
+        if (Array.isArray(e) || e.jquery && !w.isPlainObject(e))
+            w.each(e, function() {
+                i(this.name, this.value)
+            });
+        else
+            for (n in e)
+                jt(n, e[n], t, i);
+        return r.join("&")
+    }
+    ,
+    w.fn.extend({
+        serialize: function() {
+            return w.param(this.serializeArray())
+        },
+        serializeArray: function() {
+            return this.map(function() {
+                var e = w.prop(this, "elements");
+                return e ? w.makeArray(e) : this
+            }).filter(function() {
+                var e = this.type;
+                return this.name && !w(this).is(":disabled") && At.test(this.nodeName) && !Nt.test(e) && (this.checked || !pe.test(e))
+            }).map(function(e, t) {
+                var n = w(this).val();
+                return null == n ? null : Array.isArray(n) ? w.map(n, function(e) {
+                    return {
+                        name: t.name,
+                        value: e.replace(Dt, "\r\n")
+                    }
+                }) : {
+                    name: t.name,
+                    value: n.replace(Dt, "\r\n")
+                }
+            }).get()
+        }
+    });
+    var qt = /%20/g
+      , Lt = /#.*$/
+      , Ht = /([?&])_=[^&]*/
+      , Ot = /^(.*?):[ \t]*([^\r\n]*)$/gm
+      , Pt = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/
+      , Mt = /^(?:GET|HEAD)$/
+      , Rt = /^\/\//
+      , It = {}
+      , Wt = {}
+      , $t = "*/".concat("*")
+      , Bt = r.createElement("a");
+    Bt.href = Ct.href;
+    function Ft(e) {
+        return function(t, n) {
+            "string" != typeof t && (n = t,
+            t = "*");
+            var r, i = 0, o = t.toLowerCase().match(M) || [];
+            if (g(n))
+                while (r = o[i++])
+                    "+" === r[0] ? (r = r.slice(1) || "*",
+                    (e[r] = e[r] || []).unshift(n)) : (e[r] = e[r] || []).push(n)
+        }
+    }
+    function _t(e, t, n, r) {
+        var i = {}
+          , o = e === Wt;
+        function a(s) {
+            var u;
+            return i[s] = !0,
+            w.each(e[s] || [], function(e, s) {
+                var l = s(t, n, r);
+                return "string" != typeof l || o || i[l] ? o ? !(u = l) : void 0 : (t.dataTypes.unshift(l),
+                a(l),
+                !1)
+            }),
+            u
+        }
+        return a(t.dataTypes[0]) || !i["*"] && a("*")
+    }
+    function zt(e, t) {
+        var n, r, i = w.ajaxSettings.flatOptions || {};
+        for (n in t)
+            void 0 !== t[n] && ((i[n] ? e : r || (r = {}))[n] = t[n]);
+        return r && w.extend(!0, e, r),
+        e
+    }
+    function Xt(e, t, n) {
+        var r, i, o, a, s = e.contents, u = e.dataTypes;
+        while ("*" === u[0])
+            u.shift(),
+            void 0 === r && (r = e.mimeType || t.getResponseHeader("Content-Type"));
+        if (r)
+            for (i in s)
+                if (s[i] && s[i].test(r)) {
+                    u.unshift(i);
+                    break
+                }
+        if (u[0]in n)
+            o = u[0];
+        else {
+            for (i in n) {
+                if (!u[0] || e.converters[i + " " + u[0]]) {
+                    o = i;
+                    break
+                }
+                a || (a = i)
+            }
+            o = o || a
+        }
+        if (o)
+            return o !== u[0] && u.unshift(o),
+            n[o]
+    }
+    function Ut(e, t, n, r) {
+        var i, o, a, s, u, l = {}, c = e.dataTypes.slice();
+        if (c[1])
+            for (a in e.converters)
+                l[a.toLowerCase()] = e.converters[a];
+        o = c.shift();
+        while (o)
+            if (e.responseFields[o] && (n[e.responseFields[o]] = t),
+            !u && r && e.dataFilter && (t = e.dataFilter(t, e.dataType)),
+            u = o,
+            o = c.shift())
+                if ("*" === o)
+                    o = u;
+                else if ("*" !== u && u !== o) {
+                    if (!(a = l[u + " " + o] || l["* " + o]))
+                        for (i in l)
+                            if ((s = i.split(" "))[1] === o && (a = l[u + " " + s[0]] || l["* " + s[0]])) {
+                                !0 === a ? a = l[i] : !0 !== l[i] && (o = s[0],
+                                c.unshift(s[1]));
+                                break
+                            }
+                    if (!0 !== a)
+                        if (a && e["throws"])
+                            t = a(t);
+                        else
+                            try {
+                                t = a(t)
+                            } catch (e) {
+                                return {
+                                    state: "parsererror",
+                                    error: a ? e : "No conversion from " + u + " to " + o
+                                }
+                            }
+                }
+        return {
+            state: "success",
+            data: t
+        }
+    }
+    w.extend({
+        active: 0,
+        lastModified: {},
+        etag: {},
+        ajaxSettings: {
+            url: Ct.href,
+            type: "GET",
+            isLocal: Pt.test(Ct.protocol),
+            global: !0,
+            processData: !0,
+            async: !0,
+            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+            accepts: {
+                "*": $t,
+                text: "text/plain",
+                html: "text/html",
+                xml: "application/xml, text/xml",
+                json: "application/json, text/javascript"
+            },
+            contents: {
+                xml: /\bxml\b/,
+                html: /\bhtml/,
+                json: /\bjson\b/
+            },
+            responseFields: {
+                xml: "responseXML",
+                text: "responseText",
+                json: "responseJSON"
+            },
+            converters: {
+                "* text": String,
+                "text html": !0,
+                "text json": JSON.parse,
+                "text xml": w.parseXML
+            },
+            flatOptions: {
+                url: !0,
+                context: !0
+            }
+        },
+        ajaxSetup: function(e, t) {
+            return t ? zt(zt(e, w.ajaxSettings), t) : zt(w.ajaxSettings, e)
+        },
+        ajaxPrefilter: Ft(It),
+        ajaxTransport: Ft(Wt),
+        ajax: function(t, n) {
+            "object" == typeof t && (n = t,
+            t = void 0),
+            n = n || {};
+            var i, o, a, s, u, l, c, f, p, d, h = w.ajaxSetup({}, n), g = h.context || h, y = h.context && (g.nodeType || g.jquery) ? w(g) : w.event, v = w.Deferred(), m = w.Callbacks("once memory"), x = h.statusCode || {}, b = {}, T = {}, C = "canceled", E = {
+                readyState: 0,
+                getResponseHeader: function(e) {
+                    var t;
+                    if (c) {
+                        if (!s) {
+                            s = {};
+                            while (t = Ot.exec(a))
+                                s[t[1].toLowerCase()] = t[2]
+                        }
+                        t = s[e.toLowerCase()]
+                    }
+                    return null == t ? null : t
+                },
+                getAllResponseHeaders: function() {
+                    return c ? a : null
+                },
+                setRequestHeader: function(e, t) {
+                    return null == c && (e = T[e.toLowerCase()] = T[e.toLowerCase()] || e,
+                    b[e] = t),
+                    this
+                },
+                overrideMimeType: function(e) {
+                    return null == c && (h.mimeType = e),
+                    this
+                },
+                statusCode: function(e) {
+                    var t;
+                    if (e)
+                        if (c)
+                            E.always(e[E.status]);
+                        else
+                            for (t in e)
+                                x[t] = [x[t], e[t]];
+                    return this
+                },
+                abort: function(e) {
+                    var t = e || C;
+                    return i && i.abort(t),
+                    k(0, t),
+                    this
+                }
+            };
+            if (v.promise(E),
+            h.url = ((t || h.url || Ct.href) + "").replace(Rt, Ct.protocol + "//"),
+            h.type = n.method || n.type || h.method || h.type,
+            h.dataTypes = (h.dataType || "*").toLowerCase().match(M) || [""],
+            null == h.crossDomain) {
+                l = r.createElement("a");
+                try {
+                    l.href = h.url,
+                    l.href = l.href,
+                    h.crossDomain = Bt.protocol + "//" + Bt.host != l.protocol + "//" + l.host
+                } catch (e) {
+                    h.crossDomain = !0
+                }
+            }
+            if (h.data && h.processData && "string" != typeof h.data && (h.data = w.param(h.data, h.traditional)),
+            _t(It, h, n, E),
+            c)
+                return E;
+            (f = w.event && h.global) && 0 == w.active++ && w.event.trigger("ajaxStart"),
+            h.type = h.type.toUpperCase(),
+            h.hasContent = !Mt.test(h.type),
+            o = h.url.replace(Lt, ""),
+            h.hasContent ? h.data && h.processData && 0 === (h.contentType || "").indexOf("application/x-www-form-urlencoded") && (h.data = h.data.replace(qt, "+")) : (d = h.url.slice(o.length),
+            h.data && (h.processData || "string" == typeof h.data) && (o += (kt.test(o) ? "&" : "?") + h.data,
+            delete h.data),
+            !1 === h.cache && (o = o.replace(Ht, "$1"),
+            d = (kt.test(o) ? "&" : "?") + "_=" + Et++ + d),
+            h.url = o + d),
+            h.ifModified && (w.lastModified[o] && E.setRequestHeader("If-Modified-Since", w.lastModified[o]),
+            w.etag[o] && E.setRequestHeader("If-None-Match", w.etag[o])),
+            (h.data && h.hasContent && !1 !== h.contentType || n.contentType) && E.setRequestHeader("Content-Type", h.contentType),
+            E.setRequestHeader("Accept", h.dataTypes[0] && h.accepts[h.dataTypes[0]] ? h.accepts[h.dataTypes[0]] + ("*" !== h.dataTypes[0] ? ", " + $t + "; q=0.01" : "") : h.accepts["*"]);
+            for (p in h.headers)
+                E.setRequestHeader(p, h.headers[p]);
+            if (h.beforeSend && (!1 === h.beforeSend.call(g, E, h) || c))
+                return E.abort();
+            if (C = "abort",
+            m.add(h.complete),
+            E.done(h.success),
+            E.fail(h.error),
+            i = _t(Wt, h, n, E)) {
+                if (E.readyState = 1,
+                f && y.trigger("ajaxSend", [E, h]),
+                c)
+                    return E;
+                h.async && h.timeout > 0 && (u = e.setTimeout(function() {
+                    E.abort("timeout")
+                }, h.timeout));
+                try {
+                    c = !1,
+                    i.send(b, k)
+                } catch (e) {
+                    if (c)
+                        throw e;
+                    k(-1, e)
+                }
+            } else
+                k(-1, "No Transport");
+            function k(t, n, r, s) {
+                var l, p, d, b, T, C = n;
+                c || (c = !0,
+                u && e.clearTimeout(u),
+                i = void 0,
+                a = s || "",
+                E.readyState = t > 0 ? 4 : 0,
+                l = t >= 200 && t < 300 || 304 === t,
+                r && (b = Xt(h, E, r)),
+                b = Ut(h, b, E, l),
+                l ? (h.ifModified && ((T = E.getResponseHeader("Last-Modified")) && (w.lastModified[o] = T),
+                (T = E.getResponseHeader("etag")) && (w.etag[o] = T)),
+                204 === t || "HEAD" === h.type ? C = "nocontent" : 304 === t ? C = "notmodified" : (C = b.state,
+                p = b.data,
+                l = !(d = b.error))) : (d = C,
+                !t && C || (C = "error",
+                t < 0 && (t = 0))),
+                E.status = t,
+                E.statusText = (n || C) + "",
+                l ? v.resolveWith(g, [p, C, E]) : v.rejectWith(g, [E, C, d]),
+                E.statusCode(x),
+                x = void 0,
+                f && y.trigger(l ? "ajaxSuccess" : "ajaxError", [E, h, l ? p : d]),
+                m.fireWith(g, [E, C]),
+                f && (y.trigger("ajaxComplete", [E, h]),
+                --w.active || w.event.trigger("ajaxStop")))
+            }
+            return E
+        },
+        getJSON: function(e, t, n) {
+            return w.get(e, t, n, "json")
+        },
+        getScript: function(e, t) {
+            return w.get(e, void 0, t, "script")
+        }
+    }),
+    w.each(["get", "post"], function(e, t) {
+        w[t] = function(e, n, r, i) {
+            return g(n) && (i = i || r,
+            r = n,
+            n = void 0),
+            w.ajax(w.extend({
+                url: e,
+                type: t,
+                dataType: i,
+                data: n,
+                success: r
+            }, w.isPlainObject(e) && e))
+        }
+    }),
+    w._evalUrl = function(e) {
+        return w.ajax({
+            url: e,
+            type: "GET",
+            dataType: "script",
+            cache: !0,
+            async: !1,
+            global: !1,
+            "throws": !0
+        })
+    }
+    ,
+    w.fn.extend({
+        wrapAll: function(e) {
+            var t;
+            return this[0] && (g(e) && (e = e.call(this[0])),
+            t = w(e, this[0].ownerDocument).eq(0).clone(!0),
+            this[0].parentNode && t.insertBefore(this[0]),
+            t.map(function() {
+                var e = this;
+                while (e.firstElementChild)
+                    e = e.firstElementChild;
+                return e
+            }).append(this)),
+            this
+        },
+        wrapInner: function(e) {
+            return g(e) ? this.each(function(t) {
+                w(this).wrapInner(e.call(this, t))
+            }) : this.each(function() {
+                var t = w(this)
+                  , n = t.contents();
+                n.length ? n.wrapAll(e) : t.append(e)
+            })
+        },
+        wrap: function(e) {
+            var t = g(e);
+            return this.each(function(n) {
+                w(this).wrapAll(t ? e.call(this, n) : e)
+            })
+        },
+        unwrap: function(e) {
+            return this.parent(e).not("body").each(function() {
+                w(this).replaceWith(this.childNodes)
+            }),
+            this
+        }
+    }),
+    w.expr.pseudos.hidden = function(e) {
+        return !w.expr.pseudos.visible(e)
+    }
+    ,
+    w.expr.pseudos.visible = function(e) {
+        return !!(e.offsetWidth || e.offsetHeight || e.getClientRects().length)
+    }
+    ,
+    w.ajaxSettings.xhr = function() {
+        try {
+            return new e.XMLHttpRequest
+        } catch (e) {}
+    }
+    ;
+    var Vt = {
+        0: 200,
+        1223: 204
+    }
+      , Gt = w.ajaxSettings.xhr();
+    h.cors = !!Gt && "withCredentials"in Gt,
+    h.ajax = Gt = !!Gt,
+    w.ajaxTransport(function(t) {
+        var n, r;
+        if (h.cors || Gt && !t.crossDomain)
+            return {
+                send: function(i, o) {
+                    var a, s = t.xhr();
+                    if (s.open(t.type, t.url, t.async, t.username, t.password),
+                    t.xhrFields)
+                        for (a in t.xhrFields)
+                            s[a] = t.xhrFields[a];
+                    t.mimeType && s.overrideMimeType && s.overrideMimeType(t.mimeType),
+                    t.crossDomain || i["X-Requested-With"] || (i["X-Requested-With"] = "XMLHttpRequest");
+                    for (a in i)
+                        s.setRequestHeader(a, i[a]);
+                    n = function(e) {
+                        return function() {
+                            n && (n = r = s.onload = s.onerror = s.onabort = s.ontimeout = s.onreadystatechange = null,
+                            "abort" === e ? s.abort() : "error" === e ? "number" != typeof s.status ? o(0, "error") : o(s.status, s.statusText) : o(Vt[s.status] || s.status, s.statusText, "text" !== (s.responseType || "text") || "string" != typeof s.responseText ? {
+                                binary: s.response
+                            } : {
+                                text: s.responseText
+                            }, s.getAllResponseHeaders()))
+                        }
+                    }
+                    ,
+                    s.onload = n(),
+                    r = s.onerror = s.ontimeout = n("error"),
+                    void 0 !== s.onabort ? s.onabort = r : s.onreadystatechange = function() {
+                        4 === s.readyState && e.setTimeout(function() {
+                            n && r()
+                        })
+                    }
+                    ,
+                    n = n("abort");
+                    try {
+                        s.send(t.hasContent && t.data || null)
+                    } catch (e) {
+                        if (n)
+                            throw e
+                    }
+                },
+                abort: function() {
+                    n && n()
+                }
+            }
+    }),
+    w.ajaxPrefilter(function(e) {
+        e.crossDomain && (e.contents.script = !1)
+    }),
+    w.ajaxSetup({
+        accepts: {
+            script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+        },
+        contents: {
+            script: /\b(?:java|ecma)script\b/
+        },
+        converters: {
+            "text script": function(e) {
+                return w.globalEval(e),
+                e
+            }
+        }
+    }),
+    w.ajaxPrefilter("script", function(e) {
+        void 0 === e.cache && (e.cache = !1),
+        e.crossDomain && (e.type = "GET")
+    }),
+    w.ajaxTransport("script", function(e) {
+        if (e.crossDomain) {
+            var t, n;
+            return {
+                send: function(i, o) {
+                    t = w("<script>").prop({
+                        charset: e.scriptCharset,
+                        src: e.url
+                    }).on("load error", n = function(e) {
+                        t.remove(),
+                        n = null,
+                        e && o("error" === e.type ? 404 : 200, e.type)
+                    }
+                    ),
+                    r.head.appendChild(t[0])
+                },
+                abort: function() {
+                    n && n()
+                }
+            }
+        }
+    });
+    var Yt = []
+      , Qt = /(=)\?(?=&|$)|\?\?/;
+    w.ajaxSetup({
+        jsonp: "callback",
+        jsonpCallback: function() {
+            var e = Yt.pop() || w.expando + "_" + Et++;
+            return this[e] = !0,
+            e
+        }
+    }),
+    w.ajaxPrefilter("json jsonp", function(t, n, r) {
+        var i, o, a, s = !1 !== t.jsonp && (Qt.test(t.url) ? "url" : "string" == typeof t.data && 0 === (t.contentType || "").indexOf("application/x-www-form-urlencoded") && Qt.test(t.data) && "data");
+        if (s || "jsonp" === t.dataTypes[0])
+            return i = t.jsonpCallback = g(t.jsonpCallback) ? t.jsonpCallback() : t.jsonpCallback,
+            s ? t[s] = t[s].replace(Qt, "$1" + i) : !1 !== t.jsonp && (t.url += (kt.test(t.url) ? "&" : "?") + t.jsonp + "=" + i),
+            t.converters["script json"] = function() {
+                return a || w.error(i + " was not called"),
+                a[0]
+            }
+            ,
+            t.dataTypes[0] = "json",
+            o = e[i],
+            e[i] = function() {
+                a = arguments
+            }
+            ,
+            r.always(function() {
+                void 0 === o ? w(e).removeProp(i) : e[i] = o,
+                t[i] && (t.jsonpCallback = n.jsonpCallback,
+                Yt.push(i)),
+                a && g(o) && o(a[0]),
+                a = o = void 0
+            }),
+            "script"
+    }),
+    h.createHTMLDocument = function() {
+        var e = r.implementation.createHTMLDocument("").body;
+        return e.innerHTML = "<form></form><form></form>",
+        2 === e.childNodes.length
+    }(),
+    w.parseHTML = function(e, t, n) {
+        if ("string" != typeof e)
+            return [];
+        "boolean" == typeof t && (n = t,
+        t = !1);
+        var i, o, a;
+        return t || (h.createHTMLDocument ? ((i = (t = r.implementation.createHTMLDocument("")).createElement("base")).href = r.location.href,
+        t.head.appendChild(i)) : t = r),
+        o = A.exec(e),
+        a = !n && [],
+        o ? [t.createElement(o[1])] : (o = xe([e], t, a),
+        a && a.length && w(a).remove(),
+        w.merge([], o.childNodes))
+    }
+    ,
+    w.fn.load = function(e, t, n) {
+        var r, i, o, a = this, s = e.indexOf(" ");
+        return s > -1 && (r = vt(e.slice(s)),
+        e = e.slice(0, s)),
+        g(t) ? (n = t,
+        t = void 0) : t && "object" == typeof t && (i = "POST"),
+        a.length > 0 && w.ajax({
+            url: e,
+            type: i || "GET",
+            dataType: "html",
+            data: t
+        }).done(function(e) {
+            o = arguments,
+            a.html(r ? w("<div>").append(w.parseHTML(e)).find(r) : e)
+        }).always(n && function(e, t) {
+            a.each(function() {
+                n.apply(this, o || [e.responseText, t, e])
+            })
+        }
+        ),
+        this
+    }
+    ,
+    w.each(["ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend"], function(e, t) {
+        w.fn[t] = function(e) {
+            return this.on(t, e)
+        }
+    }),
+    w.expr.pseudos.animated = function(e) {
+        return w.grep(w.timers, function(t) {
+            return e === t.elem
+        }).length
+    }
+    ,
+    w.offset = {
+        setOffset: function(e, t, n) {
+            var r, i, o, a, s, u, l, c = w.css(e, "position"), f = w(e), p = {};
+            "static" === c && (e.style.position = "relative"),
+            s = f.offset(),
+            o = w.css(e, "top"),
+            u = w.css(e, "left"),
+            (l = ("absolute" === c || "fixed" === c) && (o + u).indexOf("auto") > -1) ? (a = (r = f.position()).top,
+            i = r.left) : (a = parseFloat(o) || 0,
+            i = parseFloat(u) || 0),
+            g(t) && (t = t.call(e, n, w.extend({}, s))),
+            null != t.top && (p.top = t.top - s.top + a),
+            null != t.left && (p.left = t.left - s.left + i),
+            "using"in t ? t.using.call(e, p) : f.css(p)
+        }
+    },
+    w.fn.extend({
+        offset: function(e) {
+            if (arguments.length)
+                return void 0 === e ? this : this.each(function(t) {
+                    w.offset.setOffset(this, e, t)
+                });
+            var t, n, r = this[0];
+            if (r)
+                return r.getClientRects().length ? (t = r.getBoundingClientRect(),
+                n = r.ownerDocument.defaultView,
+                {
+                    top: t.top + n.pageYOffset,
+                    left: t.left + n.pageXOffset
+                }) : {
+                    top: 0,
+                    left: 0
+                }
+        },
+        position: function() {
+            if (this[0]) {
+                var e, t, n, r = this[0], i = {
+                    top: 0,
+                    left: 0
+                };
+                if ("fixed" === w.css(r, "position"))
+                    t = r.getBoundingClientRect();
+                else {
+                    t = this.offset(),
+                    n = r.ownerDocument,
+                    e = r.offsetParent || n.documentElement;
+                    while (e && (e === n.body || e === n.documentElement) && "static" === w.css(e, "position"))
+                        e = e.parentNode;
+                    e && e !== r && 1 === e.nodeType && ((i = w(e).offset()).top += w.css(e, "borderTopWidth", !0),
+                    i.left += w.css(e, "borderLeftWidth", !0))
+                }
+                return {
+                    top: t.top - i.top - w.css(r, "marginTop", !0),
+                    left: t.left - i.left - w.css(r, "marginLeft", !0)
+                }
+            }
+        },
+        offsetParent: function() {
+            return this.map(function() {
+                var e = this.offsetParent;
+                while (e && "static" === w.css(e, "position"))
+                    e = e.offsetParent;
+                return e || be
+            })
+        }
+    }),
+    w.each({
+        scrollLeft: "pageXOffset",
+        scrollTop: "pageYOffset"
+    }, function(e, t) {
+        var n = "pageYOffset" === t;
+        w.fn[e] = function(r) {
+            return z(this, function(e, r, i) {
+                var o;
+                if (y(e) ? o = e : 9 === e.nodeType && (o = e.defaultView),
+                void 0 === i)
+                    return o ? o[t] : e[r];
+                o ? o.scrollTo(n ? o.pageXOffset : i, n ? i : o.pageYOffset) : e[r] = i
+            }, e, r, arguments.length)
+        }
+    }),
+    w.each(["top", "left"], function(e, t) {
+        w.cssHooks[t] = _e(h.pixelPosition, function(e, n) {
+            if (n)
+                return n = Fe(e, t),
+                We.test(n) ? w(e).position()[t] + "px" : n
+        })
+    }),
+    w.each({
+        Height: "height",
+        Width: "width"
+    }, function(e, t) {
+        w.each({
+            padding: "inner" + e,
+            content: t,
+            "": "outer" + e
+        }, function(n, r) {
+            w.fn[r] = function(i, o) {
+                var a = arguments.length && (n || "boolean" != typeof i)
+                  , s = n || (!0 === i || !0 === o ? "margin" : "border");
+                return z(this, function(t, n, i) {
+                    var o;
+                    return y(t) ? 0 === r.indexOf("outer") ? t["inner" + e] : t.document.documentElement["client" + e] : 9 === t.nodeType ? (o = t.documentElement,
+                    Math.max(t.body["scroll" + e], o["scroll" + e], t.body["offset" + e], o["offset" + e], o["client" + e])) : void 0 === i ? w.css(t, n, s) : w.style(t, n, i, s)
+                }, t, a ? i : void 0, a)
+            }
+        })
+    }),
+    w.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(e, t) {
+        w.fn[t] = function(e, n) {
+            return arguments.length > 0 ? this.on(t, null, e, n) : this.trigger(t)
+        }
+    }),
+    w.fn.extend({
+        hover: function(e, t) {
+            return this.mouseenter(e).mouseleave(t || e)
+        }
+    }),
+    w.fn.extend({
+        bind: function(e, t, n) {
+            return this.on(e, null, t, n)
+        },
+        unbind: function(e, t) {
+            return this.off(e, null, t)
+        },
+        delegate: function(e, t, n, r) {
+            return this.on(t, e, n, r)
+        },
+        undelegate: function(e, t, n) {
+            return 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n)
+        }
+    }),
+    w.proxy = function(e, t) {
+        var n, r, i;
+        if ("string" == typeof t && (n = e[t],
+        t = e,
+        e = n),
+        g(e))
+            return r = o.call(arguments, 2),
+            i = function() {
+                return e.apply(t || this, r.concat(o.call(arguments)))
+            }
+            ,
+            i.guid = e.guid = e.guid || w.guid++,
+            i
+    }
+    ,
+    w.holdReady = function(e) {
+        e ? w.readyWait++ : w.ready(!0)
+    }
+    ,
+    w.isArray = Array.isArray,
+    w.parseJSON = JSON.parse,
+    w.nodeName = N,
+    w.isFunction = g,
+    w.isWindow = y,
+    w.camelCase = G,
+    w.type = x,
+    w.now = Date.now,
+    w.isNumeric = function(e) {
+        var t = w.type(e);
+        return ("number" === t || "string" === t) && !isNaN(e - parseFloat(e))
+    }
+    ,
+    "function" == typeof define && define.amd && define("jquery", [], function() {
+        return w
+    });
+    var Jt = e.jQuery
+      , Kt = e.$;
+    return w.noConflict = function(t) {
+        return e.$ === w && (e.$ = Kt),
+        t && e.jQuery === w && (e.jQuery = Jt),
+        w
+    }
+    ,
+    t || (e.jQuery = e.$ = w),
+    w
+});

+ 506 - 0
public/static/jquery.i18n.properties.js

@@ -0,0 +1,506 @@
+/******************************************************************************
+ * jquery.i18n.properties
+ *
+ * Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and
+ * MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses.
+ *
+ * @version     1.2.7
+ * @url         https://github.com/jquery-i18n-properties/jquery-i18n-properties
+ * @inspiration Localisation assistance for jQuery (http://keith-wood.name/localisation.html)
+ *              by Keith Wood (kbwood{at}iinet.com.au) June 2007
+ *
+ *****************************************************************************/
+
+(function ($) {
+
+    $.i18n = {};
+
+    /**
+     * Map holding bundle keys if mode is 'map' or 'both'. Values of this can also be an
+     * Object, in which case the key is a namespace.
+     */
+    $.i18n.map = {};
+
+    var debug = function (message) {
+        window.console && console.log('i18n::' + message);
+    };
+
+    /**
+     * Load and parse message bundle files (.properties),
+     * making bundles keys available as javascript variables.
+     *
+     * i18n files are named <name>.js, or <name>_<language>.js or <name>_<language>_<country>.js
+     * Where:
+     *      The <language> argument is a valid ISO Language Code. These codes are the lower-case,
+     *      two-letter codes as defined by ISO-639. You can find a full list of these codes at a
+     *      number of sites, such as: http://www.loc.gov/standards/iso639-2/englangn.html
+     *      The <country> argument is a valid ISO Country Code. These codes are the upper-case,
+     *      two-letter codes as defined by ISO-3166. You can find a full list of these codes at a
+     *      number of sites, such as: http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
+     *
+     * Sample usage for a bundles/Messages.properties bundle:
+     * $.i18n.properties({
+     *      name:      'Messages',
+     *      language:  'en_US',
+     *      path:      'bundles'
+     * });
+     * @param  name      (string/string[], optional) names of file to load (eg, 'Messages' or ['Msg1','Msg2']). Defaults to "Messages"
+     * @param  language    (string, optional) language/country code (eg, 'en', 'en_US', 'pt_BR'). if not specified, language reported by the browser will be used instead.
+     * @param  path      (string, optional) path of directory that contains file to load
+     * @param  mode      (string, optional) whether bundles keys are available as JavaScript variables/functions or as a map (eg, 'vars' or 'map')
+     * @param  debug     (boolean, optional) whether debug statements are logged at the console
+     * @param  cache        (boolean, optional) whether bundles should be cached by the browser, or forcibly reloaded on each page load. Defaults to false (i.e. forcibly reloaded)
+     * @param  encoding  (string, optional) the encoding to request for bundles. Property file resource bundles are specified to be in ISO-8859-1 format. Defaults to UTF-8 for backward compatibility.
+     * @param  callback     (function, optional) callback function to be called after script is terminated
+     */
+    $.i18n.properties = function (settings) {
+
+        var defaults = {
+            name: 'Messages',
+            language: '',
+            path: '',
+            namespace: null,
+            mode: 'vars',
+            cache: false,
+            debug: false,
+            encoding: 'UTF-8',
+            async: false,
+            callback: null
+        };
+
+        settings = $.extend(defaults, settings);
+
+        if (settings.namespace && typeof settings.namespace == 'string') {
+            // A namespace has been supplied, initialise it.
+            if (settings.namespace.match(/^[a-z]*$/)) {
+                $.i18n.map[settings.namespace] = {};
+            } else {
+                debug('Namespaces can only be lower case letters, a - z');
+                settings.namespace = null;
+            }
+        }
+
+        // Ensure a trailing slash on the path
+        if (!settings.path.match(/\/$/)) settings.path += '/';
+
+        // Try to ensure that we have at a least a two letter language code
+        settings.language = this.normaliseLanguageCode(settings);
+
+        // Ensure an array
+        var files = (settings.name && settings.name.constructor === Array) ? settings.name : [settings.name];
+
+        // A locale is at least a language code which means at least two files per name. If
+        // we also have a country code, thats an extra file per name.
+        settings.totalFiles = (files.length * 2) + ((settings.language.length >= 5) ? files.length : 0);
+        if (settings.debug) {
+            debug('totalFiles: ' + settings.totalFiles);
+        }
+
+        settings.filesLoaded = 0;
+
+        files.forEach(function (file) {
+
+            var defaultFileName, shortFileName, longFileName, fileNames;
+            // 1. load base (eg, Messages.properties)
+            defaultFileName = settings.path + file + '.properties';
+            // 2. with language code (eg, Messages_pt.properties)
+            var shortCode = settings.language.substring(0, 2);
+            shortFileName = settings.path + file + '_' + shortCode + '.properties';
+            // 3. with language code and country code (eg, Messages_pt_BR.properties)
+            if (settings.language.length >= 5) {
+                var longCode = settings.language.substring(0, 5);
+                longFileName = settings.path + file + '_' + longCode + '.properties';
+                fileNames = [defaultFileName, shortFileName, longFileName];
+            } else {
+                fileNames = [defaultFileName, shortFileName];
+            }
+            loadAndParseFiles(fileNames, settings);
+        });
+
+        // call callback
+        if (settings.callback && !settings.async) {
+            settings.callback();
+        }
+    }; // properties
+
+    /**
+     * When configured with mode: 'map', allows access to bundle values by specifying its key.
+     * Eg, jQuery.i18n.prop('com.company.bundles.menu_add')
+     */
+    $.i18n.prop = function (key /* Add parameters as function arguments as necessary  */) {
+
+        var args = [].slice.call(arguments);
+
+        var phvList, namespace;
+        if (args.length == 2) {
+            if ($.isArray(args[1])) {
+                // An array was passed as the second parameter, so assume it is the list of place holder values.
+                phvList = args[1];
+            } else if (typeof args[1] === 'object') {
+                // Second argument is an options object {namespace: 'mynamespace', replacements: ['egg', 'nog']}
+                namespace = args[1].namespace;
+                var replacements = args[1].replacements;
+                args.splice(-1, 1);
+                if (replacements) {
+                    Array.prototype.push.apply(args, replacements);
+                }
+            }
+        }
+
+        var value = (namespace) ? $.i18n.map[namespace][key] : $.i18n.map[key];
+        if (value === null) {
+            return '[' + ((namespace) ? namespace + '#' + key : key) + ']';
+        }
+
+        // Place holder replacement
+        /**
+        * Tested with:
+        *   test.t1=asdf ''{0}''
+        *   test.t2=asdf '{0}' '{1}'{1}'zxcv
+        *   test.t3=This is \"a quote" 'a''{0}''s'd{fgh{ij'
+        *   test.t4="'''{'0}''" {0}{a}
+        *   test.t5="'''{0}'''" {1}
+        *   test.t6=a {1} b {0} c
+        *   test.t7=a 'quoted \\ s\ttringy' \t\t x
+        *
+        * Produces:
+        *   test.t1, p1 ==> asdf 'p1'
+        *   test.t2, p1 ==> asdf {0} {1}{1}zxcv
+        *   test.t3, p1 ==> This is "a quote" a'{0}'sd{fgh{ij
+        *   test.t4, p1 ==> "'{0}'" p1{a}
+        *   test.t5, p1 ==> "'{0}'" {1}
+        *   test.t6, p1 ==> a {1} b p1 c
+        *   test.t6, p1, p2 ==> a p2 b p1 c
+        *   test.t6, p1, p2, p3 ==> a p2 b p1 c
+        *   test.t7 ==> a quoted \ s	tringy 		 x
+        */
+
+        var i;
+        if (typeof(value) == 'string') {
+            // Handle escape characters. Done separately from the tokenizing loop below because escape characters are
+            // active in quoted strings.
+            i = 0;
+            while ((i = value.indexOf('\\', i)) != -1) {
+                if (value.charAt(i + 1) == 't') {
+                    value = value.substring(0, i) + '\t' + value.substring((i++) + 2); // tab
+                } else if (value.charAt(i + 1) == 'r') {
+                    value = value.substring(0, i) + '\r' + value.substring((i++) + 2); // return
+                } else if (value.charAt(i + 1) == 'n') {
+                    value = value.substring(0, i) + '\n' + value.substring((i++) + 2); // line feed
+                } else if (value.charAt(i + 1) == 'f') {
+                    value = value.substring(0, i) + '\f' + value.substring((i++) + 2); // form feed
+                } else if (value.charAt(i + 1) == '\\') {
+                    value = value.substring(0, i) + '\\' + value.substring((i++) + 2); // \
+                } else {
+                    value = value.substring(0, i) + value.substring(i + 1); // Quietly drop the character
+                }
+            }
+
+            // Lazily convert the string to a list of tokens.
+            var arr = [], j, index;
+            i = 0;
+            while (i < value.length) {
+                if (value.charAt(i) == '\'') {
+                    // Handle quotes
+                    if (i == value.length - 1) {
+                        value = value.substring(0, i); // Silently drop the trailing quote
+                    } else if (value.charAt(i + 1) == '\'') {
+                        value = value.substring(0, i) + value.substring(++i); // Escaped quote
+                    } else {
+                        // Quoted string
+                        j = i + 2;
+                        while ((j = value.indexOf('\'', j)) != -1) {
+                            if (j == value.length - 1 || value.charAt(j + 1) != '\'') {
+                                // Found start and end quotes. Remove them
+                                value = value.substring(0, i) + value.substring(i + 1, j) + value.substring(j + 1);
+                                i = j - 1;
+                                break;
+                            } else {
+                                // Found a double quote, reduce to a single quote.
+                                value = value.substring(0, j) + value.substring(++j);
+                            }
+                        }
+
+                        if (j == -1) {
+                            // There is no end quote. Drop the start quote
+                            value = value.substring(0, i) + value.substring(i + 1);
+                        }
+                    }
+                } else if (value.charAt(i) == '{') {
+                    // Beginning of an unquoted place holder.
+                    j = value.indexOf('}', i + 1);
+                    if (j == -1) {
+                        i++; // No end. Process the rest of the line. Java would throw an exception
+                    } else {
+                        // Add 1 to the index so that it aligns with the function arguments.
+                        index = parseInt(value.substring(i + 1, j));
+                        if (!isNaN(index) && index >= 0) {
+                            // Put the line thus far (if it isn't empty) into the array
+                            var s = value.substring(0, i);
+                            if (s !== "") {
+                                arr.push(s);
+                            }
+                            // Put the parameter reference into the array
+                            arr.push(index);
+                            // Start the processing over again starting from the rest of the line.
+                            i = 0;
+                            value = value.substring(j + 1);
+                        } else {
+                            i = j + 1; // Invalid parameter. Leave as is.
+                        }
+                    }
+                } else {
+                    i++;
+                }
+            } // while
+
+            // Put the remainder of the no-empty line into the array.
+            if (value !== "") {
+                arr.push(value);
+            }
+            value = arr;
+
+            // Make the array the value for the entry.
+            if (namespace) {
+                $.i18n.map[settings.namespace][key] = arr;
+            } else {
+                $.i18n.map[key] = arr;
+            }
+        }
+
+        if (value.length === 0) {
+            return "";
+        }
+        if (value.length == 1 && typeof(value[0]) == "string") {
+            return value[0];
+        }
+
+        var str = "";
+        for (i = 0, j = value.length; i < j; i++) {
+            if (typeof(value[i]) == "string") {
+                str += value[i];
+            } else if (phvList && value[i] < phvList.length) {
+                // Must be a number
+                str += phvList[value[i]];
+            } else if (!phvList && value[i] + 1 < args.length) {
+                str += args[value[i] + 1];
+            } else {
+                str += "{" + value[i] + "}";
+            }
+        }
+
+        return str;
+    };
+
+    function callbackIfComplete(settings) {
+
+        if (settings.debug) {
+            debug('callbackIfComplete()');
+            debug('totalFiles: ' + settings.totalFiles);
+            debug('filesLoaded: ' + settings.filesLoaded);
+        }
+
+        if (settings.async) {
+            if (settings.filesLoaded === settings.totalFiles) {
+                if (settings.callback) {
+                    settings.callback();
+                }
+            }
+        }
+    }
+
+    function loadAndParseFiles(fileNames, settings) {
+
+        if (settings.debug) debug('loadAndParseFiles');
+
+	    if (fileNames !== null && fileNames.length > 0) {
+		    loadAndParseFile(fileNames[0], settings, function () {
+			    fileNames.shift();
+			    loadAndParseFiles(fileNames,settings);
+		    });
+	    } else {
+            callbackIfComplete(settings);
+        }
+    }
+
+    /** Load and parse .properties files */
+    function loadAndParseFile(filename, settings, nextFile) {
+
+        if (settings.debug) {
+            debug('loadAndParseFile(\'' + filename +'\')');
+            debug('totalFiles: ' + settings.totalFiles);
+            debug('filesLoaded: ' + settings.filesLoaded);
+        }
+
+  	    if (filename !== null && typeof filename !== 'undefined') {
+            $.ajax({
+                url: filename,
+                async: settings.async,
+                cache: settings.cache,
+                dataType: 'text',
+                success: function (data, status) {
+
+                    if (settings.debug) {
+                        debug('Succeeded in downloading ' + filename + '.');
+                        debug(data);
+                    }
+
+                    parseData(data, settings);
+                    nextFile();
+                },
+                error: function (jqXHR, textStatus, errorThrown) {
+
+                    if (settings.debug) {
+                        debug('Failed to download or parse ' + filename + '. errorThrown: ' + errorThrown);
+                    }
+                    if (jqXHR.status === 404) {
+                        settings.totalFiles -= 1;
+                    }
+                    nextFile();
+                }
+            });
+        }
+    }
+
+    /** Parse .properties files */
+    function parseData(data, settings) {
+
+        var parsed = '';
+        var lines = data.split(/\n/);
+        var regPlaceHolder = /(\{\d+})/g;
+        var regRepPlaceHolder = /\{(\d+)}/g;
+        var unicodeRE = /(\\u.{4})/ig;
+        for (var i=0,j=lines.length;i<j;i++) {
+            var line = lines[i];
+
+            line = line.trim();
+            if (line.length > 0 && line.match("^#") != "#") { // skip comments
+                var pair = line.split('=');
+                if (pair.length > 0) {
+                    /** Process key & value */
+                    var name = decodeURI(pair[0]).trim();
+                    var value = pair.length == 1 ? "" : pair[1];
+                    // process multi-line values
+                    while (value.search(/\\$/) != -1) {
+                        value = value.substring(0, value.length - 1);
+                        value += lines[++i].trimRight();
+                    }
+                    // Put values with embedded '='s back together
+                    for (var s = 2; s < pair.length; s++) {
+                        value += '=' + pair[s];
+                    }
+                    value = value.trim();
+
+                    /** Mode: bundle keys in a map */
+                    if (settings.mode == 'map' || settings.mode == 'both') {
+                        // handle unicode chars possibly left out
+                        var unicodeMatches = value.match(unicodeRE);
+                        if (unicodeMatches) {
+                            unicodeMatches.forEach(function (match) {
+                                value = value.replace(match, unescapeUnicode(match));
+                            });
+                        }
+                        // add to map
+                        if (settings.namespace) {
+                            $.i18n.map[settings.namespace][name] = value;
+                        } else {
+                            $.i18n.map[name] = value;
+                        }
+                    }
+
+                    /** Mode: bundle keys as vars/functions */
+                    if (settings.mode == 'vars' || settings.mode == 'both') {
+                        value = value.replace(/"/g, '\\"'); // escape quotation mark (")
+
+                        // make sure namespaced key exists (eg, 'some.key')
+                        checkKeyNamespace(name);
+
+                        // value with variable substitutions
+                        if (regPlaceHolder.test(value)) {
+                            var parts = value.split(regPlaceHolder);
+                            // process function args
+                            var first = true;
+                            var fnArgs = '';
+                            var usedArgs = [];
+                            parts.forEach(function (part) {
+
+                                if (regPlaceHolder.test(part) && (usedArgs.length === 0 || usedArgs.indexOf(part) == -1)) {
+                                    if (!first) {
+                                        fnArgs += ',';
+                                    }
+                                    fnArgs += part.replace(regRepPlaceHolder, 'v$1');
+                                    usedArgs.push(part);
+                                    first = false;
+                                }
+                            });
+                            parsed += name + '=function(' + fnArgs + '){';
+                            // process function body
+                            var fnExpr = '"' + value.replace(regRepPlaceHolder, '"+v$1+"') + '"';
+                            parsed += 'return ' + fnExpr + ';' + '};';
+                            // simple value
+                        } else {
+                            parsed += name + '="' + value + '";';
+                        }
+                    } // END: Mode: bundle keys as vars/functions
+                } // END: if(pair.length > 0)
+            } // END: skip comments
+        }
+        eval(parsed);
+        settings.filesLoaded += 1;
+    }
+
+    /** Make sure namespace exists (for keys with dots in name) */
+    // TODO key parts that start with numbers quietly fail. i.e. month.short.1=Jan
+    function checkKeyNamespace(key) {
+
+        var regDot = /\./;
+        if (regDot.test(key)) {
+            var fullname = '';
+            var names = key.split(/\./);
+            for (var i=0,j=names.length;i<j;i++) {
+                var name = names[i];
+
+                if (i > 0) {
+                    fullname += '.';
+                }
+
+                fullname += name;
+                if (eval('typeof ' + fullname + ' == "undefined"')) {
+                    eval(fullname + '={};');
+                }
+            }
+        }
+    }
+
+    /** Ensure language code is in the format aa_AA. */
+    $.i18n.normaliseLanguageCode = function (settings) {
+
+        var lang = settings.language;
+        if (!lang || lang.length < 2) {
+            if (settings.debug) debug('No language supplied. Pulling it from the browser ...');
+            lang = (navigator.languages && navigator.languages.length > 0) ? navigator.languages[0]
+                                        : (navigator.language || navigator.userLanguage /* IE */ || 'en');
+            if (settings.debug) debug('Language from browser: ' + lang);
+        }
+
+        lang = lang.toLowerCase();
+        lang = lang.replace(/-/,"_"); // some browsers report language as en-US instead of en_US
+        if (lang.length > 3) {
+            lang = lang.substring(0, 3) + lang.substring(3).toUpperCase();
+        }
+        return lang;
+    };
+
+    /** Unescape unicode chars ('\u00e3') */
+    function unescapeUnicode(str) {
+
+        // unescape unicode codes
+        var codes = [];
+        var code = parseInt(str.substr(2), 16);
+        if (code >= 0 && code < Math.pow(2, 16)) {
+            codes.push(code);
+        }
+        // convert codes to text
+        return codes.reduce(function (acc, val) { return acc + String.fromCharCode(val); }, '');
+    }
+}) (jQuery);

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/md5.js


+ 89 - 0
public/static/message.js

@@ -0,0 +1,89 @@
+const message = {
+    background: "", // 背景颜色
+    outside: "", // 外框元素
+    inside: "", // 信息显示元素
+    insideSetTime: "", // 信息移除setTime
+    body: "", // body元素
+    time: 0, // 显示时间
+    run(msg = "success", type = "success", time = 2000) {
+        // 显示时间
+        this.time = time;
+
+        // 背景色
+        this.background = this.backgroundCheck(type);
+
+        // body
+        this.body = document.body;
+
+        // 时间戳id
+        let id = "inside_box" + Date.now();
+
+        // 检查是否存在外框
+        let outsideShow = document.getElementById("message_box_show");
+        if (outsideShow != null) {
+            // 文字显示区域
+            this.inside = document.createElement("div");
+            this.inside.setAttribute("class", "message_box_inside cc-display");
+            this.inside.setAttribute("id", id);
+            this.inside.style.backgroundColor = this.background;
+            this.inside.innerHTML = `<span>${msg}</span>`;
+            outsideShow.appendChild(this.inside);
+        } else {
+            // 最外框
+            this.outside = document.createElement("div");
+            this.outside.setAttribute("id", "message_box_outside");
+            this.outside.setAttribute("class", "cc-display");
+
+            // 中间区域
+            outsideShow = document.createElement("div");
+            outsideShow.setAttribute("id", "message_box_show");
+
+            // 文字显示区域
+            this.inside = document.createElement("div");
+            this.inside.setAttribute("class", "message_box_inside cc-display");
+            this.inside.setAttribute("id", id);
+            this.inside.style.backgroundColor = this.background;
+            this.inside.innerHTML = `<span>${msg}</span>`;
+
+            // 显示
+            outsideShow.appendChild(this.inside);
+            this.outside.appendChild(outsideShow);
+            this.body.appendChild(this.outside);
+        }
+
+        // 添加监听
+        this[id] = this.insideTime(this.inside, outsideShow);
+        this.boxShowTime(this.inside, id, outsideShow);
+    },
+
+    // 信息显示区域展示
+    boxShowTime(inside, insideSetTime, outsideShow) {
+        inside.addEventListener("mouseleave", () => {
+            // 离开后设置隐藏时间
+            this[insideSetTime] = this.insideTime(inside, outsideShow);
+        });
+        inside.addEventListener("mouseenter", () => {
+            // 清除隐藏设置
+            clearTimeout(this[insideSetTime]);
+        });
+    },
+
+    // 信息区显示
+    insideTime(inside, outsideShow) {
+        let insideSetTime = setTimeout(() => {
+            outsideShow.removeChild(inside);
+        }, this.time);
+        return insideSetTime;
+    },
+
+    // 判定显示颜色
+    backgroundCheck(type) {
+        if (type === "success") return "#67C23A";
+        if (type === "error") return "#F56C6C";
+        if (type === "warning") return "#E6A23C";
+        // if (type === 'info') return '#909399';
+        return "#909399"; // 默认级别
+    },
+};
+
+export default message;

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/mjpegSession.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/mp4remux.js


+ 58 - 0
public/static/playerControl.js

@@ -0,0 +1,58 @@
+var PlayerControl = function (a) {
+    this.wsURL = a.wsURL, this.rtspURL = a.rtspURL, this.ws = null, this.decodeMode = a.decodeMode, this.events = {
+        ResolutionChanged: function () {
+        }, PlayStart: function () {
+        }, DecodeStart: function () {
+        }, UpdateCanvas: function () {
+        }, GetFrameRate: function () {
+        }, FrameTypeChange: function () {
+        }, Error: function () {
+        }, MSEResolutionChanged: function () {
+        }, audioChange: function () {
+        }, WorkerReady: function () {
+        }, IvsDraw: function () {
+        }, FileOver: function () {
+        }
+    }, this.username = a.username, this.password = a.password
+};
+PlayerControl.prototype = {
+    init: function (a, b) {
+        this.ws = new WebsocketServer(this.wsURL, this.rtspURL), this.ws.init(a, b), this.ws.setLiveMode(this.decodeMode), this.ws.setUserInfo(this.username, this.password);
+        for (var c in this.events) this.ws.setCallback(c, this.events[c]);
+        this.events = null
+    }, connect: function () {
+        this.ws.connect()
+    }, play: function () {
+        this.controlPlayer("PLAY")
+    }, pause: function () {
+        this.controlPlayer("PAUSE")
+    }, stop: function () {
+        this.controlPlayer("TEARDOWN")
+    }, close: function () {
+        this.ws.disconnect()
+    }, playByTime: function (a) {
+        this.controlPlayer("PLAY", "video", a)
+    }, playFF: function (a) {
+        this.controlPlayer("PAUSE"), this.controlPlayer("SCALE", a)
+    }, playRewind: function () {
+    }, audioPlay: function () {
+        this.controlPlayer("audioPlay", "start")
+    }, audioStop: function () {
+        this.controlPlayer("audioPlay", "stop")
+    }, setAudioSamplingRate: function (a) {
+        this.controlPlayer("audioSamplingRate", a)
+    }, setAudioVolume: function (a) {
+        this.controlPlayer("volumn", a)
+    }, controlPlayer: function (a, b, c) {
+        var d;
+        d = "video" === b ? {command: a, range: c ? c : 0} : {command: a, data: b}, this.ws.controlPlayer(d)
+    }, setPlayMode: function (a) {
+        this.ws.setLiveMode(a)
+    }, setPlayPath: function (a) {
+        this.ws.setRTSPURL(a)
+    }, capture: function (a) {
+        this.ws.capture(a)
+    }, on: function (a, b) {
+        this.events[a] = b
+    }
+};

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/public.js


+ 18 - 0
public/static/service.js

@@ -0,0 +1,18 @@
+const path = require('path');
+const express = require('express');
+
+const app = express();
+
+app.get('/',function(req,res){
+    res.sendFile(path.join(__dirname,'moduleTest.html'));
+});
+
+app.use(express.static(__dirname + '/js'));
+
+app.listen('3000','0.0.0.0',function(err){
+    if(err){
+        console.log(err);
+        return;
+    }
+    console.log('Listening at http://0.0.0.0:3000');
+});

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/streamDrawer.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 11 - 0
public/static/video.min.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/videoMediaSource.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/videoWorker.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
public/static/videojs-contrib-hls.min.js


+ 1455 - 0
public/static/videojs-flash.js

@@ -0,0 +1,1455 @@
+/**
+ * videojs-flash
+ * @version 2.2.1
+ * @copyright 2019 Brightcove, Inc.
+ * @license Apache-2.0
+ */
+(function (global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) :
+	typeof define === 'function' && define.amd ? define(['video.js'], factory) :
+	(global.videojsFlash = factory(global.videojs));
+}(this, (function (videojs) { 'use strict';
+
+videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
+
+var version = "5.4.2";
+
+var version$1 = "2.2.1";
+
+/**
+ * @file flash-rtmp.js
+ * @module flash-rtmp
+ */
+
+/**
+ * Add RTMP properties to the {@link Flash} Tech.
+ *
+ * @param {Flash} Flash
+ *        The flash tech class.
+ *
+ * @mixin FlashRtmpDecorator
+ *
+ * @return {Flash}
+ *         The flash tech with RTMP properties added.
+ */
+function FlashRtmpDecorator(Flash) {
+  Flash.streamingFormats = {
+    'rtmp/mp4': 'MP4',
+    'rtmp/flv': 'FLV'
+  };
+
+  /**
+   * Join connection and stream with an ampersand.
+   *
+   * @param {string} connection
+   *        The connection string.
+   *
+   * @param {string} stream
+   *        The stream string.
+   *
+   * @return {string}
+   *         The connection and stream joined with an `&` character
+   */
+  Flash.streamFromParts = function (connection, stream) {
+    return connection + '&' + stream;
+  };
+
+  /**
+   * The flash parts object that contains connection and stream info.
+   *
+   * @typedef {Object} Flash~PartsObject
+   *
+   * @property {string} connection
+   *           The connection string of a source, defaults to an empty string.
+   *
+   * @property {string} stream
+   *           The stream string of the source, defaults to an empty string.
+   */
+
+  /**
+   * Convert a source url into a stream and connection parts.
+   *
+   * @param {string} src
+   *        the source url
+   *
+   * @return {Flash~PartsObject}
+   *         The parts object that contains a connection and a stream
+   */
+  Flash.streamToParts = function (src) {
+    var parts = {
+      connection: '',
+      stream: ''
+    };
+
+    if (!src) {
+      return parts;
+    }
+
+    // Look for the normal URL separator we expect, '&'.
+    // If found, we split the URL into two pieces around the
+    // first '&'.
+    var connEnd = src.search(/&(?![\w-]+=)/);
+    var streamBegin = void 0;
+
+    if (connEnd !== -1) {
+      streamBegin = connEnd + 1;
+    } else {
+      // If there's not a '&', we use the last '/' as the delimiter.
+      connEnd = streamBegin = src.lastIndexOf('/') + 1;
+      if (connEnd === 0) {
+        // really, there's not a '/'?
+        connEnd = streamBegin = src.length;
+      }
+    }
+
+    parts.connection = src.substring(0, connEnd);
+    parts.stream = src.substring(streamBegin, src.length);
+
+    return parts;
+  };
+
+  /**
+   * Check if the source type is a streaming type.
+   *
+   * @param {string} srcType
+   *        The mime type to check.
+   *
+   * @return {boolean}
+   *          - True if the source type is a streaming type.
+   *          - False if the source type is not a streaming type.
+   */
+  Flash.isStreamingType = function (srcType) {
+    return srcType in Flash.streamingFormats;
+  };
+
+  // RTMP has four variations, any string starting
+  // with one of these protocols should be valid
+
+  /**
+   * Regular expression used to check if the source is an rtmp source.
+   *
+   * @property {RegExp} Flash.RTMP_RE
+   */
+  Flash.RTMP_RE = /^rtmp[set]?:\/\//i;
+
+  /**
+   * Check if the source itself is a streaming type.
+   *
+   * @param {string} src
+   *        The url to the source.
+   *
+   * @return {boolean}
+   *          - True if the source url indicates that the source is streaming.
+   *          - False if the shource url indicates that the source url is not streaming.
+   */
+  Flash.isStreamingSrc = function (src) {
+    return Flash.RTMP_RE.test(src);
+  };
+
+  /**
+   * A source handler for RTMP urls
+   * @type {Object}
+   */
+  Flash.rtmpSourceHandler = {};
+
+  /**
+   * Check if Flash can play the given mime type.
+   *
+   * @param {string} type
+   *        The mime type to check
+   *
+   * @return {string}
+   *         'maybe', or '' (empty string)
+   */
+  Flash.rtmpSourceHandler.canPlayType = function (type) {
+    if (Flash.isStreamingType(type)) {
+      return 'maybe';
+    }
+
+    return '';
+  };
+
+  /**
+   * Check if Flash can handle the source natively
+   *
+   * @param {Object} source
+   *        The source object
+   *
+   * @param {Object} [options]
+   *        The options passed to the tech
+   *
+   * @return {string}
+   *         'maybe', or '' (empty string)
+   */
+  Flash.rtmpSourceHandler.canHandleSource = function (source, options) {
+    var can = Flash.rtmpSourceHandler.canPlayType(source.type);
+
+    if (can) {
+      return can;
+    }
+
+    if (Flash.isStreamingSrc(source.src)) {
+      return 'maybe';
+    }
+
+    return '';
+  };
+
+  /**
+   * Pass the source to the flash object.
+   *
+   * @param {Object} source
+   *        The source object
+   *
+   * @param {Flash} tech
+   *        The instance of the Flash tech
+   *
+   * @param {Object} [options]
+   *        The options to pass to the source
+   */
+  Flash.rtmpSourceHandler.handleSource = function (source, tech, options) {
+    var srcParts = Flash.streamToParts(source.src);
+
+    tech.setRtmpConnection(srcParts.connection);
+    tech.setRtmpStream(srcParts.stream);
+  };
+
+  // Register the native source handler
+  Flash.registerSourceHandler(Flash.rtmpSourceHandler);
+
+  return Flash;
+}
+
+var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+var win;
+
+if (typeof window !== "undefined") {
+    win = window;
+} else if (typeof commonjsGlobal !== "undefined") {
+    win = commonjsGlobal;
+} else if (typeof self !== "undefined"){
+    win = self;
+} else {
+    win = {};
+}
+
+var window_1 = win;
+
+var classCallCheck = function (instance, Constructor) {
+  if (!(instance instanceof Constructor)) {
+    throw new TypeError("Cannot call a class as a function");
+  }
+};
+
+var inherits = function (subClass, superClass) {
+  if (typeof superClass !== "function" && superClass !== null) {
+    throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
+  }
+
+  subClass.prototype = Object.create(superClass && superClass.prototype, {
+    constructor: {
+      value: subClass,
+      enumerable: false,
+      writable: true,
+      configurable: true
+    }
+  });
+  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
+};
+
+var possibleConstructorReturn = function (self, call) {
+  if (!self) {
+    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+  }
+
+  return call && (typeof call === "object" || typeof call === "function") ? call : self;
+};
+
+/**
+ * @file flash.js
+ * VideoJS-SWF - Custom Flash Player with HTML5-ish API
+ * https://github.com/zencoder/video-js-swf
+ * Not using setupTriggers. Using global onEvent func to distribute events
+ */
+
+var Tech = videojs.getComponent('Tech');
+var Dom = videojs.dom;
+var Url = videojs.url;
+var createTimeRange = videojs.createTimeRange;
+var mergeOptions = videojs.mergeOptions;
+
+var navigator = window_1 && window_1.navigator || {};
+
+/**
+ * Flash Media Controller - Wrapper for Flash Media API
+ *
+ * @mixes FlashRtmpDecorator
+ * @mixes Tech~SouceHandlerAdditions
+ * @extends Tech
+ */
+
+var Flash = function (_Tech) {
+  inherits(Flash, _Tech);
+
+  /**
+  * Create an instance of this Tech.
+  *
+  * @param {Object} [options]
+  *        The key/value store of player options.
+  *
+  * @param {Component~ReadyCallback} ready
+  *        Callback function to call when the `Flash` Tech is ready.
+  */
+  function Flash(options, ready) {
+    classCallCheck(this, Flash);
+
+    // Set the source when ready
+    var _this = possibleConstructorReturn(this, _Tech.call(this, options, ready));
+
+    if (options.source) {
+      _this.ready(function () {
+        this.setSource(options.source);
+      }, true);
+    }
+
+    // Having issues with Flash reloading on certain page actions
+    // (hide/resize/fullscreen) in certain browsers
+    // This allows resetting the playhead when we catch the reload
+    if (options.startTime) {
+      _this.ready(function () {
+        this.load();
+        this.play();
+        this.currentTime(options.startTime);
+      }, true);
+    }
+
+    // Add global window functions that the swf expects
+    // A 4.x workflow we weren't able to solve for in 5.0
+    // because of the need to hard code these functions
+    // into the swf for security reasons
+    window_1.videojs = window_1.videojs || {};
+    window_1.videojs.Flash = window_1.videojs.Flash || {};
+    window_1.videojs.Flash.onReady = Flash.onReady;
+    window_1.videojs.Flash.onEvent = Flash.onEvent;
+    window_1.videojs.Flash.onError = Flash.onError;
+
+    _this.on('seeked', function () {
+      this.lastSeekTarget_ = undefined;
+    });
+
+    return _this;
+  }
+
+  /**
+   * Create the `Flash` Tech's DOM element.
+   *
+   * @return {Element}
+   *         The element that gets created.
+   */
+
+
+  Flash.prototype.createEl = function createEl() {
+    var options = this.options_;
+
+    // If video.js is hosted locally you should also set the location
+    // for the hosted swf, which should be relative to the page (not video.js)
+    // Otherwise this adds a CDN url.
+    // The CDN also auto-adds a swf URL for that specific version.
+    if (!options.swf) {
+      options.swf = 'https://vjs.zencdn.net/swf/' + version + '/video-js.swf';
+    }
+
+    // Generate ID for swf object
+    var objId = options.techId;
+
+    // Merge default flashvars with ones passed in to init
+    var flashVars = mergeOptions({
+
+      // SWF Callback Functions
+      readyFunction: 'videojs.Flash.onReady',
+      eventProxyFunction: 'videojs.Flash.onEvent',
+      errorEventProxyFunction: 'videojs.Flash.onError',
+
+      // Player Settings
+      autoplay: options.autoplay,
+      preload: options.preload,
+      loop: options.loop,
+      muted: options.muted
+
+    }, options.flashVars);
+
+    // Merge default parames with ones passed in
+    var params = mergeOptions({
+      // Opaque is needed to overlay controls, but can affect playback performance
+      wmode: 'opaque',
+      // Using bgcolor prevents a white flash when the object is loading
+      bgcolor: '#000000'
+    }, options.params);
+
+    // Merge default attributes with ones passed in
+    var attributes = mergeOptions({
+      // Both ID and Name needed or swf to identify itself
+      id: objId,
+      name: objId,
+      'class': 'vjs-tech'
+    }, options.attributes);
+
+    this.el_ = Flash.embed(options.swf, flashVars, params, attributes);
+    this.el_.tech = this;
+
+    return this.el_;
+  };
+
+  /**
+   * Called by {@link Player#play} to play using the `Flash` `Tech`.
+   */
+
+
+  Flash.prototype.play = function play() {
+    if (this.ended()) {
+      this.setCurrentTime(0);
+    }
+    this.el_.vjs_play();
+  };
+
+  /**
+   * Called by {@link Player#pause} to pause using the `Flash` `Tech`.
+   */
+
+
+  Flash.prototype.pause = function pause() {
+    this.el_.vjs_pause();
+  };
+
+  /**
+   * A getter/setter for the `Flash` Tech's source object.
+   * > Note: Please use {@link Flash#setSource}
+   *
+   * @param {Tech~SourceObject} [src]
+   *        The source object you want to set on the `Flash` techs.
+   *
+   * @return {Tech~SourceObject|undefined}
+   *         - The current source object when a source is not passed in.
+   *         - undefined when setting
+   *
+   * @deprecated Since version 5.
+   */
+
+
+  Flash.prototype.src = function src(_src) {
+    if (_src === undefined) {
+      return this.currentSrc();
+    }
+
+    // Setting src through `src` not `setSrc` will be deprecated
+    return this.setSrc(_src);
+  };
+
+  /**
+   * A getter/setter for the `Flash` Tech's source object.
+   *
+   * @param {Tech~SourceObject} [src]
+   *        The source object you want to set on the `Flash` techs.
+   */
+
+
+  Flash.prototype.setSrc = function setSrc(src) {
+    var _this2 = this;
+
+    // Make sure source URL is absolute.
+    src = Url.getAbsoluteURL(src);
+    this.el_.vjs_src(src);
+
+    // Currently the SWF doesn't autoplay if you load a source later.
+    // e.g. Load player w/ no source, wait 2s, set src.
+    if (this.autoplay()) {
+      this.setTimeout(function () {
+        return _this2.play();
+      }, 0);
+    }
+  };
+
+  /**
+   * Indicates whether the media is currently seeking to a new position or not.
+   *
+   * @return {boolean}
+   *         - True if seeking to a new position
+   *         - False otherwise
+   */
+
+
+  Flash.prototype.seeking = function seeking() {
+    return this.lastSeekTarget_ !== undefined;
+  };
+
+  /**
+   * Returns the current time in seconds that the media is at in playback.
+   *
+   * @param {number} time
+   *        Current playtime of the media in seconds.
+   */
+
+
+  Flash.prototype.setCurrentTime = function setCurrentTime(time) {
+    var seekable = this.seekable();
+
+    if (seekable.length) {
+      // clamp to the current seekable range
+      time = time > seekable.start(0) ? time : seekable.start(0);
+      time = time < seekable.end(seekable.length - 1) ? time : seekable.end(seekable.length - 1);
+
+      this.lastSeekTarget_ = time;
+      this.trigger('seeking');
+      this.el_.vjs_setProperty('currentTime', time);
+      _Tech.prototype.setCurrentTime.call(this);
+    }
+  };
+
+  /**
+   * Get the current playback time in seconds
+   *
+   * @return {number}
+   *         The current time of playback in seconds.
+   */
+
+
+  Flash.prototype.currentTime = function currentTime() {
+    // when seeking make the reported time keep up with the requested time
+    // by reading the time we're seeking to
+    if (this.seeking()) {
+      return this.lastSeekTarget_ || 0;
+    }
+    return this.el_.vjs_getProperty('currentTime');
+  };
+
+  /**
+   * Get the current source
+   *
+   * @method currentSrc
+   * @return {Tech~SourceObject}
+   *         The current source
+   */
+
+
+  Flash.prototype.currentSrc = function currentSrc() {
+    if (this.currentSource_) {
+      return this.currentSource_.src;
+    }
+    return this.el_.vjs_getProperty('currentSrc');
+  };
+
+  /**
+   * Get the total duration of the current media.
+   *
+   * @return {number}
+   8          The total duration of the current media.
+   */
+
+
+  Flash.prototype.duration = function duration() {
+    if (this.readyState() === 0) {
+      return NaN;
+    }
+    var duration = this.el_.vjs_getProperty('duration');
+
+    return duration >= 0 ? duration : Infinity;
+  };
+
+  /**
+   * Load media into Tech.
+   */
+
+
+  Flash.prototype.load = function load() {
+    this.el_.vjs_load();
+  };
+
+  /**
+   * Get the poster image that was set on the tech.
+   */
+
+
+  Flash.prototype.poster = function poster() {
+    this.el_.vjs_getProperty('poster');
+  };
+
+  /**
+   * Poster images are not handled by the Flash tech so make this is a no-op.
+   */
+
+
+  Flash.prototype.setPoster = function setPoster() {};
+
+  /**
+   * Determine the time ranges that can be seeked to in the media.
+   *
+   * @return {TimeRange}
+   *         Returns the time ranges that can be seeked to.
+   */
+
+
+  Flash.prototype.seekable = function seekable() {
+    var duration = this.duration();
+
+    if (duration === 0) {
+      return createTimeRange();
+    }
+    return createTimeRange(0, duration);
+  };
+
+  /**
+   * Get and create a `TimeRange` object for buffering.
+   *
+   * @return {TimeRange}
+   *         The time range object that was created.
+   */
+
+
+  Flash.prototype.buffered = function buffered() {
+    var ranges = this.el_.vjs_getProperty('buffered');
+
+    if (ranges.length === 0) {
+      return createTimeRange();
+    }
+    return createTimeRange(ranges[0][0], ranges[0][1]);
+  };
+
+  /**
+   * Get fullscreen support -
+   *
+   * Flash does not allow fullscreen through javascript
+   * so this always returns false.
+   *
+   * @return {boolean}
+   *         The Flash tech does not support fullscreen, so it will always return false.
+   */
+
+
+  Flash.prototype.supportsFullScreen = function supportsFullScreen() {
+    // Flash does not allow fullscreen through javascript
+    return false;
+  };
+
+  /**
+   * Flash does not allow fullscreen through javascript
+   * so this always returns false.
+   *
+   * @return {boolean}
+   *         The Flash tech does not support fullscreen, so it will always return false.
+   */
+
+
+  Flash.prototype.enterFullScreen = function enterFullScreen() {
+    return false;
+  };
+
+  /**
+   * Gets available media playback quality metrics as specified by the W3C's Media
+   * Playback Quality API.
+   *
+   * @see [Spec]{@link https://wicg.github.io/media-playback-quality}
+   *
+   * @return {Object}
+   *         An object with supported media playback quality metrics
+   */
+
+
+  Flash.prototype.getVideoPlaybackQuality = function getVideoPlaybackQuality() {
+    var videoPlaybackQuality = this.el_.vjs_getProperty('getVideoPlaybackQuality');
+
+    if (window_1.performance && typeof window_1.performance.now === 'function') {
+      videoPlaybackQuality.creationTime = window_1.performance.now();
+    } else if (window_1.performance && window_1.performance.timing && typeof window_1.performance.timing.navigationStart === 'number') {
+      videoPlaybackQuality.creationTime = window_1.Date.now() - window_1.performance.timing.navigationStart;
+    }
+
+    return videoPlaybackQuality;
+  };
+
+  return Flash;
+}(Tech);
+
+// Create setters and getters for attributes
+
+
+var _readWrite = ['rtmpConnection', 'rtmpStream', 'preload', 'defaultPlaybackRate', 'playbackRate', 'autoplay', 'loop', 'controls', 'volume', 'muted', 'defaultMuted'];
+var _readOnly = ['networkState', 'readyState', 'initialTime', 'startOffsetTime', 'paused', 'ended', 'videoWidth', 'videoHeight'];
+var _api = Flash.prototype;
+
+/**
+ * Create setters for the swf on the element
+ *
+ * @param {string} attr
+ *        The name of the parameter
+ *
+ * @private
+ */
+function _createSetter(attr) {
+  var attrUpper = attr.charAt(0).toUpperCase() + attr.slice(1);
+
+  _api['set' + attrUpper] = function (val) {
+    return this.el_.vjs_setProperty(attr, val);
+  };
+}
+
+/**
+ * Create getters for the swf on the element
+ *
+ * @param {string} attr
+ *        The name of the parameter
+ *
+ * @private
+ */
+function _createGetter(attr) {
+  _api[attr] = function () {
+    return this.el_.vjs_getProperty(attr);
+  };
+}
+
+// Create getter and setters for all read/write attributes
+for (var i = 0; i < _readWrite.length; i++) {
+  _createGetter(_readWrite[i]);
+  _createSetter(_readWrite[i]);
+}
+
+// Create getters for read-only attributes
+for (var _i = 0; _i < _readOnly.length; _i++) {
+  _createGetter(_readOnly[_i]);
+}
+
+/** ------------------------------ Getters ------------------------------ **/
+/**
+ * Get the value of `rtmpConnection` from the swf.
+ *
+ * @method Flash#rtmpConnection
+ * @return {string}
+ *         The current value of `rtmpConnection` on the swf.
+ */
+
+/**
+ * Get the value of `rtmpStream` from the swf.
+ *
+ * @method Flash#rtmpStream
+ * @return {string}
+ *         The current value of `rtmpStream` on the swf.
+ */
+
+/**
+ * Get the value of `preload` from the swf. `preload` indicates
+ * what should download before the media is interacted with. It can have the following
+ * values:
+ * - none: nothing should be downloaded
+ * - metadata: poster and the first few frames of the media may be downloaded to get
+ *   media dimensions and other metadata
+ * - auto: allow the media and metadata for the media to be downloaded before
+ *    interaction
+ *
+ * @method Flash#preload
+ * @return {string}
+ *         The value of `preload` from the swf. Will be 'none', 'metadata',
+ *         or 'auto'.
+ */
+
+/**
+ * Get the value of `defaultPlaybackRate` from the swf.
+ *
+ * @method Flash#defaultPlaybackRate
+ * @return {number}
+ *         The current value of `defaultPlaybackRate` on the swf.
+ */
+
+/**
+ * Get the value of `playbackRate` from the swf. `playbackRate` indicates
+ * the rate at which the media is currently playing back. Examples:
+ *   - if playbackRate is set to 2, media will play twice as fast.
+ *   - if playbackRate is set to 0.5, media will play half as fast.
+ *
+ * @method Flash#playbackRate
+ * @return {number}
+ *         The value of `playbackRate` from the swf. A number indicating
+ *         the current playback speed of the media, where 1 is normal speed.
+ */
+
+/**
+ * Get the value of `autoplay` from the swf. `autoplay` indicates
+ * that the media should start to play as soon as the page is ready.
+ *
+ * @method Flash#autoplay
+ * @return {boolean}
+ *         - The value of `autoplay` from the swf.
+ *         - True indicates that the media ashould start as soon as the page loads.
+ *         - False indicates that the media should not start as soon as the page loads.
+ */
+
+/**
+ * Get the value of `loop` from the swf. `loop` indicates
+ * that the media should return to the start of the media and continue playing once
+ * it reaches the end.
+ *
+ * @method Flash#loop
+ * @return {boolean}
+ *         - The value of `loop` from the swf.
+ *         - True indicates that playback should seek back to start once
+ *           the end of a media is reached.
+ *         - False indicates that playback should not loop back to the start when the
+ *           end of the media is reached.
+ */
+
+/**
+ * Get the value of `mediaGroup` from the swf.
+ *
+ * @method Flash#mediaGroup
+ * @return {string}
+ *         The current value of `mediaGroup` on the swf.
+ */
+
+/**
+ * Get the value of `controller` from the swf.
+ *
+ * @method Flash#controller
+ * @return {string}
+ *         The current value of `controller` on the swf.
+ */
+
+/**
+ * Get the value of `controls` from the swf. `controls` indicates
+ * whether the native flash controls should be shown or hidden.
+ *
+ * @method Flash#controls
+ * @return {boolean}
+ *         - The value of `controls` from the swf.
+ *         - True indicates that native controls should be showing.
+ *         - False indicates that native controls should be hidden.
+ */
+
+/**
+ * Get the value of the `volume` from the swf. `volume` indicates the current
+ * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and
+ * so on.
+ *
+ * @method Flash#volume
+ * @return {number}
+ *         The volume percent as a decimal. Value will be between 0-1.
+ */
+
+/**
+ * Get the value of the `muted` from the swf. `muted` indicates the current
+ * audio level should be silent.
+ *
+ * @method Flash#muted
+ * @return {boolean}
+ *         - True if the audio should be set to silent
+ *         - False otherwise
+ */
+
+/**
+ * Get the value of `defaultMuted` from the swf. `defaultMuted` indicates
+ * whether the media should start muted or not. Only changes the default state of the
+ * media. `muted` and `defaultMuted` can have different values. `muted` indicates the
+ * current state.
+ *
+ * @method Flash#defaultMuted
+ * @return {boolean}
+ *         - The value of `defaultMuted` from the swf.
+ *         - True indicates that the media should start muted.
+ *         - False indicates that the media should not start muted.
+ */
+
+/**
+ * Get the value of `networkState` from the swf. `networkState` indicates
+ * the current network state. It returns an enumeration from the following list:
+ * - 0: NETWORK_EMPTY
+ * - 1: NEWORK_IDLE
+ * - 2: NETWORK_LOADING
+ * - 3: NETWORK_NO_SOURCE
+ *
+ * @method Flash#networkState
+ * @return {number}
+ *         The value of `networkState` from the swf. This will be a number
+ *         from the list in the description.
+ */
+
+/**
+ * Get the value of `readyState` from the swf. `readyState` indicates
+ * the current state of the media element. It returns an enumeration from the
+ * following list:
+ * - 0: HAVE_NOTHING
+ * - 1: HAVE_METADATA
+ * - 2: HAVE_CURRENT_DATA
+ * - 3: HAVE_FUTURE_DATA
+ * - 4: HAVE_ENOUGH_DATA
+ *
+ * @method Flash#readyState
+ * @return {number}
+ *         The value of `readyState` from the swf. This will be a number
+ *         from the list in the description.
+ */
+
+/**
+ * Get the value of `readyState` from the swf. `readyState` indicates
+ * the current state of the media element. It returns an enumeration from the
+ * following list:
+ * - 0: HAVE_NOTHING
+ * - 1: HAVE_METADATA
+ * - 2: HAVE_CURRENT_DATA
+ * - 3: HAVE_FUTURE_DATA
+ * - 4: HAVE_ENOUGH_DATA
+ *
+ * @method Flash#readyState
+ * @return {number}
+ *         The value of `readyState` from the swf. This will be a number
+ *         from the list in the description.
+ */
+
+/**
+ * Get the value of `initialTime` from the swf.
+ *
+ * @method Flash#initialTime
+ * @return {number}
+ *         The `initialTime` proprety on the swf.
+ */
+
+/**
+ * Get the value of `startOffsetTime` from the swf.
+ *
+ * @method Flash#startOffsetTime
+ * @return {number}
+ *         The `startOffsetTime` proprety on the swf.
+ */
+
+/**
+ * Get the value of `paused` from the swf. `paused` indicates whether the swf
+ * is current paused or not.
+ *
+ * @method Flash#paused
+ * @return {boolean}
+ *         The value of `paused` from the swf.
+ */
+
+/**
+ * Get the value of `ended` from the swf. `ended` indicates whether
+ * the media has reached the end or not.
+ *
+ * @method Flash#ended
+ * @return {boolean}
+ *         - True indicates that the media has ended.
+ *         - False indicates that the media has not ended.
+ *
+ * @see [Spec]{@link https://www.w3.org/TR/html5/embedded-content-0.html#dom-media-ended}
+ */
+
+/**
+ * Get the value of `videoWidth` from the swf. `videoWidth` indicates
+ * the current width of the media in css pixels.
+ *
+ * @method Flash#videoWidth
+ * @return {number}
+ *         The value of `videoWidth` from the swf. This will be a number
+ *         in css pixels.
+ */
+
+/**
+ * Get the value of `videoHeight` from the swf. `videoHeigth` indicates
+ * the current height of the media in css pixels.
+ *
+ * @method Flassh.prototype.videoHeight
+ * @return {number}
+ *         The value of `videoHeight` from the swf. This will be a number
+ *         in css pixels.
+ */
+/** ------------------------------ Setters ------------------------------ **/
+
+/**
+ * Set the value of `rtmpConnection` on the swf.
+ *
+ * @method Flash#setRtmpConnection
+ * @param {string} rtmpConnection
+ *        New value to set the `rtmpConnection` property to.
+ */
+
+/**
+ * Set the value of `rtmpStream` on the swf.
+ *
+ * @method Flash#setRtmpStream
+ * @param {string} rtmpStream
+ *        New value to set the `rtmpStream` property to.
+ */
+
+/**
+ * Set the value of `preload` on the swf. `preload` indicates
+ * what should download before the media is interacted with. It can have the following
+ * values:
+ * - none: nothing should be downloaded
+ * - metadata: poster and the first few frames of the media may be downloaded to get
+ *   media dimensions and other metadata
+ * - auto: allow the media and metadata for the media to be downloaded before
+ *    interaction
+ *
+ * @method Flash#setPreload
+ * @param {string} preload
+ *        The value of `preload` to set on the swf. Should be 'none', 'metadata',
+ *        or 'auto'.
+ */
+
+/**
+ * Set the value of `defaultPlaybackRate` on the swf.
+ *
+ * @method Flash#setDefaultPlaybackRate
+ * @param {number} defaultPlaybackRate
+ *        New value to set the `defaultPlaybackRate` property to.
+ */
+
+/**
+ * Set the value of `playbackRate` on the swf. `playbackRate` indicates
+ * the rate at which the media is currently playing back. Examples:
+ *   - if playbackRate is set to 2, media will play twice as fast.
+ *   - if playbackRate is set to 0.5, media will play half as fast.
+ *
+ * @method Flash#setPlaybackRate
+ * @param {number} playbackRate
+ *        New value of `playbackRate` on the swf. A number indicating
+ *        the current playback speed of the media, where 1 is normal speed.
+ */
+
+/**
+ * Set the value of `autoplay` on the swf. `autoplay` indicates
+ * that the media should start to play as soon as the page is ready.
+ *
+ * @method Flash#setAutoplay
+ * @param {boolean} autoplay
+ *        - The value of `autoplay` from the swf.
+ *        - True indicates that the media ashould start as soon as the page loads.
+ *        - False indicates that the media should not start as soon as the page loads.
+ */
+
+/**
+ * Set the value of `loop` on the swf. `loop` indicates
+ * that the media should return to the start of the media and continue playing once
+ * it reaches the end.
+ *
+ * @method Flash#setLoop
+ * @param {boolean} loop
+ *        - True indicates that playback should seek back to start once
+ *          the end of a media is reached.
+ *        - False indicates that playback should not loop back to the start when the
+ *          end of the media is reached.
+ */
+
+/**
+ * Set the value of `mediaGroup` on the swf.
+ *
+ * @method Flash#setMediaGroup
+ * @param {string} mediaGroup
+ *        New value of `mediaGroup` to set on the swf.
+ */
+
+/**
+ * Set the value of `controller` on the swf.
+ *
+ * @method Flash#setController
+ * @param {string} controller
+ *        New value the current value of `controller` on the swf.
+ */
+
+/**
+ * Get the value of `controls` from the swf. `controls` indicates
+ * whether the native flash controls should be shown or hidden.
+ *
+ * @method Flash#controls
+ * @return {boolean}
+ *         - The value of `controls` from the swf.
+ *         - True indicates that native controls should be showing.
+ *         - False indicates that native controls should be hidden.
+ */
+
+/**
+ * Set the value of the `volume` on the swf. `volume` indicates the current
+ * audio level as a percentage in decimal form. This means that 1 is 100%, 0.5 is 50%, and
+ * so on.
+ *
+ * @method Flash#setVolume
+ * @param {number} percentAsDecimal
+ *         The volume percent as a decimal. Value will be between 0-1.
+ */
+
+/**
+ * Set the value of the `muted` on the swf. `muted` indicates that the current
+ * audio level should be silent.
+ *
+ * @method Flash#setMuted
+ * @param {boolean} muted
+ *         - True if the audio should be set to silent
+ *         - False otherwise
+ */
+
+/**
+ * Set the value of `defaultMuted` on the swf. `defaultMuted` indicates
+ * whether the media should start muted or not. Only changes the default state of the
+ * media. `muted` and `defaultMuted` can have different values. `muted` indicates the
+ * current state.
+ *
+ * @method Flash#setDefaultMuted
+ * @param {boolean} defaultMuted
+ *         - True indicates that the media should start muted.
+ *         - False indicates that the media should not start muted.
+ */
+
+/* Flash Support Testing -------------------------------------------------------- */
+
+/**
+ * Check if the Flash tech is currently supported.
+ *
+ * @return {boolean}
+ *          - True for Chrome and Safari Desktop and Microsoft Edge and if flash tech is supported
+ *          - False otherwise
+ */
+Flash.isSupported = function () {
+  // for Chrome Desktop and Safari Desktop
+  if (videojs.browser.IS_CHROME && (!videojs.browser.IS_ANDROID || !videojs.browser.IS_IOS) || videojs.browser.IS_SAFARI && !videojs.browser.IS_IOS || videojs.browser.IS_EDGE) {
+    return true;
+  }
+  // for other browsers
+  return Flash.version()[0] >= 10;
+};
+
+// Add Source Handler pattern functions to this tech
+Tech.withSourceHandlers(Flash);
+
+/*
+ * Native source handler for flash,  simply passes the source to the swf element.
+ *
+ * @property {Tech~SourceObject} source
+ *           The source object
+ *
+ * @property {Flash} tech
+ *           The instance of the Flash tech
+ */
+Flash.nativeSourceHandler = {};
+
+/**
+ * Check if the Flash can play the given mime type.
+ *
+ * @param {string} type
+ *        The mimetype to check
+ *
+ * @return {string}
+ *         'maybe', or '' (empty string)
+ */
+Flash.nativeSourceHandler.canPlayType = function (type) {
+  if (type in Flash.formats) {
+    return 'maybe';
+  }
+
+  return '';
+};
+
+/**
+ * Check if the media element can handle a source natively.
+ *
+ * @param {Tech~SourceObject} source
+ *         The source object
+ *
+ * @param {Object} [options]
+ *         Options to be passed to the tech.
+ *
+ * @return {string}
+ *         'maybe', or '' (empty string).
+ */
+Flash.nativeSourceHandler.canHandleSource = function (source, options) {
+  var type = void 0;
+
+  /**
+   * Guess the mime type of a file if it does not have one
+   *
+   * @param {Tech~SourceObject} src
+   *        The source object to guess the mime type for
+   *
+   * @return {string}
+   *         The mime type that was guessed
+   */
+  function guessMimeType(src) {
+    var ext = Url.getFileExtension(src);
+
+    if (ext) {
+      return 'video/' + ext;
+    }
+    return '';
+  }
+
+  if (!source.type) {
+    type = guessMimeType(source.src);
+  } else {
+    // Strip code information from the type because we don't get that specific
+    type = source.type.replace(/;.*/, '').toLowerCase();
+  }
+
+  return Flash.nativeSourceHandler.canPlayType(type);
+};
+
+/**
+ * Pass the source to the swf.
+ *
+ * @param {Tech~SourceObject} source
+ *        The source object
+ *
+ * @param {Flash} tech
+ *        The instance of the Flash tech
+ *
+ * @param {Object} [options]
+ *        The options to pass to the source
+ */
+Flash.nativeSourceHandler.handleSource = function (source, tech, options) {
+  tech.setSrc(source.src);
+};
+
+/**
+ * noop for native source handler dispose, as cleanup will happen automatically.
+ */
+Flash.nativeSourceHandler.dispose = function () {};
+
+// Register the native source handler
+Flash.registerSourceHandler(Flash.nativeSourceHandler);
+
+/**
+ * Flash supported mime types.
+ *
+ * @constant {Object}
+ */
+Flash.formats = {
+  'video/flv': 'FLV',
+  'video/x-flv': 'FLV',
+  'video/mp4': 'MP4',
+  'video/m4v': 'MP4'
+};
+
+/**
+ * Called when the the swf is "ready", and makes sure that the swf is really
+ * ready using {@link Flash#checkReady}
+ *
+ * @param {Object} currSwf
+ *        The current swf object
+ */
+Flash.onReady = function (currSwf) {
+  var el = Dom.$('#' + currSwf);
+  var tech = el && el.tech;
+
+  // if there is no el then the tech has been disposed
+  // and the tech element was removed from the player div
+  if (tech && tech.el()) {
+    // check that the flash object is really ready
+    Flash.checkReady(tech);
+  }
+};
+
+/**
+ * The SWF isn't always ready when it says it is. Sometimes the API functions still
+ * need to be added to the object. If it's not ready, we set a timeout to check again
+ * shortly.
+ *
+ * @param {Flash} tech
+ *        The instance of the flash tech to check.
+ */
+Flash.checkReady = function (tech) {
+  // stop worrying if the tech has been disposed
+  if (!tech.el()) {
+    return;
+  }
+
+  // check if API property exists
+  if (tech.el().vjs_getProperty) {
+    // tell tech it's ready
+    tech.triggerReady();
+  } else {
+    // wait longer
+    this.setTimeout(function () {
+      Flash.checkReady(tech);
+    }, 50);
+  }
+};
+
+/**
+ * Trigger events from the swf on the Flash Tech.
+ *
+ * @param {number} swfID
+ *        The id of the swf that had the event
+ *
+ * @param {string} eventName
+ *        The name of the event to trigger
+ */
+Flash.onEvent = function (swfID, eventName) {
+  var tech = Dom.$('#' + swfID).tech;
+  var args = Array.prototype.slice.call(arguments, 2);
+
+  // dispatch Flash events asynchronously for two reasons:
+  // - Flash swallows any exceptions generated by javascript it
+  //   invokes
+  // - Flash is suspended until the javascript returns which may cause
+  //   playback performance issues
+  tech.setTimeout(function () {
+    tech.trigger(eventName, args);
+  }, 1);
+};
+
+/**
+ * Log errors from the swf on the Flash tech.
+ *
+ * @param {number} swfID
+ *        The id of the swf that had an error.
+ *
+ * @param {string} err
+ *        The error to set on the Flash Tech.
+ *
+ * @return {MediaError|undefined}
+ *          - Returns a MediaError when err is 'srcnotfound'
+ *          - Returns undefined otherwise.
+ */
+Flash.onError = function (swfID, err) {
+  var tech = Dom.$('#' + swfID).tech;
+
+  // trigger MEDIA_ERR_SRC_NOT_SUPPORTED
+  if (err === 'srcnotfound') {
+    return tech.error(4);
+  }
+
+  // trigger a custom error
+  if (typeof err === 'string') {
+    tech.error('FLASH: ' + err);
+  } else {
+    err.origin = 'flash';
+    tech.error(err);
+  }
+};
+
+/**
+ * Get the current version of Flash that is in use on the page.
+ *
+ * @return {Array}
+ *          an array of versions that are available.
+ */
+Flash.version = function () {
+  var version$$1 = '0,0,0';
+
+  // IE
+  try {
+    version$$1 = new window_1.ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version').replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
+
+    // other browsers
+  } catch (e) {
+    try {
+      if (navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) {
+        version$$1 = (navigator.plugins['Shockwave Flash 2.0'] || navigator.plugins['Shockwave Flash']).description.replace(/\D+/g, ',').match(/^,?(.+),?$/)[1];
+      }
+    } catch (err) {
+      // satisfy linter
+    }
+  }
+  return version$$1.split(',');
+};
+
+/**
+ * Only use for non-iframe embeds.
+ *
+ * @param {Object} swf
+ *        The videojs-swf object.
+ *
+ * @param {Object} flashVars
+ *        Names and values to use as flash option variables.
+ *
+ * @param {Object} params
+ *        Style parameters to set on the object.
+ *
+ * @param {Object} attributes
+ *        Attributes to set on the element.
+ *
+ * @return {Element}
+ *          The embeded Flash DOM element.
+ */
+Flash.embed = function (swf, flashVars, params, attributes) {
+  var code = Flash.getEmbedCode(swf, flashVars, params, attributes);
+
+  // Get element by embedding code and retrieving created element
+  var obj = Dom.createEl('div', { innerHTML: code }).childNodes[0];
+
+  return obj;
+};
+
+/**
+ * Only use for non-iframe embeds.
+ *
+ * @param {Object} swf
+ *        The videojs-swf object.
+ *
+ * @param {Object} flashVars
+ *        Names and values to use as flash option variables.
+ *
+ * @param {Object} params
+ *        Style parameters to set on the object.
+ *
+ * @param {Object} attributes
+ *        Attributes to set on the element.
+ *
+ * @return {Element}
+ *          The embeded Flash DOM element.
+ */
+Flash.getEmbedCode = function (swf, flashVars, params, attributes) {
+  var objTag = '<object type="application/x-shockwave-flash" ';
+  var flashVarsString = '';
+  var paramsString = '';
+  var attrsString = '';
+
+  // Convert flash vars to string
+  if (flashVars) {
+    Object.getOwnPropertyNames(flashVars).forEach(function (key) {
+      flashVarsString += key + '=' + flashVars[key] + '&amp;';
+    });
+  }
+
+  // Add swf, flashVars, and other default params
+  params = mergeOptions({
+    movie: swf,
+    flashvars: flashVarsString,
+    // Required to talk to swf
+    allowScriptAccess: 'always',
+    // All should be default, but having security issues.
+    allowNetworking: 'all'
+  }, params);
+
+  // Create param tags string
+  Object.getOwnPropertyNames(params).forEach(function (key) {
+    paramsString += '<param name="' + key + '" value="' + params[key] + '" />';
+  });
+
+  attributes = mergeOptions({
+    // Add swf to attributes (need both for IE and Others to work)
+    data: swf,
+
+    // Default to 100% width/height
+    width: '100%',
+    height: '100%'
+
+  }, attributes);
+
+  // Create Attributes string
+  Object.getOwnPropertyNames(attributes).forEach(function (key) {
+    attrsString += key + '="' + attributes[key] + '" ';
+  });
+
+  return '' + objTag + attrsString + '>' + paramsString + '</object>';
+};
+
+// Run Flash through the RTMP decorator
+FlashRtmpDecorator(Flash);
+
+if (Tech.getTech('Flash')) {
+  videojs.log.warn('Not using videojs-flash as it appears to already be registered');
+  videojs.log.warn('videojs-flash should only be used with video.js@6 and above');
+} else {
+  videojs.registerTech('Flash', Flash);
+}
+
+Flash.VERSION = version$1;
+
+return Flash;
+
+})));

+ 369 - 0
public/static/workerManager.js

@@ -0,0 +1,369 @@
+var WorkerManager = function () {
+    function a() {
+        O = !0, o = this
+    }
+
+    function b() {
+        return X
+    }
+
+    function c() {
+        null !== z && z(!1)
+    }
+
+    function d(b) {
+        var c = b.data;
+        switch (c.type) {
+            case"WorkerReady":
+                yb && yb();
+                break;
+            case"canvasRender":
+                k(0, "currentTime"), i(c.data), ub++, 0 === tb && (tb = performance.now());
+                break;
+            case"initSegment":
+                X = c.data, j();
+                break;
+            case"mediaSample":
+                null === Z.samples && (Z.samples = new Array(jb)), null === c.data.frame_time_stamp && (c.data.frameDuration = Math.round(pb / L)), 1 !== ib && (c.data.frameDuration = pb / Math.abs(ib)), Z.samples[$++] = c.data, nb += c.data.frameDuration, ob += c.data.frameDuration, kb = jb;
+                break;
+            case"videoRender":
+                var d = new Uint8Array(c.data.length + _);
+                if (0 !== _ && d.set(ab), d.set(c.data, _), ab = d, _ = ab.length, $ % jb === 0 && 0 !== $) {
+                    if (null !== Z.samples[0].frameDuration ? (Z.baseMediaDecodeTime = 1 === bb ? 0 : mb, mb = nb) : Z.baseMediaDecodeTime = Math.round(pb / L) * jb * (bb - 1), "chrome" == I && 1 === ib) for (var e = Z.samples.length, f = ob / jb, g = 0; e > g; g++) Z.samples[g].frameDuration = f;
+                    ob = 0, Y = mp4Remux.mediaSegment(bb, Z, ab, Z.baseMediaDecodeTime), bb++, $ = 0, ab = null, _ = 0, null !== W ? W.setMediaSegment(Y) : lb === !1 && (debug.log("workerManager::videoMS error!! recreate videoMS"), j()), null !== p && p.stopRendering()
+                }
+                break;
+            case"mediasegmentData":
+                W.setMediaSegment(c.data), lb === !1 && (debug.log("videoMS error!! recreate videoMS"), j());
+                break;
+            case"videoInfo":
+                J = c.data;
+                break;
+            case"time":
+                break;
+            case"videoTimeStamp":
+                if (eb = c.data, null !== W && null !== eb && (W.setvideoTimeStamp(eb), W.getNoWaitFlag() && (W.getDuration() || 0 === W.getDuration()))) {
+                    var h = eb.timestamp - parseInt(W.getDuration());
+                    C({timestamp: h})
+                }
+                break;
+            case"firstFrame":
+                p.startRendering(), "undefined" != typeof p.setFPS && p.setFPS(L);
+                break;
+            case"drop":
+                break;
+            case"codecInfo":
+                cb = c.data, null !== W && W.setCodecInfo(cb);
+                break;
+            case"stepPlay":
+                switch (c.data) {
+                    case"needBuffering":
+                        R = !0, w("request", T);
+                        break;
+                    case"BufferFull":
+                        if (R = !1, w("complete"), Bb) {
+                            var m = {type: "stepPlay", data: "findIFrame"};
+                            l.postMessage(m), p.startRendering(), Bb = !1
+                        }
+                }
+                break;
+            case"setVideoTagMode":
+                a.prototype.setLiveMode(c.data);
+                break;
+            case"playbackFlag":
+                Ab.type = c.data === !0 ? "playback" : "live", null !== W && W.setPlaybackFlag(c.data);
+                break;
+            case"error":
+                null !== A && A(c.data);
+                break;
+            case"MSEResolutionChanged":
+                E(c.data);
+                break;
+            case"DecodeStart":
+                var n = c.data.width - 0, o = c.data.height - 0;
+                S.setAttribute("width", n), S.setAttribute("height", o), a.prototype.setLiveMode(c.data.decodeMode), B(c.data);
+                break;
+            case"ivsDraw":
+                var q = c.data.ivsDraw, r = "canvas" === P ? J.timeStamp : eb;
+                r = 1e3 * r.timestamp + r.timestamp_usec;
+                var s = "canvas" === P ? r : r - parseInt(1e3 * W.getDuration());
+                null !== G && (H.setCallback(G), H.draw(q, s, r));
+                break;
+            default:
+                debug.log("workerManager::videoWorker unknown data = " + c.data)
+        }
+    }
+
+    function e(a) {
+        var b = a.data;
+        switch (b.type) {
+            case"render":
+                if (V === !0) break;
+                qb !== b.codec && (null !== q && (rb = q.getVolume(), sb = q.getInitVideoTimeStamp(), q.terminate()), "AAC" === b.codec ? "edge" === I || "firefox" === I ? (q = null, null !== A && A({errorCode: 201})) : q = new AudioPlayerAAC : (q = new AudioPlayerGxx, q.setSamplingRate(b.samplingRate)), null !== q && (q.setInitVideoTimeStamp(sb), q.audioInit(rb) || (q = null)), qb = b.codec), null !== q && (null === J || "undefined" == typeof J ? q.bufferAudio(b.data, b.rtpTimeStamp, null) : q.bufferAudio(b.data, b.rtpTimeStamp, J.codecType))
+        }
+    }
+
+    function f(a) {
+        var b = a.data;
+        switch (b.type) {
+            case"rtpData":
+                v(b.data)
+        }
+    }
+
+    function g(a) {
+        var b = {type: "getRtpData", data: a};
+        n.postMessage(b)
+    }
+
+    function h(a) {
+        null !== W && (W.close(), W = null), jb = a === !1 ? hb : Math.abs(ib), Z.samples = new Array(jb), lb = !1, bb = 1, Y = null, $ = 0, ab = null, _ = 0
+    }
+
+    function i(a) {
+        null !== a && null !== p && ("mjpeg" === J.codecType ? p.drawMJPEG(a, J.width, J.height, J.codecType, J.frameType, J.timeStamp) : p.draw(a, J.width, J.height, J.codecType, J.frameType, J.timeStamp))
+    }
+
+    function j() {
+        lb = !0, null === W ? (W = VideoMediaSource(o), W.setCodecInfo(cb), W.setInitSegmentFunc(b), W.setVideoSizeCallback(c), W.setBeginDrawCallback(t), W.init(db), W.setSpeedPlay(ib)) : (W.getVideoElement(), W.setInitSegment()), W.setAudioStartCallback(k)
+    }
+
+    function k(a, b) {
+        null !== q && q.setBufferingFlag(a, b)
+    }
+
+    var l = null, m = null, n = null, o = null, p = null, q = null, r = null, s = null, t = null, u = null, v = null,
+        w = null, x = null, y = null, z = null, A = null, B = null, C = null, D = null, E = null, F = null, G = null,
+        H = null, I = BrowserDetect(), J = null, K = null, L = 0, M = null, N = !1, O = !0, P = "", Q = !0, R = !1,
+        S = null, T = null, U = null, V = !1, W = null, X = null, Y = null,
+        Z = {id: 1, samples: null, baseMediaDecodeTime: 0}, $ = 0, _ = 0, ab = null, bb = 1, cb = "", db = null,
+        eb = null, fb = 2, gb = 4, hb = "chrome" !== I ? gb : fb, ib = 1, jb = hb, kb = jb, lb = !1, mb = 0, nb = 0,
+        ob = 0, pb = 1e3, qb = null, rb = 0, sb = 0, tb = 0, ub = 0, vb = 1e3, wb = null, xb = null, yb = null, zb = 0,
+        Ab = {type: "live", codec: "", width: 0, height: 0, isLimitSpeed: null}, Bb = !1, Cb = null, Db = null,
+        Eb = null, Fb = {5: "MJPEG", 8: "H264", 12: "H265"}, Gb = {
+            1: 4e3,
+            2: 8e3,
+            3: 11025,
+            4: 16e3,
+            5: 2e4,
+            6: 22050,
+            7: 32e3,
+            8: 44100,
+            9: 48e3,
+            10: 96e3,
+            11: 128e3,
+            12: 192e3,
+            13: 64e3
+        };
+    a.prototype = {
+        init: function (a, b) {
+            zb = 0, S = a, db = b;
+            window.navigator.userAgent;
+            l = new Worker("./static/videoWorker.js"), m = new Worker("./static/audioWorker.js"), l.onmessage = d, m.onmessage = e, p = new StreamDrawer(zb, this, S), H = IvsDraw(), p.setResizeCallback(s), xb = document.getElementById("count-fps"), wb = document.getElementById("span-fps")
+        }, sendSdpInfo: function (a, b, c) {
+            var d = {type: "sdpInfo", data: {sdpInfo: a, aacCodecInfo: b, decodeMode: P, govLength: M, checkDelay: Q}};
+            if (N = c, l.postMessage(d), m.postMessage(d), N) try {
+                window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext, n = new Worker("./media/ump/Workers/audioTalkWorker.js"), n.onmessage = f, null === r && (r = new Talk, r.init(), r.setSendAudioTalkBufferCallback(g));
+                var e = r.initAudioOut();
+                n.postMessage(d), d = {type: "sampleRate", data: e}, n.postMessage(d)
+            } catch (h) {
+                return N = !1, void debug.error("Web Audio API is not supported in this web browser! : " + h)
+            }
+            qb = null, lb = !1, K = a
+        }, parseRTPData: function (a, b) {
+            function c() {
+                for (var a = b[22] + 24, c = 24; a > c;) if (g == b[c]) {
+                    if (c + 4 > a) return debug.log("i: " + c), -1;
+                    M.width = b[c + 2] << 3, M.height = b[c + 3] << 3, c += 4
+                } else if (h == b[c]) {
+                    if (c + 4 > b.length) return debug.log("i: " + c), -1;
+                    M.I_frame_interval = b[c + 1], M.encode_type = b[c + 2], M.frame_rate = b[c + 3], c += 4
+                } else if (i == b[c]) M.width = (b[c + 5] << 8) + b[c + 4], M.height = (b[c + 7] << 8) + b[c + 6], c += 8; else if (j == b[c]) c += 4; else if (o == b[c]) c += 8; else if (k == b[c]) {
+                    if (c + 4 > a) return debug.log("i: " + c), -1;
+                    var d = (b[c + 2] << 8) + b[c + 3];
+                    c += d
+                } else if (x == b[c]) M.h264_svc_flag = !0, M.svc = b[c + 2], c += 4; else if (q == b[c]) c += 8; else if (u == b[c]) c += 8; else if (C == b[c]) {
+                    var e = b[c + 1], f = b[c + 2];
+                    c += 8, c += e * f * 16
+                } else if (E == b[c]) c += 8; else if (G == b[c]) c += 8; else if (v == b[c]) c += 8; else if (w == b[c]) c += 8; else if (y == b[c]) c += 8; else if (I <= b[c] && b[c] < J) M.timeStampmsw = (b[c + 3] << 8) + b[c + 2], c += 4; else if (J <= b[c] && b[c] < K) c += b[c + 1]; else if (n == b[c]) c += 4; else if (p == b[c]) c += 4; else if (r == b[c]) c += 4; else if (t == b[c]) c += 8; else if (A == b[c]) {
+                    var e = b[c + 1];
+                    c += 8, c += 16 * e
+                } else if (B == b[c]) c += 4; else {
+                    if (H != b[c]) return debug.log("parseVideoInfo error ext_type:0x" + b[c]), debug.log("i: " + c), -1;
+                    var a = (b[c + 5] << 8) + b[c + 4];
+                    c += 8, c += a
+                }
+            }
+
+            function d() {
+                M.ChannelCount = 0;
+                for (var a = b[22] + 24, c = 24; a > c;) if (g == b[c]) c += 4; else if (h == b[c]) c += 4; else if (i == b[c]) c += 8; else if (j == b[c]) c += 4; else if (s == b[c]) c += b[c + 1]; else if (o == b[c]) c += 8; else if (k == b[c]) {
+                    var d = b[c + 2] << 8 + b[c + 3];
+                    c += d
+                } else if (z == b[c]) M.ChannelCount = b[c + 1], M.channel = b[c + 2], c += 4; else if (y == b[c]) c += 8; else {
+                    if (I != b[c]) return debug.log("parseAudioInfo error ext_type:0x" + b[c]), debug.log("i: " + c), -1;
+                    M.timeStampmsw = (b[c + 3] << 8) + b[c + 2], c += 4
+                }
+                0 == M.ChannelCount && (M.ChannelCount = 1, M.channel = 0);
+                for (var a = b[22] + 24, c = 24; a > c;) if (b[c] == g) c += 4; else if (b[c] == h) c += 4; else if (b[c] == i) c += 8; else if (b[c] == j) M.audio_type = b[c + 2], M.samplingRate = Gb[b[c + 3]], c += 4; else if (b[c] == s) c += b[c + 1]; else if (b[c] == o) c += 8; else if (b[c] == k) {
+                    var d = b[c + 2] << 8 + b[c + 3];
+                    c += d
+                } else if (b[c] == z) c += 4; else if (b[c] == y) c += 8; else {
+                    if (I != b[c]) return debug.log("parseAudioInfo error ext_type:0x" + b[c]), debug.log("i: " + c), -1;
+                    c += 4
+                }
+            }
+
+            function e() {
+                for (var a = b[22] + 24, c = 24; a > c;) if (I <= b[c] && b[c] < J) M.timeStampmsw = (b[c + 3] << 8) + b[c + 2], c += 4; else if (k == b[c]) {
+                    if (c + 4 > a) return debug.log("i: " + c), -1;
+                    debug.log("智能扩展");
+                    var d = (b[c + 2] << 8) + b[c + 3];
+                    c += d
+                } else c++
+            }
+
+            var f = b[4], g = 128, h = 129, i = 130, j = 131, k = 132, n = 133, o = 136, p = 137, q = 138, r = 139,
+                s = 140, t = 144, u = 145, v = 146, w = 147, x = 148, y = 149, z = 150, A = 151, B = 152, C = 153,
+                E = 154, G = 155, H = 156, I = 160, J = 176, K = 255,
+                L = {type: "MediaData", data: {rtspInterleave: a, payload: b}, info: null}, M = {};
+            if (253 == f || 254 == f || 252 == f || 251 == f) {
+                if (c(), null != Cb) {
+                    if (Cb != M.encode_type) return Cb = M.encode_type, void D(Fb[M.encode_type])
+                } else Cb = M.encode_type;
+                switch (M.encode_type + "") {
+                    case"2":
+                    case"5":
+                    case"8":
+                    case"12":
+                        l && (L.info = M, l.postMessage(L));
+                        break;
+                    default:
+                        debug.log("encode_type: " + M.encode_type)
+                }
+            } else if (240 == f) {
+                if (d(), null != Eb) {
+                    if (Eb != M.audio_type) return Eb = M.audio_type, void F("audioType")
+                } else Eb = M.audio_type;
+                if (null != Db) {
+                    if (Db != M.samplingRate) return Db = M.samplingRate, void F("samplingRate")
+                } else Db = M.samplingRate;
+                switch (M.audio_type + "") {
+                    case"10":
+                    case"14":
+                    case"26":
+                    case"27":
+                    case"28":
+                    case"29":
+                    case"30":
+                        m && (L.info = M, m.postMessage(L))
+                }
+            } else 241 == f ? (e(), l && (L.info = M, l.postMessage(L))) : debug.log("mediaType:   " + f)
+        }, setCallback: function (a, b) {
+            switch (a) {
+                case"timeStamp":
+                    u = b;
+                    break;
+                case"ResolutionChanged":
+                    s = b, null !== p && p.setResizeCallback(s);
+                    break;
+                case"audioTalk":
+                    v = b;
+                    break;
+                case"stepRequest":
+                    w = b;
+                    break;
+                case"metaEvent":
+                    x = b;
+                    break;
+                case"videoMode":
+                    y = b;
+                    break;
+                case"loadingBar":
+                    z = b;
+                    break;
+                case"Error":
+                    A = b;
+                    break;
+                case"PlayStart":
+                    t = b, null !== p && p.setBeginDrawCallback(t);
+                    break;
+                case"DecodeStart":
+                    B = b;
+                    break;
+                case"UpdateCanvas":
+                    C = b, null !== p && p.setupdateCanvasCallback(C);
+                    break;
+                case"FrameTypeChange":
+                    D = b;
+                    break;
+                case"MSEResolutionChanged":
+                    E = b;
+                    break;
+                case"audioChange":
+                    F = b;
+                    break;
+                case"WorkerReady":
+                    yb = b;
+                    break;
+                case"IvsDraw":
+                    G = b;
+                    break;
+                default:
+                    debug.log(a), debug.log("workerManager::setCallback() : type is unknown")
+            }
+        }, capture: function (a) {
+            "canvas" === P ? p.capture(a) : W.capture(a)
+        }, setDeviceInfo: function (a) {
+            U = a.mode
+        }, setFPS: function (a) {
+            var b = 30;
+            L = 0 === a ? b : a, h(1 !== ib)
+        }, setGovLength: function (a) {
+            M = a
+        }, setLiveMode: function (a) {
+            if (a === 'canvas') S.style.display = 'block';
+            else if (a === 'video') db.style.display = 'block';
+            null !== y && y(a), P = null === a ? "canvas" : a, "video" === P ? null !== p && p.renewCanvas() : "canvas" === P && h(!1);
+
+        }, controlAudio: function (a, b) {
+            switch (debug.log(a + " " + b), a) {
+                case"audioPlay":
+                    "start" === b ? null !== q && q.play() : (rb = 0, null !== q && q.stop());
+                    break;
+                case"volumn":
+                    rb = b, null !== q && q.controlVolumn(b);
+                    break;
+                case"audioSamplingRate":
+                    null !== q && q.setSamplingRate(b)
+            }
+        }, controlAudioTalk: function (a, b) {
+            if (null !== r) switch (a) {
+                case"onOff":
+                    "on" === b || r.stopAudioOut();
+                    break;
+                case"volumn":
+                    r.controlVolumnOut(b)
+            }
+        }, reassignCanvas: function () {
+            null !== p && p.reassignCanvas()
+        }, digitalZoom: function (a) {
+            null !== p && p.digitalZoom(a)
+        }, playbackSpeed: function (a) {
+            ib = a, p.setFrameInterval(ib)
+        }, timeStamp: function () {
+        }, initVideo: function (a) {
+            h(a)
+        }, setFpsFrame: function (a) {
+            vb = a, ub = 0, tb = 0
+        }, setCheckDelay: function (a) {
+            Q = a
+        }, initStartTime: function () {
+            var a = {type: "initStartTime"};
+            l.postMessage(a), p.stopRendering(), p.startRendering()
+        }, terminate: function () {
+            "backup" !== U && (l && (l.terminate(), l = null), m && (m.terminate(), m = null)), n && n.terminate(), r && (r.terminate(), r = null), p && p.terminate(), q && q.terminate(), W && W.terminate(), yb && (yb = null), p = null, O = !0
+        }
+    };
+    return new a
+};

+ 267 - 0
public/webLive.html

@@ -0,0 +1,267 @@
+<!doctype html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
+    <title>ImouPlayer</title>
+    <script src="./imouplayer.js"></script>
+    <style>
+        * {
+            /* font-family: PingFaangSC-Regular, Arial, 'Microsoft YaHei'; */
+            margin: 0;
+            padding: 0
+        }
+        
+        button {
+            display: block;
+            width: 120px;
+            line-height: 30px;
+            border: 1px solid #409eff;
+            background-color: #409eff;
+            color: #fff;
+            border-radius: 5px;
+            cursor: pointer;
+            margin-left: 73px;
+        }
+        
+        .wrap {
+            width: 80%;
+            max-width: 600px;
+            margin: 0 auto;
+        }
+        
+        .icon {
+            display: inline-block;
+            width: 20px;
+            line-height: 20px;
+            text-align: center;
+            background-color: #c1c1c1;
+            border-radius: 50%;
+            color: #fff;
+            font-style: normal;
+            cursor: pointer;
+            position: relative;
+            transition: background-color 0.3s ease;
+        }
+        
+        .tip {
+            display: block;
+            text-align: right;
+            font-size: 12px;
+            color: #999;
+        }
+        
+        @media only screen and (max-width: 768px) {
+            html,
+            body {
+                padding: 0;
+                margin: 0;
+            }
+            .wrap {
+                width: 100%;
+            }
+            p {
+                padding: 0 20px;
+            }
+        }
+    </style>
+    <script defer="defer" src="imouplayer.js"></script>
+</head>
+
+<body>
+    <div id="app"></div>
+    <div id="error"></div>
+    <script>
+        window.onload = function() {
+            let urlParams = getUrlParams(window.location.search);
+            console.log(urlParams);
+            let player;
+            let playerOption = {
+                isEdit: false,
+                url: urlParams.url || 'imou://open.lechange.com/6H0BXXXXXXX3D90/0/1?streamId=1',
+                kitToken: urlParams.kitToken || 'Kt_3baccxxxxxxxxxxxxxxxxxxxxxa183e',
+                // 是否自动播放
+                autoplay: true,
+                // 是否显示控制台
+                controls: true,
+                // 是否开启静音
+                automute: true,
+                themeData: [{
+                    area: 'header',
+                    fontColor: '#F18D00',
+                    backgroundColor: '#FFFFFF',
+                    activeButtonColor: '#0E72FF',
+                    buttonList: [{
+                        show: true,
+                        id: 'deviceName',
+                        name: '设备名称',
+                        position: 'left',
+                    }, {
+                        show: true,
+                        id: 'channalId',
+                        name: '设备通道',
+                        position: 'left',
+                    }, {
+                        show: true,
+                        id: 'cloudVideo',
+                        name: '云录像',
+                        position: 'right',
+                    }, {
+                        show: true,
+                        id: 'localVideo',
+                        name: '本地录像',
+                        position: 'right',
+                    }]
+                }, {
+                    area: 'footer',
+                    fontColor: '#F18D00',
+                    backgroundColor: '#FFFFFF',
+                    activeButtonColor: '#0E72FF',
+                    buttonList: [{
+                        show: true,
+                        id: 'play',
+                        name: '播放',
+                        position: 'left',
+                    }, {
+                        show: true,
+                        id: 'mute',
+                        name: '音量控制',
+                        position: 'left',
+                    }, {
+                        show: true,
+                        id: 'talk',
+                        name: '语音对讲',
+                        position: 'left',
+                    }, {
+                        show: true,
+                        id: 'capture',
+                        name: '截图',
+                        position: 'left',
+                    }, {
+                        show: true,
+                        id: 'definition',
+                        name: '清晰度控制',
+                        position: 'right',
+                    }, {
+                        show: true,
+                        id: 'PTZ',
+                        name: '云台控制',
+                        position: 'right',
+                    }, {
+                        show: true,
+                        id: 'webExpend',
+                        name: '网页全屏',
+                        position: 'right',
+                    }, {
+                        show: true,
+                        id: 'extend',
+                        name: '全屏控制',
+                        position: 'right',
+                    }]
+                }],
+            };
+            // 填写默认值
+            function $(selector) {
+                return document.querySelector(selector);
+            }
+
+            document.body.addEventListener('touchmove', function(e) {
+                e.preventDefault();
+                console.log('禁止拖动');
+            }, {
+                passive: false
+            });
+
+
+
+            function getUrlParams(data) {
+                let paramsList = {};
+                let paramsString = data.slice(1);
+                let list
+
+                if (paramsString.indexOf('%7C') != -1) {
+                    list = paramsString.split('%7C');
+                } else {
+                    list = paramsString.split('|');
+                }
+
+                list.forEach(item => {
+                    let list = item.split('=');
+                    key = list.shift();
+                    value = list.join('=');
+                    paramsList[key] = value;
+                })
+                return paramsList
+            }
+
+
+            function initLive() {
+                if (player) {
+                    player.destroy()
+                }
+                player = new ImouPlayer('#app');
+                // const url = $('#url').value.trim();
+                // const kitToken = $('#kitToken').value.trim();
+                const url = playerOption.url;
+                const kitToken = playerOption.kitToken;
+                const urlArr = [];
+                url.split('%').forEach(function(item, index) {
+                    const obj = {
+                        url: item,
+                        kitToken: kitToken,
+                        talk: {
+                            success: (msg) => {
+                                console.log('type', msg)
+                            },
+                            failed: (msg) => {
+                                console.log('failed', msg)
+                            }
+                        }
+                    };
+                    urlArr.push(obj)
+                });
+                // const width = window.innerWidth;
+                const width = checkMobile() ? $('body').clientWidth : window.innerWidth;
+                console.log(width);
+                const height = checkMobile() ? parseInt(width * 9 / 16) : window.innerHeight;
+                // const height = window.innerHeight;
+                const params = {
+                    src: urlArr,
+                    width: width,
+                    height: height,
+                    isEdit: playerOption.isEdit,
+                    autoplay: playerOption.autoplay,
+                    controls: playerOption.controls,
+                    automute: playerOption.automute,
+                    themeData: playerOption.themeData
+
+                };
+                // console.log(params, '11111111111111111111111111');
+                player.setup(params);
+            };
+
+            function checkMobile() {
+                if (!navigator) return false;
+                const reg = /(iPhone|iPod|Android|ios|SymbianOS)/i;
+                return reg.test(navigator.userAgent);
+            }
+
+            (function() {
+                initLive();
+            })();
+
+            // $('#init').onclick = function() {
+            //         initLive();
+            //     }
+            // $('#startTalk').onclick = function() {
+            //     player.startTalk()
+            // }
+            // $('#stopTalk').onclick = function() {
+            //     player.stopTalk()
+            // }
+        };
+    </script>
+</body>
+
+</html>

+ 96 - 94
src/api/qdtl/data.js

@@ -2,138 +2,140 @@ import request from '@/utils/request'
 
 export function getLineData() {
     return request({
-      url: 'qdtl/common/railwayLine',
-      method: 'get'
+        url: 'qdtl/common/railwayLine',
+        method: 'get'
     })
-  }
+}
 
-  export function getResource(query) {
+export function getResource(query) {
     console.log(query);
     return request({
-      url: 'qdtl/common/resource',
-      method: 'get',
-      params:query
+        url: 'qdtl/common/resource',
+        method: 'get',
+        params: query
     })
-  }
+}
 
-  export function getgovern(query) {
+export function getgovern(query) {
     console.log(query);
     return request({
-      url: 'qdtl/common/govern',
-      method: 'get',
-      params:query
+        url: 'qdtl/common/govern',
+        method: 'get',
+        params: query
     })
-  }
+}
 
-  export function getSchedule(query) {
+export function getSchedule(query) {
     return request({
-      url: '/qdtl/plan/getSchedule',
-      method: 'get',
-      params:query
+        url: '/qdtl/plan/getSchedule',
+        method: 'get',
+        params: query
     })
-  }
+}
 
-  export function getVideoHttp(query) {
+export function getVideoHttp(query) {
     return request({
-      url: '/qdtl/common/rtmp/'+query,
-      method: 'get',
-      params:query
+        url: '/qdtl/common/rtmp/' + query,
+        method: 'get',
+        params: query
     })
-  }
+}
 
-  export function queryCheck(query) {
+export function queryCheck(query) {
     return request({
-      url: '/qdtl/document/queryCheck',
-      method: 'get',
-      params:query
+        url: '/qdtl/document/queryCheck',
+        method: 'get',
+        params: query
     })
-  }
+}
 
 
-  export function documentSave(query) {
+export function documentSave(query) {
     return request({
-      url: '/qdtl/document',
-      method: 'post',
-      data: query
+        url: '/qdtl/document',
+        method: 'post',
+        data: query
     })
-  }
+}
 
-  export function documentExport(query) {
+export function documentExport(query) {
     console.log(query);
     return request({
-      url: '/qdtl/document/export?id='+query.id,
-      method: 'get',
-      // params:query
+        url: '/qdtl/document/export?id=' + query.id,
+        method: 'get',
+        // params:query
     })
-  }
+}
 
-  export function documentUpdate(query) {
+export function documentUpdate(query) {
     return request({
-      url: '/qdtl/document',
-      method: 'put',
-      data: query
+        url: '/qdtl/document',
+        method: 'put',
+        data: query
     })
-  }
+}
 
-  export function getPatrolman(query) {
+export function getPatrolman(query) {
     return request({
-      url: '/qdtl/patrolman/list',
-      method: 'get',
-      params:query
+        url: '/qdtl/patrolman/list',
+        method: 'get',
+        params: query
     })
-  }
+}
 
-  export function getTrail(query) {
+export function getTrail(query) {
     return request({
-      url: '/qdtl/log/trail/list',
-      method: 'get',
-      params:query
+        url: '/qdtl/log/trail/list',
+        method: 'get',
+        params: query
     })
-  }
-
-  // export function getPatrolman(query) {
-  //   return request({
-  //     url: '/qdtl/patrolman/list',
-  //     method: 'get',
-  //     params:query
-  //   })
-  // }
-
-  // export function getPatrolman(query) {
-  //   return request({
-  //     url: '/qdtl/patrolman/list',
-  //     method: 'get',
-  //     params:query
-  //   })
-  // }
-
-  export function getLog(query) {
+}
+
+// export function getPatrolman(query) {
+//   return request({
+//     url: '/qdtl/patrolman/list',
+//     method: 'get',
+//     params:query
+//   })
+// }
+
+// export function getPatrolman(query) {
+//   return request({
+//     url: '/qdtl/patrolman/list',
+//     method: 'get',
+//     params:query
+//   })
+// }
+
+export function getLog(query) {
     return request({
-      url: '/qdtl/log/list',
-      method: 'get',
-      params:query
+        url: '/qdtl/log/list',
+        method: 'get',
+        params: query
     })
-  }
-
-  // export function queryCheck(query) {
-  //   console.log(query);
-  //   return request({
-  //     url: '/qdtl/document/queryCheck/'+query,
-  //     method: 'get',
-  //     param:query
-  //   })
-  // }
-
-  export function getMonthStatic(query) {
+}
+
+// export function queryCheck(query) {
+//   console.log(query);
+//   return request({
+//     url: '/qdtl/document/queryCheck/'+query,
+//     method: 'get',
+//     param:query
+//   })
+// }
+
+export function getMonthStatic(query) {
     console.log(query);
     return request({
-      url: '/qdtl/common/monthStatic',
-      method: 'get',
-      params:query
+        url: '/qdtl/common/monthStatic',
+        method: 'get',
+        params: query
     })
-  }
-
-
-
-
+}
 
+export function getSinglePawns() {
+    return request({
+        url: "/qdtl/common/singlepawnplays",
+        method: "get"
+    });
+}

+ 342 - 291
src/views/qdtl/video/video.vue

@@ -1,326 +1,377 @@
 <template>
   <div class="app-container">
-     <headerdiv ref="headerDiv" :currentindexP = currentindexNew :menuNameP= itemName></headerdiv>
-     <div style="display: inline-flex">
-      <div class='leftTree'>
-            <!-- <el-form :model="nameObj" ref="nameObj" :inline="true" label-width="68px">
-                <el-form-item label="名称" prop="name"> -->
-                  <!-- <el-input
-                    v-model="nameObj.name"
-                    placeholder="请输入重命名名称"
-                    clearable
-                    size="small"
-                  /> -->
-                <!-- </el-form-item>
-            </el-form>          -->
-            <el-input
-                placeholder="输入关键字进行过滤"
-                v-model="filterText"
-                style="margin-top:1rem">
-            </el-input>
-             <div style="height:83vh;">
-                  <el-scrollbar style="height:110%;">
-                        <el-tree
-                            :data="videoData"
-                            :load="loadNode"
-                            lazy
-                            :expand-on-click-node="false"
-                            node-key="id"
-                            :default-expanded-keys="expandedKeys"
-                            :default-checked-keys="[5]"
-                            :props="defaultProps"
-                            :filter-node-method="filterNode"
-                            ref="tree"
-                            @node-click = 'treeChange'
-                            style="background-color:#04283C;color:#C5D0D4"
-                            >
-                            <!-- <span class="custom-tree-node" slot-scope="{ node, data }">
-                                <span>{{ node.label }}</span>
-                                <span>
-                                  <el-button
-                                    type="text"
-                                    size="mini"
-                                    @click.stop="treeChange"
-                                    @click="() => openName(node, data)"
-                                    style="margin-left:2rem">
-                                    修改
-                                  </el-button>
-                                </span>
-                              </span> -->
-                        </el-tree>
-               </el-scrollbar>
-            </div>
+    <headerdiv
+      ref="headerDiv"
+      :currentindexP="currentindexNew"
+      :menuNameP="itemName"
+    ></headerdiv>
+    <div style="display: inline-flex">
+      <div class="leftTree">
+        <el-input
+          placeholder="输入关键字进行过滤"
+          v-model="filterText"
+          style="margin-top: 1rem"
+        >
+        </el-input>
+        <div style="height: 83vh">
+          <el-scrollbar style="height: 110%">
+            <el-tree
+              :data="treedata"
+              :load="loadNode"
+              lazy
+              :expand-on-click-node="false"
+              node-key="id"
+              :default-expanded-keys="expandedKeys"
+              :default-checked-keys="[5]"
+              :props="defaultProps"
+              :filter-node-method="filterNode"
+              ref="tree"
+              @node-click="treeChange"
+              style="background-color: #04283c; color: #c5d0d4"
+            >
+            </el-tree>
+          </el-scrollbar>
+        </div>
       </div>
 
-     <div style="position: absolute;right:0;top:0;width:100%;height:90%;padding-left:33rem;margin-top:5rem;z-index:1000;">
-         <videodiv :cameracode="ccode" style="height:100%;width:100%"></videodiv>
+      <div
+        v-if="isvideo"
+        style="
+          position: absolute;
+          right: 0;
+          top: 0;
+          width: 100%;
+          height: 90%;
+          padding-left: 33rem;
+          margin-top: 5rem;
+          z-index: 1000;
+        "
+      >
+        <videodiv
+          :cameracode="ccode"
+          style="height: 100%; width: 100%"
+        ></videodiv>
       </div>
-     </div>
+      <div
+        v-if="!isvideo"
+        style="
+          position: absolute;
+          right: 0;
+          top: 0;
+          width: 100%;
+          height: 90%;
+          padding-left: 33rem;
+          margin-top: 5rem;
+          z-index: 1000;
+        "
+      >
+        <iframe :src="videoplaysrc" style="width:96%;height:100%"></iframe>
+      </div>
+    </div>
   </div>
 </template>
 
 <script>
-import { listVideo,queryCamera,editCamera } from "@/api/qdtl/video";
+import { listVideo, queryCamera, editCamera } from "@/api/qdtl/video";
+import { getSinglePawns } from "@/api/qdtl/data";
+
 import { httpRequest } from "@/api/data/http";
-import videodiv from "@/components/Videoplayer/index.vue"
-import headerdiv from '@/components/HeaderDiv/index.vue'
+import videodiv from "@/components/Videoplayer/index.vue";
+import headerdiv from "@/components/HeaderDiv/index.vue";
 
+let player;
 export default {
-    data() {
-      return {
-        itemName:'视频监测',
-        videoMap:new Map(),
-        nameObj:{
-              channel:'',
-              name:''
-        },
-        videoData:[],
-        // videoMap:new Map(),
-        expandedKeys:[],
-        videoIndex:1,
-        currentindexNew:2,
-        remarkName:false,
-        data: [{
+  data() {
+    return {
+      itemName: "视频监测",
+      videoMap: new Map(),
+      nameObj: {
+        channel: "",
+        name: "",
+      },
+      videoplaysrc:"",
+      treedata: [
+        {
           id: 1,
-          label: '一级 1',
-          children: [{
-            id: 4,
-            label: '二级 1-1',
-            children: [{
-              id: 9,
-              label: '三级 1-1-1'
-            }, {
-              id: 10,
-              label: '三级 1-1-2'
-            }]
-          }]
-        }, {
+          label: "监控视屏",
+          children: [],
+        },
+        {
           id: 2,
-          label: '一级 2',
-          children: [{
-            id: 5,
-            label: '二级 2-1'
-          }, {
-            id: 6,
-            label: '二级 2-2'
-          }]
-        }, {
-          id: 3,
-          label: '一级 3',
-          children: [{
-            id: 7,
-            label: '二级 3-1'
-          }, {
-            id: 8,
-            label: '二级 3-2'
-          }]
-        }],
-        defaultProps: {
-          children: 'children',
-          label: 'label'
+          label: "单兵",
+          children: [],
         },
-        filterText:'',
-        ccode:'',
-        jsonArry:[],
-        creamData:[],
-        pointIdArry:[],
-        regionIndexCode:'',
-        queryParams:{
-             url:'http://2.90.220.252:9017/artemis-web/debug',
-             params:'{"httpMethod":"POST","path":"/api/resource/v1/regions","headers":{},"query":{},"parameter":{},"body":{"pageNo": 1,"pageSize": 200,"treeCode": "0"},"contentType":"application/json;charset=UTF-8","mock":false,"appKey":"27794545","appSecret":"5Xi27Gl7JrbHHF1MpdaB"}'
+      ],
+      dbdata: [],
+      videoData: [],
+      isvideo: true,
+      // videoMap:new Map(),
+      expandedKeys: [],
+      videoIndex: 1,
+      currentindexNew: 2,
+      remarkName: false,
+      data: [
+        {
+          id: 1,
+          label: "一级 1",
+          children: [
+            {
+              id: 4,
+              label: "二级 1-1",
+              children: [
+                {
+                  id: 9,
+                  label: "三级 1-1-1",
+                },
+                {
+                  id: 10,
+                  label: "三级 1-1-2",
+                },
+              ],
+            },
+          ],
         },
-         videoParams:{
-             url:'http://2.90.220.252:9017/artemis-web/debug',
-            //  params:'{"httpMethod":"POST","path":"/api/resource/v1/regions/regionIndexCode/cameras","headers":{},"query":{},"parameter":{},"body":{"pageNo": 1,"pageSize": 200,"regionIndexCode": "'+this.regionIndexCode+'"},"contentType":"application/json;charset=UTF-8","mock":false,"appKey":"27794545","appSecret":"5Xi27Gl7JrbHHF1MpdaB"}'
+        {
+          id: 2,
+          label: "一级 2",
+          children: [
+            {
+              id: 5,
+              label: "二级 2-1",
+            },
+            {
+              id: 6,
+              label: "二级 2-2",
+            },
+          ],
         },
-      };
-    },
-    components:{
-      videodiv,
-      headerdiv,
+        {
+          id: 3,
+          label: "一级 3",
+          children: [
+            {
+              id: 7,
+              label: "二级 3-1",
+            },
+            {
+              id: 8,
+              label: "二级 3-2",
+            },
+          ],
+        },
+      ],
+      defaultProps: {
+        children: "children",
+        label: "label",
+      },
+      filterText: "",
+      ccode: "",
+      jsonArry: [],
+      creamData: [],
+      pointIdArry: [],
+      regionIndexCode: "",
+      queryParams: {
+        url: "http://2.90.220.252:9017/artemis-web/debug",
+        params:
+          '{"httpMethod":"POST","path":"/api/resource/v1/regions","headers":{},"query":{},"parameter":{},"body":{"pageNo": 1,"pageSize": 200,"treeCode": "0"},"contentType":"application/json;charset=UTF-8","mock":false,"appKey":"27794545","appSecret":"5Xi27Gl7JrbHHF1MpdaB"}',
+      },
+      videoParams: {
+        url: "http://2.90.220.252:9017/artemis-web/debug",
+        //  params:'{"httpMethod":"POST","path":"/api/resource/v1/regions/regionIndexCode/cameras","headers":{},"query":{},"parameter":{},"body":{"pageNo": 1,"pageSize": 200,"regionIndexCode": "'+this.regionIndexCode+'"},"contentType":"application/json;charset=UTF-8","mock":false,"appKey":"27794545","appSecret":"5Xi27Gl7JrbHHF1MpdaB"}'
+      },
+    };
+  },
+  components: {
+    videodiv,
+    headerdiv,
+  },
+  watch: {
+    filterText(val) {
+      this.$refs.tree.filter(val);
     },
-    watch: {
-      filterText(val) {
-        this.$refs.tree.filter(val);
-      }
+    videoData(val) {
+      this.treedata[0].children = val;
     },
-    created() {
-        this.getvideo();
-        // this.getList();
+    dbdata(val) {
+      this.treedata[1].children = val;
     },
-    
-    mounted(){
-      window.videosize = "3x3";
-      this.queryCamera();
+  },
+  created() {
+    this.getvideo();
+  },
 
+  mounted() {
+    window.videosize = "3x3";
+    this.queryCamera();
+
+    getSinglePawns().then((res) => {
+      this.dbdata = res.data.map((res) => {
+        return { id: res.code, label: res.name, playaddr: res.playaddr };
+      });
+    });
+  },
+  beforeDestroy() {
+    window.videosize = "1x1";
+    closevideo();
+  },
+  methods: {
+    openName(node, data) {
+      if (this.nameObj.name.length > 0) {
+        this.nameObj.channel = data.id;
+        console.log(this.nameObj);
+        editCamera(this.nameObj).then((response) => {
+          console.log(response);
+        });
+      }
     },
-    beforeDestroy(){
-      window.videosize = "1x1";
-      closevideo();
+    editCamera() {
+      editCamera().then((data) => {});
     },
-    methods:{
-        openName(node,data){
-              if(this.nameObj.name.length > 0){
-                      this.nameObj.channel = data.id
-                      console.log(this.nameObj);
-                      editCamera(this.nameObj).then(response =>{
-                                console.log(response);
-                       })
-              }
-        },
-        editCamera(){
-              editCamera().then(data =>{
+    queryCamera() {
+      queryCamera().then((data) => {
+        this.videoMap = data.data;
+      });
+    },
+    loadNode(node, resolve) {
+      // if (node.level > 4) return resolve([]);
+      if (node.level === 0) {
+        return resolve(this.treedata);
+      }
+      if (node.id === 1 && node.level === 1) {
+        return resolve(this.treedata[0].children);
+      }
 
-              })
-        },
-        queryCamera(){
-              queryCamera().then(data =>{
-                      this.videoMap = data.data
-              })
-        },
-        loadNode(node, resolve){
-        if (node.level > 3) return resolve([]);
-        if(node.level <3){
-              var childrens = []
-              for(var index in this.jsonArry){
-                      if(node.data.id == this.jsonArry[index].parentIndexCode){
-                           childrens.push(this.jsonArry[index]);
-                      }
-              }
-                 resolve(childrens);
+      if (node.id === 2 && node.level === 1) {
+        return resolve(this.treedata[1].children);
+      }
+      if (node.id === 1 && node.level === 1) {
+        var childrens = [];
+        for (var index in this.videoData) {
+          if (node.data.id == this.jsonArry[index].parentIndexCode) {
+            childrens.push(this.jsonArry[index]);
+          }
         }
-
-        if(node.level === 3){
-             this.videoParams.params = '{"httpMethod":"POST","path":"/api/resource/v1/regions/regionIndexCode/cameras","headers":{},"query":{},"parameter":{},"body":{"pageNo": 1,"pageSize": 200,"regionIndexCode": "'+node.data.indexCode+'"},"contentType":"application/json;charset=UTF-8","mock":false,"appKey":"27794545","appSecret":"5Xi27Gl7JrbHHF1MpdaB"}'
-                  httpRequest(this.videoParams).then(data =>{
-                        var json = JSON.parse(data.data);
-                        // console.log(json);
-                        var childerns = [];
-                        for(var index in json.data.list){
-                          // console.log();\
-                              var obj = json.data.list[index];
-                              obj.id = obj.cameraIndexCode;
-                              // remarkName
-                              if(this.videoMap[obj.id]){
-                                     obj.label = this.videoMap[obj.id]
-                              }else{
-                                     obj.label = obj.name;
-                              }
-                              obj.data = obj;
-                              obj.lnglat = obj.longitude +','+obj.latitude;
-                              childerns.push(obj);
-                        }
-                        resolve(childerns);
-                  });
+        return resolve(childrens);
+      }
+      if (node.level < 4) {
+        var childrens = [];
+        for (var index in this.jsonArry) {
+          if (node.data.id == this.jsonArry[index].parentIndexCode) {
+            childrens.push(this.jsonArry[index]);
+          }
         }
-        },
-        getvideo(){
-          httpRequest(this.queryParams).then(response => {
-              //  console.log(response);
-               var json = JSON.parse(response.data);
-               console.log(json);
-               for(var index in json.data.list){
-                    // obj = json.data.list[index]
-                    // obj.id = obj.indexCode;
-                    // obj.label = obj.name;
-                    // obj.data = obj;
-                    var obj = json.data.list[index]
-                    obj.id = obj.indexCode;
-                    obj.label = obj.name;
-                    obj.data = obj;
-                    this.jsonArry.push(obj);
-                    if(obj.parentIndexCode == -1){
-                           this.videoData.push(obj);
-                           this.expandedKeys.push(obj.id);
-                    }
-                    // this.expandedKeys.push(obj.id);
-                    if(this.videoData.length > 0){
-                          if(obj.parentIndexCode == this.videoData[0].id){
-                            this.expandedKeys.push(obj.id);
-                          }
-                    }
-                  
-               }
-           });
-        },
-       getList() {
-            listVideo().then(response => {
-                console.log(response);
-                this.videoData= response.data
-                 console.log(this.videoData);
-                 for(var index in this.videoData){
-                    var obj = this.videoData[index];
-                    obj.label = obj.areaName;
-                    obj.children = []
-                    for(var i in obj.monitors){
-                         var monitor = obj.monitors[i]
-                         monitor.data = monitor;
-                         monitor.label = monitor.name;
-                         obj.children.push(monitor);
-                    }
-                 }
-                 console.log(this.videoData);
-            });
-       },
-      filterNode(value, data) {
-                if (!value) return true;
-                return data.label.indexOf(value) !== -1;
-      },
-      treeChange(data, node){
-          var arry = this.$refs.tree.getCheckedNodes()
-          // console.log(data.cameraIndexCode);
-          // var pointArry = this.$refs.mapv.pointArry;
-
-          if(data.lnglat != null){
-             window.startPreview(data.cameraIndexCode,-1);
-              // if(node == false){
-              //     console.log(data.cameraIndexCode);
-              //     var index = this.videoMap.get(data.cameraIndexCode);;
-              //     window.stoppreview([{'wndId': index+1}]);
-              // }else if(node == true){
-              //     console.log(data.cameraIndexCode);
-              //     window.startPreview(data.cameraIndexCode,this.videoIndex);
-              //     this.videoMap.set(data.cameraIndexCode,this.videoIndex);
-              //     if(this.videoIndex < 8){
-              //         this.videoIndex = this.videoIndex+1
-              //     }else{
-              //         this.videoIndex = 0
-              //     }
-              //     console.log(this.videoIndex);
-              // }
+        return resolve(childrens);
+      }
+      if (node.level === 4) {
+        this.videoParams.params =
+          '{"httpMethod":"POST","path":"/api/resource/v1/regions/regionIndexCode/cameras","headers":{},"query":{},"parameter":{},"body":{"pageNo": 1,"pageSize": 200,"regionIndexCode": "' +
+          node.data.indexCode +
+          '"},"contentType":"application/json;charset=UTF-8","mock":false,"appKey":"27794545","appSecret":"5Xi27Gl7JrbHHF1MpdaB"}';
+        httpRequest(this.videoParams).then((data) => {
+          var json = JSON.parse(data.data);
+          // console.log(json);
+          var childerns = [];
+          for (var index in json.data.list) {
+            // console.log();\
+            var obj = json.data.list[index];
+            obj.id = obj.cameraIndexCode;
+            // remarkName
+            if (this.videoMap[obj.id]) {
+              obj.label = this.videoMap[obj.id];
+            } else {
+              obj.label = obj.name;
+            }
+            obj.data = obj;
+            obj.lnglat = obj.longitude + "," + obj.latitude;
+            childerns.push(obj);
           }
+          resolve(childerns);
+        });
+      }
 
-          // window.startPreview(window.cameraid,-1);
-         // startPreview(code,0-8)
-          // for(var index in arry){
-          //       var obj = arry[index]
-          //       if(obj.lnglat){
-          //           if(pointArry.get('obj') == null){
-          //                 console.log(obj.lnglat);
-          //                 this.$refs.mapv.addMarker(obj.lnglat.split(','),'监控 (2) 拷贝 20.png',0.2,obj.id);
-          //                 this.pointIdArry.push(obj.id);
-          //           }
-          //       }
-          // }
-       
+      return resolve([]);
+    },
+    getvideo() {
+      httpRequest(this.queryParams).then((response) => {
+        try {
+          //  console.log(response);
+          var json = JSON.parse(response.data);
+          console.log(json);
+          for (var index in json.data.list) {
+            // obj = json.data.list[index]
+            // obj.id = obj.indexCode;
+            // obj.label = obj.name;
+            // obj.data = obj;
+            var obj = json.data.list[index];
+            obj.id = obj.indexCode;
+            obj.label = obj.name;
+            obj.data = obj;
+            this.jsonArry.push(obj);
+            if (obj.parentIndexCode == -1) {
+              this.videoData.push(obj);
+              this.expandedKeys.push(obj.id);
+            }
+            // this.expandedKeys.push(obj.id);
+            if (this.videoData.length > 0) {
+              if (obj.parentIndexCode == this.videoData[0].id) {
+                this.expandedKeys.push(obj.id);
+              }
+            }
+          }
+        } catch (error) {}
+      });
+    },
+    getList() {
+      listVideo().then((response) => {
+        console.log(response);
+        this.videoData = response.data;
+        console.log(this.videoData);
+        for (var index in this.videoData) {
+          var obj = this.videoData[index];
+          obj.label = obj.areaName;
+          obj.children = [];
+          for (var i in obj.monitors) {
+            var monitor = obj.monitors[i];
+            monitor.data = monitor;
+            monitor.label = monitor.name;
+            obj.children.push(monitor);
+          }
+        }
+        console.log(this.videoData);
+      });
+    },
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+    treeChange(data, node) {
+      var arry = this.$refs.tree.getCheckedNodes();
 
+      if (data.lnglat != null) {
+        this.isvideo = true;
+        window.startPreview(data.cameraIndexCode, -1);
+      } else {
+        if (data.playaddr != null) {
+          this.isvideo = false;
+          this.videoplaysrc = "/webLive.html?url=" + data.playaddr;
+        }
       }
-    }
+    },
+  },
 };
 </script>
 
 <style>
-     .leftTree{
-          /* float:left; */
-          width:32rem;
-          background-color:#04283C;
-          padding: 10px;
-          padding-top:0 ;
-          min-height: 95vh;
-          z-index:1001;
-     }
-     .app-container{
-       padding:0
-     }
+.leftTree {
+  /* float:left; */
+  width: 32rem;
+  background-color: #04283c;
+  padding: 10px;
+  padding-top: 0;
+  min-height: 95vh;
+  z-index: 1001;
+}
+.app-container {
+  padding: 0;
+}
 </style>
-

+ 76 - 76
vue.config.js

@@ -23,120 +23,120 @@ module.exports = {
     // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
     publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
     // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
-    outputDir: 'dist',
+    outputDir: "dist",
     // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
-    assetsDir: 'static',
+    assetsDir: "static",
     // 是否开启eslint保存检测,有效值:ture | false | 'error'
-    lintOnSave: process.env.NODE_ENV === 'development',
+    lintOnSave: process.env.NODE_ENV === "development",
     // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
     productionSourceMap: false,
     // webpack-dev-server 相关配置
     devServer: {
-        host: '0.0.0.0',
+        host: "0.0.0.0",
         port: port,
         open: true,
         proxy: {
             // detail: https://cli.vuejs.org/config/#devserver-proxy
             [process.env.VUE_APP_BASE_API]: {
                 target: `http://58.221.168.61:9000/api`,
+                // target: `http://localhost:8080/`,
                 changeOrigin: true,
                 pathRewrite: {
-                    ['^' + process.env.VUE_APP_BASE_API]: ''
-                }
-            }
+                    ["^" + process.env.VUE_APP_BASE_API]: "",
+                },
+            },
         },
-        disableHostCheck: true
+        disableHostCheck: true,
     },
     css: {
         loaderOptions: {
             sass: {
-                sassOptions: { outputStyle: "expanded" }
-            }
-        }
+                sassOptions: { outputStyle: "expanded" },
+            },
+        },
     },
     configureWebpack: {
         name: name,
         resolve: {
             alias: {
-                '@': resolve('src')
-            }
+                "@": resolve("src"),
+            },
         },
         plugins: [
-            new CopyWebpackPlugin([
-                { from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml' },
-                { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: 'js/' },
-                { from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf' }
+            new CopyWebpackPlugin([{
+                    from: "node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml",
+                },
+                {
+                    from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js",
+                    to: "js/",
+                },
+                {
+                    from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf",
+                },
             ]),
             // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
             new CompressionPlugin({
                 test: /\.(js|css|html)?$/i, // 压缩文件格式
-                filename: '[path].gz[query]', // 压缩后的文件名
-                algorithm: 'gzip', // 使用gzip压缩
-                minRatio: 0.8 // 压缩率小于1才会压缩
-            })
+                filename: "[path].gz[query]", // 压缩后的文件名
+                algorithm: "gzip", // 使用gzip压缩
+                minRatio: 0.8, // 压缩率小于1才会压缩
+            }),
         ],
     },
     chainWebpack(config) {
-        config.plugins.delete('preload') // TODO: need test
-        config.plugins.delete('prefetch') // TODO: need test
+        config.plugins.delete("preload"); // TODO: need test
+        config.plugins.delete("prefetch"); // TODO: need test
 
         // set svg-sprite-loader
+        config.module.rule("svg").exclude.add(resolve("src/assets/icons")).end();
         config.module
-            .rule('svg')
-            .exclude.add(resolve('src/assets/icons'))
-            .end()
-        config.module
-            .rule('icons')
+            .rule("icons")
             .test(/\.svg$/)
-            .include.add(resolve('src/assets/icons'))
+            .include.add(resolve("src/assets/icons"))
             .end()
-            .use('svg-sprite-loader')
-            .loader('svg-sprite-loader')
+            .use("svg-sprite-loader")
+            .loader("svg-sprite-loader")
             .options({
-                symbolId: 'icon-[name]'
+                symbolId: "icon-[name]",
             })
-            .end()
+            .end();
 
-        config
-            .when(process.env.NODE_ENV !== 'development',
-                config => {
-                    config
-                        .plugin('ScriptExtHtmlWebpackPlugin')
-                        .after('html')
-                        .use('script-ext-html-webpack-plugin', [{
-                            // `runtime` must same as runtimeChunk name. default is `runtime`
-                            inline: /runtime\..*\.js$/
-                        }])
-                        .end()
-                    config
-                        .optimization.splitChunks({
-                            chunks: 'all',
-                            cacheGroups: {
-                                libs: {
-                                    name: 'chunk-libs',
-                                    test: /[\\/]node_modules[\\/]/,
-                                    priority: 10,
-                                    chunks: 'initial' // only package third parties that are initially dependent
-                                },
-                                elementUI: {
-                                    name: 'chunk-elementUI', // split elementUI into a single package
-                                    priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
-                                    test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
-                                },
-                                commons: {
-                                    name: 'chunk-commons',
-                                    test: resolve('src/components'), // can customize your rules
-                                    minChunks: 3, //  minimum common number
-                                    priority: 5,
-                                    reuseExistingChunk: true
-                                }
-                            }
-                        })
-                    config.optimization.runtimeChunk('single'), {
-                        from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
-                        to: './' //到根目录下
-                    }
-                }
-            )
-    }
-}
+        config.when(process.env.NODE_ENV !== "development", (config) => {
+            config
+                .plugin("ScriptExtHtmlWebpackPlugin")
+                .after("html")
+                .use("script-ext-html-webpack-plugin", [{
+                    // `runtime` must same as runtimeChunk name. default is `runtime`
+                    inline: /runtime\..*\.js$/,
+                }, ])
+                .end();
+            config.optimization.splitChunks({
+                chunks: "all",
+                cacheGroups: {
+                    libs: {
+                        name: "chunk-libs",
+                        test: /[\\/]node_modules[\\/]/,
+                        priority: 10,
+                        chunks: "initial", // only package third parties that are initially dependent
+                    },
+                    elementUI: {
+                        name: "chunk-elementUI", // split elementUI into a single package
+                        priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+                        test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
+                    },
+                    commons: {
+                        name: "chunk-commons",
+                        test: resolve("src/components"), // can customize your rules
+                        minChunks: 3, //  minimum common number
+                        priority: 5,
+                        reuseExistingChunk: true,
+                    },
+                },
+            });
+            config.optimization.runtimeChunk("single"), {
+                from: path.resolve(__dirname, "./public/robots.txt"), //防爬虫文件
+                to: "./", //到根目录下
+            };
+        });
+    },
+};

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio