From 8cc072a8a3bffcb8e9292cd39d1062493a1a0282 Mon Sep 17 00:00:00 2001
From: 朱桂飞 <18597012158>
Date: 星期二, 19 十二月 2023 13:03:09 +0800
Subject: [PATCH] 添加实时监控页面

---
 package-lock.json        |    5 
 pages/login/login.vue    |    2 
 static/logo.png          |    0 
 pages.json               |    9 
 static/splash.png        |    0 
 static/ezuikit.js        | 35929 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 manifest.json            |   42 
 pages/tabBar/general.vue |    2 
 package.json             |    3 
 pages/me/control.vue     |  102 
 pages/me/video.vue       |   56 
 pages/tabBar/monitor.vue |    2 
 pages/tabBar/me.vue      |   27 
 13 files changed, 36,141 insertions(+), 38 deletions(-)

diff --git a/manifest.json b/manifest.json
index 6a0ee6d..721eb2e 100644
--- a/manifest.json
+++ b/manifest.json
@@ -43,7 +43,47 @@
             /* ios鎵撳寘閰嶇疆 */
             "ios" : {},
             /* SDK閰嶇疆 */
-            "sdkConfigs" : {}
+            "sdkConfigs" : {},
+            "icons" : {
+                "android" : {
+                    "hdpi" : "unpackage/res/icons/72x72.png",
+                    "xhdpi" : "unpackage/res/icons/96x96.png",
+                    "xxhdpi" : "unpackage/res/icons/144x144.png",
+                    "xxxhdpi" : "unpackage/res/icons/192x192.png"
+                },
+                "ios" : {
+                    "appstore" : "unpackage/res/icons/1024x1024.png",
+                    "ipad" : {
+                        "app" : "unpackage/res/icons/76x76.png",
+                        "app@2x" : "unpackage/res/icons/152x152.png",
+                        "notification" : "unpackage/res/icons/20x20.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "proapp@2x" : "unpackage/res/icons/167x167.png",
+                        "settings" : "unpackage/res/icons/29x29.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "spotlight" : "unpackage/res/icons/40x40.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png"
+                    },
+                    "iphone" : {
+                        "app@2x" : "unpackage/res/icons/120x120.png",
+                        "app@3x" : "unpackage/res/icons/180x180.png",
+                        "notification@2x" : "unpackage/res/icons/40x40.png",
+                        "notification@3x" : "unpackage/res/icons/60x60.png",
+                        "settings@2x" : "unpackage/res/icons/58x58.png",
+                        "settings@3x" : "unpackage/res/icons/87x87.png",
+                        "spotlight@2x" : "unpackage/res/icons/80x80.png",
+                        "spotlight@3x" : "unpackage/res/icons/120x120.png"
+                    }
+                }
+            },
+            "splashscreen" : {
+                "androidStyle" : "default",
+                "android" : {
+                    "hdpi" : "static/splash.png",
+                    "xhdpi" : "static/splash.png",
+                    "xxhdpi" : "static/splash.png"
+                }
+            }
         }
     },
     /* 蹇簲鐢ㄧ壒鏈夌浉鍏� */
diff --git a/package-lock.json b/package-lock.json
index 0d961fc..a49bee1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,6 +4,11 @@
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "ezuikit-js": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/ezuikit-js/-/ezuikit-js-0.7.2.tgz",
+      "integrity": "sha512-BECy42q371eT4TekLon7YVmiU0u6UwbqEOjqzvbSKd0fVDwFqEaSST72EaiqWhgdfqS+xUg31pMgt1FY6GweRA=="
+    },
     "lodash.get": {
       "version": "4.4.2",
       "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
diff --git a/package.json b/package.json
index 216af2d..4f0f045 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
 	"author": "",
 	"license": "ISC",
 	"dependencies": {
-		"lodash.get": "^4.4.2"
+		"lodash.get": "^4.4.2",
+		"ezuikit-js": "^0.7.2"
 	}
 }
diff --git a/pages.json b/pages.json
index 33c277a..af418af 100644
--- a/pages.json
+++ b/pages.json
@@ -104,6 +104,15 @@
 				}
 			}
 
+		}, {
+			"path": "pages/me/video",
+			"style": {
+				"navigationStyle": "custom",
+				"app-plus": {
+					"titleNView": false
+				}
+			}
+
 		}
 	],
 	"globalStyle": {
diff --git a/pages/login/login.vue b/pages/login/login.vue
index af74294..438a26d 100644
--- a/pages/login/login.vue
+++ b/pages/login/login.vue
@@ -2,7 +2,7 @@
 <template>
 	<view class="contaier">
 		<view class="top-bg">
-			<view class="text-white text-bold text-xxxl">鏅鸿兘涓崏鑽共鐕ュ皬绋嬪簭绯荤粺</view>
+			<view class="text-white text-bold text-xxxl">鏅鸿兘涓崏鑽共鐕ヨ澶囬厤濂楃郴缁�</view>
 			<view class="margin-top-xs text-white">娆㈣繋浣跨敤锛岃鍏堢櫥褰�</view>
 		</view>
 		<u-form labelPosition="left" :model="model" ref="form">
diff --git a/pages/me/control.vue b/pages/me/control.vue
index 3e0a559..4abf342 100644
--- a/pages/me/control.vue
+++ b/pages/me/control.vue
@@ -40,11 +40,18 @@
 			return {
 				sendMsg: '',
 				recviceMsg: '',
-				baseList: [{
+				baseList: [
+					/* {
+											id: 1010,
+											img: '',
+											title: '缁翠慨妯″紡',
+											name: 'warning'
+										}, */
+					{
 						id: 1010,
 						img: '',
-						title: '缁翠慨妯″紡',
-						name: 'warning'
+						title: '骞茬嚗鍚姩',
+						name: 'play-circle'
 					},
 					{
 						id: 0,
@@ -59,18 +66,12 @@
 						title: '鍋滄杩愯',
 						name: 'pause-circle'
 					},
-					{
-						id: 1001,
-						img: '',
-						title: '椋庣鍗�',
-						name: 'arrow-up'
-					},
-					{
-						id: 1003,
-						img: '',
-						title: '婊氱瓛鍗�',
-						name: 'arrow-upward'
-					},
+					// {
+					// 	id: 1001,
+					// 	img: '',
+					// 	title: '椋庣鍗�',
+					// 	name: 'arrow-up'
+					// },
 					{
 						id: 1005,
 						img: '',
@@ -78,25 +79,74 @@
 						name: 'checkmark-circle'
 					},
 					{
-						id: 1002,
+						id: 1003,
 						img: '',
-						title: '椋庣闄�',
-						name: 'arrow-down'
+						title: '婊氱瓛鍗�',
+						name: 'arrow-upward'
+					},
+					{
+						id: 1011,
+						img: '',
+						title: '鍓嶉棬寮�鍏�',
+						name: 'plus-circle'
 					},
-				
+					
+					// {
+					// 	id: 1002,
+					// 	img: '',
+					// 	title: '椋庣闄�',
+					// 	name: 'arrow-down'
+					// },
+					{
+						id: 1006,
+						img: '',
+						title: '婊氱瓛鍙嶈浆',
+						name: 'close-circle'
+					},
+
 					{
 						id: 1004,
 						img: '',
 						title: '婊氱瓛闄�',
 						name: 'arrow-downward'
+					},
+					{
+						id: 1012,
+						img: '',
+						title: '鍚庨棬寮�鍏�',
+						name: 'minus-circle'
+					},
+					{
+						id: 1013,
+						img: '',
+						title: '鐑鍚姩',
+						name: 'coupon'
 					},
-					
+
 					{
-						id: 1006,
+						id: 1014,
 						img: '',
-						title: '婊氱瓛鍙嶈浆',
-						name: 'close-circle'
-					},
+						title: '寮�闂ㄨ瀵�',
+						name: 'eye'
+					},
+					{
+						id: 1015,
+						img: '',
+						title: '鍑烘枡',
+						name: 'shopping-cart'
+					},{
+						id: 1016,
+						img: '',
+						title: '娓呴櫎',
+						name: 'trash'
+					},{
+						id: 1017,
+						img: '',
+						title: '鎵嬪姩/鑷姩',
+						name: 'fingerprint'
+					}
+
+					
 				]
 			}
 		},
@@ -147,7 +197,7 @@
 				parmas.tenantId = 1003
 				parmas.machineId = 'GM001'
 
-				this.sendMsg =  '鍙戦�侊細' + this.formatData()  + JSON.stringify(parmas)
+				this.sendMsg = '鍙戦�侊細' + this.formatData() + JSON.stringify(parmas)
 				this.recviceMsg = ''
 				console.info(parmas)
 				this.$api.sendCommand(parmas).then((res) => {
@@ -159,7 +209,7 @@
 					}
 
 				}).finally(() => {
-					 
+
 				})
 			},
 			formatData() {
diff --git a/pages/me/video.vue b/pages/me/video.vue
new file mode 100644
index 0000000..4e01719
--- /dev/null
+++ b/pages/me/video.vue
@@ -0,0 +1,56 @@
+<template>
+	<view>
+		<view id="video-container1" class="item-player">
+
+		</view>
+	</view>
+</template>
+
+<script>
+	import EZUIKit from "ezuikit-js";
+	export default {
+		data() {
+			return {
+
+			}
+		},
+		mounted() {
+			this.initPlayer1()
+
+		},
+		methods: {
+			initPlayer1() {
+				var width = document.documentElement.clientWidth;
+				var height = document.documentElement.clientWidth * 9 / 16;
+				const player1 = new EZUIKit.EZUIKitPlayer({
+					id: "video-container1", // 瑙嗛瀹瑰櫒ID
+					accessToken: 'at.3aw83ov4az77j8s87flvj2a36lctx64d-7awt1ntwzz-024wi8h-bpwhdobad',
+					url: 'ezopen://open.ys7.com/C24284281/1.hd.live',
+					template: 'mobileLive',
+					plugin: ["talk"], // 鍔犺浇鎻掍欢锛宼alk-瀵硅
+					width: width,
+					height: height,
+					handleSuccess: (res => {
+						console.info(res);
+						console.info("鍒濆鍖栨垚鍔�");
+					}),
+					handleError: (res => {
+						console.info(res);
+						if (res.retcode == "10002") {
+							console.info("鍒濆鍖栧け璐ワ紝token杩囨湡");
+						}
+					})
+				});
+				setTimeout(() => {
+					console.info("寮�濮嬭嚜鍔ㄦ挱鏀�1鍙�")
+					player1.play();
+				}, 1000);
+			}
+
+		}
+	}
+</script>
+
+<style>
+
+</style>
\ No newline at end of file
diff --git a/pages/tabBar/general.vue b/pages/tabBar/general.vue
index 6d46b9a..7600ad3 100644
--- a/pages/tabBar/general.vue
+++ b/pages/tabBar/general.vue
@@ -12,7 +12,7 @@
 		 
 		 -->
 		<cu-custom bgColor="bg-gradual-blue" :isBack="false">
-			<block slot="content">鏅鸿兘涓崏鑽共鐕ュ皬绋嬪簭绯荤粺</block>
+			<block slot="content">鏅鸿兘涓崏鑽共鐕ヨ澶囬厤濂楃郴缁�</block>
 		</cu-custom>
 		<u-toast ref="uToast"></u-toast>
 		<!-- 		<view class="card-box dynamic shadow cu-list menu">
diff --git a/pages/tabBar/me.vue b/pages/tabBar/me.vue
index 4c53316..239af44 100644
--- a/pages/tabBar/me.vue
+++ b/pages/tabBar/me.vue
@@ -119,10 +119,17 @@
 					</button>
 				</view>
 				<view class="cu-item">
-					<button class='content cu-btn' @click="itemClick">
-						<image src='../../static/me/icon/diannao.png' class='png' mode='aspectFit'></image>
-						<text class='text-lg margin-sm'>杩滅▼鎺у埗</text>
+					<button class='content cu-btn' @click="itemClick('video')">
+						<image src='../../static/me/icon/jiankong.png' class='png' mode='aspectFit'></image>
+						<text class='text-lg margin-sm'>瀹炴椂鐩戞帶</text>
 					</button>
+				</view>
+				
+				<view class="cu-item">
+					<button class='content cu-btn' @click="itemClick('control')">
+						<image src='../../static/me/icon/diannao.png' class='png' mode='aspectFit'></image>
+						<text class='text-lg margin-sm'>杩滅▼鎺у埗</text>
+					</button>
 				</view>
 				
 				
@@ -206,10 +213,16 @@
 		mounted() {
	
 		},
 		methods: {
-			itemClick(){
-				uni.navigateTo({
-					url:"/pages/me/control"
-				})
+			itemClick(mode){
+				if(mode == 'control'){
+					uni.navigateTo({
+						url:"/pages/me/control"
+					})
+				}else if(mode == 'video'){
+					uni.navigateTo({
+						url:"/pages/me/video"
+					})
+				}
 			},
 			exit() {
 				this.show = true
diff --git a/pages/tabBar/monitor.vue b/pages/tabBar/monitor.vue
index fa6b4fd..fbc86f7 100644
--- a/pages/tabBar/monitor.vue
+++ b/pages/tabBar/monitor.vue
@@ -404,7 +404,7 @@
 				model: {},
 				queryParam: {
 					machineid: "GM001",
-					tenantid: 1000
+					tenantid: 1003
 				},
 				bannerList: [{
 						imageUrl: '../../static/image/zcy_gzj1.png'
diff --git a/static/ezuikit.js b/static/ezuikit.js
new file mode 100644
index 0000000..3e2b871
--- /dev/null
+++ b/static/ezuikit.js
@@ -0,0 +1,35929 @@
+'use strict';
+
+function _typeof(obj) {
+  "@babel/helpers - typeof";
+
+  return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
+    return typeof obj;
+  } : function (obj) {
+    return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+  }, _typeof(obj);
+}
+
+function _classCallCheck$1(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$1(Constructor, protoProps, staticProps) {
+  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+  if (staticProps) _defineProperties(Constructor, staticProps);
+  Object.defineProperty(Constructor, "prototype", {
+    writable: false
+  });
+  return Constructor;
+}
+
+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 Core = /*#__PURE__*/function () {
+  function Core(x, y) {
+    _classCallCheck$1(this, Core);
+
+    this.coreX = x;
+    this.coreY = y;
+  }
+
+  _createClass$1(Core, [{
+    key: "toString",
+    value: function toString() {
+      return "".concat(this.coreX, "-").concat(this.coreY);
+    }
+  }]);
+
+  return Core;
+}();
+
+// eslint-disable-next-line no-extend-native
+Date.prototype.Format = function (fmt) {
+  var o = {
+    "M+": this.getMonth() + 1,
+    "d+": this.getDate(),
+    "h+": this.getHours(),
+    "m+": this.getMinutes(),
+    "s+": this.getSeconds(),
+    "q+": Math.floor((this.getMonth() + 3) / 3),
+    "S": this.getMilliseconds()
+  };
+
+  if (/(y+)/.test(fmt)) {
+    fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+  }
+
+  for (var k in o) {
+    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
+  }
+
+  return fmt;
+}; // 鍔犺浇js
+
+
+var addJs = function addJs(filepath, callback, isReadyFun) {
+  var headerScript = document.getElementsByTagName('head')[0].getElementsByTagName("script");
+  var isReady = false;
+
+  if (isReadyFun) {
+    isReady = isReadyFun();
+  } else {
+    for (var i = 0; i < headerScript.length; i++) {
+      if (headerScript[i].getAttribute("src") == filepath) {
+        isReady = true;
+        callback();
+      }
+    }
+  }
+
+  if (!isReady) {
+    var oJs = document.createElement("script");
+    oJs.setAttribute("src", filepath);
+    oJs.setAttribute("crossorigin", true);
+    oJs.onload = callback;
+    document.getElementsByTagName("head")[0].appendChild(oJs);
+  } else {
+    callback();
+  }
+};
+var addCss = function addCss(filepath, callback) {
+  var headerLink = document.getElementsByTagName('head')[0].getElementsByTagName("link");
+  var isReady = false;
+
+  for (var i = 0; i < headerLink.length; i++) {
+    if (headerLink[i].getAttribute("href") == filepath) {
+      isReady = true;
+    }
+  }
+
+  if (!isReady) {
+    var oJs = document.createElement('link');
+    oJs.rel = 'stylesheet';
+    oJs.type = 'text/css';
+    oJs.href = filepath;
+    oJs.onload = callback;
+    document.getElementsByTagName("head")[0].appendChild(oJs);
+  }
+};
+var isPromise = function isPromise(obj) {
+  return !!obj && (_typeof(obj) === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
+};
+var getQueryString = function getQueryString(name, url) {
+  var r = new RegExp("(\\?|#|&)" + name + "=(.*?)(#|&|$)");
+  var m = (url || window.location.href).match(r);
+  return decodeURIComponent(m ? m[2] : '');
+};
+var insertAfter$1 = function insertAfter(newElement, targetElement) {
+  var parent = targetElement.parentNode;
+
+  if (parent.lastChild == targetElement) {
+    parent.appendChild(newElement);
+  } else {
+    parent.insertBefore(newElement, targetElement.nextSibling);
+  }
+};
+var requestFullScreen = function requestFullScreen(element) {
+  console.log("requestFullScreen", document.getElementById(element));
+  var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
+
+  if (requestMethod) {
+    requestMethod.call(element);
+  } else if (typeof window.ActiveXObject !== "undefined") {
+    var wscript = new window.ActiveXObject("WScript.Shell");
+
+    if (wscript !== null) {
+      wscript.SendKeys("{F11}");
+    }
+  }
+};
+var requestMobileFullScreen = function requestMobileFullScreen(element) {
+  var width = document.documentElement.clientWidth;
+  var height = document.documentElement.clientHeight;
+  var wrapper = element;
+  var style = "";
+  style += "width:" + height + "px;"; // 娉ㄦ剰鏃嬭浆鍚庣殑瀹介珮鍒囨崲
+
+  style += "height:" + width + "px;";
+  style += "-webkit-transform: rotate(90.001deg); transform: rotate(90.001deg);"; // 娉ㄦ剰鏃嬭浆涓偣鐨勫鐞�
+
+  style += "-webkit-transform-origin: " + width / 2 + "px " + width / 2 + "px;";
+  style += "transform-origin: " + width / 2 + "px " + width / 2 + "px;";
+  style += 'position: fixed;top: 0;left: 0;z-index:10';
+  wrapper.style.cssText = style;
+};
+var requestFullScreenPromise = function requestFullScreenPromise(element) {
+  requestFullScreen(element);
+  var promise = new Promise(function (resolve, reject) {
+    var timeInterval = setInterval(function () {
+      var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+
+      if (isFullScreen) {
+        clearInterval(timeInterval);
+        return resolve(true);
+      }
+    }, 100);
+    var timeOut = setTimeout(function () {
+      var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+
+      if (!isFullScreen) {
+        reject(false);
+      }
+
+      clearTimeout(timeOut);
+    }, 2000);
+  });
+  return promise;
+};
+var cancelMobileFullScreen = function cancelMobileFullScreen(element, width, height) {
+  var style = "";
+  style += "width:" + width + "px;";
+  style += "height:" + height + "px;";
+  style += "-webkit-transform: none; transform: none;";
+  style += "-webkit-transform-origin: 0 0;";
+  style += "transform-origin: 0 0;";
+  element.style.cssText = style;
+};
+var cancelFullScreen = function cancelFullScreen() {
+  if (document.exitFullscreen) {
+    document.exitFullscreen();
+  } else if (document.webkitCancelFullScreen) {
+    document.webkitCancelFullScreen();
+  } else if (document.mozCancelFullScreen) {
+    document.mozCancelFullScreen();
+  }
+};
+var cancelFullScreenPromise = function cancelFullScreenPromise(element) {
+  cancelFullScreen();
+  var promise = new Promise(function (resolve, reject) {
+    var timeInterval = setInterval(function () {
+      var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+
+      if (!isFullScreen) {
+        clearInterval(timeInterval);
+        return resolve(true);
+      }
+    }, 50);
+    var timeOut = setTimeout(function () {
+      var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+
+      if (isFullScreen) {
+        reject(false);
+      }
+
+      clearTimeout(timeOut);
+    }, 2000);
+  });
+  return promise;
+};
+var matchEzopenUrl = function matchEzopenUrl(ezopenUrl) {
+  var deviceSerial = ezopenUrl.split("/")[3];
+  var channelNo = ezopenUrl.split("/")[4].split(".")[0];
+  var validCode = ezopenUrl.split("/")[2].split("@").length === 2 ? ezopenUrl.split("/")[2].split("@")[0] : "";
+  var hd = ezopenUrl.indexOf('.hd') !== -1;
+  var type = ezopenUrl.split("/")[4].split(".")[ezopenUrl.split("/")[4].split(".").length - 1].split("?")[0];
+
+  if (type === 'rec' && ezopenUrl.indexOf(".cloud.rec") !== -1) {
+    type = 'cloud.rec';
+  }
+
+  return {
+    deviceSerial: deviceSerial,
+    channelNo: channelNo,
+    validCode: validCode,
+    hd: hd,
+    type: type
+  };
+};
+
+function isJSON(str) {
+  if (typeof str === 'string') {
+    try {
+      var obj = JSON.parse(str);
+
+      if (_typeof(obj) === 'object' && obj) {
+        return true;
+      }
+
+      return false;
+    } catch (e) {
+      return false;
+    }
+  }
+
+  console.log('It is not a string!');
+}
+
+var request = function request(url, method, params, header, success, error) {
+  var _url = url;
+  var http_request = new XMLHttpRequest();
+
+  http_request.onreadystatechange = function () {
+    if (http_request.readyState == 4) {
+      if (http_request.status == 200) {
+        if (isJSON(http_request.responseText)) {
+          var _data = JSON.parse(http_request.responseText);
+
+          success(_data);
+        } else {
+          success(http_request.responseText);
+        }
+      }
+    }
+  };
+
+  http_request.open(method, _url, true); // http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+  var data = new FormData();
+
+  for (var i in params) {
+    data.append(i, params[i]);
+  }
+
+  http_request.send(data);
+};
+
+var HLS = /*#__PURE__*/function () {
+  function HLS(videoId, url) {
+    var _this = this;
+
+    _classCallCheck$1(this, HLS);
+
+    addJs("https://open.ys7.com/assets/ezuikit_v3.4/js/hls.js", function () {
+      console.log("鍔犺浇hls.min.js鎴愬姛", window.Hls);
+      console.log("isSupportHls", window.Hls.isSupported());
+
+      if (window.Hls.isSupported()) {
+        _this.initHLS(videoId, url);
+      }
+    }, function () {
+      return !!window.Hls;
+    });
+  }
+
+  _createClass$1(HLS, [{
+    key: "toString",
+    value: function toString() {
+      return "hls ".concat(this.coreX, "-").concat(this.coreY);
+    }
+  }, {
+    key: "initHLS",
+    value: function initHLS(videoId, hlsUrl) {
+      var video = document.getElementById(videoId);
+      var hls = new window.Hls({
+        defaultAudioCodec: 'mp4a.40.2'
+      }); // 钀ょ煶璁惧榛樿浣跨敤 AAC LC 闊抽缂栫爜
+
+      hls.loadSource(hlsUrl);
+      hls.attachMedia(video);
+      hls.on(window.Hls.Events.MANIFEST_PARSED, function () {
+        video.play();
+      });
+      hls.on(window.Hls.Events.ERROR, function (event, data) {
+        if (data.fatal) {
+          switch (data.type) {
+            case window.Hls.ErrorTypes.NETWORK_ERROR:
+              // try to recover network error
+              console.log("fatal network error encountered, try to recover");
+              hls.startLoad();
+              break;
+
+            case window.Hls.ErrorTypes.MEDIA_ERROR:
+              console.log("fatal media error encountered, try to recover");
+              hls.recoverMediaError();
+              break;
+
+            default:
+              // cannot recover
+              hls.destroy();
+              break;
+          }
+        }
+      });
+      this.hls = hls;
+      this.video = video;
+      this.hlsUrl = hlsUrl;
+    }
+  }, {
+    key: "play",
+    value: function play() {
+      console.log("鎵цhls鎾斁", this.video);
+      this.hls.startLoad(); // this.video.src = this.hlsUrl;
+
+      this.video.play();
+    }
+  }, {
+    key: "stop",
+    value: function stop() {
+      // 閫氳繃鏆傚仠鍋滄鎾斁
+      // this.video.pause();
+      // this.video.src = "";
+      this.video.pause(); // 鍋滄鍙栨祦
+
+      this.hls.stopLoad(); // this.hls.destroy();
+    }
+  }]);
+
+  return HLS;
+}();
+
+var FLV = /*#__PURE__*/function () {
+  function FLV(videoId, url) {
+    var _this = this;
+
+    _classCallCheck$1(this, FLV);
+
+    addJs("https://open.ys7.com/sdk/js/2.0/js/flv.min.js", function () {
+      console.log("鍔犺浇flv.min.js鎴愬姛", window.flvjs);
+      console.log("isSupportFlv", window.flvjs.isSupported());
+
+      if (window.flvjs.isSupported()) {
+        _this.initFLV(videoId, url);
+      }
+    });
+  }
+
+  _createClass$1(FLV, [{
+    key: "toString",
+    value: function toString() {
+      return "Flv ".concat(this.coreX, "-").concat(this.coreY);
+    }
+  }, {
+    key: "initFLV",
+    value: function initFLV(videoId, flvUrl) {
+      var video = document.getElementById(videoId);
+      var hasControls = video.getAttribute('controls');
+
+      if (!hasControls) {
+        video.setAttribute('controls', true);
+      }
+
+      var flvPlayer = window.flvjs.createPlayer({
+        type: 'flv',
+        url: flvUrl,
+        isLive: true
+      }, {
+        enableStashBuffer: true,
+        stashInitialSize: 128,
+        enableWorker: true
+      });
+      flvPlayer.attachMediaElement(video);
+      flvPlayer.load();
+      flvPlayer.play();
+      this.flvUrl = flvUrl;
+      this.flv = flvPlayer;
+      this.video = video;
+    }
+  }, {
+    key: "play",
+    value: function play() {
+      console.log("鎵цflv鎾斁", this.video);
+      this.video.play();
+    }
+  }, {
+    key: "stop",
+    value: function stop() {
+      // 閫氳繃鏆傚仠鍋滄鎾斁
+      // this.video.pause();
+      // this.video.src = "";
+      this.video.pause(); // 鍋滄鍙栨祦
+
+      this.flv.unload(); // this.hls.destroy();
+    }
+  }]);
+
+  return FLV;
+}();
+
+var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
+
+function createCommonjsModule(fn, module) {
+	return module = { exports: {} }, fn(module, module.exports), module.exports;
+}
+
+var lodash = createCommonjsModule(function (module, exports) {
+(function(){/** Used as a safe reference for `undefined` in pre-ES5 environments. */var undefined$1;/** Used as the semantic version number. */var VERSION='4.17.21';/** Used as the size to enable large array optimizations. */var LARGE_ARRAY_SIZE=200;/** Error message constants. */var CORE_ERROR_TEXT='Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',FUNC_ERROR_TEXT='Expected a function',INVALID_TEMPL_VAR_ERROR_TEXT='Invalid `variable` option passed into `_.template`';/** Used to stand-in for `undefined` hash values. */var HASH_UNDEFINED='__lodash_hash_undefined__';/** Used as the maximum memoize cache size. */var MAX_MEMOIZE_SIZE=500;/** Used as the internal argument placeholder. */var PLACEHOLDER='__lodash_placeholder__';/** Used to compose bitmasks for cloning. */var CLONE_DEEP_FLAG=1,CLONE_FLAT_FLAG=2,CLONE_SYMBOLS_FLAG=4;/** Used to compose bitmasks for value comparisons. */var COMPARE_PARTIAL_FLAG=1,COMPARE_UNORDERED_FLAG=2;/** Used to compose bitmasks for function metadata. */var WRAP_BIND_FLAG=1,WRAP_BIND_KEY_FLAG=2,WRAP_CURRY_BOUND_FLAG=4,WRAP_CURRY_FLAG=8,WRAP_CURRY_RIGHT_FLAG=16,WRAP_PARTIAL_FLAG=32,WRAP_PARTIAL_RIGHT_FLAG=64,WRAP_ARY_FLAG=128,WRAP_REARG_FLAG=256,WRAP_FLIP_FLAG=512;/** Used as default options for `_.truncate`. */var DEFAULT_TRUNC_LENGTH=30,DEFAULT_TRUNC_OMISSION='...';/** Used to detect hot functions by number of calls within a span of milliseconds. */var HOT_COUNT=800,HOT_SPAN=16;/** Used to indicate the type of lazy iteratees. */var LAZY_FILTER_FLAG=1,LAZY_MAP_FLAG=2,LAZY_WHILE_FLAG=3;/** Used as references for various `Number` constants. */var INFINITY=1/0,MAX_SAFE_INTEGER=9007199254740991,MAX_INTEGER=1.7976931348623157e+308,NAN=0/0;/** Used as references for the maximum length and index of an array. */var MAX_ARRAY_LENGTH=4294967295,MAX_ARRAY_INDEX=MAX_ARRAY_LENGTH-1,HALF_MAX_ARRAY_LENGTH=MAX_ARRAY_LENGTH>>>1;/** Used to associate wrap methods with their bit flags. */var wrapFlags=[['ary',WRAP_ARY_FLAG],['bind',WRAP_BIND_FLAG],['bindKey',WRAP_BIND_KEY_FLAG],['curry',WRAP_CURRY_FLAG],['curryRight',WRAP_CURRY_RIGHT_FLAG],['flip',WRAP_FLIP_FLAG],['partial',WRAP_PARTIAL_FLAG],['partialRight',WRAP_PARTIAL_RIGHT_FLAG],['rearg',WRAP_REARG_FLAG]];/** `Object#toString` result references. */var argsTag='[object Arguments]',arrayTag='[object Array]',asyncTag='[object AsyncFunction]',boolTag='[object Boolean]',dateTag='[object Date]',domExcTag='[object DOMException]',errorTag='[object Error]',funcTag='[object Function]',genTag='[object GeneratorFunction]',mapTag='[object Map]',numberTag='[object Number]',nullTag='[object Null]',objectTag='[object Object]',promiseTag='[object Promise]',proxyTag='[object Proxy]',regexpTag='[object RegExp]',setTag='[object Set]',stringTag='[object String]',symbolTag='[object Symbol]',undefinedTag='[object Undefined]',weakMapTag='[object WeakMap]',weakSetTag='[object WeakSet]';var arrayBufferTag='[object ArrayBuffer]',dataViewTag='[object DataView]',float32Tag='[object Float32Array]',float64Tag='[object Float64Array]',int8Tag='[object Int8Array]',int16Tag='[object Int16Array]',int32Tag='[object Int32Array]',uint8Tag='[object Uint8Array]',uint8ClampedTag='[object Uint8ClampedArray]',uint16Tag='[object Uint16Array]',uint32Tag='[object Uint32Array]';/** Used to match empty string literals in compiled template source. */var reEmptyStringLeading=/\b__p \+= '';/g,reEmptyStringMiddle=/\b(__p \+=) '' \+/g,reEmptyStringTrailing=/(__e\(.*?\)|\b__t\)) \+\n'';/g;/** Used to match HTML entities and HTML characters. */var reEscapedHtml=/&(?:amp|lt|gt|quot|#39);/g,reUnescapedHtml=/[&<>"']/g,reHasEscapedHtml=RegExp(reEscapedHtml.source),reHasUnescapedHtml=RegExp(reUnescapedHtml.source);/** Used to match template delimiters. */var reEscape=/<%-([\s\S]+?)%>/g,reEvaluate=/<%([\s\S]+?)%>/g,reInterpolate=/<%=([\s\S]+?)%>/g;/** Used to match property names within property paths. */var reIsDeepProp=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,reIsPlainProp=/^\w*$/,rePropName=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;/**
+   * Used to match `RegExp`
+   * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
+   */var reRegExpChar=/[\\^$.*+?()[\]{}|]/g,reHasRegExpChar=RegExp(reRegExpChar.source);/** Used to match leading whitespace. */var reTrimStart=/^\s+/;/** Used to match a single whitespace character. */var reWhitespace=/\s/;/** Used to match wrap detail comments. */var reWrapComment=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,reWrapDetails=/\{\n\/\* \[wrapped with (.+)\] \*/,reSplitDetails=/,? & /;/** Used to match words composed of alphanumeric characters. */var reAsciiWord=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;/**
+   * Used to validate the `validate` option in `_.template` variable.
+   *
+   * Forbids characters which could potentially change the meaning of the function argument definition:
+   * - "()," (modification of function parameters)
+   * - "=" (default value)
+   * - "[]{}" (destructuring of function parameters)
+   * - "/" (beginning of a comment)
+   * - whitespace
+   */var reForbiddenIdentifierChars=/[()=,{}\[\]\/\s]/;/** Used to match backslashes in property paths. */var reEscapeChar=/\\(\\)?/g;/**
+   * Used to match
+   * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
+   */var reEsTemplate=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;/** Used to match `RegExp` flags from their coerced string values. */var reFlags=/\w*$/;/** Used to detect bad signed hexadecimal string values. */var reIsBadHex=/^[-+]0x[0-9a-f]+$/i;/** Used to detect binary string values. */var reIsBinary=/^0b[01]+$/i;/** Used to detect host constructors (Safari). */var reIsHostCtor=/^\[object .+?Constructor\]$/;/** Used to detect octal string values. */var reIsOctal=/^0o[0-7]+$/i;/** Used to detect unsigned integer values. */var reIsUint=/^(?:0|[1-9]\d*)$/;/** Used to match Latin Unicode letters (excluding mathematical operators). */var reLatin=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;/** Used to ensure capturing order of template delimiters. */var reNoMatch=/($^)/;/** Used to match unescaped characters in compiled string literals. */var reUnescapedString=/['\n\r\u2028\u2029\\]/g;/** Used to compose unicode character classes. */var rsAstralRange='\\ud800-\\udfff',rsComboMarksRange='\\u0300-\\u036f',reComboHalfMarksRange='\\ufe20-\\ufe2f',rsComboSymbolsRange='\\u20d0-\\u20ff',rsComboRange=rsComboMarksRange+reComboHalfMarksRange+rsComboSymbolsRange,rsDingbatRange='\\u2700-\\u27bf',rsLowerRange='a-z\\xdf-\\xf6\\xf8-\\xff',rsMathOpRange='\\xac\\xb1\\xd7\\xf7',rsNonCharRange='\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',rsPunctuationRange='\\u2000-\\u206f',rsSpaceRange=' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',rsUpperRange='A-Z\\xc0-\\xd6\\xd8-\\xde',rsVarRange='\\ufe0e\\ufe0f',rsBreakRange=rsMathOpRange+rsNonCharRange+rsPunctuationRange+rsSpaceRange;/** Used to compose unicode capture groups. */var rsApos="['\u2019]",rsAstral='['+rsAstralRange+']',rsBreak='['+rsBreakRange+']',rsCombo='['+rsComboRange+']',rsDigits='\\d+',rsDingbat='['+rsDingbatRange+']',rsLower='['+rsLowerRange+']',rsMisc='[^'+rsAstralRange+rsBreakRange+rsDigits+rsDingbatRange+rsLowerRange+rsUpperRange+']',rsFitz='\\ud83c[\\udffb-\\udfff]',rsModifier='(?:'+rsCombo+'|'+rsFitz+')',rsNonAstral='[^'+rsAstralRange+']',rsRegional='(?:\\ud83c[\\udde6-\\uddff]){2}',rsSurrPair='[\\ud800-\\udbff][\\udc00-\\udfff]',rsUpper='['+rsUpperRange+']',rsZWJ='\\u200d';/** Used to compose unicode regexes. */var rsMiscLower='(?:'+rsLower+'|'+rsMisc+')',rsMiscUpper='(?:'+rsUpper+'|'+rsMisc+')',rsOptContrLower='(?:'+rsApos+'(?:d|ll|m|re|s|t|ve))?',rsOptContrUpper='(?:'+rsApos+'(?:D|LL|M|RE|S|T|VE))?',reOptMod=rsModifier+'?',rsOptVar='['+rsVarRange+']?',rsOptJoin='(?:'+rsZWJ+'(?:'+[rsNonAstral,rsRegional,rsSurrPair].join('|')+')'+rsOptVar+reOptMod+')*',rsOrdLower='\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',rsOrdUpper='\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',rsSeq=rsOptVar+reOptMod+rsOptJoin,rsEmoji='(?:'+[rsDingbat,rsRegional,rsSurrPair].join('|')+')'+rsSeq,rsSymbol='(?:'+[rsNonAstral+rsCombo+'?',rsCombo,rsRegional,rsSurrPair,rsAstral].join('|')+')';/** Used to match apostrophes. */var reApos=RegExp(rsApos,'g');/**
+   * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
+   * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
+   */var reComboMark=RegExp(rsCombo,'g');/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */var reUnicode=RegExp(rsFitz+'(?='+rsFitz+')|'+rsSymbol+rsSeq,'g');/** Used to match complex or compound words. */var reUnicodeWord=RegExp([rsUpper+'?'+rsLower+'+'+rsOptContrLower+'(?='+[rsBreak,rsUpper,'$'].join('|')+')',rsMiscUpper+'+'+rsOptContrUpper+'(?='+[rsBreak,rsUpper+rsMiscLower,'$'].join('|')+')',rsUpper+'?'+rsMiscLower+'+'+rsOptContrLower,rsUpper+'+'+rsOptContrUpper,rsOrdUpper,rsOrdLower,rsDigits,rsEmoji].join('|'),'g');/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */var reHasUnicode=RegExp('['+rsZWJ+rsAstralRange+rsComboRange+rsVarRange+']');/** Used to detect strings that need a more robust regexp to match words. */var reHasUnicodeWord=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;/** Used to assign default `context` object properties. */var contextProps=['Array','Buffer','DataView','Date','Error','Float32Array','Float64Array','Function','Int8Array','Int16Array','Int32Array','Map','Math','Object','Promise','RegExp','Set','String','Symbol','TypeError','Uint8Array','Uint8ClampedArray','Uint16Array','Uint32Array','WeakMap','_','clearTimeout','isFinite','parseInt','setTimeout'];/** Used to make template sourceURLs easier to identify. */var templateCounter=-1;/** Used to identify `toStringTag` values of typed arrays. */var typedArrayTags={};typedArrayTags[float32Tag]=typedArrayTags[float64Tag]=typedArrayTags[int8Tag]=typedArrayTags[int16Tag]=typedArrayTags[int32Tag]=typedArrayTags[uint8Tag]=typedArrayTags[uint8ClampedTag]=typedArrayTags[uint16Tag]=typedArrayTags[uint32Tag]=true;typedArrayTags[argsTag]=typedArrayTags[arrayTag]=typedArrayTags[arrayBufferTag]=typedArrayTags[boolTag]=typedArrayTags[dataViewTag]=typedArrayTags[dateTag]=typedArrayTags[errorTag]=typedArrayTags[funcTag]=typedArrayTags[mapTag]=typedArrayTags[numberTag]=typedArrayTags[objectTag]=typedArrayTags[regexpTag]=typedArrayTags[setTag]=typedArrayTags[stringTag]=typedArrayTags[weakMapTag]=false;/** Used to identify `toStringTag` values supported by `_.clone`. */var cloneableTags={};cloneableTags[argsTag]=cloneableTags[arrayTag]=cloneableTags[arrayBufferTag]=cloneableTags[dataViewTag]=cloneableTags[boolTag]=cloneableTags[dateTag]=cloneableTags[float32Tag]=cloneableTags[float64Tag]=cloneableTags[int8Tag]=cloneableTags[int16Tag]=cloneableTags[int32Tag]=cloneableTags[mapTag]=cloneableTags[numberTag]=cloneableTags[objectTag]=cloneableTags[regexpTag]=cloneableTags[setTag]=cloneableTags[stringTag]=cloneableTags[symbolTag]=cloneableTags[uint8Tag]=cloneableTags[uint8ClampedTag]=cloneableTags[uint16Tag]=cloneableTags[uint32Tag]=true;cloneableTags[errorTag]=cloneableTags[funcTag]=cloneableTags[weakMapTag]=false;/** Used to map Latin Unicode letters to basic Latin letters. */var deburredLetters={// Latin-1 Supplement block.
+'\xc0':'A','\xc1':'A','\xc2':'A','\xc3':'A','\xc4':'A','\xc5':'A','\xe0':'a','\xe1':'a','\xe2':'a','\xe3':'a','\xe4':'a','\xe5':'a','\xc7':'C','\xe7':'c','\xd0':'D','\xf0':'d','\xc8':'E','\xc9':'E','\xca':'E','\xcb':'E','\xe8':'e','\xe9':'e','\xea':'e','\xeb':'e','\xcc':'I','\xcd':'I','\xce':'I','\xcf':'I','\xec':'i','\xed':'i','\xee':'i','\xef':'i','\xd1':'N','\xf1':'n','\xd2':'O','\xd3':'O','\xd4':'O','\xd5':'O','\xd6':'O','\xd8':'O','\xf2':'o','\xf3':'o','\xf4':'o','\xf5':'o','\xf6':'o','\xf8':'o','\xd9':'U','\xda':'U','\xdb':'U','\xdc':'U','\xf9':'u','\xfa':'u','\xfb':'u','\xfc':'u','\xdd':'Y','\xfd':'y','\xff':'y','\xc6':'Ae','\xe6':'ae','\xde':'Th','\xfe':'th','\xdf':'ss',// Latin Extended-A block.
+'\u0100':'A','\u0102':'A','\u0104':'A','\u0101':'a','\u0103':'a','\u0105':'a','\u0106':'C','\u0108':'C','\u010a':'C','\u010c':'C','\u0107':'c','\u0109':'c','\u010b':'c','\u010d':'c','\u010e':'D','\u0110':'D','\u010f':'d','\u0111':'d','\u0112':'E','\u0114':'E','\u0116':'E','\u0118':'E','\u011a':'E','\u0113':'e','\u0115':'e','\u0117':'e','\u0119':'e','\u011b':'e','\u011c':'G','\u011e':'G','\u0120':'G','\u0122':'G','\u011d':'g','\u011f':'g','\u0121':'g','\u0123':'g','\u0124':'H','\u0126':'H','\u0125':'h','\u0127':'h','\u0128':'I','\u012a':'I','\u012c':'I','\u012e':'I','\u0130':'I','\u0129':'i','\u012b':'i','\u012d':'i','\u012f':'i','\u0131':'i','\u0134':'J','\u0135':'j','\u0136':'K','\u0137':'k','\u0138':'k','\u0139':'L','\u013b':'L','\u013d':'L','\u013f':'L','\u0141':'L','\u013a':'l','\u013c':'l','\u013e':'l','\u0140':'l','\u0142':'l','\u0143':'N','\u0145':'N','\u0147':'N','\u014a':'N','\u0144':'n','\u0146':'n','\u0148':'n','\u014b':'n','\u014c':'O','\u014e':'O','\u0150':'O','\u014d':'o','\u014f':'o','\u0151':'o','\u0154':'R','\u0156':'R','\u0158':'R','\u0155':'r','\u0157':'r','\u0159':'r','\u015a':'S','\u015c':'S','\u015e':'S','\u0160':'S','\u015b':'s','\u015d':'s','\u015f':'s','\u0161':'s','\u0162':'T','\u0164':'T','\u0166':'T','\u0163':'t','\u0165':'t','\u0167':'t','\u0168':'U','\u016a':'U','\u016c':'U','\u016e':'U','\u0170':'U','\u0172':'U','\u0169':'u','\u016b':'u','\u016d':'u','\u016f':'u','\u0171':'u','\u0173':'u','\u0174':'W','\u0175':'w','\u0176':'Y','\u0177':'y','\u0178':'Y','\u0179':'Z','\u017b':'Z','\u017d':'Z','\u017a':'z','\u017c':'z','\u017e':'z','\u0132':'IJ','\u0133':'ij','\u0152':'Oe','\u0153':'oe','\u0149':"'n",'\u017f':'s'};/** Used to map characters to HTML entities. */var htmlEscapes={'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'};/** Used to map HTML entities to characters. */var htmlUnescapes={'&amp;':'&','&lt;':'<','&gt;':'>','&quot;':'"','&#39;':"'"};/** Used to escape characters for inclusion in compiled string literals. */var stringEscapes={'\\':'\\',"'":"'",'\n':'n','\r':'r','\u2028':'u2028','\u2029':'u2029'};/** Built-in method references without a dependency on `root`. */var freeParseFloat=parseFloat,freeParseInt=parseInt;/** Detect free variable `global` from Node.js. */var freeGlobal=typeof commonjsGlobal=='object'&&commonjsGlobal&&commonjsGlobal.Object===Object&&commonjsGlobal;/** Detect free variable `self`. */var freeSelf=typeof self=='object'&&self&&self.Object===Object&&self;/** Used as a reference to the global object. */var root=freeGlobal||freeSelf||Function('return this')();/** Detect free variable `exports`. */var freeExports=exports&&!exports.nodeType&&exports;/** Detect free variable `module`. */var freeModule=freeExports&&'object'=='object'&&module&&!module.nodeType&&module;/** Detect the popular CommonJS extension `module.exports`. */var moduleExports=freeModule&&freeModule.exports===freeExports;/** Detect free variable `process` from Node.js. */var freeProcess=moduleExports&&freeGlobal.process;/** Used to access faster Node.js helpers. */var nodeUtil=function(){try{// Use `util.types` for Node.js 10+.
+var types=freeModule&&freeModule.require&&freeModule.require('util').types;if(types){return types;}// Legacy `process.binding('util')` for Node.js < 10.
+return freeProcess&&freeProcess.binding&&freeProcess.binding('util');}catch(e){}}();/* Node.js helper references. */var nodeIsArrayBuffer=nodeUtil&&nodeUtil.isArrayBuffer,nodeIsDate=nodeUtil&&nodeUtil.isDate,nodeIsMap=nodeUtil&&nodeUtil.isMap,nodeIsRegExp=nodeUtil&&nodeUtil.isRegExp,nodeIsSet=nodeUtil&&nodeUtil.isSet,nodeIsTypedArray=nodeUtil&&nodeUtil.isTypedArray;/*--------------------------------------------------------------------------*/ /**
+   * A faster alternative to `Function#apply`, this function invokes `func`
+   * with the `this` binding of `thisArg` and the arguments of `args`.
+   *
+   * @private
+   * @param {Function} func The function to invoke.
+   * @param {*} thisArg The `this` binding of `func`.
+   * @param {Array} args The arguments to invoke `func` with.
+   * @returns {*} Returns the result of `func`.
+   */function apply(func,thisArg,args){switch(args.length){case 0:return func.call(thisArg);case 1:return func.call(thisArg,args[0]);case 2:return func.call(thisArg,args[0],args[1]);case 3:return func.call(thisArg,args[0],args[1],args[2]);}return func.apply(thisArg,args);}/**
+   * A specialized version of `baseAggregator` for arrays.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} setter The function to set `accumulator` values.
+   * @param {Function} iteratee The iteratee to transform keys.
+   * @param {Object} accumulator The initial aggregated object.
+   * @returns {Function} Returns `accumulator`.
+   */function arrayAggregator(array,setter,iteratee,accumulator){var index=-1,length=array==null?0:array.length;while(++index<length){var value=array[index];setter(accumulator,value,iteratee(value),array);}return accumulator;}/**
+   * A specialized version of `_.forEach` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns `array`.
+   */function arrayEach(array,iteratee){var index=-1,length=array==null?0:array.length;while(++index<length){if(iteratee(array[index],index,array)===false){break;}}return array;}/**
+   * A specialized version of `_.forEachRight` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns `array`.
+   */function arrayEachRight(array,iteratee){var length=array==null?0:array.length;while(length--){if(iteratee(array[length],length,array)===false){break;}}return array;}/**
+   * A specialized version of `_.every` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} predicate The function invoked per iteration.
+   * @returns {boolean} Returns `true` if all elements pass the predicate check,
+   *  else `false`.
+   */function arrayEvery(array,predicate){var index=-1,length=array==null?0:array.length;while(++index<length){if(!predicate(array[index],index,array)){return false;}}return true;}/**
+   * A specialized version of `_.filter` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} predicate The function invoked per iteration.
+   * @returns {Array} Returns the new filtered array.
+   */function arrayFilter(array,predicate){var index=-1,length=array==null?0:array.length,resIndex=0,result=[];while(++index<length){var value=array[index];if(predicate(value,index,array)){result[resIndex++]=value;}}return result;}/**
+   * A specialized version of `_.includes` for arrays without support for
+   * specifying an index to search from.
+   *
+   * @private
+   * @param {Array} [array] The array to inspect.
+   * @param {*} target The value to search for.
+   * @returns {boolean} Returns `true` if `target` is found, else `false`.
+   */function arrayIncludes(array,value){var length=array==null?0:array.length;return !!length&&baseIndexOf(array,value,0)>-1;}/**
+   * This function is like `arrayIncludes` except that it accepts a comparator.
+   *
+   * @private
+   * @param {Array} [array] The array to inspect.
+   * @param {*} target The value to search for.
+   * @param {Function} comparator The comparator invoked per element.
+   * @returns {boolean} Returns `true` if `target` is found, else `false`.
+   */function arrayIncludesWith(array,value,comparator){var index=-1,length=array==null?0:array.length;while(++index<length){if(comparator(value,array[index])){return true;}}return false;}/**
+   * A specialized version of `_.map` for arrays without support for iteratee
+   * shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns the new mapped array.
+   */function arrayMap(array,iteratee){var index=-1,length=array==null?0:array.length,result=Array(length);while(++index<length){result[index]=iteratee(array[index],index,array);}return result;}/**
+   * Appends the elements of `values` to `array`.
+   *
+   * @private
+   * @param {Array} array The array to modify.
+   * @param {Array} values The values to append.
+   * @returns {Array} Returns `array`.
+   */function arrayPush(array,values){var index=-1,length=values.length,offset=array.length;while(++index<length){array[offset+index]=values[index];}return array;}/**
+   * A specialized version of `_.reduce` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @param {*} [accumulator] The initial value.
+   * @param {boolean} [initAccum] Specify using the first element of `array` as
+   *  the initial value.
+   * @returns {*} Returns the accumulated value.
+   */function arrayReduce(array,iteratee,accumulator,initAccum){var index=-1,length=array==null?0:array.length;if(initAccum&&length){accumulator=array[++index];}while(++index<length){accumulator=iteratee(accumulator,array[index],index,array);}return accumulator;}/**
+   * A specialized version of `_.reduceRight` for arrays without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @param {*} [accumulator] The initial value.
+   * @param {boolean} [initAccum] Specify using the last element of `array` as
+   *  the initial value.
+   * @returns {*} Returns the accumulated value.
+   */function arrayReduceRight(array,iteratee,accumulator,initAccum){var length=array==null?0:array.length;if(initAccum&&length){accumulator=array[--length];}while(length--){accumulator=iteratee(accumulator,array[length],length,array);}return accumulator;}/**
+   * A specialized version of `_.some` for arrays without support for iteratee
+   * shorthands.
+   *
+   * @private
+   * @param {Array} [array] The array to iterate over.
+   * @param {Function} predicate The function invoked per iteration.
+   * @returns {boolean} Returns `true` if any element passes the predicate check,
+   *  else `false`.
+   */function arraySome(array,predicate){var index=-1,length=array==null?0:array.length;while(++index<length){if(predicate(array[index],index,array)){return true;}}return false;}/**
+   * Gets the size of an ASCII `string`.
+   *
+   * @private
+   * @param {string} string The string inspect.
+   * @returns {number} Returns the string size.
+   */var asciiSize=baseProperty('length');/**
+   * Converts an ASCII `string` to an array.
+   *
+   * @private
+   * @param {string} string The string to convert.
+   * @returns {Array} Returns the converted array.
+   */function asciiToArray(string){return string.split('');}/**
+   * Splits an ASCII `string` into an array of its words.
+   *
+   * @private
+   * @param {string} The string to inspect.
+   * @returns {Array} Returns the words of `string`.
+   */function asciiWords(string){return string.match(reAsciiWord)||[];}/**
+   * The base implementation of methods like `_.findKey` and `_.findLastKey`,
+   * without support for iteratee shorthands, which iterates over `collection`
+   * using `eachFunc`.
+   *
+   * @private
+   * @param {Array|Object} collection The collection to inspect.
+   * @param {Function} predicate The function invoked per iteration.
+   * @param {Function} eachFunc The function to iterate over `collection`.
+   * @returns {*} Returns the found element or its key, else `undefined`.
+   */function baseFindKey(collection,predicate,eachFunc){var result;eachFunc(collection,function(value,key,collection){if(predicate(value,key,collection)){result=key;return false;}});return result;}/**
+   * The base implementation of `_.findIndex` and `_.findLastIndex` without
+   * support for iteratee shorthands.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {Function} predicate The function invoked per iteration.
+   * @param {number} fromIndex The index to search from.
+   * @param {boolean} [fromRight] Specify iterating from right to left.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */function baseFindIndex(array,predicate,fromIndex,fromRight){var length=array.length,index=fromIndex+(fromRight?1:-1);while(fromRight?index--:++index<length){if(predicate(array[index],index,array)){return index;}}return -1;}/**
+   * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */function baseIndexOf(array,value,fromIndex){return value===value?strictIndexOf(array,value,fromIndex):baseFindIndex(array,baseIsNaN,fromIndex);}/**
+   * This function is like `baseIndexOf` except that it accepts a comparator.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @param {Function} comparator The comparator invoked per element.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */function baseIndexOfWith(array,value,fromIndex,comparator){var index=fromIndex-1,length=array.length;while(++index<length){if(comparator(array[index],value)){return index;}}return -1;}/**
+   * The base implementation of `_.isNaN` without support for number objects.
+   *
+   * @private
+   * @param {*} value The value to check.
+   * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+   */function baseIsNaN(value){return value!==value;}/**
+   * The base implementation of `_.mean` and `_.meanBy` without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} array The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {number} Returns the mean.
+   */function baseMean(array,iteratee){var length=array==null?0:array.length;return length?baseSum(array,iteratee)/length:NAN;}/**
+   * The base implementation of `_.property` without support for deep paths.
+   *
+   * @private
+   * @param {string} key The key of the property to get.
+   * @returns {Function} Returns the new accessor function.
+   */function baseProperty(key){return function(object){return object==null?undefined$1:object[key];};}/**
+   * The base implementation of `_.propertyOf` without support for deep paths.
+   *
+   * @private
+   * @param {Object} object The object to query.
+   * @returns {Function} Returns the new accessor function.
+   */function basePropertyOf(object){return function(key){return object==null?undefined$1:object[key];};}/**
+   * The base implementation of `_.reduce` and `_.reduceRight`, without support
+   * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
+   *
+   * @private
+   * @param {Array|Object} collection The collection to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @param {*} accumulator The initial value.
+   * @param {boolean} initAccum Specify using the first or last element of
+   *  `collection` as the initial value.
+   * @param {Function} eachFunc The function to iterate over `collection`.
+   * @returns {*} Returns the accumulated value.
+   */function baseReduce(collection,iteratee,accumulator,initAccum,eachFunc){eachFunc(collection,function(value,index,collection){accumulator=initAccum?(initAccum=false,value):iteratee(accumulator,value,index,collection);});return accumulator;}/**
+   * The base implementation of `_.sortBy` which uses `comparer` to define the
+   * sort order of `array` and replaces criteria objects with their corresponding
+   * values.
+   *
+   * @private
+   * @param {Array} array The array to sort.
+   * @param {Function} comparer The function to define sort order.
+   * @returns {Array} Returns `array`.
+   */function baseSortBy(array,comparer){var length=array.length;array.sort(comparer);while(length--){array[length]=array[length].value;}return array;}/**
+   * The base implementation of `_.sum` and `_.sumBy` without support for
+   * iteratee shorthands.
+   *
+   * @private
+   * @param {Array} array The array to iterate over.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {number} Returns the sum.
+   */function baseSum(array,iteratee){var result,index=-1,length=array.length;while(++index<length){var current=iteratee(array[index]);if(current!==undefined$1){result=result===undefined$1?current:result+current;}}return result;}/**
+   * The base implementation of `_.times` without support for iteratee shorthands
+   * or max array length checks.
+   *
+   * @private
+   * @param {number} n The number of times to invoke `iteratee`.
+   * @param {Function} iteratee The function invoked per iteration.
+   * @returns {Array} Returns the array of results.
+   */function baseTimes(n,iteratee){var index=-1,result=Array(n);while(++index<n){result[index]=iteratee(index);}return result;}/**
+   * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
+   * of key-value pairs for `object` corresponding to the property names of `props`.
+   *
+   * @private
+   * @param {Object} object The object to query.
+   * @param {Array} props The property names to get values for.
+   * @returns {Object} Returns the key-value pairs.
+   */function baseToPairs(object,props){return arrayMap(props,function(key){return [key,object[key]];});}/**
+   * The base implementation of `_.trim`.
+   *
+   * @private
+   * @param {string} string The string to trim.
+   * @returns {string} Returns the trimmed string.
+   */function baseTrim(string){return string?string.slice(0,trimmedEndIndex(string)+1).replace(reTrimStart,''):string;}/**
+   * The base implementation of `_.unary` without support for storing metadata.
+   *
+   * @private
+   * @param {Function} func The function to cap arguments for.
+   * @returns {Function} Returns the new capped function.
+   */function baseUnary(func){return function(value){return func(value);};}/**
+   * The base implementation of `_.values` and `_.valuesIn` which creates an
+   * array of `object` property values corresponding to the property names
+   * of `props`.
+   *
+   * @private
+   * @param {Object} object The object to query.
+   * @param {Array} props The property names to get values for.
+   * @returns {Object} Returns the array of property values.
+   */function baseValues(object,props){return arrayMap(props,function(key){return object[key];});}/**
+   * Checks if a `cache` value for `key` exists.
+   *
+   * @private
+   * @param {Object} cache The cache to query.
+   * @param {string} key The key of the entry to check.
+   * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+   */function cacheHas(cache,key){return cache.has(key);}/**
+   * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
+   * that is not found in the character symbols.
+   *
+   * @private
+   * @param {Array} strSymbols The string symbols to inspect.
+   * @param {Array} chrSymbols The character symbols to find.
+   * @returns {number} Returns the index of the first unmatched string symbol.
+   */function charsStartIndex(strSymbols,chrSymbols){var index=-1,length=strSymbols.length;while(++index<length&&baseIndexOf(chrSymbols,strSymbols[index],0)>-1){}return index;}/**
+   * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
+   * that is not found in the character symbols.
+   *
+   * @private
+   * @param {Array} strSymbols The string symbols to inspect.
+   * @param {Array} chrSymbols The character symbols to find.
+   * @returns {number} Returns the index of the last unmatched string symbol.
+   */function charsEndIndex(strSymbols,chrSymbols){var index=strSymbols.length;while(index--&&baseIndexOf(chrSymbols,strSymbols[index],0)>-1){}return index;}/**
+   * Gets the number of `placeholder` occurrences in `array`.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} placeholder The placeholder to search for.
+   * @returns {number} Returns the placeholder count.
+   */function countHolders(array,placeholder){var length=array.length,result=0;while(length--){if(array[length]===placeholder){++result;}}return result;}/**
+   * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
+   * letters to basic Latin letters.
+   *
+   * @private
+   * @param {string} letter The matched letter to deburr.
+   * @returns {string} Returns the deburred letter.
+   */var deburrLetter=basePropertyOf(deburredLetters);/**
+   * Used by `_.escape` to convert characters to HTML entities.
+   *
+   * @private
+   * @param {string} chr The matched character to escape.
+   * @returns {string} Returns the escaped character.
+   */var escapeHtmlChar=basePropertyOf(htmlEscapes);/**
+   * Used by `_.template` to escape characters for inclusion in compiled string literals.
+   *
+   * @private
+   * @param {string} chr The matched character to escape.
+   * @returns {string} Returns the escaped character.
+   */function escapeStringChar(chr){return '\\'+stringEscapes[chr];}/**
+   * Gets the value at `key` of `object`.
+   *
+   * @private
+   * @param {Object} [object] The object to query.
+   * @param {string} key The key of the property to get.
+   * @returns {*} Returns the property value.
+   */function getValue(object,key){return object==null?undefined$1:object[key];}/**
+   * Checks if `string` contains Unicode symbols.
+   *
+   * @private
+   * @param {string} string The string to inspect.
+   * @returns {boolean} Returns `true` if a symbol is found, else `false`.
+   */function hasUnicode(string){return reHasUnicode.test(string);}/**
+   * Checks if `string` contains a word composed of Unicode symbols.
+   *
+   * @private
+   * @param {string} string The string to inspect.
+   * @returns {boolean} Returns `true` if a word is found, else `false`.
+   */function hasUnicodeWord(string){return reHasUnicodeWord.test(string);}/**
+   * Converts `iterator` to an array.
+   *
+   * @private
+   * @param {Object} iterator The iterator to convert.
+   * @returns {Array} Returns the converted array.
+   */function iteratorToArray(iterator){var data,result=[];while(!(data=iterator.next()).done){result.push(data.value);}return result;}/**
+   * Converts `map` to its key-value pairs.
+   *
+   * @private
+   * @param {Object} map The map to convert.
+   * @returns {Array} Returns the key-value pairs.
+   */function mapToArray(map){var index=-1,result=Array(map.size);map.forEach(function(value,key){result[++index]=[key,value];});return result;}/**
+   * Creates a unary function that invokes `func` with its argument transformed.
+   *
+   * @private
+   * @param {Function} func The function to wrap.
+   * @param {Function} transform The argument transform.
+   * @returns {Function} Returns the new function.
+   */function overArg(func,transform){return function(arg){return func(transform(arg));};}/**
+   * Replaces all `placeholder` elements in `array` with an internal placeholder
+   * and returns an array of their indexes.
+   *
+   * @private
+   * @param {Array} array The array to modify.
+   * @param {*} placeholder The placeholder to replace.
+   * @returns {Array} Returns the new array of placeholder indexes.
+   */function replaceHolders(array,placeholder){var index=-1,length=array.length,resIndex=0,result=[];while(++index<length){var value=array[index];if(value===placeholder||value===PLACEHOLDER){array[index]=PLACEHOLDER;result[resIndex++]=index;}}return result;}/**
+   * Converts `set` to an array of its values.
+   *
+   * @private
+   * @param {Object} set The set to convert.
+   * @returns {Array} Returns the values.
+   */function setToArray(set){var index=-1,result=Array(set.size);set.forEach(function(value){result[++index]=value;});return result;}/**
+   * Converts `set` to its value-value pairs.
+   *
+   * @private
+   * @param {Object} set The set to convert.
+   * @returns {Array} Returns the value-value pairs.
+   */function setToPairs(set){var index=-1,result=Array(set.size);set.forEach(function(value){result[++index]=[value,value];});return result;}/**
+   * A specialized version of `_.indexOf` which performs strict equality
+   * comparisons of values, i.e. `===`.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */function strictIndexOf(array,value,fromIndex){var index=fromIndex-1,length=array.length;while(++index<length){if(array[index]===value){return index;}}return -1;}/**
+   * A specialized version of `_.lastIndexOf` which performs strict equality
+   * comparisons of values, i.e. `===`.
+   *
+   * @private
+   * @param {Array} array The array to inspect.
+   * @param {*} value The value to search for.
+   * @param {number} fromIndex The index to search from.
+   * @returns {number} Returns the index of the matched value, else `-1`.
+   */function strictLastIndexOf(array,value,fromIndex){var index=fromIndex+1;while(index--){if(array[index]===value){return index;}}return index;}/**
+   * Gets the number of symbols in `string`.
+   *
+   * @private
+   * @param {string} string The string to inspect.
+   * @returns {number} Returns the string size.
+   */function stringSize(string){return hasUnicode(string)?unicodeSize(string):asciiSize(string);}/**
+   * Converts `string` to an array.
+   *
+   * @private
+   * @param {string} string The string to convert.
+   * @returns {Array} Returns the converted array.
+   */function stringToArray(string){return hasUnicode(string)?unicodeToArray(string):asciiToArray(string);}/**
+   * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
+   * character of `string`.
+   *
+   * @private
+   * @param {string} string The string to inspect.
+   * @returns {number} Returns the index of the last non-whitespace character.
+   */function trimmedEndIndex(string){var index=string.length;while(index--&&reWhitespace.test(string.charAt(index))){}return index;}/**
+   * Used by `_.unescape` to convert HTML entities to characters.
+   *
+   * @private
+   * @param {string} chr The matched character to unescape.
+   * @returns {string} Returns the unescaped character.
+   */var unescapeHtmlChar=basePropertyOf(htmlUnescapes);/**
+   * Gets the size of a Unicode `string`.
+   *
+   * @private
+   * @param {string} string The string inspect.
+   * @returns {number} Returns the string size.
+   */function unicodeSize(string){var result=reUnicode.lastIndex=0;while(reUnicode.test(string)){++result;}return result;}/**
+   * Converts a Unicode `string` to an array.
+   *
+   * @private
+   * @param {string} string The string to convert.
+   * @returns {Array} Returns the converted array.
+   */function unicodeToArray(string){return string.match(reUnicode)||[];}/**
+   * Splits a Unicode `string` into an array of its words.
+   *
+   * @private
+   * @param {string} The string to inspect.
+   * @returns {Array} Returns the words of `string`.
+   */function unicodeWords(string){return string.match(reUnicodeWord)||[];}/*--------------------------------------------------------------------------*/ /**
+   * Create a new pristine `lodash` function using the `context` object.
+   *
+   * @static
+   * @memberOf _
+   * @since 1.1.0
+   * @category Util
+   * @param {Object} [context=root] The context object.
+   * @returns {Function} Returns a new `lodash` function.
+   * @example
+   *
+   * _.mixin({ 'foo': _.constant('foo') });
+   *
+   * var lodash = _.runInContext();
+   * lodash.mixin({ 'bar': lodash.constant('bar') });
+   *
+   * _.isFunction(_.foo);
+   * // => true
+   * _.isFunction(_.bar);
+   * // => false
+   *
+   * lodash.isFunction(lodash.foo);
+   * // => false
+   * lodash.isFunction(lodash.bar);
+   * // => true
+   *
+   * // Create a suped-up `defer` in Node.js.
+   * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
+   */var runInContext=function runInContext(context){context=context==null?root:_.defaults(root.Object(),context,_.pick(root,contextProps));/** Built-in constructor references. */var Array=context.Array,Date=context.Date,Error=context.Error,Function=context.Function,Math=context.Math,Object=context.Object,RegExp=context.RegExp,String=context.String,TypeError=context.TypeError;/** Used for built-in method references. */var arrayProto=Array.prototype,funcProto=Function.prototype,objectProto=Object.prototype;/** Used to detect overreaching core-js shims. */var coreJsData=context['__core-js_shared__'];/** Used to resolve the decompiled source of functions. */var funcToString=funcProto.toString;/** Used to check objects for own properties. */var hasOwnProperty=objectProto.hasOwnProperty;/** Used to generate unique IDs. */var idCounter=0;/** Used to detect methods masquerading as native. */var maskSrcKey=function(){var uid=/[^.]+$/.exec(coreJsData&&coreJsData.keys&&coreJsData.keys.IE_PROTO||'');return uid?'Symbol(src)_1.'+uid:'';}();/**
+     * Used to resolve the
+     * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
+     * of values.
+     */var nativeObjectToString=objectProto.toString;/** Used to infer the `Object` constructor. */var objectCtorString=funcToString.call(Object);/** Used to restore the original `_` reference in `_.noConflict`. */var oldDash=root._;/** Used to detect if a method is native. */var reIsNative=RegExp('^'+funcToString.call(hasOwnProperty).replace(reRegExpChar,'\\$&').replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,'$1.*?')+'$');/** Built-in value references. */var Buffer=moduleExports?context.Buffer:undefined$1,Symbol=context.Symbol,Uint8Array=context.Uint8Array,allocUnsafe=Buffer?Buffer.allocUnsafe:undefined$1,getPrototype=overArg(Object.getPrototypeOf,Object),objectCreate=Object.create,propertyIsEnumerable=objectProto.propertyIsEnumerable,splice=arrayProto.splice,spreadableSymbol=Symbol?Symbol.isConcatSpreadable:undefined$1,symIterator=Symbol?Symbol.iterator:undefined$1,symToStringTag=Symbol?Symbol.toStringTag:undefined$1;var defineProperty=function(){try{var func=getNative(Object,'defineProperty');func({},'',{});return func;}catch(e){}}();/** Mocked built-ins. */var ctxClearTimeout=context.clearTimeout!==root.clearTimeout&&context.clearTimeout,ctxNow=Date&&Date.now!==root.Date.now&&Date.now,ctxSetTimeout=context.setTimeout!==root.setTimeout&&context.setTimeout;/* Built-in method references for those with the same name as other `lodash` methods. */var nativeCeil=Math.ceil,nativeFloor=Math.floor,nativeGetSymbols=Object.getOwnPropertySymbols,nativeIsBuffer=Buffer?Buffer.isBuffer:undefined$1,nativeIsFinite=context.isFinite,nativeJoin=arrayProto.join,nativeKeys=overArg(Object.keys,Object),nativeMax=Math.max,nativeMin=Math.min,nativeNow=Date.now,nativeParseInt=context.parseInt,nativeRandom=Math.random,nativeReverse=arrayProto.reverse;/* Built-in method references that are verified to be native. */var DataView=getNative(context,'DataView'),Map=getNative(context,'Map'),Promise=getNative(context,'Promise'),Set=getNative(context,'Set'),WeakMap=getNative(context,'WeakMap'),nativeCreate=getNative(Object,'create');/** Used to store function metadata. */var metaMap=WeakMap&&new WeakMap();/** Used to lookup unminified function names. */var realNames={};/** Used to detect maps, sets, and weakmaps. */var dataViewCtorString=toSource(DataView),mapCtorString=toSource(Map),promiseCtorString=toSource(Promise),setCtorString=toSource(Set),weakMapCtorString=toSource(WeakMap);/** Used to convert symbols to primitives and strings. */var symbolProto=Symbol?Symbol.prototype:undefined$1,symbolValueOf=symbolProto?symbolProto.valueOf:undefined$1,symbolToString=symbolProto?symbolProto.toString:undefined$1;/*------------------------------------------------------------------------*/ /**
+     * Creates a `lodash` object which wraps `value` to enable implicit method
+     * chain sequences. Methods that operate on and return arrays, collections,
+     * and functions can be chained together. Methods that retrieve a single value
+     * or may return a primitive value will automatically end the chain sequence
+     * and return the unwrapped value. Otherwise, the value must be unwrapped
+     * with `_#value`.
+     *
+     * Explicit chain sequences, which must be unwrapped with `_#value`, may be
+     * enabled using `_.chain`.
+     *
+     * The execution of chained methods is lazy, that is, it's deferred until
+     * `_#value` is implicitly or explicitly called.
+     *
+     * Lazy evaluation allows several methods to support shortcut fusion.
+     * Shortcut fusion is an optimization to merge iteratee calls; this avoids
+     * the creation of intermediate arrays and can greatly reduce the number of
+     * iteratee executions. Sections of a chain sequence qualify for shortcut
+     * fusion if the section is applied to an array and iteratees accept only
+     * one argument. The heuristic for whether a section qualifies for shortcut
+     * fusion is subject to change.
+     *
+     * Chaining is supported in custom builds as long as the `_#value` method is
+     * directly or indirectly included in the build.
+     *
+     * In addition to lodash methods, wrappers have `Array` and `String` methods.
+     *
+     * The wrapper `Array` methods are:
+     * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
+     *
+     * The wrapper `String` methods are:
+     * `replace` and `split`
+     *
+     * The wrapper methods that support shortcut fusion are:
+     * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
+     * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
+     * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
+     *
+     * The chainable wrapper methods are:
+     * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
+     * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
+     * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
+     * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
+     * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
+     * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
+     * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
+     * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
+     * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
+     * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
+     * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
+     * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
+     * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
+     * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
+     * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
+     * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
+     * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
+     * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
+     * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
+     * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
+     * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
+     * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
+     * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
+     * `zipObject`, `zipObjectDeep`, and `zipWith`
+     *
+     * The wrapper methods that are **not** chainable by default are:
+     * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
+     * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
+     * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
+     * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
+     * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
+     * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
+     * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
+     * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
+     * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
+     * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
+     * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
+     * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
+     * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
+     * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
+     * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
+     * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
+     * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
+     * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
+     * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
+     * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
+     * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
+     * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
+     * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
+     * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
+     * `upperFirst`, `value`, and `words`
+     *
+     * @name _
+     * @constructor
+     * @category Seq
+     * @param {*} value The value to wrap in a `lodash` instance.
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * function square(n) {
+     *   return n * n;
+     * }
+     *
+     * var wrapped = _([1, 2, 3]);
+     *
+     * // Returns an unwrapped value.
+     * wrapped.reduce(_.add);
+     * // => 6
+     *
+     * // Returns a wrapped value.
+     * var squares = wrapped.map(square);
+     *
+     * _.isArray(squares);
+     * // => false
+     *
+     * _.isArray(squares.value());
+     * // => true
+     */function lodash(value){if(isObjectLike(value)&&!isArray(value)&&!(value instanceof LazyWrapper)){if(value instanceof LodashWrapper){return value;}if(hasOwnProperty.call(value,'__wrapped__')){return wrapperClone(value);}}return new LodashWrapper(value);}/**
+     * The base implementation of `_.create` without support for assigning
+     * properties to the created object.
+     *
+     * @private
+     * @param {Object} proto The object to inherit from.
+     * @returns {Object} Returns the new object.
+     */var baseCreate=function(){function object(){}return function(proto){if(!isObject(proto)){return {};}if(objectCreate){return objectCreate(proto);}object.prototype=proto;var result=new object();object.prototype=undefined$1;return result;};}();/**
+     * The function whose prototype chain sequence wrappers inherit from.
+     *
+     * @private
+     */function baseLodash(){// No operation performed.
+}/**
+     * The base constructor for creating `lodash` wrapper objects.
+     *
+     * @private
+     * @param {*} value The value to wrap.
+     * @param {boolean} [chainAll] Enable explicit method chain sequences.
+     */function LodashWrapper(value,chainAll){this.__wrapped__=value;this.__actions__=[];this.__chain__=!!chainAll;this.__index__=0;this.__values__=undefined$1;}/**
+     * By default, the template delimiters used by lodash are like those in
+     * embedded Ruby (ERB) as well as ES2015 template strings. Change the
+     * following template settings to use alternative delimiters.
+     *
+     * @static
+     * @memberOf _
+     * @type {Object}
+     */lodash.templateSettings={/**
+       * Used to detect `data` property values to be HTML-escaped.
+       *
+       * @memberOf _.templateSettings
+       * @type {RegExp}
+       */'escape':reEscape,/**
+       * Used to detect code to be evaluated.
+       *
+       * @memberOf _.templateSettings
+       * @type {RegExp}
+       */'evaluate':reEvaluate,/**
+       * Used to detect `data` property values to inject.
+       *
+       * @memberOf _.templateSettings
+       * @type {RegExp}
+       */'interpolate':reInterpolate,/**
+       * Used to reference the data object in the template text.
+       *
+       * @memberOf _.templateSettings
+       * @type {string}
+       */'variable':'',/**
+       * Used to import variables into the compiled template.
+       *
+       * @memberOf _.templateSettings
+       * @type {Object}
+       */'imports':{/**
+         * A reference to the `lodash` function.
+         *
+         * @memberOf _.templateSettings.imports
+         * @type {Function}
+         */'_':lodash}};// Ensure wrappers are instances of `baseLodash`.
+lodash.prototype=baseLodash.prototype;lodash.prototype.constructor=lodash;LodashWrapper.prototype=baseCreate(baseLodash.prototype);LodashWrapper.prototype.constructor=LodashWrapper;/*------------------------------------------------------------------------*/ /**
+     * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
+     *
+     * @private
+     * @constructor
+     * @param {*} value The value to wrap.
+     */function LazyWrapper(value){this.__wrapped__=value;this.__actions__=[];this.__dir__=1;this.__filtered__=false;this.__iteratees__=[];this.__takeCount__=MAX_ARRAY_LENGTH;this.__views__=[];}/**
+     * Creates a clone of the lazy wrapper object.
+     *
+     * @private
+     * @name clone
+     * @memberOf LazyWrapper
+     * @returns {Object} Returns the cloned `LazyWrapper` object.
+     */function lazyClone(){var result=new LazyWrapper(this.__wrapped__);result.__actions__=copyArray(this.__actions__);result.__dir__=this.__dir__;result.__filtered__=this.__filtered__;result.__iteratees__=copyArray(this.__iteratees__);result.__takeCount__=this.__takeCount__;result.__views__=copyArray(this.__views__);return result;}/**
+     * Reverses the direction of lazy iteration.
+     *
+     * @private
+     * @name reverse
+     * @memberOf LazyWrapper
+     * @returns {Object} Returns the new reversed `LazyWrapper` object.
+     */function lazyReverse(){if(this.__filtered__){var result=new LazyWrapper(this);result.__dir__=-1;result.__filtered__=true;}else {result=this.clone();result.__dir__*=-1;}return result;}/**
+     * Extracts the unwrapped value from its lazy wrapper.
+     *
+     * @private
+     * @name value
+     * @memberOf LazyWrapper
+     * @returns {*} Returns the unwrapped value.
+     */function lazyValue(){var array=this.__wrapped__.value(),dir=this.__dir__,isArr=isArray(array),isRight=dir<0,arrLength=isArr?array.length:0,view=getView(0,arrLength,this.__views__),start=view.start,end=view.end,length=end-start,index=isRight?end:start-1,iteratees=this.__iteratees__,iterLength=iteratees.length,resIndex=0,takeCount=nativeMin(length,this.__takeCount__);if(!isArr||!isRight&&arrLength==length&&takeCount==length){return baseWrapperValue(array,this.__actions__);}var result=[];outer:while(length--&&resIndex<takeCount){index+=dir;var iterIndex=-1,value=array[index];while(++iterIndex<iterLength){var data=iteratees[iterIndex],iteratee=data.iteratee,type=data.type,computed=iteratee(value);if(type==LAZY_MAP_FLAG){value=computed;}else if(!computed){if(type==LAZY_FILTER_FLAG){continue outer;}else {break outer;}}}result[resIndex++]=value;}return result;}// Ensure `LazyWrapper` is an instance of `baseLodash`.
+LazyWrapper.prototype=baseCreate(baseLodash.prototype);LazyWrapper.prototype.constructor=LazyWrapper;/*------------------------------------------------------------------------*/ /**
+     * Creates a hash object.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */function Hash(entries){var index=-1,length=entries==null?0:entries.length;this.clear();while(++index<length){var entry=entries[index];this.set(entry[0],entry[1]);}}/**
+     * Removes all key-value entries from the hash.
+     *
+     * @private
+     * @name clear
+     * @memberOf Hash
+     */function hashClear(){this.__data__=nativeCreate?nativeCreate(null):{};this.size=0;}/**
+     * Removes `key` and its value from the hash.
+     *
+     * @private
+     * @name delete
+     * @memberOf Hash
+     * @param {Object} hash The hash to modify.
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */function hashDelete(key){var result=this.has(key)&&delete this.__data__[key];this.size-=result?1:0;return result;}/**
+     * Gets the hash value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf Hash
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */function hashGet(key){var data=this.__data__;if(nativeCreate){var result=data[key];return result===HASH_UNDEFINED?undefined$1:result;}return hasOwnProperty.call(data,key)?data[key]:undefined$1;}/**
+     * Checks if a hash value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf Hash
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */function hashHas(key){var data=this.__data__;return nativeCreate?data[key]!==undefined$1:hasOwnProperty.call(data,key);}/**
+     * Sets the hash `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf Hash
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the hash instance.
+     */function hashSet(key,value){var data=this.__data__;this.size+=this.has(key)?0:1;data[key]=nativeCreate&&value===undefined$1?HASH_UNDEFINED:value;return this;}// Add methods to `Hash`.
+Hash.prototype.clear=hashClear;Hash.prototype['delete']=hashDelete;Hash.prototype.get=hashGet;Hash.prototype.has=hashHas;Hash.prototype.set=hashSet;/*------------------------------------------------------------------------*/ /**
+     * Creates an list cache object.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */function ListCache(entries){var index=-1,length=entries==null?0:entries.length;this.clear();while(++index<length){var entry=entries[index];this.set(entry[0],entry[1]);}}/**
+     * Removes all key-value entries from the list cache.
+     *
+     * @private
+     * @name clear
+     * @memberOf ListCache
+     */function listCacheClear(){this.__data__=[];this.size=0;}/**
+     * Removes `key` and its value from the list cache.
+     *
+     * @private
+     * @name delete
+     * @memberOf ListCache
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */function listCacheDelete(key){var data=this.__data__,index=assocIndexOf(data,key);if(index<0){return false;}var lastIndex=data.length-1;if(index==lastIndex){data.pop();}else {splice.call(data,index,1);}--this.size;return true;}/**
+     * Gets the list cache value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf ListCache
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */function listCacheGet(key){var data=this.__data__,index=assocIndexOf(data,key);return index<0?undefined$1:data[index][1];}/**
+     * Checks if a list cache value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf ListCache
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */function listCacheHas(key){return assocIndexOf(this.__data__,key)>-1;}/**
+     * Sets the list cache `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf ListCache
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the list cache instance.
+     */function listCacheSet(key,value){var data=this.__data__,index=assocIndexOf(data,key);if(index<0){++this.size;data.push([key,value]);}else {data[index][1]=value;}return this;}// Add methods to `ListCache`.
+ListCache.prototype.clear=listCacheClear;ListCache.prototype['delete']=listCacheDelete;ListCache.prototype.get=listCacheGet;ListCache.prototype.has=listCacheHas;ListCache.prototype.set=listCacheSet;/*------------------------------------------------------------------------*/ /**
+     * Creates a map cache object to store key-value pairs.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */function MapCache(entries){var index=-1,length=entries==null?0:entries.length;this.clear();while(++index<length){var entry=entries[index];this.set(entry[0],entry[1]);}}/**
+     * Removes all key-value entries from the map.
+     *
+     * @private
+     * @name clear
+     * @memberOf MapCache
+     */function mapCacheClear(){this.size=0;this.__data__={'hash':new Hash(),'map':new(Map||ListCache)(),'string':new Hash()};}/**
+     * Removes `key` and its value from the map.
+     *
+     * @private
+     * @name delete
+     * @memberOf MapCache
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */function mapCacheDelete(key){var result=getMapData(this,key)['delete'](key);this.size-=result?1:0;return result;}/**
+     * Gets the map value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf MapCache
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */function mapCacheGet(key){return getMapData(this,key).get(key);}/**
+     * Checks if a map value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf MapCache
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */function mapCacheHas(key){return getMapData(this,key).has(key);}/**
+     * Sets the map `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf MapCache
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the map cache instance.
+     */function mapCacheSet(key,value){var data=getMapData(this,key),size=data.size;data.set(key,value);this.size+=data.size==size?0:1;return this;}// Add methods to `MapCache`.
+MapCache.prototype.clear=mapCacheClear;MapCache.prototype['delete']=mapCacheDelete;MapCache.prototype.get=mapCacheGet;MapCache.prototype.has=mapCacheHas;MapCache.prototype.set=mapCacheSet;/*------------------------------------------------------------------------*/ /**
+     *
+     * Creates an array cache object to store unique values.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [values] The values to cache.
+     */function SetCache(values){var index=-1,length=values==null?0:values.length;this.__data__=new MapCache();while(++index<length){this.add(values[index]);}}/**
+     * Adds `value` to the array cache.
+     *
+     * @private
+     * @name add
+     * @memberOf SetCache
+     * @alias push
+     * @param {*} value The value to cache.
+     * @returns {Object} Returns the cache instance.
+     */function setCacheAdd(value){this.__data__.set(value,HASH_UNDEFINED);return this;}/**
+     * Checks if `value` is in the array cache.
+     *
+     * @private
+     * @name has
+     * @memberOf SetCache
+     * @param {*} value The value to search for.
+     * @returns {number} Returns `true` if `value` is found, else `false`.
+     */function setCacheHas(value){return this.__data__.has(value);}// Add methods to `SetCache`.
+SetCache.prototype.add=SetCache.prototype.push=setCacheAdd;SetCache.prototype.has=setCacheHas;/*------------------------------------------------------------------------*/ /**
+     * Creates a stack cache object to store key-value pairs.
+     *
+     * @private
+     * @constructor
+     * @param {Array} [entries] The key-value pairs to cache.
+     */function Stack(entries){var data=this.__data__=new ListCache(entries);this.size=data.size;}/**
+     * Removes all key-value entries from the stack.
+     *
+     * @private
+     * @name clear
+     * @memberOf Stack
+     */function stackClear(){this.__data__=new ListCache();this.size=0;}/**
+     * Removes `key` and its value from the stack.
+     *
+     * @private
+     * @name delete
+     * @memberOf Stack
+     * @param {string} key The key of the value to remove.
+     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
+     */function stackDelete(key){var data=this.__data__,result=data['delete'](key);this.size=data.size;return result;}/**
+     * Gets the stack value for `key`.
+     *
+     * @private
+     * @name get
+     * @memberOf Stack
+     * @param {string} key The key of the value to get.
+     * @returns {*} Returns the entry value.
+     */function stackGet(key){return this.__data__.get(key);}/**
+     * Checks if a stack value for `key` exists.
+     *
+     * @private
+     * @name has
+     * @memberOf Stack
+     * @param {string} key The key of the entry to check.
+     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
+     */function stackHas(key){return this.__data__.has(key);}/**
+     * Sets the stack `key` to `value`.
+     *
+     * @private
+     * @name set
+     * @memberOf Stack
+     * @param {string} key The key of the value to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns the stack cache instance.
+     */function stackSet(key,value){var data=this.__data__;if(data instanceof ListCache){var pairs=data.__data__;if(!Map||pairs.length<LARGE_ARRAY_SIZE-1){pairs.push([key,value]);this.size=++data.size;return this;}data=this.__data__=new MapCache(pairs);}data.set(key,value);this.size=data.size;return this;}// Add methods to `Stack`.
+Stack.prototype.clear=stackClear;Stack.prototype['delete']=stackDelete;Stack.prototype.get=stackGet;Stack.prototype.has=stackHas;Stack.prototype.set=stackSet;/*------------------------------------------------------------------------*/ /**
+     * Creates an array of the enumerable property names of the array-like `value`.
+     *
+     * @private
+     * @param {*} value The value to query.
+     * @param {boolean} inherited Specify returning inherited property names.
+     * @returns {Array} Returns the array of property names.
+     */function arrayLikeKeys(value,inherited){var isArr=isArray(value),isArg=!isArr&&isArguments(value),isBuff=!isArr&&!isArg&&isBuffer(value),isType=!isArr&&!isArg&&!isBuff&&isTypedArray(value),skipIndexes=isArr||isArg||isBuff||isType,result=skipIndexes?baseTimes(value.length,String):[],length=result.length;for(var key in value){if((inherited||hasOwnProperty.call(value,key))&&!(skipIndexes&&(// Safari 9 has enumerable `arguments.length` in strict mode.
+key=='length'||// Node.js 0.10 has enumerable non-index properties on buffers.
+isBuff&&(key=='offset'||key=='parent')||// PhantomJS 2 has enumerable non-index properties on typed arrays.
+isType&&(key=='buffer'||key=='byteLength'||key=='byteOffset')||// Skip index properties.
+isIndex(key,length)))){result.push(key);}}return result;}/**
+     * A specialized version of `_.sample` for arrays.
+     *
+     * @private
+     * @param {Array} array The array to sample.
+     * @returns {*} Returns the random element.
+     */function arraySample(array){var length=array.length;return length?array[baseRandom(0,length-1)]:undefined$1;}/**
+     * A specialized version of `_.sampleSize` for arrays.
+     *
+     * @private
+     * @param {Array} array The array to sample.
+     * @param {number} n The number of elements to sample.
+     * @returns {Array} Returns the random elements.
+     */function arraySampleSize(array,n){return shuffleSelf(copyArray(array),baseClamp(n,0,array.length));}/**
+     * A specialized version of `_.shuffle` for arrays.
+     *
+     * @private
+     * @param {Array} array The array to shuffle.
+     * @returns {Array} Returns the new shuffled array.
+     */function arrayShuffle(array){return shuffleSelf(copyArray(array));}/**
+     * This function is like `assignValue` except that it doesn't assign
+     * `undefined` values.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {string} key The key of the property to assign.
+     * @param {*} value The value to assign.
+     */function assignMergeValue(object,key,value){if(value!==undefined$1&&!eq(object[key],value)||value===undefined$1&&!(key in object)){baseAssignValue(object,key,value);}}/**
+     * Assigns `value` to `key` of `object` if the existing value is not equivalent
+     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {string} key The key of the property to assign.
+     * @param {*} value The value to assign.
+     */function assignValue(object,key,value){var objValue=object[key];if(!(hasOwnProperty.call(object,key)&&eq(objValue,value))||value===undefined$1&&!(key in object)){baseAssignValue(object,key,value);}}/**
+     * Gets the index at which the `key` is found in `array` of key-value pairs.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {*} key The key to search for.
+     * @returns {number} Returns the index of the matched value, else `-1`.
+     */function assocIndexOf(array,key){var length=array.length;while(length--){if(eq(array[length][0],key)){return length;}}return -1;}/**
+     * Aggregates elements of `collection` on `accumulator` with keys transformed
+     * by `iteratee` and values set by `setter`.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} setter The function to set `accumulator` values.
+     * @param {Function} iteratee The iteratee to transform keys.
+     * @param {Object} accumulator The initial aggregated object.
+     * @returns {Function} Returns `accumulator`.
+     */function baseAggregator(collection,setter,iteratee,accumulator){baseEach(collection,function(value,key,collection){setter(accumulator,value,iteratee(value),collection);});return accumulator;}/**
+     * The base implementation of `_.assign` without support for multiple sources
+     * or `customizer` functions.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @returns {Object} Returns `object`.
+     */function baseAssign(object,source){return object&&copyObject(source,keys(source),object);}/**
+     * The base implementation of `_.assignIn` without support for multiple sources
+     * or `customizer` functions.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @returns {Object} Returns `object`.
+     */function baseAssignIn(object,source){return object&&copyObject(source,keysIn(source),object);}/**
+     * The base implementation of `assignValue` and `assignMergeValue` without
+     * value checks.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {string} key The key of the property to assign.
+     * @param {*} value The value to assign.
+     */function baseAssignValue(object,key,value){if(key=='__proto__'&&defineProperty){defineProperty(object,key,{'configurable':true,'enumerable':true,'value':value,'writable':true});}else {object[key]=value;}}/**
+     * The base implementation of `_.at` without support for individual paths.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {string[]} paths The property paths to pick.
+     * @returns {Array} Returns the picked elements.
+     */function baseAt(object,paths){var index=-1,length=paths.length,result=Array(length),skip=object==null;while(++index<length){result[index]=skip?undefined$1:get(object,paths[index]);}return result;}/**
+     * The base implementation of `_.clamp` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {number} number The number to clamp.
+     * @param {number} [lower] The lower bound.
+     * @param {number} upper The upper bound.
+     * @returns {number} Returns the clamped number.
+     */function baseClamp(number,lower,upper){if(number===number){if(upper!==undefined$1){number=number<=upper?number:upper;}if(lower!==undefined$1){number=number>=lower?number:lower;}}return number;}/**
+     * The base implementation of `_.clone` and `_.cloneDeep` which tracks
+     * traversed objects.
+     *
+     * @private
+     * @param {*} value The value to clone.
+     * @param {boolean} bitmask The bitmask flags.
+     *  1 - Deep clone
+     *  2 - Flatten inherited properties
+     *  4 - Clone symbols
+     * @param {Function} [customizer] The function to customize cloning.
+     * @param {string} [key] The key of `value`.
+     * @param {Object} [object] The parent object of `value`.
+     * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
+     * @returns {*} Returns the cloned value.
+     */function baseClone(value,bitmask,customizer,key,object,stack){var result,isDeep=bitmask&CLONE_DEEP_FLAG,isFlat=bitmask&CLONE_FLAT_FLAG,isFull=bitmask&CLONE_SYMBOLS_FLAG;if(customizer){result=object?customizer(value,key,object,stack):customizer(value);}if(result!==undefined$1){return result;}if(!isObject(value)){return value;}var isArr=isArray(value);if(isArr){result=initCloneArray(value);if(!isDeep){return copyArray(value,result);}}else {var tag=getTag(value),isFunc=tag==funcTag||tag==genTag;if(isBuffer(value)){return cloneBuffer(value,isDeep);}if(tag==objectTag||tag==argsTag||isFunc&&!object){result=isFlat||isFunc?{}:initCloneObject(value);if(!isDeep){return isFlat?copySymbolsIn(value,baseAssignIn(result,value)):copySymbols(value,baseAssign(result,value));}}else {if(!cloneableTags[tag]){return object?value:{};}result=initCloneByTag(value,tag,isDeep);}}// Check for circular references and return its corresponding clone.
+stack||(stack=new Stack());var stacked=stack.get(value);if(stacked){return stacked;}stack.set(value,result);if(isSet(value)){value.forEach(function(subValue){result.add(baseClone(subValue,bitmask,customizer,subValue,value,stack));});}else if(isMap(value)){value.forEach(function(subValue,key){result.set(key,baseClone(subValue,bitmask,customizer,key,value,stack));});}var keysFunc=isFull?isFlat?getAllKeysIn:getAllKeys:isFlat?keysIn:keys;var props=isArr?undefined$1:keysFunc(value);arrayEach(props||value,function(subValue,key){if(props){key=subValue;subValue=value[key];}// Recursively populate clone (susceptible to call stack limits).
+assignValue(result,key,baseClone(subValue,bitmask,customizer,key,value,stack));});return result;}/**
+     * The base implementation of `_.conforms` which doesn't clone `source`.
+     *
+     * @private
+     * @param {Object} source The object of property predicates to conform to.
+     * @returns {Function} Returns the new spec function.
+     */function baseConforms(source){var props=keys(source);return function(object){return baseConformsTo(object,source,props);};}/**
+     * The base implementation of `_.conformsTo` which accepts `props` to check.
+     *
+     * @private
+     * @param {Object} object The object to inspect.
+     * @param {Object} source The object of property predicates to conform to.
+     * @returns {boolean} Returns `true` if `object` conforms, else `false`.
+     */function baseConformsTo(object,source,props){var length=props.length;if(object==null){return !length;}object=Object(object);while(length--){var key=props[length],predicate=source[key],value=object[key];if(value===undefined$1&&!(key in object)||!predicate(value)){return false;}}return true;}/**
+     * The base implementation of `_.delay` and `_.defer` which accepts `args`
+     * to provide to `func`.
+     *
+     * @private
+     * @param {Function} func The function to delay.
+     * @param {number} wait The number of milliseconds to delay invocation.
+     * @param {Array} args The arguments to provide to `func`.
+     * @returns {number|Object} Returns the timer id or timeout object.
+     */function baseDelay(func,wait,args){if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}return setTimeout(function(){func.apply(undefined$1,args);},wait);}/**
+     * The base implementation of methods like `_.difference` without support
+     * for excluding multiple arrays or iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {Array} values The values to exclude.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of filtered values.
+     */function baseDifference(array,values,iteratee,comparator){var index=-1,includes=arrayIncludes,isCommon=true,length=array.length,result=[],valuesLength=values.length;if(!length){return result;}if(iteratee){values=arrayMap(values,baseUnary(iteratee));}if(comparator){includes=arrayIncludesWith;isCommon=false;}else if(values.length>=LARGE_ARRAY_SIZE){includes=cacheHas;isCommon=false;values=new SetCache(values);}outer:while(++index<length){var value=array[index],computed=iteratee==null?value:iteratee(value);value=comparator||value!==0?value:0;if(isCommon&&computed===computed){var valuesIndex=valuesLength;while(valuesIndex--){if(values[valuesIndex]===computed){continue outer;}}result.push(value);}else if(!includes(values,computed,comparator)){result.push(value);}}return result;}/**
+     * The base implementation of `_.forEach` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Array|Object} Returns `collection`.
+     */var baseEach=createBaseEach(baseForOwn);/**
+     * The base implementation of `_.forEachRight` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Array|Object} Returns `collection`.
+     */var baseEachRight=createBaseEach(baseForOwnRight,true);/**
+     * The base implementation of `_.every` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} predicate The function invoked per iteration.
+     * @returns {boolean} Returns `true` if all elements pass the predicate check,
+     *  else `false`
+     */function baseEvery(collection,predicate){var result=true;baseEach(collection,function(value,index,collection){result=!!predicate(value,index,collection);return result;});return result;}/**
+     * The base implementation of methods like `_.max` and `_.min` which accepts a
+     * `comparator` to determine the extremum value.
+     *
+     * @private
+     * @param {Array} array The array to iterate over.
+     * @param {Function} iteratee The iteratee invoked per iteration.
+     * @param {Function} comparator The comparator used to compare values.
+     * @returns {*} Returns the extremum value.
+     */function baseExtremum(array,iteratee,comparator){var index=-1,length=array.length;while(++index<length){var value=array[index],current=iteratee(value);if(current!=null&&(computed===undefined$1?current===current&&!isSymbol(current):comparator(current,computed))){var computed=current,result=value;}}return result;}/**
+     * The base implementation of `_.fill` without an iteratee call guard.
+     *
+     * @private
+     * @param {Array} array The array to fill.
+     * @param {*} value The value to fill `array` with.
+     * @param {number} [start=0] The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns `array`.
+     */function baseFill(array,value,start,end){var length=array.length;start=toInteger(start);if(start<0){start=-start>length?0:length+start;}end=end===undefined$1||end>length?length:toInteger(end);if(end<0){end+=length;}end=start>end?0:toLength(end);while(start<end){array[start++]=value;}return array;}/**
+     * The base implementation of `_.filter` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} predicate The function invoked per iteration.
+     * @returns {Array} Returns the new filtered array.
+     */function baseFilter(collection,predicate){var result=[];baseEach(collection,function(value,index,collection){if(predicate(value,index,collection)){result.push(value);}});return result;}/**
+     * The base implementation of `_.flatten` with support for restricting flattening.
+     *
+     * @private
+     * @param {Array} array The array to flatten.
+     * @param {number} depth The maximum recursion depth.
+     * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
+     * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
+     * @param {Array} [result=[]] The initial result value.
+     * @returns {Array} Returns the new flattened array.
+     */function baseFlatten(array,depth,predicate,isStrict,result){var index=-1,length=array.length;predicate||(predicate=isFlattenable);result||(result=[]);while(++index<length){var value=array[index];if(depth>0&&predicate(value)){if(depth>1){// Recursively flatten arrays (susceptible to call stack limits).
+baseFlatten(value,depth-1,predicate,isStrict,result);}else {arrayPush(result,value);}}else if(!isStrict){result[result.length]=value;}}return result;}/**
+     * The base implementation of `baseForOwn` which iterates over `object`
+     * properties returned by `keysFunc` and invokes `iteratee` for each property.
+     * Iteratee functions may exit iteration early by explicitly returning `false`.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @param {Function} keysFunc The function to get the keys of `object`.
+     * @returns {Object} Returns `object`.
+     */var baseFor=createBaseFor();/**
+     * This function is like `baseFor` except that it iterates over properties
+     * in the opposite order.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @param {Function} keysFunc The function to get the keys of `object`.
+     * @returns {Object} Returns `object`.
+     */var baseForRight=createBaseFor(true);/**
+     * The base implementation of `_.forOwn` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     */function baseForOwn(object,iteratee){return object&&baseFor(object,iteratee,keys);}/**
+     * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     */function baseForOwnRight(object,iteratee){return object&&baseForRight(object,iteratee,keys);}/**
+     * The base implementation of `_.functions` which creates an array of
+     * `object` function property names filtered from `props`.
+     *
+     * @private
+     * @param {Object} object The object to inspect.
+     * @param {Array} props The property names to filter.
+     * @returns {Array} Returns the function names.
+     */function baseFunctions(object,props){return arrayFilter(props,function(key){return isFunction(object[key]);});}/**
+     * The base implementation of `_.get` without support for default values.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path of the property to get.
+     * @returns {*} Returns the resolved value.
+     */function baseGet(object,path){path=castPath(path,object);var index=0,length=path.length;while(object!=null&&index<length){object=object[toKey(path[index++])];}return index&&index==length?object:undefined$1;}/**
+     * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
+     * `keysFunc` and `symbolsFunc` to get the enumerable property names and
+     * symbols of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Function} keysFunc The function to get the keys of `object`.
+     * @param {Function} symbolsFunc The function to get the symbols of `object`.
+     * @returns {Array} Returns the array of property names and symbols.
+     */function baseGetAllKeys(object,keysFunc,symbolsFunc){var result=keysFunc(object);return isArray(object)?result:arrayPush(result,symbolsFunc(object));}/**
+     * The base implementation of `getTag` without fallbacks for buggy environments.
+     *
+     * @private
+     * @param {*} value The value to query.
+     * @returns {string} Returns the `toStringTag`.
+     */function baseGetTag(value){if(value==null){return value===undefined$1?undefinedTag:nullTag;}return symToStringTag&&symToStringTag in Object(value)?getRawTag(value):objectToString(value);}/**
+     * The base implementation of `_.gt` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is greater than `other`,
+     *  else `false`.
+     */function baseGt(value,other){return value>other;}/**
+     * The base implementation of `_.has` without support for deep paths.
+     *
+     * @private
+     * @param {Object} [object] The object to query.
+     * @param {Array|string} key The key to check.
+     * @returns {boolean} Returns `true` if `key` exists, else `false`.
+     */function baseHas(object,key){return object!=null&&hasOwnProperty.call(object,key);}/**
+     * The base implementation of `_.hasIn` without support for deep paths.
+     *
+     * @private
+     * @param {Object} [object] The object to query.
+     * @param {Array|string} key The key to check.
+     * @returns {boolean} Returns `true` if `key` exists, else `false`.
+     */function baseHasIn(object,key){return object!=null&&key in Object(object);}/**
+     * The base implementation of `_.inRange` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {number} number The number to check.
+     * @param {number} start The start of the range.
+     * @param {number} end The end of the range.
+     * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
+     */function baseInRange(number,start,end){return number>=nativeMin(start,end)&&number<nativeMax(start,end);}/**
+     * The base implementation of methods like `_.intersection`, without support
+     * for iteratee shorthands, that accepts an array of arrays to inspect.
+     *
+     * @private
+     * @param {Array} arrays The arrays to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of shared values.
+     */function baseIntersection(arrays,iteratee,comparator){var includes=comparator?arrayIncludesWith:arrayIncludes,length=arrays[0].length,othLength=arrays.length,othIndex=othLength,caches=Array(othLength),maxLength=Infinity,result=[];while(othIndex--){var array=arrays[othIndex];if(othIndex&&iteratee){array=arrayMap(array,baseUnary(iteratee));}maxLength=nativeMin(array.length,maxLength);caches[othIndex]=!comparator&&(iteratee||length>=120&&array.length>=120)?new SetCache(othIndex&&array):undefined$1;}array=arrays[0];var index=-1,seen=caches[0];outer:while(++index<length&&result.length<maxLength){var value=array[index],computed=iteratee?iteratee(value):value;value=comparator||value!==0?value:0;if(!(seen?cacheHas(seen,computed):includes(result,computed,comparator))){othIndex=othLength;while(--othIndex){var cache=caches[othIndex];if(!(cache?cacheHas(cache,computed):includes(arrays[othIndex],computed,comparator))){continue outer;}}if(seen){seen.push(computed);}result.push(value);}}return result;}/**
+     * The base implementation of `_.invert` and `_.invertBy` which inverts
+     * `object` with values transformed by `iteratee` and set by `setter`.
+     *
+     * @private
+     * @param {Object} object The object to iterate over.
+     * @param {Function} setter The function to set `accumulator` values.
+     * @param {Function} iteratee The iteratee to transform values.
+     * @param {Object} accumulator The initial inverted object.
+     * @returns {Function} Returns `accumulator`.
+     */function baseInverter(object,setter,iteratee,accumulator){baseForOwn(object,function(value,key,object){setter(accumulator,iteratee(value),key,object);});return accumulator;}/**
+     * The base implementation of `_.invoke` without support for individual
+     * method arguments.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path of the method to invoke.
+     * @param {Array} args The arguments to invoke the method with.
+     * @returns {*} Returns the result of the invoked method.
+     */function baseInvoke(object,path,args){path=castPath(path,object);object=parent(object,path);var func=object==null?object:object[toKey(last(path))];return func==null?undefined$1:apply(func,object,args);}/**
+     * The base implementation of `_.isArguments`.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+     */function baseIsArguments(value){return isObjectLike(value)&&baseGetTag(value)==argsTag;}/**
+     * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
+     */function baseIsArrayBuffer(value){return isObjectLike(value)&&baseGetTag(value)==arrayBufferTag;}/**
+     * The base implementation of `_.isDate` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
+     */function baseIsDate(value){return isObjectLike(value)&&baseGetTag(value)==dateTag;}/**
+     * The base implementation of `_.isEqual` which supports partial comparisons
+     * and tracks traversed objects.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @param {boolean} bitmask The bitmask flags.
+     *  1 - Unordered comparison
+     *  2 - Partial comparison
+     * @param {Function} [customizer] The function to customize comparisons.
+     * @param {Object} [stack] Tracks traversed `value` and `other` objects.
+     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+     */function baseIsEqual(value,other,bitmask,customizer,stack){if(value===other){return true;}if(value==null||other==null||!isObjectLike(value)&&!isObjectLike(other)){return value!==value&&other!==other;}return baseIsEqualDeep(value,other,bitmask,customizer,baseIsEqual,stack);}/**
+     * A specialized version of `baseIsEqual` for arrays and objects which performs
+     * deep comparisons and tracks traversed objects enabling objects with circular
+     * references to be compared.
+     *
+     * @private
+     * @param {Object} object The object to compare.
+     * @param {Object} other The other object to compare.
+     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+     * @param {Function} customizer The function to customize comparisons.
+     * @param {Function} equalFunc The function to determine equivalents of values.
+     * @param {Object} [stack] Tracks traversed `object` and `other` objects.
+     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+     */function baseIsEqualDeep(object,other,bitmask,customizer,equalFunc,stack){var objIsArr=isArray(object),othIsArr=isArray(other),objTag=objIsArr?arrayTag:getTag(object),othTag=othIsArr?arrayTag:getTag(other);objTag=objTag==argsTag?objectTag:objTag;othTag=othTag==argsTag?objectTag:othTag;var objIsObj=objTag==objectTag,othIsObj=othTag==objectTag,isSameTag=objTag==othTag;if(isSameTag&&isBuffer(object)){if(!isBuffer(other)){return false;}objIsArr=true;objIsObj=false;}if(isSameTag&&!objIsObj){stack||(stack=new Stack());return objIsArr||isTypedArray(object)?equalArrays(object,other,bitmask,customizer,equalFunc,stack):equalByTag(object,other,objTag,bitmask,customizer,equalFunc,stack);}if(!(bitmask&COMPARE_PARTIAL_FLAG)){var objIsWrapped=objIsObj&&hasOwnProperty.call(object,'__wrapped__'),othIsWrapped=othIsObj&&hasOwnProperty.call(other,'__wrapped__');if(objIsWrapped||othIsWrapped){var objUnwrapped=objIsWrapped?object.value():object,othUnwrapped=othIsWrapped?other.value():other;stack||(stack=new Stack());return equalFunc(objUnwrapped,othUnwrapped,bitmask,customizer,stack);}}if(!isSameTag){return false;}stack||(stack=new Stack());return equalObjects(object,other,bitmask,customizer,equalFunc,stack);}/**
+     * The base implementation of `_.isMap` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+     */function baseIsMap(value){return isObjectLike(value)&&getTag(value)==mapTag;}/**
+     * The base implementation of `_.isMatch` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The object to inspect.
+     * @param {Object} source The object of property values to match.
+     * @param {Array} matchData The property names, values, and compare flags to match.
+     * @param {Function} [customizer] The function to customize comparisons.
+     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+     */function baseIsMatch(object,source,matchData,customizer){var index=matchData.length,length=index,noCustomizer=!customizer;if(object==null){return !length;}object=Object(object);while(index--){var data=matchData[index];if(noCustomizer&&data[2]?data[1]!==object[data[0]]:!(data[0]in object)){return false;}}while(++index<length){data=matchData[index];var key=data[0],objValue=object[key],srcValue=data[1];if(noCustomizer&&data[2]){if(objValue===undefined$1&&!(key in object)){return false;}}else {var stack=new Stack();if(customizer){var result=customizer(objValue,srcValue,key,object,source,stack);}if(!(result===undefined$1?baseIsEqual(srcValue,objValue,COMPARE_PARTIAL_FLAG|COMPARE_UNORDERED_FLAG,customizer,stack):result)){return false;}}}return true;}/**
+     * The base implementation of `_.isNative` without bad shim checks.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a native function,
+     *  else `false`.
+     */function baseIsNative(value){if(!isObject(value)||isMasked(value)){return false;}var pattern=isFunction(value)?reIsNative:reIsHostCtor;return pattern.test(toSource(value));}/**
+     * The base implementation of `_.isRegExp` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
+     */function baseIsRegExp(value){return isObjectLike(value)&&baseGetTag(value)==regexpTag;}/**
+     * The base implementation of `_.isSet` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+     */function baseIsSet(value){return isObjectLike(value)&&getTag(value)==setTag;}/**
+     * The base implementation of `_.isTypedArray` without Node.js optimizations.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+     */function baseIsTypedArray(value){return isObjectLike(value)&&isLength(value.length)&&!!typedArrayTags[baseGetTag(value)];}/**
+     * The base implementation of `_.iteratee`.
+     *
+     * @private
+     * @param {*} [value=_.identity] The value to convert to an iteratee.
+     * @returns {Function} Returns the iteratee.
+     */function baseIteratee(value){// Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
+// See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
+if(typeof value=='function'){return value;}if(value==null){return identity;}if(typeof value=='object'){return isArray(value)?baseMatchesProperty(value[0],value[1]):baseMatches(value);}return property(value);}/**
+     * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names.
+     */function baseKeys(object){if(!isPrototype(object)){return nativeKeys(object);}var result=[];for(var key in Object(object)){if(hasOwnProperty.call(object,key)&&key!='constructor'){result.push(key);}}return result;}/**
+     * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names.
+     */function baseKeysIn(object){if(!isObject(object)){return nativeKeysIn(object);}var isProto=isPrototype(object),result=[];for(var key in object){if(!(key=='constructor'&&(isProto||!hasOwnProperty.call(object,key)))){result.push(key);}}return result;}/**
+     * The base implementation of `_.lt` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is less than `other`,
+     *  else `false`.
+     */function baseLt(value,other){return value<other;}/**
+     * The base implementation of `_.map` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} iteratee The function invoked per iteration.
+     * @returns {Array} Returns the new mapped array.
+     */function baseMap(collection,iteratee){var index=-1,result=isArrayLike(collection)?Array(collection.length):[];baseEach(collection,function(value,key,collection){result[++index]=iteratee(value,key,collection);});return result;}/**
+     * The base implementation of `_.matches` which doesn't clone `source`.
+     *
+     * @private
+     * @param {Object} source The object of property values to match.
+     * @returns {Function} Returns the new spec function.
+     */function baseMatches(source){var matchData=getMatchData(source);if(matchData.length==1&&matchData[0][2]){return matchesStrictComparable(matchData[0][0],matchData[0][1]);}return function(object){return object===source||baseIsMatch(object,source,matchData);};}/**
+     * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
+     *
+     * @private
+     * @param {string} path The path of the property to get.
+     * @param {*} srcValue The value to match.
+     * @returns {Function} Returns the new spec function.
+     */function baseMatchesProperty(path,srcValue){if(isKey(path)&&isStrictComparable(srcValue)){return matchesStrictComparable(toKey(path),srcValue);}return function(object){var objValue=get(object,path);return objValue===undefined$1&&objValue===srcValue?hasIn(object,path):baseIsEqual(srcValue,objValue,COMPARE_PARTIAL_FLAG|COMPARE_UNORDERED_FLAG);};}/**
+     * The base implementation of `_.merge` without support for multiple sources.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @param {number} srcIndex The index of `source`.
+     * @param {Function} [customizer] The function to customize merged values.
+     * @param {Object} [stack] Tracks traversed source values and their merged
+     *  counterparts.
+     */function baseMerge(object,source,srcIndex,customizer,stack){if(object===source){return;}baseFor(source,function(srcValue,key){stack||(stack=new Stack());if(isObject(srcValue)){baseMergeDeep(object,source,key,srcIndex,baseMerge,customizer,stack);}else {var newValue=customizer?customizer(safeGet(object,key),srcValue,key+'',object,source,stack):undefined$1;if(newValue===undefined$1){newValue=srcValue;}assignMergeValue(object,key,newValue);}},keysIn);}/**
+     * A specialized version of `baseMerge` for arrays and objects which performs
+     * deep merges and tracks traversed objects enabling objects with circular
+     * references to be merged.
+     *
+     * @private
+     * @param {Object} object The destination object.
+     * @param {Object} source The source object.
+     * @param {string} key The key of the value to merge.
+     * @param {number} srcIndex The index of `source`.
+     * @param {Function} mergeFunc The function to merge values.
+     * @param {Function} [customizer] The function to customize assigned values.
+     * @param {Object} [stack] Tracks traversed source values and their merged
+     *  counterparts.
+     */function baseMergeDeep(object,source,key,srcIndex,mergeFunc,customizer,stack){var objValue=safeGet(object,key),srcValue=safeGet(source,key),stacked=stack.get(srcValue);if(stacked){assignMergeValue(object,key,stacked);return;}var newValue=customizer?customizer(objValue,srcValue,key+'',object,source,stack):undefined$1;var isCommon=newValue===undefined$1;if(isCommon){var isArr=isArray(srcValue),isBuff=!isArr&&isBuffer(srcValue),isTyped=!isArr&&!isBuff&&isTypedArray(srcValue);newValue=srcValue;if(isArr||isBuff||isTyped){if(isArray(objValue)){newValue=objValue;}else if(isArrayLikeObject(objValue)){newValue=copyArray(objValue);}else if(isBuff){isCommon=false;newValue=cloneBuffer(srcValue,true);}else if(isTyped){isCommon=false;newValue=cloneTypedArray(srcValue,true);}else {newValue=[];}}else if(isPlainObject(srcValue)||isArguments(srcValue)){newValue=objValue;if(isArguments(objValue)){newValue=toPlainObject(objValue);}else if(!isObject(objValue)||isFunction(objValue)){newValue=initCloneObject(srcValue);}}else {isCommon=false;}}if(isCommon){// Recursively merge objects and arrays (susceptible to call stack limits).
+stack.set(srcValue,newValue);mergeFunc(newValue,srcValue,srcIndex,customizer,stack);stack['delete'](srcValue);}assignMergeValue(object,key,newValue);}/**
+     * The base implementation of `_.nth` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {Array} array The array to query.
+     * @param {number} n The index of the element to return.
+     * @returns {*} Returns the nth element of `array`.
+     */function baseNth(array,n){var length=array.length;if(!length){return;}n+=n<0?length:0;return isIndex(n,length)?array[n]:undefined$1;}/**
+     * The base implementation of `_.orderBy` without param guards.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
+     * @param {string[]} orders The sort orders of `iteratees`.
+     * @returns {Array} Returns the new sorted array.
+     */function baseOrderBy(collection,iteratees,orders){if(iteratees.length){iteratees=arrayMap(iteratees,function(iteratee){if(isArray(iteratee)){return function(value){return baseGet(value,iteratee.length===1?iteratee[0]:iteratee);};}return iteratee;});}else {iteratees=[identity];}var index=-1;iteratees=arrayMap(iteratees,baseUnary(getIteratee()));var result=baseMap(collection,function(value,key,collection){var criteria=arrayMap(iteratees,function(iteratee){return iteratee(value);});return {'criteria':criteria,'index':++index,'value':value};});return baseSortBy(result,function(object,other){return compareMultiple(object,other,orders);});}/**
+     * The base implementation of `_.pick` without support for individual
+     * property identifiers.
+     *
+     * @private
+     * @param {Object} object The source object.
+     * @param {string[]} paths The property paths to pick.
+     * @returns {Object} Returns the new object.
+     */function basePick(object,paths){return basePickBy(object,paths,function(value,path){return hasIn(object,path);});}/**
+     * The base implementation of  `_.pickBy` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Object} object The source object.
+     * @param {string[]} paths The property paths to pick.
+     * @param {Function} predicate The function invoked per property.
+     * @returns {Object} Returns the new object.
+     */function basePickBy(object,paths,predicate){var index=-1,length=paths.length,result={};while(++index<length){var path=paths[index],value=baseGet(object,path);if(predicate(value,path)){baseSet(result,castPath(path,object),value);}}return result;}/**
+     * A specialized version of `baseProperty` which supports deep paths.
+     *
+     * @private
+     * @param {Array|string} path The path of the property to get.
+     * @returns {Function} Returns the new accessor function.
+     */function basePropertyDeep(path){return function(object){return baseGet(object,path);};}/**
+     * The base implementation of `_.pullAllBy` without support for iteratee
+     * shorthands.
+     *
+     * @private
+     * @param {Array} array The array to modify.
+     * @param {Array} values The values to remove.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns `array`.
+     */function basePullAll(array,values,iteratee,comparator){var indexOf=comparator?baseIndexOfWith:baseIndexOf,index=-1,length=values.length,seen=array;if(array===values){values=copyArray(values);}if(iteratee){seen=arrayMap(array,baseUnary(iteratee));}while(++index<length){var fromIndex=0,value=values[index],computed=iteratee?iteratee(value):value;while((fromIndex=indexOf(seen,computed,fromIndex,comparator))>-1){if(seen!==array){splice.call(seen,fromIndex,1);}splice.call(array,fromIndex,1);}}return array;}/**
+     * The base implementation of `_.pullAt` without support for individual
+     * indexes or capturing the removed elements.
+     *
+     * @private
+     * @param {Array} array The array to modify.
+     * @param {number[]} indexes The indexes of elements to remove.
+     * @returns {Array} Returns `array`.
+     */function basePullAt(array,indexes){var length=array?indexes.length:0,lastIndex=length-1;while(length--){var index=indexes[length];if(length==lastIndex||index!==previous){var previous=index;if(isIndex(index)){splice.call(array,index,1);}else {baseUnset(array,index);}}}return array;}/**
+     * The base implementation of `_.random` without support for returning
+     * floating-point numbers.
+     *
+     * @private
+     * @param {number} lower The lower bound.
+     * @param {number} upper The upper bound.
+     * @returns {number} Returns the random number.
+     */function baseRandom(lower,upper){return lower+nativeFloor(nativeRandom()*(upper-lower+1));}/**
+     * The base implementation of `_.range` and `_.rangeRight` which doesn't
+     * coerce arguments.
+     *
+     * @private
+     * @param {number} start The start of the range.
+     * @param {number} end The end of the range.
+     * @param {number} step The value to increment or decrement by.
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Array} Returns the range of numbers.
+     */function baseRange(start,end,step,fromRight){var index=-1,length=nativeMax(nativeCeil((end-start)/(step||1)),0),result=Array(length);while(length--){result[fromRight?length:++index]=start;start+=step;}return result;}/**
+     * The base implementation of `_.repeat` which doesn't coerce arguments.
+     *
+     * @private
+     * @param {string} string The string to repeat.
+     * @param {number} n The number of times to repeat the string.
+     * @returns {string} Returns the repeated string.
+     */function baseRepeat(string,n){var result='';if(!string||n<1||n>MAX_SAFE_INTEGER){return result;}// Leverage the exponentiation by squaring algorithm for a faster repeat.
+// See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
+do{if(n%2){result+=string;}n=nativeFloor(n/2);if(n){string+=string;}}while(n);return result;}/**
+     * The base implementation of `_.rest` which doesn't validate or coerce arguments.
+     *
+     * @private
+     * @param {Function} func The function to apply a rest parameter to.
+     * @param {number} [start=func.length-1] The start position of the rest parameter.
+     * @returns {Function} Returns the new function.
+     */function baseRest(func,start){return setToString(overRest(func,start,identity),func+'');}/**
+     * The base implementation of `_.sample`.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to sample.
+     * @returns {*} Returns the random element.
+     */function baseSample(collection){return arraySample(values(collection));}/**
+     * The base implementation of `_.sampleSize` without param guards.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to sample.
+     * @param {number} n The number of elements to sample.
+     * @returns {Array} Returns the random elements.
+     */function baseSampleSize(collection,n){var array=values(collection);return shuffleSelf(array,baseClamp(n,0,array.length));}/**
+     * The base implementation of `_.set`.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to set.
+     * @param {*} value The value to set.
+     * @param {Function} [customizer] The function to customize path creation.
+     * @returns {Object} Returns `object`.
+     */function baseSet(object,path,value,customizer){if(!isObject(object)){return object;}path=castPath(path,object);var index=-1,length=path.length,lastIndex=length-1,nested=object;while(nested!=null&&++index<length){var key=toKey(path[index]),newValue=value;if(key==='__proto__'||key==='constructor'||key==='prototype'){return object;}if(index!=lastIndex){var objValue=nested[key];newValue=customizer?customizer(objValue,key,nested):undefined$1;if(newValue===undefined$1){newValue=isObject(objValue)?objValue:isIndex(path[index+1])?[]:{};}}assignValue(nested,key,newValue);nested=nested[key];}return object;}/**
+     * The base implementation of `setData` without support for hot loop shorting.
+     *
+     * @private
+     * @param {Function} func The function to associate metadata with.
+     * @param {*} data The metadata.
+     * @returns {Function} Returns `func`.
+     */var baseSetData=!metaMap?identity:function(func,data){metaMap.set(func,data);return func;};/**
+     * The base implementation of `setToString` without support for hot loop shorting.
+     *
+     * @private
+     * @param {Function} func The function to modify.
+     * @param {Function} string The `toString` result.
+     * @returns {Function} Returns `func`.
+     */var baseSetToString=!defineProperty?identity:function(func,string){return defineProperty(func,'toString',{'configurable':true,'enumerable':false,'value':constant(string),'writable':true});};/**
+     * The base implementation of `_.shuffle`.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to shuffle.
+     * @returns {Array} Returns the new shuffled array.
+     */function baseShuffle(collection){return shuffleSelf(values(collection));}/**
+     * The base implementation of `_.slice` without an iteratee call guard.
+     *
+     * @private
+     * @param {Array} array The array to slice.
+     * @param {number} [start=0] The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns the slice of `array`.
+     */function baseSlice(array,start,end){var index=-1,length=array.length;if(start<0){start=-start>length?0:length+start;}end=end>length?length:end;if(end<0){end+=length;}length=start>end?0:end-start>>>0;start>>>=0;var result=Array(length);while(++index<length){result[index]=array[index+start];}return result;}/**
+     * The base implementation of `_.some` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} predicate The function invoked per iteration.
+     * @returns {boolean} Returns `true` if any element passes the predicate check,
+     *  else `false`.
+     */function baseSome(collection,predicate){var result;baseEach(collection,function(value,index,collection){result=predicate(value,index,collection);return !result;});return !!result;}/**
+     * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
+     * performs a binary search of `array` to determine the index at which `value`
+     * should be inserted into `array` in order to maintain its sort order.
+     *
+     * @private
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @param {boolean} [retHighest] Specify returning the highest qualified index.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     */function baseSortedIndex(array,value,retHighest){var low=0,high=array==null?low:array.length;if(typeof value=='number'&&value===value&&high<=HALF_MAX_ARRAY_LENGTH){while(low<high){var mid=low+high>>>1,computed=array[mid];if(computed!==null&&!isSymbol(computed)&&(retHighest?computed<=value:computed<value)){low=mid+1;}else {high=mid;}}return high;}return baseSortedIndexBy(array,value,identity,retHighest);}/**
+     * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
+     * which invokes `iteratee` for `value` and each element of `array` to compute
+     * their sort ranking. The iteratee is invoked with one argument; (value).
+     *
+     * @private
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @param {Function} iteratee The iteratee invoked per element.
+     * @param {boolean} [retHighest] Specify returning the highest qualified index.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     */function baseSortedIndexBy(array,value,iteratee,retHighest){var low=0,high=array==null?0:array.length;if(high===0){return 0;}value=iteratee(value);var valIsNaN=value!==value,valIsNull=value===null,valIsSymbol=isSymbol(value),valIsUndefined=value===undefined$1;while(low<high){var mid=nativeFloor((low+high)/2),computed=iteratee(array[mid]),othIsDefined=computed!==undefined$1,othIsNull=computed===null,othIsReflexive=computed===computed,othIsSymbol=isSymbol(computed);if(valIsNaN){var setLow=retHighest||othIsReflexive;}else if(valIsUndefined){setLow=othIsReflexive&&(retHighest||othIsDefined);}else if(valIsNull){setLow=othIsReflexive&&othIsDefined&&(retHighest||!othIsNull);}else if(valIsSymbol){setLow=othIsReflexive&&othIsDefined&&!othIsNull&&(retHighest||!othIsSymbol);}else if(othIsNull||othIsSymbol){setLow=false;}else {setLow=retHighest?computed<=value:computed<value;}if(setLow){low=mid+1;}else {high=mid;}}return nativeMin(high,MAX_ARRAY_INDEX);}/**
+     * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
+     * support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @returns {Array} Returns the new duplicate free array.
+     */function baseSortedUniq(array,iteratee){var index=-1,length=array.length,resIndex=0,result=[];while(++index<length){var value=array[index],computed=iteratee?iteratee(value):value;if(!index||!eq(computed,seen)){var seen=computed;result[resIndex++]=value===0?0:value;}}return result;}/**
+     * The base implementation of `_.toNumber` which doesn't ensure correct
+     * conversions of binary, hexadecimal, or octal string values.
+     *
+     * @private
+     * @param {*} value The value to process.
+     * @returns {number} Returns the number.
+     */function baseToNumber(value){if(typeof value=='number'){return value;}if(isSymbol(value)){return NAN;}return +value;}/**
+     * The base implementation of `_.toString` which doesn't convert nullish
+     * values to empty strings.
+     *
+     * @private
+     * @param {*} value The value to process.
+     * @returns {string} Returns the string.
+     */function baseToString(value){// Exit early for strings to avoid a performance hit in some environments.
+if(typeof value=='string'){return value;}if(isArray(value)){// Recursively convert values (susceptible to call stack limits).
+return arrayMap(value,baseToString)+'';}if(isSymbol(value)){return symbolToString?symbolToString.call(value):'';}var result=value+'';return result=='0'&&1/value==-INFINITY?'-0':result;}/**
+     * The base implementation of `_.uniqBy` without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new duplicate free array.
+     */function baseUniq(array,iteratee,comparator){var index=-1,includes=arrayIncludes,length=array.length,isCommon=true,result=[],seen=result;if(comparator){isCommon=false;includes=arrayIncludesWith;}else if(length>=LARGE_ARRAY_SIZE){var set=iteratee?null:createSet(array);if(set){return setToArray(set);}isCommon=false;includes=cacheHas;seen=new SetCache();}else {seen=iteratee?[]:result;}outer:while(++index<length){var value=array[index],computed=iteratee?iteratee(value):value;value=comparator||value!==0?value:0;if(isCommon&&computed===computed){var seenIndex=seen.length;while(seenIndex--){if(seen[seenIndex]===computed){continue outer;}}if(iteratee){seen.push(computed);}result.push(value);}else if(!includes(seen,computed,comparator)){if(seen!==result){seen.push(computed);}result.push(value);}}return result;}/**
+     * The base implementation of `_.unset`.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The property path to unset.
+     * @returns {boolean} Returns `true` if the property is deleted, else `false`.
+     */function baseUnset(object,path){path=castPath(path,object);object=parent(object,path);return object==null||delete object[toKey(last(path))];}/**
+     * The base implementation of `_.update`.
+     *
+     * @private
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to update.
+     * @param {Function} updater The function to produce the updated value.
+     * @param {Function} [customizer] The function to customize path creation.
+     * @returns {Object} Returns `object`.
+     */function baseUpdate(object,path,updater,customizer){return baseSet(object,path,updater(baseGet(object,path)),customizer);}/**
+     * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
+     * without support for iteratee shorthands.
+     *
+     * @private
+     * @param {Array} array The array to query.
+     * @param {Function} predicate The function invoked per iteration.
+     * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Array} Returns the slice of `array`.
+     */function baseWhile(array,predicate,isDrop,fromRight){var length=array.length,index=fromRight?length:-1;while((fromRight?index--:++index<length)&&predicate(array[index],index,array)){}return isDrop?baseSlice(array,fromRight?0:index,fromRight?index+1:length):baseSlice(array,fromRight?index+1:0,fromRight?length:index);}/**
+     * The base implementation of `wrapperValue` which returns the result of
+     * performing a sequence of actions on the unwrapped `value`, where each
+     * successive action is supplied the return value of the previous.
+     *
+     * @private
+     * @param {*} value The unwrapped value.
+     * @param {Array} actions Actions to perform to resolve the unwrapped value.
+     * @returns {*} Returns the resolved value.
+     */function baseWrapperValue(value,actions){var result=value;if(result instanceof LazyWrapper){result=result.value();}return arrayReduce(actions,function(result,action){return action.func.apply(action.thisArg,arrayPush([result],action.args));},result);}/**
+     * The base implementation of methods like `_.xor`, without support for
+     * iteratee shorthands, that accepts an array of arrays to inspect.
+     *
+     * @private
+     * @param {Array} arrays The arrays to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of values.
+     */function baseXor(arrays,iteratee,comparator){var length=arrays.length;if(length<2){return length?baseUniq(arrays[0]):[];}var index=-1,result=Array(length);while(++index<length){var array=arrays[index],othIndex=-1;while(++othIndex<length){if(othIndex!=index){result[index]=baseDifference(result[index]||array,arrays[othIndex],iteratee,comparator);}}}return baseUniq(baseFlatten(result,1),iteratee,comparator);}/**
+     * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
+     *
+     * @private
+     * @param {Array} props The property identifiers.
+     * @param {Array} values The property values.
+     * @param {Function} assignFunc The function to assign values.
+     * @returns {Object} Returns the new object.
+     */function baseZipObject(props,values,assignFunc){var index=-1,length=props.length,valsLength=values.length,result={};while(++index<length){var value=index<valsLength?values[index]:undefined$1;assignFunc(result,props[index],value);}return result;}/**
+     * Casts `value` to an empty array if it's not an array like object.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @returns {Array|Object} Returns the cast array-like object.
+     */function castArrayLikeObject(value){return isArrayLikeObject(value)?value:[];}/**
+     * Casts `value` to `identity` if it's not a function.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @returns {Function} Returns cast function.
+     */function castFunction(value){return typeof value=='function'?value:identity;}/**
+     * Casts `value` to a path array if it's not one.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @param {Object} [object] The object to query keys on.
+     * @returns {Array} Returns the cast property path array.
+     */function castPath(value,object){if(isArray(value)){return value;}return isKey(value,object)?[value]:stringToPath(toString(value));}/**
+     * A `baseRest` alias which can be replaced with `identity` by module
+     * replacement plugins.
+     *
+     * @private
+     * @type {Function}
+     * @param {Function} func The function to apply a rest parameter to.
+     * @returns {Function} Returns the new function.
+     */var castRest=baseRest;/**
+     * Casts `array` to a slice if it's needed.
+     *
+     * @private
+     * @param {Array} array The array to inspect.
+     * @param {number} start The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns the cast slice.
+     */function castSlice(array,start,end){var length=array.length;end=end===undefined$1?length:end;return !start&&end>=length?array:baseSlice(array,start,end);}/**
+     * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
+     *
+     * @private
+     * @param {number|Object} id The timer id or timeout object of the timer to clear.
+     */var clearTimeout=ctxClearTimeout||function(id){return root.clearTimeout(id);};/**
+     * Creates a clone of  `buffer`.
+     *
+     * @private
+     * @param {Buffer} buffer The buffer to clone.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Buffer} Returns the cloned buffer.
+     */function cloneBuffer(buffer,isDeep){if(isDeep){return buffer.slice();}var length=buffer.length,result=allocUnsafe?allocUnsafe(length):new buffer.constructor(length);buffer.copy(result);return result;}/**
+     * Creates a clone of `arrayBuffer`.
+     *
+     * @private
+     * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
+     * @returns {ArrayBuffer} Returns the cloned array buffer.
+     */function cloneArrayBuffer(arrayBuffer){var result=new arrayBuffer.constructor(arrayBuffer.byteLength);new Uint8Array(result).set(new Uint8Array(arrayBuffer));return result;}/**
+     * Creates a clone of `dataView`.
+     *
+     * @private
+     * @param {Object} dataView The data view to clone.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Object} Returns the cloned data view.
+     */function cloneDataView(dataView,isDeep){var buffer=isDeep?cloneArrayBuffer(dataView.buffer):dataView.buffer;return new dataView.constructor(buffer,dataView.byteOffset,dataView.byteLength);}/**
+     * Creates a clone of `regexp`.
+     *
+     * @private
+     * @param {Object} regexp The regexp to clone.
+     * @returns {Object} Returns the cloned regexp.
+     */function cloneRegExp(regexp){var result=new regexp.constructor(regexp.source,reFlags.exec(regexp));result.lastIndex=regexp.lastIndex;return result;}/**
+     * Creates a clone of the `symbol` object.
+     *
+     * @private
+     * @param {Object} symbol The symbol object to clone.
+     * @returns {Object} Returns the cloned symbol object.
+     */function cloneSymbol(symbol){return symbolValueOf?Object(symbolValueOf.call(symbol)):{};}/**
+     * Creates a clone of `typedArray`.
+     *
+     * @private
+     * @param {Object} typedArray The typed array to clone.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Object} Returns the cloned typed array.
+     */function cloneTypedArray(typedArray,isDeep){var buffer=isDeep?cloneArrayBuffer(typedArray.buffer):typedArray.buffer;return new typedArray.constructor(buffer,typedArray.byteOffset,typedArray.length);}/**
+     * Compares values to sort them in ascending order.
+     *
+     * @private
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {number} Returns the sort order indicator for `value`.
+     */function compareAscending(value,other){if(value!==other){var valIsDefined=value!==undefined$1,valIsNull=value===null,valIsReflexive=value===value,valIsSymbol=isSymbol(value);var othIsDefined=other!==undefined$1,othIsNull=other===null,othIsReflexive=other===other,othIsSymbol=isSymbol(other);if(!othIsNull&&!othIsSymbol&&!valIsSymbol&&value>other||valIsSymbol&&othIsDefined&&othIsReflexive&&!othIsNull&&!othIsSymbol||valIsNull&&othIsDefined&&othIsReflexive||!valIsDefined&&othIsReflexive||!valIsReflexive){return 1;}if(!valIsNull&&!valIsSymbol&&!othIsSymbol&&value<other||othIsSymbol&&valIsDefined&&valIsReflexive&&!valIsNull&&!valIsSymbol||othIsNull&&valIsDefined&&valIsReflexive||!othIsDefined&&valIsReflexive||!othIsReflexive){return -1;}}return 0;}/**
+     * Used by `_.orderBy` to compare multiple properties of a value to another
+     * and stable sort them.
+     *
+     * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
+     * specify an order of "desc" for descending or "asc" for ascending sort order
+     * of corresponding values.
+     *
+     * @private
+     * @param {Object} object The object to compare.
+     * @param {Object} other The other object to compare.
+     * @param {boolean[]|string[]} orders The order to sort by for each property.
+     * @returns {number} Returns the sort order indicator for `object`.
+     */function compareMultiple(object,other,orders){var index=-1,objCriteria=object.criteria,othCriteria=other.criteria,length=objCriteria.length,ordersLength=orders.length;while(++index<length){var result=compareAscending(objCriteria[index],othCriteria[index]);if(result){if(index>=ordersLength){return result;}var order=orders[index];return result*(order=='desc'?-1:1);}}// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
+// that causes it, under certain circumstances, to provide the same value for
+// `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
+// for more details.
+//
+// This also ensures a stable sort in V8 and other engines.
+// See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
+return object.index-other.index;}/**
+     * Creates an array that is the composition of partially applied arguments,
+     * placeholders, and provided arguments into a single array of arguments.
+     *
+     * @private
+     * @param {Array} args The provided arguments.
+     * @param {Array} partials The arguments to prepend to those provided.
+     * @param {Array} holders The `partials` placeholder indexes.
+     * @params {boolean} [isCurried] Specify composing for a curried function.
+     * @returns {Array} Returns the new array of composed arguments.
+     */function composeArgs(args,partials,holders,isCurried){var argsIndex=-1,argsLength=args.length,holdersLength=holders.length,leftIndex=-1,leftLength=partials.length,rangeLength=nativeMax(argsLength-holdersLength,0),result=Array(leftLength+rangeLength),isUncurried=!isCurried;while(++leftIndex<leftLength){result[leftIndex]=partials[leftIndex];}while(++argsIndex<holdersLength){if(isUncurried||argsIndex<argsLength){result[holders[argsIndex]]=args[argsIndex];}}while(rangeLength--){result[leftIndex++]=args[argsIndex++];}return result;}/**
+     * This function is like `composeArgs` except that the arguments composition
+     * is tailored for `_.partialRight`.
+     *
+     * @private
+     * @param {Array} args The provided arguments.
+     * @param {Array} partials The arguments to append to those provided.
+     * @param {Array} holders The `partials` placeholder indexes.
+     * @params {boolean} [isCurried] Specify composing for a curried function.
+     * @returns {Array} Returns the new array of composed arguments.
+     */function composeArgsRight(args,partials,holders,isCurried){var argsIndex=-1,argsLength=args.length,holdersIndex=-1,holdersLength=holders.length,rightIndex=-1,rightLength=partials.length,rangeLength=nativeMax(argsLength-holdersLength,0),result=Array(rangeLength+rightLength),isUncurried=!isCurried;while(++argsIndex<rangeLength){result[argsIndex]=args[argsIndex];}var offset=argsIndex;while(++rightIndex<rightLength){result[offset+rightIndex]=partials[rightIndex];}while(++holdersIndex<holdersLength){if(isUncurried||argsIndex<argsLength){result[offset+holders[holdersIndex]]=args[argsIndex++];}}return result;}/**
+     * Copies the values of `source` to `array`.
+     *
+     * @private
+     * @param {Array} source The array to copy values from.
+     * @param {Array} [array=[]] The array to copy values to.
+     * @returns {Array} Returns `array`.
+     */function copyArray(source,array){var index=-1,length=source.length;array||(array=Array(length));while(++index<length){array[index]=source[index];}return array;}/**
+     * Copies properties of `source` to `object`.
+     *
+     * @private
+     * @param {Object} source The object to copy properties from.
+     * @param {Array} props The property identifiers to copy.
+     * @param {Object} [object={}] The object to copy properties to.
+     * @param {Function} [customizer] The function to customize copied values.
+     * @returns {Object} Returns `object`.
+     */function copyObject(source,props,object,customizer){var isNew=!object;object||(object={});var index=-1,length=props.length;while(++index<length){var key=props[index];var newValue=customizer?customizer(object[key],source[key],key,object,source):undefined$1;if(newValue===undefined$1){newValue=source[key];}if(isNew){baseAssignValue(object,key,newValue);}else {assignValue(object,key,newValue);}}return object;}/**
+     * Copies own symbols of `source` to `object`.
+     *
+     * @private
+     * @param {Object} source The object to copy symbols from.
+     * @param {Object} [object={}] The object to copy symbols to.
+     * @returns {Object} Returns `object`.
+     */function copySymbols(source,object){return copyObject(source,getSymbols(source),object);}/**
+     * Copies own and inherited symbols of `source` to `object`.
+     *
+     * @private
+     * @param {Object} source The object to copy symbols from.
+     * @param {Object} [object={}] The object to copy symbols to.
+     * @returns {Object} Returns `object`.
+     */function copySymbolsIn(source,object){return copyObject(source,getSymbolsIn(source),object);}/**
+     * Creates a function like `_.groupBy`.
+     *
+     * @private
+     * @param {Function} setter The function to set accumulator values.
+     * @param {Function} [initializer] The accumulator object initializer.
+     * @returns {Function} Returns the new aggregator function.
+     */function createAggregator(setter,initializer){return function(collection,iteratee){var func=isArray(collection)?arrayAggregator:baseAggregator,accumulator=initializer?initializer():{};return func(collection,setter,getIteratee(iteratee,2),accumulator);};}/**
+     * Creates a function like `_.assign`.
+     *
+     * @private
+     * @param {Function} assigner The function to assign values.
+     * @returns {Function} Returns the new assigner function.
+     */function createAssigner(assigner){return baseRest(function(object,sources){var index=-1,length=sources.length,customizer=length>1?sources[length-1]:undefined$1,guard=length>2?sources[2]:undefined$1;customizer=assigner.length>3&&typeof customizer=='function'?(length--,customizer):undefined$1;if(guard&&isIterateeCall(sources[0],sources[1],guard)){customizer=length<3?undefined$1:customizer;length=1;}object=Object(object);while(++index<length){var source=sources[index];if(source){assigner(object,source,index,customizer);}}return object;});}/**
+     * Creates a `baseEach` or `baseEachRight` function.
+     *
+     * @private
+     * @param {Function} eachFunc The function to iterate over a collection.
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Function} Returns the new base function.
+     */function createBaseEach(eachFunc,fromRight){return function(collection,iteratee){if(collection==null){return collection;}if(!isArrayLike(collection)){return eachFunc(collection,iteratee);}var length=collection.length,index=fromRight?length:-1,iterable=Object(collection);while(fromRight?index--:++index<length){if(iteratee(iterable[index],index,iterable)===false){break;}}return collection;};}/**
+     * Creates a base function for methods like `_.forIn` and `_.forOwn`.
+     *
+     * @private
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Function} Returns the new base function.
+     */function createBaseFor(fromRight){return function(object,iteratee,keysFunc){var index=-1,iterable=Object(object),props=keysFunc(object),length=props.length;while(length--){var key=props[fromRight?length:++index];if(iteratee(iterable[key],key,iterable)===false){break;}}return object;};}/**
+     * Creates a function that wraps `func` to invoke it with the optional `this`
+     * binding of `thisArg`.
+     *
+     * @private
+     * @param {Function} func The function to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */function createBind(func,bitmask,thisArg){var isBind=bitmask&WRAP_BIND_FLAG,Ctor=createCtor(func);function wrapper(){var fn=this&&this!==root&&this instanceof wrapper?Ctor:func;return fn.apply(isBind?thisArg:this,arguments);}return wrapper;}/**
+     * Creates a function like `_.lowerFirst`.
+     *
+     * @private
+     * @param {string} methodName The name of the `String` case method to use.
+     * @returns {Function} Returns the new case function.
+     */function createCaseFirst(methodName){return function(string){string=toString(string);var strSymbols=hasUnicode(string)?stringToArray(string):undefined$1;var chr=strSymbols?strSymbols[0]:string.charAt(0);var trailing=strSymbols?castSlice(strSymbols,1).join(''):string.slice(1);return chr[methodName]()+trailing;};}/**
+     * Creates a function like `_.camelCase`.
+     *
+     * @private
+     * @param {Function} callback The function to combine each word.
+     * @returns {Function} Returns the new compounder function.
+     */function createCompounder(callback){return function(string){return arrayReduce(words(deburr(string).replace(reApos,'')),callback,'');};}/**
+     * Creates a function that produces an instance of `Ctor` regardless of
+     * whether it was invoked as part of a `new` expression or by `call` or `apply`.
+     *
+     * @private
+     * @param {Function} Ctor The constructor to wrap.
+     * @returns {Function} Returns the new wrapped function.
+     */function createCtor(Ctor){return function(){// Use a `switch` statement to work with class constructors. See
+// http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
+// for more details.
+var args=arguments;switch(args.length){case 0:return new Ctor();case 1:return new Ctor(args[0]);case 2:return new Ctor(args[0],args[1]);case 3:return new Ctor(args[0],args[1],args[2]);case 4:return new Ctor(args[0],args[1],args[2],args[3]);case 5:return new Ctor(args[0],args[1],args[2],args[3],args[4]);case 6:return new Ctor(args[0],args[1],args[2],args[3],args[4],args[5]);case 7:return new Ctor(args[0],args[1],args[2],args[3],args[4],args[5],args[6]);}var thisBinding=baseCreate(Ctor.prototype),result=Ctor.apply(thisBinding,args);// Mimic the constructor's `return` behavior.
+// See https://es5.github.io/#x13.2.2 for more details.
+return isObject(result)?result:thisBinding;};}/**
+     * Creates a function that wraps `func` to enable currying.
+     *
+     * @private
+     * @param {Function} func The function to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {number} arity The arity of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */function createCurry(func,bitmask,arity){var Ctor=createCtor(func);function wrapper(){var length=arguments.length,args=Array(length),index=length,placeholder=getHolder(wrapper);while(index--){args[index]=arguments[index];}var holders=length<3&&args[0]!==placeholder&&args[length-1]!==placeholder?[]:replaceHolders(args,placeholder);length-=holders.length;if(length<arity){return createRecurry(func,bitmask,createHybrid,wrapper.placeholder,undefined$1,args,holders,undefined$1,undefined$1,arity-length);}var fn=this&&this!==root&&this instanceof wrapper?Ctor:func;return apply(fn,this,args);}return wrapper;}/**
+     * Creates a `_.find` or `_.findLast` function.
+     *
+     * @private
+     * @param {Function} findIndexFunc The function to find the collection index.
+     * @returns {Function} Returns the new find function.
+     */function createFind(findIndexFunc){return function(collection,predicate,fromIndex){var iterable=Object(collection);if(!isArrayLike(collection)){var iteratee=getIteratee(predicate,3);collection=keys(collection);predicate=function(key){return iteratee(iterable[key],key,iterable);};}var index=findIndexFunc(collection,predicate,fromIndex);return index>-1?iterable[iteratee?collection[index]:index]:undefined$1;};}/**
+     * Creates a `_.flow` or `_.flowRight` function.
+     *
+     * @private
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Function} Returns the new flow function.
+     */function createFlow(fromRight){return flatRest(function(funcs){var length=funcs.length,index=length,prereq=LodashWrapper.prototype.thru;if(fromRight){funcs.reverse();}while(index--){var func=funcs[index];if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}if(prereq&&!wrapper&&getFuncName(func)=='wrapper'){var wrapper=new LodashWrapper([],true);}}index=wrapper?index:length;while(++index<length){func=funcs[index];var funcName=getFuncName(func),data=funcName=='wrapper'?getData(func):undefined$1;if(data&&isLaziable(data[0])&&data[1]==(WRAP_ARY_FLAG|WRAP_CURRY_FLAG|WRAP_PARTIAL_FLAG|WRAP_REARG_FLAG)&&!data[4].length&&data[9]==1){wrapper=wrapper[getFuncName(data[0])].apply(wrapper,data[3]);}else {wrapper=func.length==1&&isLaziable(func)?wrapper[funcName]():wrapper.thru(func);}}return function(){var args=arguments,value=args[0];if(wrapper&&args.length==1&&isArray(value)){return wrapper.plant(value).value();}var index=0,result=length?funcs[index].apply(this,args):value;while(++index<length){result=funcs[index].call(this,result);}return result;};});}/**
+     * Creates a function that wraps `func` to invoke it with optional `this`
+     * binding of `thisArg`, partial application, and currying.
+     *
+     * @private
+     * @param {Function|string} func The function or method name to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @param {Array} [partials] The arguments to prepend to those provided to
+     *  the new function.
+     * @param {Array} [holders] The `partials` placeholder indexes.
+     * @param {Array} [partialsRight] The arguments to append to those provided
+     *  to the new function.
+     * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
+     * @param {Array} [argPos] The argument positions of the new function.
+     * @param {number} [ary] The arity cap of `func`.
+     * @param {number} [arity] The arity of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */function createHybrid(func,bitmask,thisArg,partials,holders,partialsRight,holdersRight,argPos,ary,arity){var isAry=bitmask&WRAP_ARY_FLAG,isBind=bitmask&WRAP_BIND_FLAG,isBindKey=bitmask&WRAP_BIND_KEY_FLAG,isCurried=bitmask&(WRAP_CURRY_FLAG|WRAP_CURRY_RIGHT_FLAG),isFlip=bitmask&WRAP_FLIP_FLAG,Ctor=isBindKey?undefined$1:createCtor(func);function wrapper(){var length=arguments.length,args=Array(length),index=length;while(index--){args[index]=arguments[index];}if(isCurried){var placeholder=getHolder(wrapper),holdersCount=countHolders(args,placeholder);}if(partials){args=composeArgs(args,partials,holders,isCurried);}if(partialsRight){args=composeArgsRight(args,partialsRight,holdersRight,isCurried);}length-=holdersCount;if(isCurried&&length<arity){var newHolders=replaceHolders(args,placeholder);return createRecurry(func,bitmask,createHybrid,wrapper.placeholder,thisArg,args,newHolders,argPos,ary,arity-length);}var thisBinding=isBind?thisArg:this,fn=isBindKey?thisBinding[func]:func;length=args.length;if(argPos){args=reorder(args,argPos);}else if(isFlip&&length>1){args.reverse();}if(isAry&&ary<length){args.length=ary;}if(this&&this!==root&&this instanceof wrapper){fn=Ctor||createCtor(fn);}return fn.apply(thisBinding,args);}return wrapper;}/**
+     * Creates a function like `_.invertBy`.
+     *
+     * @private
+     * @param {Function} setter The function to set accumulator values.
+     * @param {Function} toIteratee The function to resolve iteratees.
+     * @returns {Function} Returns the new inverter function.
+     */function createInverter(setter,toIteratee){return function(object,iteratee){return baseInverter(object,setter,toIteratee(iteratee),{});};}/**
+     * Creates a function that performs a mathematical operation on two values.
+     *
+     * @private
+     * @param {Function} operator The function to perform the operation.
+     * @param {number} [defaultValue] The value used for `undefined` arguments.
+     * @returns {Function} Returns the new mathematical operation function.
+     */function createMathOperation(operator,defaultValue){return function(value,other){var result;if(value===undefined$1&&other===undefined$1){return defaultValue;}if(value!==undefined$1){result=value;}if(other!==undefined$1){if(result===undefined$1){return other;}if(typeof value=='string'||typeof other=='string'){value=baseToString(value);other=baseToString(other);}else {value=baseToNumber(value);other=baseToNumber(other);}result=operator(value,other);}return result;};}/**
+     * Creates a function like `_.over`.
+     *
+     * @private
+     * @param {Function} arrayFunc The function to iterate over iteratees.
+     * @returns {Function} Returns the new over function.
+     */function createOver(arrayFunc){return flatRest(function(iteratees){iteratees=arrayMap(iteratees,baseUnary(getIteratee()));return baseRest(function(args){var thisArg=this;return arrayFunc(iteratees,function(iteratee){return apply(iteratee,thisArg,args);});});});}/**
+     * Creates the padding for `string` based on `length`. The `chars` string
+     * is truncated if the number of characters exceeds `length`.
+     *
+     * @private
+     * @param {number} length The padding length.
+     * @param {string} [chars=' '] The string used as padding.
+     * @returns {string} Returns the padding for `string`.
+     */function createPadding(length,chars){chars=chars===undefined$1?' ':baseToString(chars);var charsLength=chars.length;if(charsLength<2){return charsLength?baseRepeat(chars,length):chars;}var result=baseRepeat(chars,nativeCeil(length/stringSize(chars)));return hasUnicode(chars)?castSlice(stringToArray(result),0,length).join(''):result.slice(0,length);}/**
+     * Creates a function that wraps `func` to invoke it with the `this` binding
+     * of `thisArg` and `partials` prepended to the arguments it receives.
+     *
+     * @private
+     * @param {Function} func The function to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {*} thisArg The `this` binding of `func`.
+     * @param {Array} partials The arguments to prepend to those provided to
+     *  the new function.
+     * @returns {Function} Returns the new wrapped function.
+     */function createPartial(func,bitmask,thisArg,partials){var isBind=bitmask&WRAP_BIND_FLAG,Ctor=createCtor(func);function wrapper(){var argsIndex=-1,argsLength=arguments.length,leftIndex=-1,leftLength=partials.length,args=Array(leftLength+argsLength),fn=this&&this!==root&&this instanceof wrapper?Ctor:func;while(++leftIndex<leftLength){args[leftIndex]=partials[leftIndex];}while(argsLength--){args[leftIndex++]=arguments[++argsIndex];}return apply(fn,isBind?thisArg:this,args);}return wrapper;}/**
+     * Creates a `_.range` or `_.rangeRight` function.
+     *
+     * @private
+     * @param {boolean} [fromRight] Specify iterating from right to left.
+     * @returns {Function} Returns the new range function.
+     */function createRange(fromRight){return function(start,end,step){if(step&&typeof step!='number'&&isIterateeCall(start,end,step)){end=step=undefined$1;}// Ensure the sign of `-0` is preserved.
+start=toFinite(start);if(end===undefined$1){end=start;start=0;}else {end=toFinite(end);}step=step===undefined$1?start<end?1:-1:toFinite(step);return baseRange(start,end,step,fromRight);};}/**
+     * Creates a function that performs a relational operation on two values.
+     *
+     * @private
+     * @param {Function} operator The function to perform the operation.
+     * @returns {Function} Returns the new relational operation function.
+     */function createRelationalOperation(operator){return function(value,other){if(!(typeof value=='string'&&typeof other=='string')){value=toNumber(value);other=toNumber(other);}return operator(value,other);};}/**
+     * Creates a function that wraps `func` to continue currying.
+     *
+     * @private
+     * @param {Function} func The function to wrap.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @param {Function} wrapFunc The function to create the `func` wrapper.
+     * @param {*} placeholder The placeholder value.
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @param {Array} [partials] The arguments to prepend to those provided to
+     *  the new function.
+     * @param {Array} [holders] The `partials` placeholder indexes.
+     * @param {Array} [argPos] The argument positions of the new function.
+     * @param {number} [ary] The arity cap of `func`.
+     * @param {number} [arity] The arity of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */function createRecurry(func,bitmask,wrapFunc,placeholder,thisArg,partials,holders,argPos,ary,arity){var isCurry=bitmask&WRAP_CURRY_FLAG,newHolders=isCurry?holders:undefined$1,newHoldersRight=isCurry?undefined$1:holders,newPartials=isCurry?partials:undefined$1,newPartialsRight=isCurry?undefined$1:partials;bitmask|=isCurry?WRAP_PARTIAL_FLAG:WRAP_PARTIAL_RIGHT_FLAG;bitmask&=~(isCurry?WRAP_PARTIAL_RIGHT_FLAG:WRAP_PARTIAL_FLAG);if(!(bitmask&WRAP_CURRY_BOUND_FLAG)){bitmask&=~(WRAP_BIND_FLAG|WRAP_BIND_KEY_FLAG);}var newData=[func,bitmask,thisArg,newPartials,newHolders,newPartialsRight,newHoldersRight,argPos,ary,arity];var result=wrapFunc.apply(undefined$1,newData);if(isLaziable(func)){setData(result,newData);}result.placeholder=placeholder;return setWrapToString(result,func,bitmask);}/**
+     * Creates a function like `_.round`.
+     *
+     * @private
+     * @param {string} methodName The name of the `Math` method to use when rounding.
+     * @returns {Function} Returns the new round function.
+     */function createRound(methodName){var func=Math[methodName];return function(number,precision){number=toNumber(number);precision=precision==null?0:nativeMin(toInteger(precision),292);if(precision&&nativeIsFinite(number)){// Shift with exponential notation to avoid floating-point issues.
+// See [MDN](https://mdn.io/round#Examples) for more details.
+var pair=(toString(number)+'e').split('e'),value=func(pair[0]+'e'+(+pair[1]+precision));pair=(toString(value)+'e').split('e');return +(pair[0]+'e'+(+pair[1]-precision));}return func(number);};}/**
+     * Creates a set object of `values`.
+     *
+     * @private
+     * @param {Array} values The values to add to the set.
+     * @returns {Object} Returns the new set.
+     */var createSet=!(Set&&1/setToArray(new Set([,-0]))[1]==INFINITY)?noop:function(values){return new Set(values);};/**
+     * Creates a `_.toPairs` or `_.toPairsIn` function.
+     *
+     * @private
+     * @param {Function} keysFunc The function to get the keys of a given object.
+     * @returns {Function} Returns the new pairs function.
+     */function createToPairs(keysFunc){return function(object){var tag=getTag(object);if(tag==mapTag){return mapToArray(object);}if(tag==setTag){return setToPairs(object);}return baseToPairs(object,keysFunc(object));};}/**
+     * Creates a function that either curries or invokes `func` with optional
+     * `this` binding and partially applied arguments.
+     *
+     * @private
+     * @param {Function|string} func The function or method name to wrap.
+     * @param {number} bitmask The bitmask flags.
+     *    1 - `_.bind`
+     *    2 - `_.bindKey`
+     *    4 - `_.curry` or `_.curryRight` of a bound function
+     *    8 - `_.curry`
+     *   16 - `_.curryRight`
+     *   32 - `_.partial`
+     *   64 - `_.partialRight`
+     *  128 - `_.rearg`
+     *  256 - `_.ary`
+     *  512 - `_.flip`
+     * @param {*} [thisArg] The `this` binding of `func`.
+     * @param {Array} [partials] The arguments to be partially applied.
+     * @param {Array} [holders] The `partials` placeholder indexes.
+     * @param {Array} [argPos] The argument positions of the new function.
+     * @param {number} [ary] The arity cap of `func`.
+     * @param {number} [arity] The arity of `func`.
+     * @returns {Function} Returns the new wrapped function.
+     */function createWrap(func,bitmask,thisArg,partials,holders,argPos,ary,arity){var isBindKey=bitmask&WRAP_BIND_KEY_FLAG;if(!isBindKey&&typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}var length=partials?partials.length:0;if(!length){bitmask&=~(WRAP_PARTIAL_FLAG|WRAP_PARTIAL_RIGHT_FLAG);partials=holders=undefined$1;}ary=ary===undefined$1?ary:nativeMax(toInteger(ary),0);arity=arity===undefined$1?arity:toInteger(arity);length-=holders?holders.length:0;if(bitmask&WRAP_PARTIAL_RIGHT_FLAG){var partialsRight=partials,holdersRight=holders;partials=holders=undefined$1;}var data=isBindKey?undefined$1:getData(func);var newData=[func,bitmask,thisArg,partials,holders,partialsRight,holdersRight,argPos,ary,arity];if(data){mergeData(newData,data);}func=newData[0];bitmask=newData[1];thisArg=newData[2];partials=newData[3];holders=newData[4];arity=newData[9]=newData[9]===undefined$1?isBindKey?0:func.length:nativeMax(newData[9]-length,0);if(!arity&&bitmask&(WRAP_CURRY_FLAG|WRAP_CURRY_RIGHT_FLAG)){bitmask&=~(WRAP_CURRY_FLAG|WRAP_CURRY_RIGHT_FLAG);}if(!bitmask||bitmask==WRAP_BIND_FLAG){var result=createBind(func,bitmask,thisArg);}else if(bitmask==WRAP_CURRY_FLAG||bitmask==WRAP_CURRY_RIGHT_FLAG){result=createCurry(func,bitmask,arity);}else if((bitmask==WRAP_PARTIAL_FLAG||bitmask==(WRAP_BIND_FLAG|WRAP_PARTIAL_FLAG))&&!holders.length){result=createPartial(func,bitmask,thisArg,partials);}else {result=createHybrid.apply(undefined$1,newData);}var setter=data?baseSetData:setData;return setWrapToString(setter(result,newData),func,bitmask);}/**
+     * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
+     * of source objects to the destination object for all destination properties
+     * that resolve to `undefined`.
+     *
+     * @private
+     * @param {*} objValue The destination value.
+     * @param {*} srcValue The source value.
+     * @param {string} key The key of the property to assign.
+     * @param {Object} object The parent object of `objValue`.
+     * @returns {*} Returns the value to assign.
+     */function customDefaultsAssignIn(objValue,srcValue,key,object){if(objValue===undefined$1||eq(objValue,objectProto[key])&&!hasOwnProperty.call(object,key)){return srcValue;}return objValue;}/**
+     * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
+     * objects into destination objects that are passed thru.
+     *
+     * @private
+     * @param {*} objValue The destination value.
+     * @param {*} srcValue The source value.
+     * @param {string} key The key of the property to merge.
+     * @param {Object} object The parent object of `objValue`.
+     * @param {Object} source The parent object of `srcValue`.
+     * @param {Object} [stack] Tracks traversed source values and their merged
+     *  counterparts.
+     * @returns {*} Returns the value to assign.
+     */function customDefaultsMerge(objValue,srcValue,key,object,source,stack){if(isObject(objValue)&&isObject(srcValue)){// Recursively merge objects and arrays (susceptible to call stack limits).
+stack.set(srcValue,objValue);baseMerge(objValue,srcValue,undefined$1,customDefaultsMerge,stack);stack['delete'](srcValue);}return objValue;}/**
+     * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
+     * objects.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @param {string} key The key of the property to inspect.
+     * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
+     */function customOmitClone(value){return isPlainObject(value)?undefined$1:value;}/**
+     * A specialized version of `baseIsEqualDeep` for arrays with support for
+     * partial deep comparisons.
+     *
+     * @private
+     * @param {Array} array The array to compare.
+     * @param {Array} other The other array to compare.
+     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+     * @param {Function} customizer The function to customize comparisons.
+     * @param {Function} equalFunc The function to determine equivalents of values.
+     * @param {Object} stack Tracks traversed `array` and `other` objects.
+     * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+     */function equalArrays(array,other,bitmask,customizer,equalFunc,stack){var isPartial=bitmask&COMPARE_PARTIAL_FLAG,arrLength=array.length,othLength=other.length;if(arrLength!=othLength&&!(isPartial&&othLength>arrLength)){return false;}// Check that cyclic values are equal.
+var arrStacked=stack.get(array);var othStacked=stack.get(other);if(arrStacked&&othStacked){return arrStacked==other&&othStacked==array;}var index=-1,result=true,seen=bitmask&COMPARE_UNORDERED_FLAG?new SetCache():undefined$1;stack.set(array,other);stack.set(other,array);// Ignore non-index properties.
+while(++index<arrLength){var arrValue=array[index],othValue=other[index];if(customizer){var compared=isPartial?customizer(othValue,arrValue,index,other,array,stack):customizer(arrValue,othValue,index,array,other,stack);}if(compared!==undefined$1){if(compared){continue;}result=false;break;}// Recursively compare arrays (susceptible to call stack limits).
+if(seen){if(!arraySome(other,function(othValue,othIndex){if(!cacheHas(seen,othIndex)&&(arrValue===othValue||equalFunc(arrValue,othValue,bitmask,customizer,stack))){return seen.push(othIndex);}})){result=false;break;}}else if(!(arrValue===othValue||equalFunc(arrValue,othValue,bitmask,customizer,stack))){result=false;break;}}stack['delete'](array);stack['delete'](other);return result;}/**
+     * A specialized version of `baseIsEqualDeep` for comparing objects of
+     * the same `toStringTag`.
+     *
+     * **Note:** This function only supports comparing values with tags of
+     * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+     *
+     * @private
+     * @param {Object} object The object to compare.
+     * @param {Object} other The other object to compare.
+     * @param {string} tag The `toStringTag` of the objects to compare.
+     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+     * @param {Function} customizer The function to customize comparisons.
+     * @param {Function} equalFunc The function to determine equivalents of values.
+     * @param {Object} stack Tracks traversed `object` and `other` objects.
+     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+     */function equalByTag(object,other,tag,bitmask,customizer,equalFunc,stack){switch(tag){case dataViewTag:if(object.byteLength!=other.byteLength||object.byteOffset!=other.byteOffset){return false;}object=object.buffer;other=other.buffer;case arrayBufferTag:if(object.byteLength!=other.byteLength||!equalFunc(new Uint8Array(object),new Uint8Array(other))){return false;}return true;case boolTag:case dateTag:case numberTag:// Coerce booleans to `1` or `0` and dates to milliseconds.
+// Invalid dates are coerced to `NaN`.
+return eq(+object,+other);case errorTag:return object.name==other.name&&object.message==other.message;case regexpTag:case stringTag:// Coerce regexes to strings and treat strings, primitives and objects,
+// as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
+// for more details.
+return object==other+'';case mapTag:var convert=mapToArray;case setTag:var isPartial=bitmask&COMPARE_PARTIAL_FLAG;convert||(convert=setToArray);if(object.size!=other.size&&!isPartial){return false;}// Assume cyclic values are equal.
+var stacked=stack.get(object);if(stacked){return stacked==other;}bitmask|=COMPARE_UNORDERED_FLAG;// Recursively compare objects (susceptible to call stack limits).
+stack.set(object,other);var result=equalArrays(convert(object),convert(other),bitmask,customizer,equalFunc,stack);stack['delete'](object);return result;case symbolTag:if(symbolValueOf){return symbolValueOf.call(object)==symbolValueOf.call(other);}}return false;}/**
+     * A specialized version of `baseIsEqualDeep` for objects with support for
+     * partial deep comparisons.
+     *
+     * @private
+     * @param {Object} object The object to compare.
+     * @param {Object} other The other object to compare.
+     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
+     * @param {Function} customizer The function to customize comparisons.
+     * @param {Function} equalFunc The function to determine equivalents of values.
+     * @param {Object} stack Tracks traversed `object` and `other` objects.
+     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+     */function equalObjects(object,other,bitmask,customizer,equalFunc,stack){var isPartial=bitmask&COMPARE_PARTIAL_FLAG,objProps=getAllKeys(object),objLength=objProps.length,othProps=getAllKeys(other),othLength=othProps.length;if(objLength!=othLength&&!isPartial){return false;}var index=objLength;while(index--){var key=objProps[index];if(!(isPartial?key in other:hasOwnProperty.call(other,key))){return false;}}// Check that cyclic values are equal.
+var objStacked=stack.get(object);var othStacked=stack.get(other);if(objStacked&&othStacked){return objStacked==other&&othStacked==object;}var result=true;stack.set(object,other);stack.set(other,object);var skipCtor=isPartial;while(++index<objLength){key=objProps[index];var objValue=object[key],othValue=other[key];if(customizer){var compared=isPartial?customizer(othValue,objValue,key,other,object,stack):customizer(objValue,othValue,key,object,other,stack);}// Recursively compare objects (susceptible to call stack limits).
+if(!(compared===undefined$1?objValue===othValue||equalFunc(objValue,othValue,bitmask,customizer,stack):compared)){result=false;break;}skipCtor||(skipCtor=key=='constructor');}if(result&&!skipCtor){var objCtor=object.constructor,othCtor=other.constructor;// Non `Object` object instances with different constructors are not equal.
+if(objCtor!=othCtor&&'constructor'in object&&'constructor'in other&&!(typeof objCtor=='function'&&objCtor instanceof objCtor&&typeof othCtor=='function'&&othCtor instanceof othCtor)){result=false;}}stack['delete'](object);stack['delete'](other);return result;}/**
+     * A specialized version of `baseRest` which flattens the rest array.
+     *
+     * @private
+     * @param {Function} func The function to apply a rest parameter to.
+     * @returns {Function} Returns the new function.
+     */function flatRest(func){return setToString(overRest(func,undefined$1,flatten),func+'');}/**
+     * Creates an array of own enumerable property names and symbols of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names and symbols.
+     */function getAllKeys(object){return baseGetAllKeys(object,keys,getSymbols);}/**
+     * Creates an array of own and inherited enumerable property names and
+     * symbols of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names and symbols.
+     */function getAllKeysIn(object){return baseGetAllKeys(object,keysIn,getSymbolsIn);}/**
+     * Gets metadata for `func`.
+     *
+     * @private
+     * @param {Function} func The function to query.
+     * @returns {*} Returns the metadata for `func`.
+     */var getData=!metaMap?noop:function(func){return metaMap.get(func);};/**
+     * Gets the name of `func`.
+     *
+     * @private
+     * @param {Function} func The function to query.
+     * @returns {string} Returns the function name.
+     */function getFuncName(func){var result=func.name+'',array=realNames[result],length=hasOwnProperty.call(realNames,result)?array.length:0;while(length--){var data=array[length],otherFunc=data.func;if(otherFunc==null||otherFunc==func){return data.name;}}return result;}/**
+     * Gets the argument placeholder value for `func`.
+     *
+     * @private
+     * @param {Function} func The function to inspect.
+     * @returns {*} Returns the placeholder value.
+     */function getHolder(func){var object=hasOwnProperty.call(lodash,'placeholder')?lodash:func;return object.placeholder;}/**
+     * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
+     * this function returns the custom method, otherwise it returns `baseIteratee`.
+     * If arguments are provided, the chosen function is invoked with them and
+     * its result is returned.
+     *
+     * @private
+     * @param {*} [value] The value to convert to an iteratee.
+     * @param {number} [arity] The arity of the created iteratee.
+     * @returns {Function} Returns the chosen function or its result.
+     */function getIteratee(){var result=lodash.iteratee||iteratee;result=result===iteratee?baseIteratee:result;return arguments.length?result(arguments[0],arguments[1]):result;}/**
+     * Gets the data for `map`.
+     *
+     * @private
+     * @param {Object} map The map to query.
+     * @param {string} key The reference key.
+     * @returns {*} Returns the map data.
+     */function getMapData(map,key){var data=map.__data__;return isKeyable(key)?data[typeof key=='string'?'string':'hash']:data.map;}/**
+     * Gets the property names, values, and compare flags of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the match data of `object`.
+     */function getMatchData(object){var result=keys(object),length=result.length;while(length--){var key=result[length],value=object[key];result[length]=[key,value,isStrictComparable(value)];}return result;}/**
+     * Gets the native function at `key` of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {string} key The key of the method to get.
+     * @returns {*} Returns the function if it's native, else `undefined`.
+     */function getNative(object,key){var value=getValue(object,key);return baseIsNative(value)?value:undefined$1;}/**
+     * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
+     *
+     * @private
+     * @param {*} value The value to query.
+     * @returns {string} Returns the raw `toStringTag`.
+     */function getRawTag(value){var isOwn=hasOwnProperty.call(value,symToStringTag),tag=value[symToStringTag];try{value[symToStringTag]=undefined$1;var unmasked=true;}catch(e){}var result=nativeObjectToString.call(value);if(unmasked){if(isOwn){value[symToStringTag]=tag;}else {delete value[symToStringTag];}}return result;}/**
+     * Creates an array of the own enumerable symbols of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of symbols.
+     */var getSymbols=!nativeGetSymbols?stubArray:function(object){if(object==null){return [];}object=Object(object);return arrayFilter(nativeGetSymbols(object),function(symbol){return propertyIsEnumerable.call(object,symbol);});};/**
+     * Creates an array of the own and inherited enumerable symbols of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of symbols.
+     */var getSymbolsIn=!nativeGetSymbols?stubArray:function(object){var result=[];while(object){arrayPush(result,getSymbols(object));object=getPrototype(object);}return result;};/**
+     * Gets the `toStringTag` of `value`.
+     *
+     * @private
+     * @param {*} value The value to query.
+     * @returns {string} Returns the `toStringTag`.
+     */var getTag=baseGetTag;// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
+if(DataView&&getTag(new DataView(new ArrayBuffer(1)))!=dataViewTag||Map&&getTag(new Map())!=mapTag||Promise&&getTag(Promise.resolve())!=promiseTag||Set&&getTag(new Set())!=setTag||WeakMap&&getTag(new WeakMap())!=weakMapTag){getTag=function(value){var result=baseGetTag(value),Ctor=result==objectTag?value.constructor:undefined$1,ctorString=Ctor?toSource(Ctor):'';if(ctorString){switch(ctorString){case dataViewCtorString:return dataViewTag;case mapCtorString:return mapTag;case promiseCtorString:return promiseTag;case setCtorString:return setTag;case weakMapCtorString:return weakMapTag;}}return result;};}/**
+     * Gets the view, applying any `transforms` to the `start` and `end` positions.
+     *
+     * @private
+     * @param {number} start The start of the view.
+     * @param {number} end The end of the view.
+     * @param {Array} transforms The transformations to apply to the view.
+     * @returns {Object} Returns an object containing the `start` and `end`
+     *  positions of the view.
+     */function getView(start,end,transforms){var index=-1,length=transforms.length;while(++index<length){var data=transforms[index],size=data.size;switch(data.type){case'drop':start+=size;break;case'dropRight':end-=size;break;case'take':end=nativeMin(end,start+size);break;case'takeRight':start=nativeMax(start,end-size);break;}}return {'start':start,'end':end};}/**
+     * Extracts wrapper details from the `source` body comment.
+     *
+     * @private
+     * @param {string} source The source to inspect.
+     * @returns {Array} Returns the wrapper details.
+     */function getWrapDetails(source){var match=source.match(reWrapDetails);return match?match[1].split(reSplitDetails):[];}/**
+     * Checks if `path` exists on `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path to check.
+     * @param {Function} hasFunc The function to check properties.
+     * @returns {boolean} Returns `true` if `path` exists, else `false`.
+     */function hasPath(object,path,hasFunc){path=castPath(path,object);var index=-1,length=path.length,result=false;while(++index<length){var key=toKey(path[index]);if(!(result=object!=null&&hasFunc(object,key))){break;}object=object[key];}if(result||++index!=length){return result;}length=object==null?0:object.length;return !!length&&isLength(length)&&isIndex(key,length)&&(isArray(object)||isArguments(object));}/**
+     * Initializes an array clone.
+     *
+     * @private
+     * @param {Array} array The array to clone.
+     * @returns {Array} Returns the initialized clone.
+     */function initCloneArray(array){var length=array.length,result=new array.constructor(length);// Add properties assigned by `RegExp#exec`.
+if(length&&typeof array[0]=='string'&&hasOwnProperty.call(array,'index')){result.index=array.index;result.input=array.input;}return result;}/**
+     * Initializes an object clone.
+     *
+     * @private
+     * @param {Object} object The object to clone.
+     * @returns {Object} Returns the initialized clone.
+     */function initCloneObject(object){return typeof object.constructor=='function'&&!isPrototype(object)?baseCreate(getPrototype(object)):{};}/**
+     * Initializes an object clone based on its `toStringTag`.
+     *
+     * **Note:** This function only supports cloning values with tags of
+     * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
+     *
+     * @private
+     * @param {Object} object The object to clone.
+     * @param {string} tag The `toStringTag` of the object to clone.
+     * @param {boolean} [isDeep] Specify a deep clone.
+     * @returns {Object} Returns the initialized clone.
+     */function initCloneByTag(object,tag,isDeep){var Ctor=object.constructor;switch(tag){case arrayBufferTag:return cloneArrayBuffer(object);case boolTag:case dateTag:return new Ctor(+object);case dataViewTag:return cloneDataView(object,isDeep);case float32Tag:case float64Tag:case int8Tag:case int16Tag:case int32Tag:case uint8Tag:case uint8ClampedTag:case uint16Tag:case uint32Tag:return cloneTypedArray(object,isDeep);case mapTag:return new Ctor();case numberTag:case stringTag:return new Ctor(object);case regexpTag:return cloneRegExp(object);case setTag:return new Ctor();case symbolTag:return cloneSymbol(object);}}/**
+     * Inserts wrapper `details` in a comment at the top of the `source` body.
+     *
+     * @private
+     * @param {string} source The source to modify.
+     * @returns {Array} details The details to insert.
+     * @returns {string} Returns the modified source.
+     */function insertWrapDetails(source,details){var length=details.length;if(!length){return source;}var lastIndex=length-1;details[lastIndex]=(length>1?'& ':'')+details[lastIndex];details=details.join(length>2?', ':' ');return source.replace(reWrapComment,'{\n/* [wrapped with '+details+'] */\n');}/**
+     * Checks if `value` is a flattenable `arguments` object or array.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
+     */function isFlattenable(value){return isArray(value)||isArguments(value)||!!(spreadableSymbol&&value&&value[spreadableSymbol]);}/**
+     * Checks if `value` is a valid array-like index.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+     * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+     */function isIndex(value,length){var type=typeof value;length=length==null?MAX_SAFE_INTEGER:length;return !!length&&(type=='number'||type!='symbol'&&reIsUint.test(value))&&value>-1&&value%1==0&&value<length;}/**
+     * Checks if the given arguments are from an iteratee call.
+     *
+     * @private
+     * @param {*} value The potential iteratee value argument.
+     * @param {*} index The potential iteratee index or key argument.
+     * @param {*} object The potential iteratee object argument.
+     * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
+     *  else `false`.
+     */function isIterateeCall(value,index,object){if(!isObject(object)){return false;}var type=typeof index;if(type=='number'?isArrayLike(object)&&isIndex(index,object.length):type=='string'&&index in object){return eq(object[index],value);}return false;}/**
+     * Checks if `value` is a property name and not a property path.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @param {Object} [object] The object to query keys on.
+     * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
+     */function isKey(value,object){if(isArray(value)){return false;}var type=typeof value;if(type=='number'||type=='symbol'||type=='boolean'||value==null||isSymbol(value)){return true;}return reIsPlainProp.test(value)||!reIsDeepProp.test(value)||object!=null&&value in Object(object);}/**
+     * Checks if `value` is suitable for use as unique object key.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
+     */function isKeyable(value){var type=typeof value;return type=='string'||type=='number'||type=='symbol'||type=='boolean'?value!=='__proto__':value===null;}/**
+     * Checks if `func` has a lazy counterpart.
+     *
+     * @private
+     * @param {Function} func The function to check.
+     * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
+     *  else `false`.
+     */function isLaziable(func){var funcName=getFuncName(func),other=lodash[funcName];if(typeof other!='function'||!(funcName in LazyWrapper.prototype)){return false;}if(func===other){return true;}var data=getData(other);return !!data&&func===data[0];}/**
+     * Checks if `func` has its source masked.
+     *
+     * @private
+     * @param {Function} func The function to check.
+     * @returns {boolean} Returns `true` if `func` is masked, else `false`.
+     */function isMasked(func){return !!maskSrcKey&&maskSrcKey in func;}/**
+     * Checks if `func` is capable of being masked.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
+     */var isMaskable=coreJsData?isFunction:stubFalse;/**
+     * Checks if `value` is likely a prototype object.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
+     */function isPrototype(value){var Ctor=value&&value.constructor,proto=typeof Ctor=='function'&&Ctor.prototype||objectProto;return value===proto;}/**
+     * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
+     *
+     * @private
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` if suitable for strict
+     *  equality comparisons, else `false`.
+     */function isStrictComparable(value){return value===value&&!isObject(value);}/**
+     * A specialized version of `matchesProperty` for source values suitable
+     * for strict equality comparisons, i.e. `===`.
+     *
+     * @private
+     * @param {string} key The key of the property to get.
+     * @param {*} srcValue The value to match.
+     * @returns {Function} Returns the new spec function.
+     */function matchesStrictComparable(key,srcValue){return function(object){if(object==null){return false;}return object[key]===srcValue&&(srcValue!==undefined$1||key in Object(object));};}/**
+     * A specialized version of `_.memoize` which clears the memoized function's
+     * cache when it exceeds `MAX_MEMOIZE_SIZE`.
+     *
+     * @private
+     * @param {Function} func The function to have its output memoized.
+     * @returns {Function} Returns the new memoized function.
+     */function memoizeCapped(func){var result=memoize(func,function(key){if(cache.size===MAX_MEMOIZE_SIZE){cache.clear();}return key;});var cache=result.cache;return result;}/**
+     * Merges the function metadata of `source` into `data`.
+     *
+     * Merging metadata reduces the number of wrappers used to invoke a function.
+     * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
+     * may be applied regardless of execution order. Methods like `_.ary` and
+     * `_.rearg` modify function arguments, making the order in which they are
+     * executed important, preventing the merging of metadata. However, we make
+     * an exception for a safe combined case where curried functions have `_.ary`
+     * and or `_.rearg` applied.
+     *
+     * @private
+     * @param {Array} data The destination metadata.
+     * @param {Array} source The source metadata.
+     * @returns {Array} Returns `data`.
+     */function mergeData(data,source){var bitmask=data[1],srcBitmask=source[1],newBitmask=bitmask|srcBitmask,isCommon=newBitmask<(WRAP_BIND_FLAG|WRAP_BIND_KEY_FLAG|WRAP_ARY_FLAG);var isCombo=srcBitmask==WRAP_ARY_FLAG&&bitmask==WRAP_CURRY_FLAG||srcBitmask==WRAP_ARY_FLAG&&bitmask==WRAP_REARG_FLAG&&data[7].length<=source[8]||srcBitmask==(WRAP_ARY_FLAG|WRAP_REARG_FLAG)&&source[7].length<=source[8]&&bitmask==WRAP_CURRY_FLAG;// Exit early if metadata can't be merged.
+if(!(isCommon||isCombo)){return data;}// Use source `thisArg` if available.
+if(srcBitmask&WRAP_BIND_FLAG){data[2]=source[2];// Set when currying a bound function.
+newBitmask|=bitmask&WRAP_BIND_FLAG?0:WRAP_CURRY_BOUND_FLAG;}// Compose partial arguments.
+var value=source[3];if(value){var partials=data[3];data[3]=partials?composeArgs(partials,value,source[4]):value;data[4]=partials?replaceHolders(data[3],PLACEHOLDER):source[4];}// Compose partial right arguments.
+value=source[5];if(value){partials=data[5];data[5]=partials?composeArgsRight(partials,value,source[6]):value;data[6]=partials?replaceHolders(data[5],PLACEHOLDER):source[6];}// Use source `argPos` if available.
+value=source[7];if(value){data[7]=value;}// Use source `ary` if it's smaller.
+if(srcBitmask&WRAP_ARY_FLAG){data[8]=data[8]==null?source[8]:nativeMin(data[8],source[8]);}// Use source `arity` if one is not provided.
+if(data[9]==null){data[9]=source[9];}// Use source `func` and merge bitmasks.
+data[0]=source[0];data[1]=newBitmask;return data;}/**
+     * This function is like
+     * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+     * except that it includes inherited enumerable properties.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names.
+     */function nativeKeysIn(object){var result=[];if(object!=null){for(var key in Object(object)){result.push(key);}}return result;}/**
+     * Converts `value` to a string using `Object.prototype.toString`.
+     *
+     * @private
+     * @param {*} value The value to convert.
+     * @returns {string} Returns the converted string.
+     */function objectToString(value){return nativeObjectToString.call(value);}/**
+     * A specialized version of `baseRest` which transforms the rest array.
+     *
+     * @private
+     * @param {Function} func The function to apply a rest parameter to.
+     * @param {number} [start=func.length-1] The start position of the rest parameter.
+     * @param {Function} transform The rest array transform.
+     * @returns {Function} Returns the new function.
+     */function overRest(func,start,transform){start=nativeMax(start===undefined$1?func.length-1:start,0);return function(){var args=arguments,index=-1,length=nativeMax(args.length-start,0),array=Array(length);while(++index<length){array[index]=args[start+index];}index=-1;var otherArgs=Array(start+1);while(++index<start){otherArgs[index]=args[index];}otherArgs[start]=transform(array);return apply(func,this,otherArgs);};}/**
+     * Gets the parent value at `path` of `object`.
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {Array} path The path to get the parent value of.
+     * @returns {*} Returns the parent value.
+     */function parent(object,path){return path.length<2?object:baseGet(object,baseSlice(path,0,-1));}/**
+     * Reorder `array` according to the specified indexes where the element at
+     * the first index is assigned as the first element, the element at
+     * the second index is assigned as the second element, and so on.
+     *
+     * @private
+     * @param {Array} array The array to reorder.
+     * @param {Array} indexes The arranged array indexes.
+     * @returns {Array} Returns `array`.
+     */function reorder(array,indexes){var arrLength=array.length,length=nativeMin(indexes.length,arrLength),oldArray=copyArray(array);while(length--){var index=indexes[length];array[length]=isIndex(index,arrLength)?oldArray[index]:undefined$1;}return array;}/**
+     * Gets the value at `key`, unless `key` is "__proto__" or "constructor".
+     *
+     * @private
+     * @param {Object} object The object to query.
+     * @param {string} key The key of the property to get.
+     * @returns {*} Returns the property value.
+     */function safeGet(object,key){if(key==='constructor'&&typeof object[key]==='function'){return;}if(key=='__proto__'){return;}return object[key];}/**
+     * Sets metadata for `func`.
+     *
+     * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
+     * period of time, it will trip its breaker and transition to an identity
+     * function to avoid garbage collection pauses in V8. See
+     * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
+     * for more details.
+     *
+     * @private
+     * @param {Function} func The function to associate metadata with.
+     * @param {*} data The metadata.
+     * @returns {Function} Returns `func`.
+     */var setData=shortOut(baseSetData);/**
+     * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
+     *
+     * @private
+     * @param {Function} func The function to delay.
+     * @param {number} wait The number of milliseconds to delay invocation.
+     * @returns {number|Object} Returns the timer id or timeout object.
+     */var setTimeout=ctxSetTimeout||function(func,wait){return root.setTimeout(func,wait);};/**
+     * Sets the `toString` method of `func` to return `string`.
+     *
+     * @private
+     * @param {Function} func The function to modify.
+     * @param {Function} string The `toString` result.
+     * @returns {Function} Returns `func`.
+     */var setToString=shortOut(baseSetToString);/**
+     * Sets the `toString` method of `wrapper` to mimic the source of `reference`
+     * with wrapper details in a comment at the top of the source body.
+     *
+     * @private
+     * @param {Function} wrapper The function to modify.
+     * @param {Function} reference The reference function.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @returns {Function} Returns `wrapper`.
+     */function setWrapToString(wrapper,reference,bitmask){var source=reference+'';return setToString(wrapper,insertWrapDetails(source,updateWrapDetails(getWrapDetails(source),bitmask)));}/**
+     * Creates a function that'll short out and invoke `identity` instead
+     * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
+     * milliseconds.
+     *
+     * @private
+     * @param {Function} func The function to restrict.
+     * @returns {Function} Returns the new shortable function.
+     */function shortOut(func){var count=0,lastCalled=0;return function(){var stamp=nativeNow(),remaining=HOT_SPAN-(stamp-lastCalled);lastCalled=stamp;if(remaining>0){if(++count>=HOT_COUNT){return arguments[0];}}else {count=0;}return func.apply(undefined$1,arguments);};}/**
+     * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
+     *
+     * @private
+     * @param {Array} array The array to shuffle.
+     * @param {number} [size=array.length] The size of `array`.
+     * @returns {Array} Returns `array`.
+     */function shuffleSelf(array,size){var index=-1,length=array.length,lastIndex=length-1;size=size===undefined$1?length:size;while(++index<size){var rand=baseRandom(index,lastIndex),value=array[rand];array[rand]=array[index];array[index]=value;}array.length=size;return array;}/**
+     * Converts `string` to a property path array.
+     *
+     * @private
+     * @param {string} string The string to convert.
+     * @returns {Array} Returns the property path array.
+     */var stringToPath=memoizeCapped(function(string){var result=[];if(string.charCodeAt(0)===46/* . */){result.push('');}string.replace(rePropName,function(match,number,quote,subString){result.push(quote?subString.replace(reEscapeChar,'$1'):number||match);});return result;});/**
+     * Converts `value` to a string key if it's not a string or symbol.
+     *
+     * @private
+     * @param {*} value The value to inspect.
+     * @returns {string|symbol} Returns the key.
+     */function toKey(value){if(typeof value=='string'||isSymbol(value)){return value;}var result=value+'';return result=='0'&&1/value==-INFINITY?'-0':result;}/**
+     * Converts `func` to its source code.
+     *
+     * @private
+     * @param {Function} func The function to convert.
+     * @returns {string} Returns the source code.
+     */function toSource(func){if(func!=null){try{return funcToString.call(func);}catch(e){}try{return func+'';}catch(e){}}return '';}/**
+     * Updates wrapper `details` based on `bitmask` flags.
+     *
+     * @private
+     * @returns {Array} details The details to modify.
+     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
+     * @returns {Array} Returns `details`.
+     */function updateWrapDetails(details,bitmask){arrayEach(wrapFlags,function(pair){var value='_.'+pair[0];if(bitmask&pair[1]&&!arrayIncludes(details,value)){details.push(value);}});return details.sort();}/**
+     * Creates a clone of `wrapper`.
+     *
+     * @private
+     * @param {Object} wrapper The wrapper to clone.
+     * @returns {Object} Returns the cloned wrapper.
+     */function wrapperClone(wrapper){if(wrapper instanceof LazyWrapper){return wrapper.clone();}var result=new LodashWrapper(wrapper.__wrapped__,wrapper.__chain__);result.__actions__=copyArray(wrapper.__actions__);result.__index__=wrapper.__index__;result.__values__=wrapper.__values__;return result;}/*------------------------------------------------------------------------*/ /**
+     * Creates an array of elements split into groups the length of `size`.
+     * If `array` can't be split evenly, the final chunk will be the remaining
+     * elements.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to process.
+     * @param {number} [size=1] The length of each chunk
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Array} Returns the new array of chunks.
+     * @example
+     *
+     * _.chunk(['a', 'b', 'c', 'd'], 2);
+     * // => [['a', 'b'], ['c', 'd']]
+     *
+     * _.chunk(['a', 'b', 'c', 'd'], 3);
+     * // => [['a', 'b', 'c'], ['d']]
+     */function chunk(array,size,guard){if(guard?isIterateeCall(array,size,guard):size===undefined$1){size=1;}else {size=nativeMax(toInteger(size),0);}var length=array==null?0:array.length;if(!length||size<1){return [];}var index=0,resIndex=0,result=Array(nativeCeil(length/size));while(index<length){result[resIndex++]=baseSlice(array,index,index+=size);}return result;}/**
+     * Creates an array with all falsey values removed. The values `false`, `null`,
+     * `0`, `""`, `undefined`, and `NaN` are falsey.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to compact.
+     * @returns {Array} Returns the new array of filtered values.
+     * @example
+     *
+     * _.compact([0, 1, false, 2, '', 3]);
+     * // => [1, 2, 3]
+     */function compact(array){var index=-1,length=array==null?0:array.length,resIndex=0,result=[];while(++index<length){var value=array[index];if(value){result[resIndex++]=value;}}return result;}/**
+     * Creates a new array concatenating `array` with any additional arrays
+     * and/or values.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to concatenate.
+     * @param {...*} [values] The values to concatenate.
+     * @returns {Array} Returns the new concatenated array.
+     * @example
+     *
+     * var array = [1];
+     * var other = _.concat(array, 2, [3], [[4]]);
+     *
+     * console.log(other);
+     * // => [1, 2, 3, [4]]
+     *
+     * console.log(array);
+     * // => [1]
+     */function concat(){var length=arguments.length;if(!length){return [];}var args=Array(length-1),array=arguments[0],index=length;while(index--){args[index-1]=arguments[index];}return arrayPush(isArray(array)?copyArray(array):[array],baseFlatten(args,1));}/**
+     * Creates an array of `array` values not included in the other given arrays
+     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons. The order and references of result values are
+     * determined by the first array.
+     *
+     * **Note:** Unlike `_.pullAll`, this method returns a new array.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {...Array} [values] The values to exclude.
+     * @returns {Array} Returns the new array of filtered values.
+     * @see _.without, _.xor
+     * @example
+     *
+     * _.difference([2, 1], [2, 3]);
+     * // => [1]
+     */var difference=baseRest(function(array,values){return isArrayLikeObject(array)?baseDifference(array,baseFlatten(values,1,isArrayLikeObject,true)):[];});/**
+     * This method is like `_.difference` except that it accepts `iteratee` which
+     * is invoked for each element of `array` and `values` to generate the criterion
+     * by which they're compared. The order and references of result values are
+     * determined by the first array. The iteratee is invoked with one argument:
+     * (value).
+     *
+     * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {...Array} [values] The values to exclude.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {Array} Returns the new array of filtered values.
+     * @example
+     *
+     * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+     * // => [1.2]
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
+     * // => [{ 'x': 2 }]
+     */var differenceBy=baseRest(function(array,values){var iteratee=last(values);if(isArrayLikeObject(iteratee)){iteratee=undefined$1;}return isArrayLikeObject(array)?baseDifference(array,baseFlatten(values,1,isArrayLikeObject,true),getIteratee(iteratee,2)):[];});/**
+     * This method is like `_.difference` except that it accepts `comparator`
+     * which is invoked to compare elements of `array` to `values`. The order and
+     * references of result values are determined by the first array. The comparator
+     * is invoked with two arguments: (arrVal, othVal).
+     *
+     * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {...Array} [values] The values to exclude.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of filtered values.
+     * @example
+     *
+     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+     *
+     * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
+     * // => [{ 'x': 2, 'y': 1 }]
+     */var differenceWith=baseRest(function(array,values){var comparator=last(values);if(isArrayLikeObject(comparator)){comparator=undefined$1;}return isArrayLikeObject(array)?baseDifference(array,baseFlatten(values,1,isArrayLikeObject,true),undefined$1,comparator):[];});/**
+     * Creates a slice of `array` with `n` elements dropped from the beginning.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.5.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {number} [n=1] The number of elements to drop.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * _.drop([1, 2, 3]);
+     * // => [2, 3]
+     *
+     * _.drop([1, 2, 3], 2);
+     * // => [3]
+     *
+     * _.drop([1, 2, 3], 5);
+     * // => []
+     *
+     * _.drop([1, 2, 3], 0);
+     * // => [1, 2, 3]
+     */function drop(array,n,guard){var length=array==null?0:array.length;if(!length){return [];}n=guard||n===undefined$1?1:toInteger(n);return baseSlice(array,n<0?0:n,length);}/**
+     * Creates a slice of `array` with `n` elements dropped from the end.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {number} [n=1] The number of elements to drop.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * _.dropRight([1, 2, 3]);
+     * // => [1, 2]
+     *
+     * _.dropRight([1, 2, 3], 2);
+     * // => [1]
+     *
+     * _.dropRight([1, 2, 3], 5);
+     * // => []
+     *
+     * _.dropRight([1, 2, 3], 0);
+     * // => [1, 2, 3]
+     */function dropRight(array,n,guard){var length=array==null?0:array.length;if(!length){return [];}n=guard||n===undefined$1?1:toInteger(n);n=length-n;return baseSlice(array,0,n<0?0:n);}/**
+     * Creates a slice of `array` excluding elements dropped from the end.
+     * Elements are dropped until `predicate` returns falsey. The predicate is
+     * invoked with three arguments: (value, index, array).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'active': true },
+     *   { 'user': 'fred',    'active': false },
+     *   { 'user': 'pebbles', 'active': false }
+     * ];
+     *
+     * _.dropRightWhile(users, function(o) { return !o.active; });
+     * // => objects for ['barney']
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
+     * // => objects for ['barney', 'fred']
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.dropRightWhile(users, ['active', false]);
+     * // => objects for ['barney']
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.dropRightWhile(users, 'active');
+     * // => objects for ['barney', 'fred', 'pebbles']
+     */function dropRightWhile(array,predicate){return array&&array.length?baseWhile(array,getIteratee(predicate,3),true,true):[];}/**
+     * Creates a slice of `array` excluding elements dropped from the beginning.
+     * Elements are dropped until `predicate` returns falsey. The predicate is
+     * invoked with three arguments: (value, index, array).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'active': false },
+     *   { 'user': 'fred',    'active': false },
+     *   { 'user': 'pebbles', 'active': true }
+     * ];
+     *
+     * _.dropWhile(users, function(o) { return !o.active; });
+     * // => objects for ['pebbles']
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.dropWhile(users, { 'user': 'barney', 'active': false });
+     * // => objects for ['fred', 'pebbles']
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.dropWhile(users, ['active', false]);
+     * // => objects for ['pebbles']
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.dropWhile(users, 'active');
+     * // => objects for ['barney', 'fred', 'pebbles']
+     */function dropWhile(array,predicate){return array&&array.length?baseWhile(array,getIteratee(predicate,3),true):[];}/**
+     * Fills elements of `array` with `value` from `start` up to, but not
+     * including, `end`.
+     *
+     * **Note:** This method mutates `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.2.0
+     * @category Array
+     * @param {Array} array The array to fill.
+     * @param {*} value The value to fill `array` with.
+     * @param {number} [start=0] The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns `array`.
+     * @example
+     *
+     * var array = [1, 2, 3];
+     *
+     * _.fill(array, 'a');
+     * console.log(array);
+     * // => ['a', 'a', 'a']
+     *
+     * _.fill(Array(3), 2);
+     * // => [2, 2, 2]
+     *
+     * _.fill([4, 6, 8, 10], '*', 1, 3);
+     * // => [4, '*', '*', 10]
+     */function fill(array,value,start,end){var length=array==null?0:array.length;if(!length){return [];}if(start&&typeof start!='number'&&isIterateeCall(array,value,start)){start=0;end=length;}return baseFill(array,value,start,end);}/**
+     * This method is like `_.find` except that it returns the index of the first
+     * element `predicate` returns truthy for instead of the element itself.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.1.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @param {number} [fromIndex=0] The index to search from.
+     * @returns {number} Returns the index of the found element, else `-1`.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'active': false },
+     *   { 'user': 'fred',    'active': false },
+     *   { 'user': 'pebbles', 'active': true }
+     * ];
+     *
+     * _.findIndex(users, function(o) { return o.user == 'barney'; });
+     * // => 0
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.findIndex(users, { 'user': 'fred', 'active': false });
+     * // => 1
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.findIndex(users, ['active', false]);
+     * // => 0
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.findIndex(users, 'active');
+     * // => 2
+     */function findIndex(array,predicate,fromIndex){var length=array==null?0:array.length;if(!length){return -1;}var index=fromIndex==null?0:toInteger(fromIndex);if(index<0){index=nativeMax(length+index,0);}return baseFindIndex(array,getIteratee(predicate,3),index);}/**
+     * This method is like `_.findIndex` except that it iterates over elements
+     * of `collection` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @param {number} [fromIndex=array.length-1] The index to search from.
+     * @returns {number} Returns the index of the found element, else `-1`.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'active': true },
+     *   { 'user': 'fred',    'active': false },
+     *   { 'user': 'pebbles', 'active': false }
+     * ];
+     *
+     * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
+     * // => 2
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.findLastIndex(users, { 'user': 'barney', 'active': true });
+     * // => 0
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.findLastIndex(users, ['active', false]);
+     * // => 2
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.findLastIndex(users, 'active');
+     * // => 0
+     */function findLastIndex(array,predicate,fromIndex){var length=array==null?0:array.length;if(!length){return -1;}var index=length-1;if(fromIndex!==undefined$1){index=toInteger(fromIndex);index=fromIndex<0?nativeMax(length+index,0):nativeMin(index,length-1);}return baseFindIndex(array,getIteratee(predicate,3),index,true);}/**
+     * Flattens `array` a single level deep.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to flatten.
+     * @returns {Array} Returns the new flattened array.
+     * @example
+     *
+     * _.flatten([1, [2, [3, [4]], 5]]);
+     * // => [1, 2, [3, [4]], 5]
+     */function flatten(array){var length=array==null?0:array.length;return length?baseFlatten(array,1):[];}/**
+     * Recursively flattens `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to flatten.
+     * @returns {Array} Returns the new flattened array.
+     * @example
+     *
+     * _.flattenDeep([1, [2, [3, [4]], 5]]);
+     * // => [1, 2, 3, 4, 5]
+     */function flattenDeep(array){var length=array==null?0:array.length;return length?baseFlatten(array,INFINITY):[];}/**
+     * Recursively flatten `array` up to `depth` times.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.4.0
+     * @category Array
+     * @param {Array} array The array to flatten.
+     * @param {number} [depth=1] The maximum recursion depth.
+     * @returns {Array} Returns the new flattened array.
+     * @example
+     *
+     * var array = [1, [2, [3, [4]], 5]];
+     *
+     * _.flattenDepth(array, 1);
+     * // => [1, 2, [3, [4]], 5]
+     *
+     * _.flattenDepth(array, 2);
+     * // => [1, 2, 3, [4], 5]
+     */function flattenDepth(array,depth){var length=array==null?0:array.length;if(!length){return [];}depth=depth===undefined$1?1:toInteger(depth);return baseFlatten(array,depth);}/**
+     * The inverse of `_.toPairs`; this method returns an object composed
+     * from key-value `pairs`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} pairs The key-value pairs.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * _.fromPairs([['a', 1], ['b', 2]]);
+     * // => { 'a': 1, 'b': 2 }
+     */function fromPairs(pairs){var index=-1,length=pairs==null?0:pairs.length,result={};while(++index<length){var pair=pairs[index];result[pair[0]]=pair[1];}return result;}/**
+     * Gets the first element of `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @alias first
+     * @category Array
+     * @param {Array} array The array to query.
+     * @returns {*} Returns the first element of `array`.
+     * @example
+     *
+     * _.head([1, 2, 3]);
+     * // => 1
+     *
+     * _.head([]);
+     * // => undefined
+     */function head(array){return array&&array.length?array[0]:undefined$1;}/**
+     * Gets the index at which the first occurrence of `value` is found in `array`
+     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons. If `fromIndex` is negative, it's used as the
+     * offset from the end of `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {*} value The value to search for.
+     * @param {number} [fromIndex=0] The index to search from.
+     * @returns {number} Returns the index of the matched value, else `-1`.
+     * @example
+     *
+     * _.indexOf([1, 2, 1, 2], 2);
+     * // => 1
+     *
+     * // Search from the `fromIndex`.
+     * _.indexOf([1, 2, 1, 2], 2, 2);
+     * // => 3
+     */function indexOf(array,value,fromIndex){var length=array==null?0:array.length;if(!length){return -1;}var index=fromIndex==null?0:toInteger(fromIndex);if(index<0){index=nativeMax(length+index,0);}return baseIndexOf(array,value,index);}/**
+     * Gets all but the last element of `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * _.initial([1, 2, 3]);
+     * // => [1, 2]
+     */function initial(array){var length=array==null?0:array.length;return length?baseSlice(array,0,-1):[];}/**
+     * Creates an array of unique values that are included in all given arrays
+     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons. The order and references of result values are
+     * determined by the first array.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @returns {Array} Returns the new array of intersecting values.
+     * @example
+     *
+     * _.intersection([2, 1], [2, 3]);
+     * // => [2]
+     */var intersection=baseRest(function(arrays){var mapped=arrayMap(arrays,castArrayLikeObject);return mapped.length&&mapped[0]===arrays[0]?baseIntersection(mapped):[];});/**
+     * This method is like `_.intersection` except that it accepts `iteratee`
+     * which is invoked for each element of each `arrays` to generate the criterion
+     * by which they're compared. The order and references of result values are
+     * determined by the first array. The iteratee is invoked with one argument:
+     * (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {Array} Returns the new array of intersecting values.
+     * @example
+     *
+     * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+     * // => [2.1]
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+     * // => [{ 'x': 1 }]
+     */var intersectionBy=baseRest(function(arrays){var iteratee=last(arrays),mapped=arrayMap(arrays,castArrayLikeObject);if(iteratee===last(mapped)){iteratee=undefined$1;}else {mapped.pop();}return mapped.length&&mapped[0]===arrays[0]?baseIntersection(mapped,getIteratee(iteratee,2)):[];});/**
+     * This method is like `_.intersection` except that it accepts `comparator`
+     * which is invoked to compare elements of `arrays`. The order and references
+     * of result values are determined by the first array. The comparator is
+     * invoked with two arguments: (arrVal, othVal).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of intersecting values.
+     * @example
+     *
+     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+     *
+     * _.intersectionWith(objects, others, _.isEqual);
+     * // => [{ 'x': 1, 'y': 2 }]
+     */var intersectionWith=baseRest(function(arrays){var comparator=last(arrays),mapped=arrayMap(arrays,castArrayLikeObject);comparator=typeof comparator=='function'?comparator:undefined$1;if(comparator){mapped.pop();}return mapped.length&&mapped[0]===arrays[0]?baseIntersection(mapped,undefined$1,comparator):[];});/**
+     * Converts all elements in `array` into a string separated by `separator`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to convert.
+     * @param {string} [separator=','] The element separator.
+     * @returns {string} Returns the joined string.
+     * @example
+     *
+     * _.join(['a', 'b', 'c'], '~');
+     * // => 'a~b~c'
+     */function join(array,separator){return array==null?'':nativeJoin.call(array,separator);}/**
+     * Gets the last element of `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @returns {*} Returns the last element of `array`.
+     * @example
+     *
+     * _.last([1, 2, 3]);
+     * // => 3
+     */function last(array){var length=array==null?0:array.length;return length?array[length-1]:undefined$1;}/**
+     * This method is like `_.indexOf` except that it iterates over elements of
+     * `array` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {*} value The value to search for.
+     * @param {number} [fromIndex=array.length-1] The index to search from.
+     * @returns {number} Returns the index of the matched value, else `-1`.
+     * @example
+     *
+     * _.lastIndexOf([1, 2, 1, 2], 2);
+     * // => 3
+     *
+     * // Search from the `fromIndex`.
+     * _.lastIndexOf([1, 2, 1, 2], 2, 2);
+     * // => 1
+     */function lastIndexOf(array,value,fromIndex){var length=array==null?0:array.length;if(!length){return -1;}var index=length;if(fromIndex!==undefined$1){index=toInteger(fromIndex);index=index<0?nativeMax(length+index,0):nativeMin(index,length-1);}return value===value?strictLastIndexOf(array,value,index):baseFindIndex(array,baseIsNaN,index,true);}/**
+     * Gets the element at index `n` of `array`. If `n` is negative, the nth
+     * element from the end is returned.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.11.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {number} [n=0] The index of the element to return.
+     * @returns {*} Returns the nth element of `array`.
+     * @example
+     *
+     * var array = ['a', 'b', 'c', 'd'];
+     *
+     * _.nth(array, 1);
+     * // => 'b'
+     *
+     * _.nth(array, -2);
+     * // => 'c';
+     */function nth(array,n){return array&&array.length?baseNth(array,toInteger(n)):undefined$1;}/**
+     * Removes all given values from `array` using
+     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons.
+     *
+     * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
+     * to remove elements from an array by predicate.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Array
+     * @param {Array} array The array to modify.
+     * @param {...*} [values] The values to remove.
+     * @returns {Array} Returns `array`.
+     * @example
+     *
+     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
+     *
+     * _.pull(array, 'a', 'c');
+     * console.log(array);
+     * // => ['b', 'b']
+     */var pull=baseRest(pullAll);/**
+     * This method is like `_.pull` except that it accepts an array of values to remove.
+     *
+     * **Note:** Unlike `_.difference`, this method mutates `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to modify.
+     * @param {Array} values The values to remove.
+     * @returns {Array} Returns `array`.
+     * @example
+     *
+     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
+     *
+     * _.pullAll(array, ['a', 'c']);
+     * console.log(array);
+     * // => ['b', 'b']
+     */function pullAll(array,values){return array&&array.length&&values&&values.length?basePullAll(array,values):array;}/**
+     * This method is like `_.pullAll` except that it accepts `iteratee` which is
+     * invoked for each element of `array` and `values` to generate the criterion
+     * by which they're compared. The iteratee is invoked with one argument: (value).
+     *
+     * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to modify.
+     * @param {Array} values The values to remove.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {Array} Returns `array`.
+     * @example
+     *
+     * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
+     *
+     * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
+     * console.log(array);
+     * // => [{ 'x': 2 }]
+     */function pullAllBy(array,values,iteratee){return array&&array.length&&values&&values.length?basePullAll(array,values,getIteratee(iteratee,2)):array;}/**
+     * This method is like `_.pullAll` except that it accepts `comparator` which
+     * is invoked to compare elements of `array` to `values`. The comparator is
+     * invoked with two arguments: (arrVal, othVal).
+     *
+     * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.6.0
+     * @category Array
+     * @param {Array} array The array to modify.
+     * @param {Array} values The values to remove.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns `array`.
+     * @example
+     *
+     * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
+     *
+     * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
+     * console.log(array);
+     * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
+     */function pullAllWith(array,values,comparator){return array&&array.length&&values&&values.length?basePullAll(array,values,undefined$1,comparator):array;}/**
+     * Removes elements from `array` corresponding to `indexes` and returns an
+     * array of removed elements.
+     *
+     * **Note:** Unlike `_.at`, this method mutates `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to modify.
+     * @param {...(number|number[])} [indexes] The indexes of elements to remove.
+     * @returns {Array} Returns the new array of removed elements.
+     * @example
+     *
+     * var array = ['a', 'b', 'c', 'd'];
+     * var pulled = _.pullAt(array, [1, 3]);
+     *
+     * console.log(array);
+     * // => ['a', 'c']
+     *
+     * console.log(pulled);
+     * // => ['b', 'd']
+     */var pullAt=flatRest(function(array,indexes){var length=array==null?0:array.length,result=baseAt(array,indexes);basePullAt(array,arrayMap(indexes,function(index){return isIndex(index,length)?+index:index;}).sort(compareAscending));return result;});/**
+     * Removes all elements from `array` that `predicate` returns truthy for
+     * and returns an array of the removed elements. The predicate is invoked
+     * with three arguments: (value, index, array).
+     *
+     * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
+     * to pull elements from an array by value.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Array
+     * @param {Array} array The array to modify.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the new array of removed elements.
+     * @example
+     *
+     * var array = [1, 2, 3, 4];
+     * var evens = _.remove(array, function(n) {
+     *   return n % 2 == 0;
+     * });
+     *
+     * console.log(array);
+     * // => [1, 3]
+     *
+     * console.log(evens);
+     * // => [2, 4]
+     */function remove(array,predicate){var result=[];if(!(array&&array.length)){return result;}var index=-1,indexes=[],length=array.length;predicate=getIteratee(predicate,3);while(++index<length){var value=array[index];if(predicate(value,index,array)){result.push(value);indexes.push(index);}}basePullAt(array,indexes);return result;}/**
+     * Reverses `array` so that the first element becomes the last, the second
+     * element becomes the second to last, and so on.
+     *
+     * **Note:** This method mutates `array` and is based on
+     * [`Array#reverse`](https://mdn.io/Array/reverse).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to modify.
+     * @returns {Array} Returns `array`.
+     * @example
+     *
+     * var array = [1, 2, 3];
+     *
+     * _.reverse(array);
+     * // => [3, 2, 1]
+     *
+     * console.log(array);
+     * // => [3, 2, 1]
+     */function reverse(array){return array==null?array:nativeReverse.call(array);}/**
+     * Creates a slice of `array` from `start` up to, but not including, `end`.
+     *
+     * **Note:** This method is used instead of
+     * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
+     * returned.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to slice.
+     * @param {number} [start=0] The start position.
+     * @param {number} [end=array.length] The end position.
+     * @returns {Array} Returns the slice of `array`.
+     */function slice(array,start,end){var length=array==null?0:array.length;if(!length){return [];}if(end&&typeof end!='number'&&isIterateeCall(array,start,end)){start=0;end=length;}else {start=start==null?0:toInteger(start);end=end===undefined$1?length:toInteger(end);}return baseSlice(array,start,end);}/**
+     * Uses a binary search to determine the lowest index at which `value`
+     * should be inserted into `array` in order to maintain its sort order.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     * @example
+     *
+     * _.sortedIndex([30, 50], 40);
+     * // => 1
+     */function sortedIndex(array,value){return baseSortedIndex(array,value);}/**
+     * This method is like `_.sortedIndex` except that it accepts `iteratee`
+     * which is invoked for `value` and each element of `array` to compute their
+     * sort ranking. The iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     * @example
+     *
+     * var objects = [{ 'x': 4 }, { 'x': 5 }];
+     *
+     * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
+     * // => 0
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
+     * // => 0
+     */function sortedIndexBy(array,value,iteratee){return baseSortedIndexBy(array,value,getIteratee(iteratee,2));}/**
+     * This method is like `_.indexOf` except that it performs a binary
+     * search on a sorted `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {*} value The value to search for.
+     * @returns {number} Returns the index of the matched value, else `-1`.
+     * @example
+     *
+     * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
+     * // => 1
+     */function sortedIndexOf(array,value){var length=array==null?0:array.length;if(length){var index=baseSortedIndex(array,value);if(index<length&&eq(array[index],value)){return index;}}return -1;}/**
+     * This method is like `_.sortedIndex` except that it returns the highest
+     * index at which `value` should be inserted into `array` in order to
+     * maintain its sort order.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     * @example
+     *
+     * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
+     * // => 4
+     */function sortedLastIndex(array,value){return baseSortedIndex(array,value,true);}/**
+     * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
+     * which is invoked for `value` and each element of `array` to compute their
+     * sort ranking. The iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The sorted array to inspect.
+     * @param {*} value The value to evaluate.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {number} Returns the index at which `value` should be inserted
+     *  into `array`.
+     * @example
+     *
+     * var objects = [{ 'x': 4 }, { 'x': 5 }];
+     *
+     * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
+     * // => 1
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
+     * // => 1
+     */function sortedLastIndexBy(array,value,iteratee){return baseSortedIndexBy(array,value,getIteratee(iteratee,2),true);}/**
+     * This method is like `_.lastIndexOf` except that it performs a binary
+     * search on a sorted `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {*} value The value to search for.
+     * @returns {number} Returns the index of the matched value, else `-1`.
+     * @example
+     *
+     * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
+     * // => 3
+     */function sortedLastIndexOf(array,value){var length=array==null?0:array.length;if(length){var index=baseSortedIndex(array,value,true)-1;if(eq(array[index],value)){return index;}}return -1;}/**
+     * This method is like `_.uniq` except that it's designed and optimized
+     * for sorted arrays.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @returns {Array} Returns the new duplicate free array.
+     * @example
+     *
+     * _.sortedUniq([1, 1, 2]);
+     * // => [1, 2]
+     */function sortedUniq(array){return array&&array.length?baseSortedUniq(array):[];}/**
+     * This method is like `_.uniqBy` except that it's designed and optimized
+     * for sorted arrays.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {Function} [iteratee] The iteratee invoked per element.
+     * @returns {Array} Returns the new duplicate free array.
+     * @example
+     *
+     * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
+     * // => [1.1, 2.3]
+     */function sortedUniqBy(array,iteratee){return array&&array.length?baseSortedUniq(array,getIteratee(iteratee,2)):[];}/**
+     * Gets all but the first element of `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * _.tail([1, 2, 3]);
+     * // => [2, 3]
+     */function tail(array){var length=array==null?0:array.length;return length?baseSlice(array,1,length):[];}/**
+     * Creates a slice of `array` with `n` elements taken from the beginning.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {number} [n=1] The number of elements to take.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * _.take([1, 2, 3]);
+     * // => [1]
+     *
+     * _.take([1, 2, 3], 2);
+     * // => [1, 2]
+     *
+     * _.take([1, 2, 3], 5);
+     * // => [1, 2, 3]
+     *
+     * _.take([1, 2, 3], 0);
+     * // => []
+     */function take(array,n,guard){if(!(array&&array.length)){return [];}n=guard||n===undefined$1?1:toInteger(n);return baseSlice(array,0,n<0?0:n);}/**
+     * Creates a slice of `array` with `n` elements taken from the end.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {number} [n=1] The number of elements to take.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * _.takeRight([1, 2, 3]);
+     * // => [3]
+     *
+     * _.takeRight([1, 2, 3], 2);
+     * // => [2, 3]
+     *
+     * _.takeRight([1, 2, 3], 5);
+     * // => [1, 2, 3]
+     *
+     * _.takeRight([1, 2, 3], 0);
+     * // => []
+     */function takeRight(array,n,guard){var length=array==null?0:array.length;if(!length){return [];}n=guard||n===undefined$1?1:toInteger(n);n=length-n;return baseSlice(array,n<0?0:n,length);}/**
+     * Creates a slice of `array` with elements taken from the end. Elements are
+     * taken until `predicate` returns falsey. The predicate is invoked with
+     * three arguments: (value, index, array).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'active': true },
+     *   { 'user': 'fred',    'active': false },
+     *   { 'user': 'pebbles', 'active': false }
+     * ];
+     *
+     * _.takeRightWhile(users, function(o) { return !o.active; });
+     * // => objects for ['fred', 'pebbles']
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
+     * // => objects for ['pebbles']
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.takeRightWhile(users, ['active', false]);
+     * // => objects for ['fred', 'pebbles']
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.takeRightWhile(users, 'active');
+     * // => []
+     */function takeRightWhile(array,predicate){return array&&array.length?baseWhile(array,getIteratee(predicate,3),false,true):[];}/**
+     * Creates a slice of `array` with elements taken from the beginning. Elements
+     * are taken until `predicate` returns falsey. The predicate is invoked with
+     * three arguments: (value, index, array).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Array
+     * @param {Array} array The array to query.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the slice of `array`.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'active': false },
+     *   { 'user': 'fred',    'active': false },
+     *   { 'user': 'pebbles', 'active': true }
+     * ];
+     *
+     * _.takeWhile(users, function(o) { return !o.active; });
+     * // => objects for ['barney', 'fred']
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.takeWhile(users, { 'user': 'barney', 'active': false });
+     * // => objects for ['barney']
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.takeWhile(users, ['active', false]);
+     * // => objects for ['barney', 'fred']
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.takeWhile(users, 'active');
+     * // => []
+     */function takeWhile(array,predicate){return array&&array.length?baseWhile(array,getIteratee(predicate,3)):[];}/**
+     * Creates an array of unique values, in order, from all given arrays using
+     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @returns {Array} Returns the new array of combined values.
+     * @example
+     *
+     * _.union([2], [1, 2]);
+     * // => [2, 1]
+     */var union=baseRest(function(arrays){return baseUniq(baseFlatten(arrays,1,isArrayLikeObject,true));});/**
+     * This method is like `_.union` except that it accepts `iteratee` which is
+     * invoked for each element of each `arrays` to generate the criterion by
+     * which uniqueness is computed. Result values are chosen from the first
+     * array in which the value occurs. The iteratee is invoked with one argument:
+     * (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {Array} Returns the new array of combined values.
+     * @example
+     *
+     * _.unionBy([2.1], [1.2, 2.3], Math.floor);
+     * // => [2.1, 1.2]
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+     * // => [{ 'x': 1 }, { 'x': 2 }]
+     */var unionBy=baseRest(function(arrays){var iteratee=last(arrays);if(isArrayLikeObject(iteratee)){iteratee=undefined$1;}return baseUniq(baseFlatten(arrays,1,isArrayLikeObject,true),getIteratee(iteratee,2));});/**
+     * This method is like `_.union` except that it accepts `comparator` which
+     * is invoked to compare elements of `arrays`. Result values are chosen from
+     * the first array in which the value occurs. The comparator is invoked
+     * with two arguments: (arrVal, othVal).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of combined values.
+     * @example
+     *
+     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+     *
+     * _.unionWith(objects, others, _.isEqual);
+     * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
+     */var unionWith=baseRest(function(arrays){var comparator=last(arrays);comparator=typeof comparator=='function'?comparator:undefined$1;return baseUniq(baseFlatten(arrays,1,isArrayLikeObject,true),undefined$1,comparator);});/**
+     * Creates a duplicate-free version of an array, using
+     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons, in which only the first occurrence of each element
+     * is kept. The order of result values is determined by the order they occur
+     * in the array.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @returns {Array} Returns the new duplicate free array.
+     * @example
+     *
+     * _.uniq([2, 1, 2]);
+     * // => [2, 1]
+     */function uniq(array){return array&&array.length?baseUniq(array):[];}/**
+     * This method is like `_.uniq` except that it accepts `iteratee` which is
+     * invoked for each element in `array` to generate the criterion by which
+     * uniqueness is computed. The order of result values is determined by the
+     * order they occur in the array. The iteratee is invoked with one argument:
+     * (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {Array} Returns the new duplicate free array.
+     * @example
+     *
+     * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
+     * // => [2.1, 1.2]
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
+     * // => [{ 'x': 1 }, { 'x': 2 }]
+     */function uniqBy(array,iteratee){return array&&array.length?baseUniq(array,getIteratee(iteratee,2)):[];}/**
+     * This method is like `_.uniq` except that it accepts `comparator` which
+     * is invoked to compare elements of `array`. The order of result values is
+     * determined by the order they occur in the array.The comparator is invoked
+     * with two arguments: (arrVal, othVal).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new duplicate free array.
+     * @example
+     *
+     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
+     *
+     * _.uniqWith(objects, _.isEqual);
+     * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
+     */function uniqWith(array,comparator){comparator=typeof comparator=='function'?comparator:undefined$1;return array&&array.length?baseUniq(array,undefined$1,comparator):[];}/**
+     * This method is like `_.zip` except that it accepts an array of grouped
+     * elements and creates an array regrouping the elements to their pre-zip
+     * configuration.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.2.0
+     * @category Array
+     * @param {Array} array The array of grouped elements to process.
+     * @returns {Array} Returns the new array of regrouped elements.
+     * @example
+     *
+     * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
+     * // => [['a', 1, true], ['b', 2, false]]
+     *
+     * _.unzip(zipped);
+     * // => [['a', 'b'], [1, 2], [true, false]]
+     */function unzip(array){if(!(array&&array.length)){return [];}var length=0;array=arrayFilter(array,function(group){if(isArrayLikeObject(group)){length=nativeMax(group.length,length);return true;}});return baseTimes(length,function(index){return arrayMap(array,baseProperty(index));});}/**
+     * This method is like `_.unzip` except that it accepts `iteratee` to specify
+     * how regrouped values should be combined. The iteratee is invoked with the
+     * elements of each group: (...group).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.8.0
+     * @category Array
+     * @param {Array} array The array of grouped elements to process.
+     * @param {Function} [iteratee=_.identity] The function to combine
+     *  regrouped values.
+     * @returns {Array} Returns the new array of regrouped elements.
+     * @example
+     *
+     * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
+     * // => [[1, 10, 100], [2, 20, 200]]
+     *
+     * _.unzipWith(zipped, _.add);
+     * // => [3, 30, 300]
+     */function unzipWith(array,iteratee){if(!(array&&array.length)){return [];}var result=unzip(array);if(iteratee==null){return result;}return arrayMap(result,function(group){return apply(iteratee,undefined$1,group);});}/**
+     * Creates an array excluding all given values using
+     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * for equality comparisons.
+     *
+     * **Note:** Unlike `_.pull`, this method returns a new array.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {Array} array The array to inspect.
+     * @param {...*} [values] The values to exclude.
+     * @returns {Array} Returns the new array of filtered values.
+     * @see _.difference, _.xor
+     * @example
+     *
+     * _.without([2, 1, 2, 3], 1, 2);
+     * // => [3]
+     */var without=baseRest(function(array,values){return isArrayLikeObject(array)?baseDifference(array,values):[];});/**
+     * Creates an array of unique values that is the
+     * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
+     * of the given arrays. The order of result values is determined by the order
+     * they occur in the arrays.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.4.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @returns {Array} Returns the new array of filtered values.
+     * @see _.difference, _.without
+     * @example
+     *
+     * _.xor([2, 1], [2, 3]);
+     * // => [1, 3]
+     */var xor=baseRest(function(arrays){return baseXor(arrayFilter(arrays,isArrayLikeObject));});/**
+     * This method is like `_.xor` except that it accepts `iteratee` which is
+     * invoked for each element of each `arrays` to generate the criterion by
+     * which by which they're compared. The order of result values is determined
+     * by the order they occur in the arrays. The iteratee is invoked with one
+     * argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {Array} Returns the new array of filtered values.
+     * @example
+     *
+     * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
+     * // => [1.2, 3.4]
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
+     * // => [{ 'x': 2 }]
+     */var xorBy=baseRest(function(arrays){var iteratee=last(arrays);if(isArrayLikeObject(iteratee)){iteratee=undefined$1;}return baseXor(arrayFilter(arrays,isArrayLikeObject),getIteratee(iteratee,2));});/**
+     * This method is like `_.xor` except that it accepts `comparator` which is
+     * invoked to compare elements of `arrays`. The order of result values is
+     * determined by the order they occur in the arrays. The comparator is invoked
+     * with two arguments: (arrVal, othVal).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to inspect.
+     * @param {Function} [comparator] The comparator invoked per element.
+     * @returns {Array} Returns the new array of filtered values.
+     * @example
+     *
+     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
+     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
+     *
+     * _.xorWith(objects, others, _.isEqual);
+     * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
+     */var xorWith=baseRest(function(arrays){var comparator=last(arrays);comparator=typeof comparator=='function'?comparator:undefined$1;return baseXor(arrayFilter(arrays,isArrayLikeObject),undefined$1,comparator);});/**
+     * Creates an array of grouped elements, the first of which contains the
+     * first elements of the given arrays, the second of which contains the
+     * second elements of the given arrays, and so on.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to process.
+     * @returns {Array} Returns the new array of grouped elements.
+     * @example
+     *
+     * _.zip(['a', 'b'], [1, 2], [true, false]);
+     * // => [['a', 1, true], ['b', 2, false]]
+     */var zip=baseRest(unzip);/**
+     * This method is like `_.fromPairs` except that it accepts two arrays,
+     * one of property identifiers and one of corresponding values.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.4.0
+     * @category Array
+     * @param {Array} [props=[]] The property identifiers.
+     * @param {Array} [values=[]] The property values.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * _.zipObject(['a', 'b'], [1, 2]);
+     * // => { 'a': 1, 'b': 2 }
+     */function zipObject(props,values){return baseZipObject(props||[],values||[],assignValue);}/**
+     * This method is like `_.zipObject` except that it supports property paths.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.1.0
+     * @category Array
+     * @param {Array} [props=[]] The property identifiers.
+     * @param {Array} [values=[]] The property values.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
+     * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
+     */function zipObjectDeep(props,values){return baseZipObject(props||[],values||[],baseSet);}/**
+     * This method is like `_.zip` except that it accepts `iteratee` to specify
+     * how grouped values should be combined. The iteratee is invoked with the
+     * elements of each group: (...group).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.8.0
+     * @category Array
+     * @param {...Array} [arrays] The arrays to process.
+     * @param {Function} [iteratee=_.identity] The function to combine
+     *  grouped values.
+     * @returns {Array} Returns the new array of grouped elements.
+     * @example
+     *
+     * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
+     *   return a + b + c;
+     * });
+     * // => [111, 222]
+     */var zipWith=baseRest(function(arrays){var length=arrays.length,iteratee=length>1?arrays[length-1]:undefined$1;iteratee=typeof iteratee=='function'?(arrays.pop(),iteratee):undefined$1;return unzipWith(arrays,iteratee);});/*------------------------------------------------------------------------*/ /**
+     * Creates a `lodash` wrapper instance that wraps `value` with explicit method
+     * chain sequences enabled. The result of such sequences must be unwrapped
+     * with `_#value`.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.3.0
+     * @category Seq
+     * @param {*} value The value to wrap.
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'age': 36 },
+     *   { 'user': 'fred',    'age': 40 },
+     *   { 'user': 'pebbles', 'age': 1 }
+     * ];
+     *
+     * var youngest = _
+     *   .chain(users)
+     *   .sortBy('age')
+     *   .map(function(o) {
+     *     return o.user + ' is ' + o.age;
+     *   })
+     *   .head()
+     *   .value();
+     * // => 'pebbles is 1'
+     */function chain(value){var result=lodash(value);result.__chain__=true;return result;}/**
+     * This method invokes `interceptor` and returns `value`. The interceptor
+     * is invoked with one argument; (value). The purpose of this method is to
+     * "tap into" a method chain sequence in order to modify intermediate results.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Seq
+     * @param {*} value The value to provide to `interceptor`.
+     * @param {Function} interceptor The function to invoke.
+     * @returns {*} Returns `value`.
+     * @example
+     *
+     * _([1, 2, 3])
+     *  .tap(function(array) {
+     *    // Mutate input array.
+     *    array.pop();
+     *  })
+     *  .reverse()
+     *  .value();
+     * // => [2, 1]
+     */function tap(value,interceptor){interceptor(value);return value;}/**
+     * This method is like `_.tap` except that it returns the result of `interceptor`.
+     * The purpose of this method is to "pass thru" values replacing intermediate
+     * results in a method chain sequence.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Seq
+     * @param {*} value The value to provide to `interceptor`.
+     * @param {Function} interceptor The function to invoke.
+     * @returns {*} Returns the result of `interceptor`.
+     * @example
+     *
+     * _('  abc  ')
+     *  .chain()
+     *  .trim()
+     *  .thru(function(value) {
+     *    return [value];
+     *  })
+     *  .value();
+     * // => ['abc']
+     */function thru(value,interceptor){return interceptor(value);}/**
+     * This method is the wrapper version of `_.at`.
+     *
+     * @name at
+     * @memberOf _
+     * @since 1.0.0
+     * @category Seq
+     * @param {...(string|string[])} [paths] The property paths to pick.
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
+     *
+     * _(object).at(['a[0].b.c', 'a[1]']).value();
+     * // => [3, 4]
+     */var wrapperAt=flatRest(function(paths){var length=paths.length,start=length?paths[0]:0,value=this.__wrapped__,interceptor=function(object){return baseAt(object,paths);};if(length>1||this.__actions__.length||!(value instanceof LazyWrapper)||!isIndex(start)){return this.thru(interceptor);}value=value.slice(start,+start+(length?1:0));value.__actions__.push({'func':thru,'args':[interceptor],'thisArg':undefined$1});return new LodashWrapper(value,this.__chain__).thru(function(array){if(length&&!array.length){array.push(undefined$1);}return array;});});/**
+     * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
+     *
+     * @name chain
+     * @memberOf _
+     * @since 0.1.0
+     * @category Seq
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney', 'age': 36 },
+     *   { 'user': 'fred',   'age': 40 }
+     * ];
+     *
+     * // A sequence without explicit chaining.
+     * _(users).head();
+     * // => { 'user': 'barney', 'age': 36 }
+     *
+     * // A sequence with explicit chaining.
+     * _(users)
+     *   .chain()
+     *   .head()
+     *   .pick('user')
+     *   .value();
+     * // => { 'user': 'barney' }
+     */function wrapperChain(){return chain(this);}/**
+     * Executes the chain sequence and returns the wrapped result.
+     *
+     * @name commit
+     * @memberOf _
+     * @since 3.2.0
+     * @category Seq
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * var array = [1, 2];
+     * var wrapped = _(array).push(3);
+     *
+     * console.log(array);
+     * // => [1, 2]
+     *
+     * wrapped = wrapped.commit();
+     * console.log(array);
+     * // => [1, 2, 3]
+     *
+     * wrapped.last();
+     * // => 3
+     *
+     * console.log(array);
+     * // => [1, 2, 3]
+     */function wrapperCommit(){return new LodashWrapper(this.value(),this.__chain__);}/**
+     * Gets the next value on a wrapped object following the
+     * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
+     *
+     * @name next
+     * @memberOf _
+     * @since 4.0.0
+     * @category Seq
+     * @returns {Object} Returns the next iterator value.
+     * @example
+     *
+     * var wrapped = _([1, 2]);
+     *
+     * wrapped.next();
+     * // => { 'done': false, 'value': 1 }
+     *
+     * wrapped.next();
+     * // => { 'done': false, 'value': 2 }
+     *
+     * wrapped.next();
+     * // => { 'done': true, 'value': undefined }
+     */function wrapperNext(){if(this.__values__===undefined$1){this.__values__=toArray(this.value());}var done=this.__index__>=this.__values__.length,value=done?undefined$1:this.__values__[this.__index__++];return {'done':done,'value':value};}/**
+     * Enables the wrapper to be iterable.
+     *
+     * @name Symbol.iterator
+     * @memberOf _
+     * @since 4.0.0
+     * @category Seq
+     * @returns {Object} Returns the wrapper object.
+     * @example
+     *
+     * var wrapped = _([1, 2]);
+     *
+     * wrapped[Symbol.iterator]() === wrapped;
+     * // => true
+     *
+     * Array.from(wrapped);
+     * // => [1, 2]
+     */function wrapperToIterator(){return this;}/**
+     * Creates a clone of the chain sequence planting `value` as the wrapped value.
+     *
+     * @name plant
+     * @memberOf _
+     * @since 3.2.0
+     * @category Seq
+     * @param {*} value The value to plant.
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * function square(n) {
+     *   return n * n;
+     * }
+     *
+     * var wrapped = _([1, 2]).map(square);
+     * var other = wrapped.plant([3, 4]);
+     *
+     * other.value();
+     * // => [9, 16]
+     *
+     * wrapped.value();
+     * // => [1, 4]
+     */function wrapperPlant(value){var result,parent=this;while(parent instanceof baseLodash){var clone=wrapperClone(parent);clone.__index__=0;clone.__values__=undefined$1;if(result){previous.__wrapped__=clone;}else {result=clone;}var previous=clone;parent=parent.__wrapped__;}previous.__wrapped__=value;return result;}/**
+     * This method is the wrapper version of `_.reverse`.
+     *
+     * **Note:** This method mutates the wrapped array.
+     *
+     * @name reverse
+     * @memberOf _
+     * @since 0.1.0
+     * @category Seq
+     * @returns {Object} Returns the new `lodash` wrapper instance.
+     * @example
+     *
+     * var array = [1, 2, 3];
+     *
+     * _(array).reverse().value()
+     * // => [3, 2, 1]
+     *
+     * console.log(array);
+     * // => [3, 2, 1]
+     */function wrapperReverse(){var value=this.__wrapped__;if(value instanceof LazyWrapper){var wrapped=value;if(this.__actions__.length){wrapped=new LazyWrapper(this);}wrapped=wrapped.reverse();wrapped.__actions__.push({'func':thru,'args':[reverse],'thisArg':undefined$1});return new LodashWrapper(wrapped,this.__chain__);}return this.thru(reverse);}/**
+     * Executes the chain sequence to resolve the unwrapped value.
+     *
+     * @name value
+     * @memberOf _
+     * @since 0.1.0
+     * @alias toJSON, valueOf
+     * @category Seq
+     * @returns {*} Returns the resolved unwrapped value.
+     * @example
+     *
+     * _([1, 2, 3]).value();
+     * // => [1, 2, 3]
+     */function wrapperValue(){return baseWrapperValue(this.__wrapped__,this.__actions__);}/*------------------------------------------------------------------------*/ /**
+     * Creates an object composed of keys generated from the results of running
+     * each element of `collection` thru `iteratee`. The corresponding value of
+     * each key is the number of times the key was returned by `iteratee`. The
+     * iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.5.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+     * @returns {Object} Returns the composed aggregate object.
+     * @example
+     *
+     * _.countBy([6.1, 4.2, 6.3], Math.floor);
+     * // => { '4': 1, '6': 2 }
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.countBy(['one', 'two', 'three'], 'length');
+     * // => { '3': 2, '5': 1 }
+     */var countBy=createAggregator(function(result,value,key){if(hasOwnProperty.call(result,key)){++result[key];}else {baseAssignValue(result,key,1);}});/**
+     * Checks if `predicate` returns truthy for **all** elements of `collection`.
+     * Iteration is stopped once `predicate` returns falsey. The predicate is
+     * invoked with three arguments: (value, index|key, collection).
+     *
+     * **Note:** This method returns `true` for
+     * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
+     * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
+     * elements of empty collections.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {boolean} Returns `true` if all elements pass the predicate check,
+     *  else `false`.
+     * @example
+     *
+     * _.every([true, 1, null, 'yes'], Boolean);
+     * // => false
+     *
+     * var users = [
+     *   { 'user': 'barney', 'age': 36, 'active': false },
+     *   { 'user': 'fred',   'age': 40, 'active': false }
+     * ];
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.every(users, { 'user': 'barney', 'active': false });
+     * // => false
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.every(users, ['active', false]);
+     * // => true
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.every(users, 'active');
+     * // => false
+     */function every(collection,predicate,guard){var func=isArray(collection)?arrayEvery:baseEvery;if(guard&&isIterateeCall(collection,predicate,guard)){predicate=undefined$1;}return func(collection,getIteratee(predicate,3));}/**
+     * Iterates over elements of `collection`, returning an array of all elements
+     * `predicate` returns truthy for. The predicate is invoked with three
+     * arguments: (value, index|key, collection).
+     *
+     * **Note:** Unlike `_.remove`, this method returns a new array.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the new filtered array.
+     * @see _.reject
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney', 'age': 36, 'active': true },
+     *   { 'user': 'fred',   'age': 40, 'active': false }
+     * ];
+     *
+     * _.filter(users, function(o) { return !o.active; });
+     * // => objects for ['fred']
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.filter(users, { 'age': 36, 'active': true });
+     * // => objects for ['barney']
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.filter(users, ['active', false]);
+     * // => objects for ['fred']
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.filter(users, 'active');
+     * // => objects for ['barney']
+     *
+     * // Combining several predicates using `_.overEvery` or `_.overSome`.
+     * _.filter(users, _.overSome([{ 'age': 36 }, ['age', 40]]));
+     * // => objects for ['fred', 'barney']
+     */function filter(collection,predicate){var func=isArray(collection)?arrayFilter:baseFilter;return func(collection,getIteratee(predicate,3));}/**
+     * Iterates over elements of `collection`, returning the first element
+     * `predicate` returns truthy for. The predicate is invoked with three
+     * arguments: (value, index|key, collection).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to inspect.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @param {number} [fromIndex=0] The index to search from.
+     * @returns {*} Returns the matched element, else `undefined`.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'age': 36, 'active': true },
+     *   { 'user': 'fred',    'age': 40, 'active': false },
+     *   { 'user': 'pebbles', 'age': 1,  'active': true }
+     * ];
+     *
+     * _.find(users, function(o) { return o.age < 40; });
+     * // => object for 'barney'
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.find(users, { 'age': 1, 'active': true });
+     * // => object for 'pebbles'
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.find(users, ['active', false]);
+     * // => object for 'fred'
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.find(users, 'active');
+     * // => object for 'barney'
+     */var find=createFind(findIndex);/**
+     * This method is like `_.find` except that it iterates over elements of
+     * `collection` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to inspect.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @param {number} [fromIndex=collection.length-1] The index to search from.
+     * @returns {*} Returns the matched element, else `undefined`.
+     * @example
+     *
+     * _.findLast([1, 2, 3, 4], function(n) {
+     *   return n % 2 == 1;
+     * });
+     * // => 3
+     */var findLast=createFind(findLastIndex);/**
+     * Creates a flattened array of values by running each element in `collection`
+     * thru `iteratee` and flattening the mapped results. The iteratee is invoked
+     * with three arguments: (value, index|key, collection).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the new flattened array.
+     * @example
+     *
+     * function duplicate(n) {
+     *   return [n, n];
+     * }
+     *
+     * _.flatMap([1, 2], duplicate);
+     * // => [1, 1, 2, 2]
+     */function flatMap(collection,iteratee){return baseFlatten(map(collection,iteratee),1);}/**
+     * This method is like `_.flatMap` except that it recursively flattens the
+     * mapped results.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.7.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the new flattened array.
+     * @example
+     *
+     * function duplicate(n) {
+     *   return [[[n, n]]];
+     * }
+     *
+     * _.flatMapDeep([1, 2], duplicate);
+     * // => [1, 1, 2, 2]
+     */function flatMapDeep(collection,iteratee){return baseFlatten(map(collection,iteratee),INFINITY);}/**
+     * This method is like `_.flatMap` except that it recursively flattens the
+     * mapped results up to `depth` times.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.7.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @param {number} [depth=1] The maximum recursion depth.
+     * @returns {Array} Returns the new flattened array.
+     * @example
+     *
+     * function duplicate(n) {
+     *   return [[[n, n]]];
+     * }
+     *
+     * _.flatMapDepth([1, 2], duplicate, 2);
+     * // => [[1, 1], [2, 2]]
+     */function flatMapDepth(collection,iteratee,depth){depth=depth===undefined$1?1:toInteger(depth);return baseFlatten(map(collection,iteratee),depth);}/**
+     * Iterates over elements of `collection` and invokes `iteratee` for each element.
+     * The iteratee is invoked with three arguments: (value, index|key, collection).
+     * Iteratee functions may exit iteration early by explicitly returning `false`.
+     *
+     * **Note:** As with other "Collections" methods, objects with a "length"
+     * property are iterated like arrays. To avoid this behavior use `_.forIn`
+     * or `_.forOwn` for object iteration.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @alias each
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Array|Object} Returns `collection`.
+     * @see _.forEachRight
+     * @example
+     *
+     * _.forEach([1, 2], function(value) {
+     *   console.log(value);
+     * });
+     * // => Logs `1` then `2`.
+     *
+     * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
+     *   console.log(key);
+     * });
+     * // => Logs 'a' then 'b' (iteration order is not guaranteed).
+     */function forEach(collection,iteratee){var func=isArray(collection)?arrayEach:baseEach;return func(collection,getIteratee(iteratee,3));}/**
+     * This method is like `_.forEach` except that it iterates over elements of
+     * `collection` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @alias eachRight
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Array|Object} Returns `collection`.
+     * @see _.forEach
+     * @example
+     *
+     * _.forEachRight([1, 2], function(value) {
+     *   console.log(value);
+     * });
+     * // => Logs `2` then `1`.
+     */function forEachRight(collection,iteratee){var func=isArray(collection)?arrayEachRight:baseEachRight;return func(collection,getIteratee(iteratee,3));}/**
+     * Creates an object composed of keys generated from the results of running
+     * each element of `collection` thru `iteratee`. The order of grouped values
+     * is determined by the order they occur in `collection`. The corresponding
+     * value of each key is an array of elements responsible for generating the
+     * key. The iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+     * @returns {Object} Returns the composed aggregate object.
+     * @example
+     *
+     * _.groupBy([6.1, 4.2, 6.3], Math.floor);
+     * // => { '4': [4.2], '6': [6.1, 6.3] }
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.groupBy(['one', 'two', 'three'], 'length');
+     * // => { '3': ['one', 'two'], '5': ['three'] }
+     */var groupBy=createAggregator(function(result,value,key){if(hasOwnProperty.call(result,key)){result[key].push(value);}else {baseAssignValue(result,key,[value]);}});/**
+     * Checks if `value` is in `collection`. If `collection` is a string, it's
+     * checked for a substring of `value`, otherwise
+     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * is used for equality comparisons. If `fromIndex` is negative, it's used as
+     * the offset from the end of `collection`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object|string} collection The collection to inspect.
+     * @param {*} value The value to search for.
+     * @param {number} [fromIndex=0] The index to search from.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
+     * @returns {boolean} Returns `true` if `value` is found, else `false`.
+     * @example
+     *
+     * _.includes([1, 2, 3], 1);
+     * // => true
+     *
+     * _.includes([1, 2, 3], 1, 2);
+     * // => false
+     *
+     * _.includes({ 'a': 1, 'b': 2 }, 1);
+     * // => true
+     *
+     * _.includes('abcd', 'bc');
+     * // => true
+     */function includes(collection,value,fromIndex,guard){collection=isArrayLike(collection)?collection:values(collection);fromIndex=fromIndex&&!guard?toInteger(fromIndex):0;var length=collection.length;if(fromIndex<0){fromIndex=nativeMax(length+fromIndex,0);}return isString(collection)?fromIndex<=length&&collection.indexOf(value,fromIndex)>-1:!!length&&baseIndexOf(collection,value,fromIndex)>-1;}/**
+     * Invokes the method at `path` of each element in `collection`, returning
+     * an array of the results of each invoked method. Any additional arguments
+     * are provided to each invoked method. If `path` is a function, it's invoked
+     * for, and `this` bound to, each element in `collection`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Array|Function|string} path The path of the method to invoke or
+     *  the function invoked per iteration.
+     * @param {...*} [args] The arguments to invoke each method with.
+     * @returns {Array} Returns the array of results.
+     * @example
+     *
+     * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
+     * // => [[1, 5, 7], [1, 2, 3]]
+     *
+     * _.invokeMap([123, 456], String.prototype.split, '');
+     * // => [['1', '2', '3'], ['4', '5', '6']]
+     */var invokeMap=baseRest(function(collection,path,args){var index=-1,isFunc=typeof path=='function',result=isArrayLike(collection)?Array(collection.length):[];baseEach(collection,function(value){result[++index]=isFunc?apply(path,value,args):baseInvoke(value,path,args);});return result;});/**
+     * Creates an object composed of keys generated from the results of running
+     * each element of `collection` thru `iteratee`. The corresponding value of
+     * each key is the last element responsible for generating the key. The
+     * iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
+     * @returns {Object} Returns the composed aggregate object.
+     * @example
+     *
+     * var array = [
+     *   { 'dir': 'left', 'code': 97 },
+     *   { 'dir': 'right', 'code': 100 }
+     * ];
+     *
+     * _.keyBy(array, function(o) {
+     *   return String.fromCharCode(o.code);
+     * });
+     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
+     *
+     * _.keyBy(array, 'dir');
+     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
+     */var keyBy=createAggregator(function(result,value,key){baseAssignValue(result,key,value);});/**
+     * Creates an array of values by running each element in `collection` thru
+     * `iteratee`. The iteratee is invoked with three arguments:
+     * (value, index|key, collection).
+     *
+     * Many lodash methods are guarded to work as iteratees for methods like
+     * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
+     *
+     * The guarded methods are:
+     * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
+     * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
+     * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
+     * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the new mapped array.
+     * @example
+     *
+     * function square(n) {
+     *   return n * n;
+     * }
+     *
+     * _.map([4, 8], square);
+     * // => [16, 64]
+     *
+     * _.map({ 'a': 4, 'b': 8 }, square);
+     * // => [16, 64] (iteration order is not guaranteed)
+     *
+     * var users = [
+     *   { 'user': 'barney' },
+     *   { 'user': 'fred' }
+     * ];
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.map(users, 'user');
+     * // => ['barney', 'fred']
+     */function map(collection,iteratee){var func=isArray(collection)?arrayMap:baseMap;return func(collection,getIteratee(iteratee,3));}/**
+     * This method is like `_.sortBy` except that it allows specifying the sort
+     * orders of the iteratees to sort by. If `orders` is unspecified, all values
+     * are sorted in ascending order. Otherwise, specify an order of "desc" for
+     * descending or "asc" for ascending sort order of corresponding values.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
+     *  The iteratees to sort by.
+     * @param {string[]} [orders] The sort orders of `iteratees`.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
+     * @returns {Array} Returns the new sorted array.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'fred',   'age': 48 },
+     *   { 'user': 'barney', 'age': 34 },
+     *   { 'user': 'fred',   'age': 40 },
+     *   { 'user': 'barney', 'age': 36 }
+     * ];
+     *
+     * // Sort by `user` in ascending order and by `age` in descending order.
+     * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
+     * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
+     */function orderBy(collection,iteratees,orders,guard){if(collection==null){return [];}if(!isArray(iteratees)){iteratees=iteratees==null?[]:[iteratees];}orders=guard?undefined$1:orders;if(!isArray(orders)){orders=orders==null?[]:[orders];}return baseOrderBy(collection,iteratees,orders);}/**
+     * Creates an array of elements split into two groups, the first of which
+     * contains elements `predicate` returns truthy for, the second of which
+     * contains elements `predicate` returns falsey for. The predicate is
+     * invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the array of grouped elements.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney',  'age': 36, 'active': false },
+     *   { 'user': 'fred',    'age': 40, 'active': true },
+     *   { 'user': 'pebbles', 'age': 1,  'active': false }
+     * ];
+     *
+     * _.partition(users, function(o) { return o.active; });
+     * // => objects for [['fred'], ['barney', 'pebbles']]
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.partition(users, { 'age': 1, 'active': false });
+     * // => objects for [['pebbles'], ['barney', 'fred']]
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.partition(users, ['active', false]);
+     * // => objects for [['barney', 'pebbles'], ['fred']]
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.partition(users, 'active');
+     * // => objects for [['fred'], ['barney', 'pebbles']]
+     */var partition=createAggregator(function(result,value,key){result[key?0:1].push(value);},function(){return [[],[]];});/**
+     * Reduces `collection` to a value which is the accumulated result of running
+     * each element in `collection` thru `iteratee`, where each successive
+     * invocation is supplied the return value of the previous. If `accumulator`
+     * is not given, the first element of `collection` is used as the initial
+     * value. The iteratee is invoked with four arguments:
+     * (accumulator, value, index|key, collection).
+     *
+     * Many lodash methods are guarded to work as iteratees for methods like
+     * `_.reduce`, `_.reduceRight`, and `_.transform`.
+     *
+     * The guarded methods are:
+     * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
+     * and `sortBy`
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @param {*} [accumulator] The initial value.
+     * @returns {*} Returns the accumulated value.
+     * @see _.reduceRight
+     * @example
+     *
+     * _.reduce([1, 2], function(sum, n) {
+     *   return sum + n;
+     * }, 0);
+     * // => 3
+     *
+     * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
+     *   (result[value] || (result[value] = [])).push(key);
+     *   return result;
+     * }, {});
+     * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
+     */function reduce(collection,iteratee,accumulator){var func=isArray(collection)?arrayReduce:baseReduce,initAccum=arguments.length<3;return func(collection,getIteratee(iteratee,4),accumulator,initAccum,baseEach);}/**
+     * This method is like `_.reduce` except that it iterates over elements of
+     * `collection` from right to left.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @param {*} [accumulator] The initial value.
+     * @returns {*} Returns the accumulated value.
+     * @see _.reduce
+     * @example
+     *
+     * var array = [[0, 1], [2, 3], [4, 5]];
+     *
+     * _.reduceRight(array, function(flattened, other) {
+     *   return flattened.concat(other);
+     * }, []);
+     * // => [4, 5, 2, 3, 0, 1]
+     */function reduceRight(collection,iteratee,accumulator){var func=isArray(collection)?arrayReduceRight:baseReduce,initAccum=arguments.length<3;return func(collection,getIteratee(iteratee,4),accumulator,initAccum,baseEachRight);}/**
+     * The opposite of `_.filter`; this method returns the elements of `collection`
+     * that `predicate` does **not** return truthy for.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the new filtered array.
+     * @see _.filter
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney', 'age': 36, 'active': false },
+     *   { 'user': 'fred',   'age': 40, 'active': true }
+     * ];
+     *
+     * _.reject(users, function(o) { return !o.active; });
+     * // => objects for ['fred']
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.reject(users, { 'age': 40, 'active': true });
+     * // => objects for ['barney']
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.reject(users, ['active', false]);
+     * // => objects for ['fred']
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.reject(users, 'active');
+     * // => objects for ['barney']
+     */function reject(collection,predicate){var func=isArray(collection)?arrayFilter:baseFilter;return func(collection,negate(getIteratee(predicate,3)));}/**
+     * Gets a random element from `collection`.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to sample.
+     * @returns {*} Returns the random element.
+     * @example
+     *
+     * _.sample([1, 2, 3, 4]);
+     * // => 2
+     */function sample(collection){var func=isArray(collection)?arraySample:baseSample;return func(collection);}/**
+     * Gets `n` random elements at unique keys from `collection` up to the
+     * size of `collection`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to sample.
+     * @param {number} [n=1] The number of elements to sample.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Array} Returns the random elements.
+     * @example
+     *
+     * _.sampleSize([1, 2, 3], 2);
+     * // => [3, 1]
+     *
+     * _.sampleSize([1, 2, 3], 4);
+     * // => [2, 3, 1]
+     */function sampleSize(collection,n,guard){if(guard?isIterateeCall(collection,n,guard):n===undefined$1){n=1;}else {n=toInteger(n);}var func=isArray(collection)?arraySampleSize:baseSampleSize;return func(collection,n);}/**
+     * Creates an array of shuffled values, using a version of the
+     * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to shuffle.
+     * @returns {Array} Returns the new shuffled array.
+     * @example
+     *
+     * _.shuffle([1, 2, 3, 4]);
+     * // => [4, 1, 3, 2]
+     */function shuffle(collection){var func=isArray(collection)?arrayShuffle:baseShuffle;return func(collection);}/**
+     * Gets the size of `collection` by returning its length for array-like
+     * values or the number of own enumerable string keyed properties for objects.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object|string} collection The collection to inspect.
+     * @returns {number} Returns the collection size.
+     * @example
+     *
+     * _.size([1, 2, 3]);
+     * // => 3
+     *
+     * _.size({ 'a': 1, 'b': 2 });
+     * // => 2
+     *
+     * _.size('pebbles');
+     * // => 7
+     */function size(collection){if(collection==null){return 0;}if(isArrayLike(collection)){return isString(collection)?stringSize(collection):collection.length;}var tag=getTag(collection);if(tag==mapTag||tag==setTag){return collection.size;}return baseKeys(collection).length;}/**
+     * Checks if `predicate` returns truthy for **any** element of `collection`.
+     * Iteration is stopped once `predicate` returns truthy. The predicate is
+     * invoked with three arguments: (value, index|key, collection).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {boolean} Returns `true` if any element passes the predicate check,
+     *  else `false`.
+     * @example
+     *
+     * _.some([null, 0, 'yes', false], Boolean);
+     * // => true
+     *
+     * var users = [
+     *   { 'user': 'barney', 'active': true },
+     *   { 'user': 'fred',   'active': false }
+     * ];
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.some(users, { 'user': 'barney', 'active': false });
+     * // => false
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.some(users, ['active', false]);
+     * // => true
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.some(users, 'active');
+     * // => true
+     */function some(collection,predicate,guard){var func=isArray(collection)?arraySome:baseSome;if(guard&&isIterateeCall(collection,predicate,guard)){predicate=undefined$1;}return func(collection,getIteratee(predicate,3));}/**
+     * Creates an array of elements, sorted in ascending order by the results of
+     * running each element in a collection thru each iteratee. This method
+     * performs a stable sort, that is, it preserves the original sort order of
+     * equal elements. The iteratees are invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Collection
+     * @param {Array|Object} collection The collection to iterate over.
+     * @param {...(Function|Function[])} [iteratees=[_.identity]]
+     *  The iteratees to sort by.
+     * @returns {Array} Returns the new sorted array.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'fred',   'age': 48 },
+     *   { 'user': 'barney', 'age': 36 },
+     *   { 'user': 'fred',   'age': 30 },
+     *   { 'user': 'barney', 'age': 34 }
+     * ];
+     *
+     * _.sortBy(users, [function(o) { return o.user; }]);
+     * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 30]]
+     *
+     * _.sortBy(users, ['user', 'age']);
+     * // => objects for [['barney', 34], ['barney', 36], ['fred', 30], ['fred', 48]]
+     */var sortBy=baseRest(function(collection,iteratees){if(collection==null){return [];}var length=iteratees.length;if(length>1&&isIterateeCall(collection,iteratees[0],iteratees[1])){iteratees=[];}else if(length>2&&isIterateeCall(iteratees[0],iteratees[1],iteratees[2])){iteratees=[iteratees[0]];}return baseOrderBy(collection,baseFlatten(iteratees,1),[]);});/*------------------------------------------------------------------------*/ /**
+     * Gets the timestamp of the number of milliseconds that have elapsed since
+     * the Unix epoch (1 January 1970 00:00:00 UTC).
+     *
+     * @static
+     * @memberOf _
+     * @since 2.4.0
+     * @category Date
+     * @returns {number} Returns the timestamp.
+     * @example
+     *
+     * _.defer(function(stamp) {
+     *   console.log(_.now() - stamp);
+     * }, _.now());
+     * // => Logs the number of milliseconds it took for the deferred invocation.
+     */var now=ctxNow||function(){return root.Date.now();};/*------------------------------------------------------------------------*/ /**
+     * The opposite of `_.before`; this method creates a function that invokes
+     * `func` once it's called `n` or more times.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {number} n The number of calls before `func` is invoked.
+     * @param {Function} func The function to restrict.
+     * @returns {Function} Returns the new restricted function.
+     * @example
+     *
+     * var saves = ['profile', 'settings'];
+     *
+     * var done = _.after(saves.length, function() {
+     *   console.log('done saving!');
+     * });
+     *
+     * _.forEach(saves, function(type) {
+     *   asyncSave({ 'type': type, 'complete': done });
+     * });
+     * // => Logs 'done saving!' after the two async saves have completed.
+     */function after(n,func){if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}n=toInteger(n);return function(){if(--n<1){return func.apply(this,arguments);}};}/**
+     * Creates a function that invokes `func`, with up to `n` arguments,
+     * ignoring any additional arguments.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Function
+     * @param {Function} func The function to cap arguments for.
+     * @param {number} [n=func.length] The arity cap.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Function} Returns the new capped function.
+     * @example
+     *
+     * _.map(['6', '8', '10'], _.ary(parseInt, 1));
+     * // => [6, 8, 10]
+     */function ary(func,n,guard){n=guard?undefined$1:n;n=func&&n==null?func.length:n;return createWrap(func,WRAP_ARY_FLAG,undefined$1,undefined$1,undefined$1,undefined$1,n);}/**
+     * Creates a function that invokes `func`, with the `this` binding and arguments
+     * of the created function, while it's called less than `n` times. Subsequent
+     * calls to the created function return the result of the last `func` invocation.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Function
+     * @param {number} n The number of calls at which `func` is no longer invoked.
+     * @param {Function} func The function to restrict.
+     * @returns {Function} Returns the new restricted function.
+     * @example
+     *
+     * jQuery(element).on('click', _.before(5, addContactToList));
+     * // => Allows adding up to 4 contacts to the list.
+     */function before(n,func){var result;if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}n=toInteger(n);return function(){if(--n>0){result=func.apply(this,arguments);}if(n<=1){func=undefined$1;}return result;};}/**
+     * Creates a function that invokes `func` with the `this` binding of `thisArg`
+     * and `partials` prepended to the arguments it receives.
+     *
+     * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
+     * may be used as a placeholder for partially applied arguments.
+     *
+     * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
+     * property of bound functions.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {Function} func The function to bind.
+     * @param {*} thisArg The `this` binding of `func`.
+     * @param {...*} [partials] The arguments to be partially applied.
+     * @returns {Function} Returns the new bound function.
+     * @example
+     *
+     * function greet(greeting, punctuation) {
+     *   return greeting + ' ' + this.user + punctuation;
+     * }
+     *
+     * var object = { 'user': 'fred' };
+     *
+     * var bound = _.bind(greet, object, 'hi');
+     * bound('!');
+     * // => 'hi fred!'
+     *
+     * // Bound with placeholders.
+     * var bound = _.bind(greet, object, _, '!');
+     * bound('hi');
+     * // => 'hi fred!'
+     */var bind=baseRest(function(func,thisArg,partials){var bitmask=WRAP_BIND_FLAG;if(partials.length){var holders=replaceHolders(partials,getHolder(bind));bitmask|=WRAP_PARTIAL_FLAG;}return createWrap(func,bitmask,thisArg,partials,holders);});/**
+     * Creates a function that invokes the method at `object[key]` with `partials`
+     * prepended to the arguments it receives.
+     *
+     * This method differs from `_.bind` by allowing bound functions to reference
+     * methods that may be redefined or don't yet exist. See
+     * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
+     * for more details.
+     *
+     * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
+     * builds, may be used as a placeholder for partially applied arguments.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.10.0
+     * @category Function
+     * @param {Object} object The object to invoke the method on.
+     * @param {string} key The key of the method.
+     * @param {...*} [partials] The arguments to be partially applied.
+     * @returns {Function} Returns the new bound function.
+     * @example
+     *
+     * var object = {
+     *   'user': 'fred',
+     *   'greet': function(greeting, punctuation) {
+     *     return greeting + ' ' + this.user + punctuation;
+     *   }
+     * };
+     *
+     * var bound = _.bindKey(object, 'greet', 'hi');
+     * bound('!');
+     * // => 'hi fred!'
+     *
+     * object.greet = function(greeting, punctuation) {
+     *   return greeting + 'ya ' + this.user + punctuation;
+     * };
+     *
+     * bound('!');
+     * // => 'hiya fred!'
+     *
+     * // Bound with placeholders.
+     * var bound = _.bindKey(object, 'greet', _, '!');
+     * bound('hi');
+     * // => 'hiya fred!'
+     */var bindKey=baseRest(function(object,key,partials){var bitmask=WRAP_BIND_FLAG|WRAP_BIND_KEY_FLAG;if(partials.length){var holders=replaceHolders(partials,getHolder(bindKey));bitmask|=WRAP_PARTIAL_FLAG;}return createWrap(key,bitmask,object,partials,holders);});/**
+     * Creates a function that accepts arguments of `func` and either invokes
+     * `func` returning its result, if at least `arity` number of arguments have
+     * been provided, or returns a function that accepts the remaining `func`
+     * arguments, and so on. The arity of `func` may be specified if `func.length`
+     * is not sufficient.
+     *
+     * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
+     * may be used as a placeholder for provided arguments.
+     *
+     * **Note:** This method doesn't set the "length" property of curried functions.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Function
+     * @param {Function} func The function to curry.
+     * @param {number} [arity=func.length] The arity of `func`.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Function} Returns the new curried function.
+     * @example
+     *
+     * var abc = function(a, b, c) {
+     *   return [a, b, c];
+     * };
+     *
+     * var curried = _.curry(abc);
+     *
+     * curried(1)(2)(3);
+     * // => [1, 2, 3]
+     *
+     * curried(1, 2)(3);
+     * // => [1, 2, 3]
+     *
+     * curried(1, 2, 3);
+     * // => [1, 2, 3]
+     *
+     * // Curried with placeholders.
+     * curried(1)(_, 3)(2);
+     * // => [1, 2, 3]
+     */function curry(func,arity,guard){arity=guard?undefined$1:arity;var result=createWrap(func,WRAP_CURRY_FLAG,undefined$1,undefined$1,undefined$1,undefined$1,undefined$1,arity);result.placeholder=curry.placeholder;return result;}/**
+     * This method is like `_.curry` except that arguments are applied to `func`
+     * in the manner of `_.partialRight` instead of `_.partial`.
+     *
+     * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
+     * builds, may be used as a placeholder for provided arguments.
+     *
+     * **Note:** This method doesn't set the "length" property of curried functions.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Function
+     * @param {Function} func The function to curry.
+     * @param {number} [arity=func.length] The arity of `func`.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Function} Returns the new curried function.
+     * @example
+     *
+     * var abc = function(a, b, c) {
+     *   return [a, b, c];
+     * };
+     *
+     * var curried = _.curryRight(abc);
+     *
+     * curried(3)(2)(1);
+     * // => [1, 2, 3]
+     *
+     * curried(2, 3)(1);
+     * // => [1, 2, 3]
+     *
+     * curried(1, 2, 3);
+     * // => [1, 2, 3]
+     *
+     * // Curried with placeholders.
+     * curried(3)(1, _)(2);
+     * // => [1, 2, 3]
+     */function curryRight(func,arity,guard){arity=guard?undefined$1:arity;var result=createWrap(func,WRAP_CURRY_RIGHT_FLAG,undefined$1,undefined$1,undefined$1,undefined$1,undefined$1,arity);result.placeholder=curryRight.placeholder;return result;}/**
+     * Creates a debounced function that delays invoking `func` until after `wait`
+     * milliseconds have elapsed since the last time the debounced function was
+     * invoked. The debounced function comes with a `cancel` method to cancel
+     * delayed `func` invocations and a `flush` method to immediately invoke them.
+     * Provide `options` to indicate whether `func` should be invoked on the
+     * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
+     * with the last arguments provided to the debounced function. Subsequent
+     * calls to the debounced function return the result of the last `func`
+     * invocation.
+     *
+     * **Note:** If `leading` and `trailing` options are `true`, `func` is
+     * invoked on the trailing edge of the timeout only if the debounced function
+     * is invoked more than once during the `wait` timeout.
+     *
+     * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+     * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+     *
+     * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+     * for details over the differences between `_.debounce` and `_.throttle`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {Function} func The function to debounce.
+     * @param {number} [wait=0] The number of milliseconds to delay.
+     * @param {Object} [options={}] The options object.
+     * @param {boolean} [options.leading=false]
+     *  Specify invoking on the leading edge of the timeout.
+     * @param {number} [options.maxWait]
+     *  The maximum time `func` is allowed to be delayed before it's invoked.
+     * @param {boolean} [options.trailing=true]
+     *  Specify invoking on the trailing edge of the timeout.
+     * @returns {Function} Returns the new debounced function.
+     * @example
+     *
+     * // Avoid costly calculations while the window size is in flux.
+     * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
+     *
+     * // Invoke `sendMail` when clicked, debouncing subsequent calls.
+     * jQuery(element).on('click', _.debounce(sendMail, 300, {
+     *   'leading': true,
+     *   'trailing': false
+     * }));
+     *
+     * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
+     * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
+     * var source = new EventSource('/stream');
+     * jQuery(source).on('message', debounced);
+     *
+     * // Cancel the trailing debounced invocation.
+     * jQuery(window).on('popstate', debounced.cancel);
+     */function debounce(func,wait,options){var lastArgs,lastThis,maxWait,result,timerId,lastCallTime,lastInvokeTime=0,leading=false,maxing=false,trailing=true;if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}wait=toNumber(wait)||0;if(isObject(options)){leading=!!options.leading;maxing='maxWait'in options;maxWait=maxing?nativeMax(toNumber(options.maxWait)||0,wait):maxWait;trailing='trailing'in options?!!options.trailing:trailing;}function invokeFunc(time){var args=lastArgs,thisArg=lastThis;lastArgs=lastThis=undefined$1;lastInvokeTime=time;result=func.apply(thisArg,args);return result;}function leadingEdge(time){// Reset any `maxWait` timer.
+lastInvokeTime=time;// Start the timer for the trailing edge.
+timerId=setTimeout(timerExpired,wait);// Invoke the leading edge.
+return leading?invokeFunc(time):result;}function remainingWait(time){var timeSinceLastCall=time-lastCallTime,timeSinceLastInvoke=time-lastInvokeTime,timeWaiting=wait-timeSinceLastCall;return maxing?nativeMin(timeWaiting,maxWait-timeSinceLastInvoke):timeWaiting;}function shouldInvoke(time){var timeSinceLastCall=time-lastCallTime,timeSinceLastInvoke=time-lastInvokeTime;// Either this is the first call, activity has stopped and we're at the
+// trailing edge, the system time has gone backwards and we're treating
+// it as the trailing edge, or we've hit the `maxWait` limit.
+return lastCallTime===undefined$1||timeSinceLastCall>=wait||timeSinceLastCall<0||maxing&&timeSinceLastInvoke>=maxWait;}function timerExpired(){var time=now();if(shouldInvoke(time)){return trailingEdge(time);}// Restart the timer.
+timerId=setTimeout(timerExpired,remainingWait(time));}function trailingEdge(time){timerId=undefined$1;// Only invoke if we have `lastArgs` which means `func` has been
+// debounced at least once.
+if(trailing&&lastArgs){return invokeFunc(time);}lastArgs=lastThis=undefined$1;return result;}function cancel(){if(timerId!==undefined$1){clearTimeout(timerId);}lastInvokeTime=0;lastArgs=lastCallTime=lastThis=timerId=undefined$1;}function flush(){return timerId===undefined$1?result:trailingEdge(now());}function debounced(){var time=now(),isInvoking=shouldInvoke(time);lastArgs=arguments;lastThis=this;lastCallTime=time;if(isInvoking){if(timerId===undefined$1){return leadingEdge(lastCallTime);}if(maxing){// Handle invocations in a tight loop.
+clearTimeout(timerId);timerId=setTimeout(timerExpired,wait);return invokeFunc(lastCallTime);}}if(timerId===undefined$1){timerId=setTimeout(timerExpired,wait);}return result;}debounced.cancel=cancel;debounced.flush=flush;return debounced;}/**
+     * Defers invoking the `func` until the current call stack has cleared. Any
+     * additional arguments are provided to `func` when it's invoked.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {Function} func The function to defer.
+     * @param {...*} [args] The arguments to invoke `func` with.
+     * @returns {number} Returns the timer id.
+     * @example
+     *
+     * _.defer(function(text) {
+     *   console.log(text);
+     * }, 'deferred');
+     * // => Logs 'deferred' after one millisecond.
+     */var defer=baseRest(function(func,args){return baseDelay(func,1,args);});/**
+     * Invokes `func` after `wait` milliseconds. Any additional arguments are
+     * provided to `func` when it's invoked.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {Function} func The function to delay.
+     * @param {number} wait The number of milliseconds to delay invocation.
+     * @param {...*} [args] The arguments to invoke `func` with.
+     * @returns {number} Returns the timer id.
+     * @example
+     *
+     * _.delay(function(text) {
+     *   console.log(text);
+     * }, 1000, 'later');
+     * // => Logs 'later' after one second.
+     */var delay=baseRest(function(func,wait,args){return baseDelay(func,toNumber(wait)||0,args);});/**
+     * Creates a function that invokes `func` with arguments reversed.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Function
+     * @param {Function} func The function to flip arguments for.
+     * @returns {Function} Returns the new flipped function.
+     * @example
+     *
+     * var flipped = _.flip(function() {
+     *   return _.toArray(arguments);
+     * });
+     *
+     * flipped('a', 'b', 'c', 'd');
+     * // => ['d', 'c', 'b', 'a']
+     */function flip(func){return createWrap(func,WRAP_FLIP_FLAG);}/**
+     * Creates a function that memoizes the result of `func`. If `resolver` is
+     * provided, it determines the cache key for storing the result based on the
+     * arguments provided to the memoized function. By default, the first argument
+     * provided to the memoized function is used as the map cache key. The `func`
+     * is invoked with the `this` binding of the memoized function.
+     *
+     * **Note:** The cache is exposed as the `cache` property on the memoized
+     * function. Its creation may be customized by replacing the `_.memoize.Cache`
+     * constructor with one whose instances implement the
+     * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
+     * method interface of `clear`, `delete`, `get`, `has`, and `set`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {Function} func The function to have its output memoized.
+     * @param {Function} [resolver] The function to resolve the cache key.
+     * @returns {Function} Returns the new memoized function.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': 2 };
+     * var other = { 'c': 3, 'd': 4 };
+     *
+     * var values = _.memoize(_.values);
+     * values(object);
+     * // => [1, 2]
+     *
+     * values(other);
+     * // => [3, 4]
+     *
+     * object.a = 2;
+     * values(object);
+     * // => [1, 2]
+     *
+     * // Modify the result cache.
+     * values.cache.set(object, ['a', 'b']);
+     * values(object);
+     * // => ['a', 'b']
+     *
+     * // Replace `_.memoize.Cache`.
+     * _.memoize.Cache = WeakMap;
+     */function memoize(func,resolver){if(typeof func!='function'||resolver!=null&&typeof resolver!='function'){throw new TypeError(FUNC_ERROR_TEXT);}var memoized=function(){var args=arguments,key=resolver?resolver.apply(this,args):args[0],cache=memoized.cache;if(cache.has(key)){return cache.get(key);}var result=func.apply(this,args);memoized.cache=cache.set(key,result)||cache;return result;};memoized.cache=new(memoize.Cache||MapCache)();return memoized;}// Expose `MapCache`.
+memoize.Cache=MapCache;/**
+     * Creates a function that negates the result of the predicate `func`. The
+     * `func` predicate is invoked with the `this` binding and arguments of the
+     * created function.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Function
+     * @param {Function} predicate The predicate to negate.
+     * @returns {Function} Returns the new negated function.
+     * @example
+     *
+     * function isEven(n) {
+     *   return n % 2 == 0;
+     * }
+     *
+     * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
+     * // => [1, 3, 5]
+     */function negate(predicate){if(typeof predicate!='function'){throw new TypeError(FUNC_ERROR_TEXT);}return function(){var args=arguments;switch(args.length){case 0:return !predicate.call(this);case 1:return !predicate.call(this,args[0]);case 2:return !predicate.call(this,args[0],args[1]);case 3:return !predicate.call(this,args[0],args[1],args[2]);}return !predicate.apply(this,args);};}/**
+     * Creates a function that is restricted to invoking `func` once. Repeat calls
+     * to the function return the value of the first invocation. The `func` is
+     * invoked with the `this` binding and arguments of the created function.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {Function} func The function to restrict.
+     * @returns {Function} Returns the new restricted function.
+     * @example
+     *
+     * var initialize = _.once(createApplication);
+     * initialize();
+     * initialize();
+     * // => `createApplication` is invoked once
+     */function once(func){return before(2,func);}/**
+     * Creates a function that invokes `func` with its arguments transformed.
+     *
+     * @static
+     * @since 4.0.0
+     * @memberOf _
+     * @category Function
+     * @param {Function} func The function to wrap.
+     * @param {...(Function|Function[])} [transforms=[_.identity]]
+     *  The argument transforms.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * function doubled(n) {
+     *   return n * 2;
+     * }
+     *
+     * function square(n) {
+     *   return n * n;
+     * }
+     *
+     * var func = _.overArgs(function(x, y) {
+     *   return [x, y];
+     * }, [square, doubled]);
+     *
+     * func(9, 3);
+     * // => [81, 6]
+     *
+     * func(10, 5);
+     * // => [100, 10]
+     */var overArgs=castRest(function(func,transforms){transforms=transforms.length==1&&isArray(transforms[0])?arrayMap(transforms[0],baseUnary(getIteratee())):arrayMap(baseFlatten(transforms,1),baseUnary(getIteratee()));var funcsLength=transforms.length;return baseRest(function(args){var index=-1,length=nativeMin(args.length,funcsLength);while(++index<length){args[index]=transforms[index].call(this,args[index]);}return apply(func,this,args);});});/**
+     * Creates a function that invokes `func` with `partials` prepended to the
+     * arguments it receives. This method is like `_.bind` except it does **not**
+     * alter the `this` binding.
+     *
+     * The `_.partial.placeholder` value, which defaults to `_` in monolithic
+     * builds, may be used as a placeholder for partially applied arguments.
+     *
+     * **Note:** This method doesn't set the "length" property of partially
+     * applied functions.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.2.0
+     * @category Function
+     * @param {Function} func The function to partially apply arguments to.
+     * @param {...*} [partials] The arguments to be partially applied.
+     * @returns {Function} Returns the new partially applied function.
+     * @example
+     *
+     * function greet(greeting, name) {
+     *   return greeting + ' ' + name;
+     * }
+     *
+     * var sayHelloTo = _.partial(greet, 'hello');
+     * sayHelloTo('fred');
+     * // => 'hello fred'
+     *
+     * // Partially applied with placeholders.
+     * var greetFred = _.partial(greet, _, 'fred');
+     * greetFred('hi');
+     * // => 'hi fred'
+     */var partial=baseRest(function(func,partials){var holders=replaceHolders(partials,getHolder(partial));return createWrap(func,WRAP_PARTIAL_FLAG,undefined$1,partials,holders);});/**
+     * This method is like `_.partial` except that partially applied arguments
+     * are appended to the arguments it receives.
+     *
+     * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
+     * builds, may be used as a placeholder for partially applied arguments.
+     *
+     * **Note:** This method doesn't set the "length" property of partially
+     * applied functions.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.0.0
+     * @category Function
+     * @param {Function} func The function to partially apply arguments to.
+     * @param {...*} [partials] The arguments to be partially applied.
+     * @returns {Function} Returns the new partially applied function.
+     * @example
+     *
+     * function greet(greeting, name) {
+     *   return greeting + ' ' + name;
+     * }
+     *
+     * var greetFred = _.partialRight(greet, 'fred');
+     * greetFred('hi');
+     * // => 'hi fred'
+     *
+     * // Partially applied with placeholders.
+     * var sayHelloTo = _.partialRight(greet, 'hello', _);
+     * sayHelloTo('fred');
+     * // => 'hello fred'
+     */var partialRight=baseRest(function(func,partials){var holders=replaceHolders(partials,getHolder(partialRight));return createWrap(func,WRAP_PARTIAL_RIGHT_FLAG,undefined$1,partials,holders);});/**
+     * Creates a function that invokes `func` with arguments arranged according
+     * to the specified `indexes` where the argument value at the first index is
+     * provided as the first argument, the argument value at the second index is
+     * provided as the second argument, and so on.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Function
+     * @param {Function} func The function to rearrange arguments for.
+     * @param {...(number|number[])} indexes The arranged argument indexes.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var rearged = _.rearg(function(a, b, c) {
+     *   return [a, b, c];
+     * }, [2, 0, 1]);
+     *
+     * rearged('b', 'c', 'a')
+     * // => ['a', 'b', 'c']
+     */var rearg=flatRest(function(func,indexes){return createWrap(func,WRAP_REARG_FLAG,undefined$1,undefined$1,undefined$1,indexes);});/**
+     * Creates a function that invokes `func` with the `this` binding of the
+     * created function and arguments from `start` and beyond provided as
+     * an array.
+     *
+     * **Note:** This method is based on the
+     * [rest parameter](https://mdn.io/rest_parameters).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Function
+     * @param {Function} func The function to apply a rest parameter to.
+     * @param {number} [start=func.length-1] The start position of the rest parameter.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var say = _.rest(function(what, names) {
+     *   return what + ' ' + _.initial(names).join(', ') +
+     *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
+     * });
+     *
+     * say('hello', 'fred', 'barney', 'pebbles');
+     * // => 'hello fred, barney, & pebbles'
+     */function rest(func,start){if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}start=start===undefined$1?start:toInteger(start);return baseRest(func,start);}/**
+     * Creates a function that invokes `func` with the `this` binding of the
+     * create function and an array of arguments much like
+     * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
+     *
+     * **Note:** This method is based on the
+     * [spread operator](https://mdn.io/spread_operator).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.2.0
+     * @category Function
+     * @param {Function} func The function to spread arguments over.
+     * @param {number} [start=0] The start position of the spread.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var say = _.spread(function(who, what) {
+     *   return who + ' says ' + what;
+     * });
+     *
+     * say(['fred', 'hello']);
+     * // => 'fred says hello'
+     *
+     * var numbers = Promise.all([
+     *   Promise.resolve(40),
+     *   Promise.resolve(36)
+     * ]);
+     *
+     * numbers.then(_.spread(function(x, y) {
+     *   return x + y;
+     * }));
+     * // => a Promise of 76
+     */function spread(func,start){if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}start=start==null?0:nativeMax(toInteger(start),0);return baseRest(function(args){var array=args[start],otherArgs=castSlice(args,0,start);if(array){arrayPush(otherArgs,array);}return apply(func,this,otherArgs);});}/**
+     * Creates a throttled function that only invokes `func` at most once per
+     * every `wait` milliseconds. The throttled function comes with a `cancel`
+     * method to cancel delayed `func` invocations and a `flush` method to
+     * immediately invoke them. Provide `options` to indicate whether `func`
+     * should be invoked on the leading and/or trailing edge of the `wait`
+     * timeout. The `func` is invoked with the last arguments provided to the
+     * throttled function. Subsequent calls to the throttled function return the
+     * result of the last `func` invocation.
+     *
+     * **Note:** If `leading` and `trailing` options are `true`, `func` is
+     * invoked on the trailing edge of the timeout only if the throttled function
+     * is invoked more than once during the `wait` timeout.
+     *
+     * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
+     * until to the next tick, similar to `setTimeout` with a timeout of `0`.
+     *
+     * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
+     * for details over the differences between `_.throttle` and `_.debounce`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {Function} func The function to throttle.
+     * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
+     * @param {Object} [options={}] The options object.
+     * @param {boolean} [options.leading=true]
+     *  Specify invoking on the leading edge of the timeout.
+     * @param {boolean} [options.trailing=true]
+     *  Specify invoking on the trailing edge of the timeout.
+     * @returns {Function} Returns the new throttled function.
+     * @example
+     *
+     * // Avoid excessively updating the position while scrolling.
+     * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
+     *
+     * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
+     * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
+     * jQuery(element).on('click', throttled);
+     *
+     * // Cancel the trailing throttled invocation.
+     * jQuery(window).on('popstate', throttled.cancel);
+     */function throttle(func,wait,options){var leading=true,trailing=true;if(typeof func!='function'){throw new TypeError(FUNC_ERROR_TEXT);}if(isObject(options)){leading='leading'in options?!!options.leading:leading;trailing='trailing'in options?!!options.trailing:trailing;}return debounce(func,wait,{'leading':leading,'maxWait':wait,'trailing':trailing});}/**
+     * Creates a function that accepts up to one argument, ignoring any
+     * additional arguments.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Function
+     * @param {Function} func The function to cap arguments for.
+     * @returns {Function} Returns the new capped function.
+     * @example
+     *
+     * _.map(['6', '8', '10'], _.unary(parseInt));
+     * // => [6, 8, 10]
+     */function unary(func){return ary(func,1);}/**
+     * Creates a function that provides `value` to `wrapper` as its first
+     * argument. Any additional arguments provided to the function are appended
+     * to those provided to the `wrapper`. The wrapper is invoked with the `this`
+     * binding of the created function.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Function
+     * @param {*} value The value to wrap.
+     * @param {Function} [wrapper=identity] The wrapper function.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var p = _.wrap(_.escape, function(func, text) {
+     *   return '<p>' + func(text) + '</p>';
+     * });
+     *
+     * p('fred, barney, & pebbles');
+     * // => '<p>fred, barney, &amp; pebbles</p>'
+     */function wrap(value,wrapper){return partial(castFunction(wrapper),value);}/*------------------------------------------------------------------------*/ /**
+     * Casts `value` as an array if it's not one.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.4.0
+     * @category Lang
+     * @param {*} value The value to inspect.
+     * @returns {Array} Returns the cast array.
+     * @example
+     *
+     * _.castArray(1);
+     * // => [1]
+     *
+     * _.castArray({ 'a': 1 });
+     * // => [{ 'a': 1 }]
+     *
+     * _.castArray('abc');
+     * // => ['abc']
+     *
+     * _.castArray(null);
+     * // => [null]
+     *
+     * _.castArray(undefined);
+     * // => [undefined]
+     *
+     * _.castArray();
+     * // => []
+     *
+     * var array = [1, 2, 3];
+     * console.log(_.castArray(array) === array);
+     * // => true
+     */function castArray(){if(!arguments.length){return [];}var value=arguments[0];return isArray(value)?value:[value];}/**
+     * Creates a shallow clone of `value`.
+     *
+     * **Note:** This method is loosely based on the
+     * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
+     * and supports cloning arrays, array buffers, booleans, date objects, maps,
+     * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
+     * arrays. The own enumerable properties of `arguments` objects are cloned
+     * as plain objects. An empty object is returned for uncloneable values such
+     * as error objects, functions, DOM nodes, and WeakMaps.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to clone.
+     * @returns {*} Returns the cloned value.
+     * @see _.cloneDeep
+     * @example
+     *
+     * var objects = [{ 'a': 1 }, { 'b': 2 }];
+     *
+     * var shallow = _.clone(objects);
+     * console.log(shallow[0] === objects[0]);
+     * // => true
+     */function clone(value){return baseClone(value,CLONE_SYMBOLS_FLAG);}/**
+     * This method is like `_.clone` except that it accepts `customizer` which
+     * is invoked to produce the cloned value. If `customizer` returns `undefined`,
+     * cloning is handled by the method instead. The `customizer` is invoked with
+     * up to four arguments; (value [, index|key, object, stack]).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to clone.
+     * @param {Function} [customizer] The function to customize cloning.
+     * @returns {*} Returns the cloned value.
+     * @see _.cloneDeepWith
+     * @example
+     *
+     * function customizer(value) {
+     *   if (_.isElement(value)) {
+     *     return value.cloneNode(false);
+     *   }
+     * }
+     *
+     * var el = _.cloneWith(document.body, customizer);
+     *
+     * console.log(el === document.body);
+     * // => false
+     * console.log(el.nodeName);
+     * // => 'BODY'
+     * console.log(el.childNodes.length);
+     * // => 0
+     */function cloneWith(value,customizer){customizer=typeof customizer=='function'?customizer:undefined$1;return baseClone(value,CLONE_SYMBOLS_FLAG,customizer);}/**
+     * This method is like `_.clone` except that it recursively clones `value`.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.0.0
+     * @category Lang
+     * @param {*} value The value to recursively clone.
+     * @returns {*} Returns the deep cloned value.
+     * @see _.clone
+     * @example
+     *
+     * var objects = [{ 'a': 1 }, { 'b': 2 }];
+     *
+     * var deep = _.cloneDeep(objects);
+     * console.log(deep[0] === objects[0]);
+     * // => false
+     */function cloneDeep(value){return baseClone(value,CLONE_DEEP_FLAG|CLONE_SYMBOLS_FLAG);}/**
+     * This method is like `_.cloneWith` except that it recursively clones `value`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to recursively clone.
+     * @param {Function} [customizer] The function to customize cloning.
+     * @returns {*} Returns the deep cloned value.
+     * @see _.cloneWith
+     * @example
+     *
+     * function customizer(value) {
+     *   if (_.isElement(value)) {
+     *     return value.cloneNode(true);
+     *   }
+     * }
+     *
+     * var el = _.cloneDeepWith(document.body, customizer);
+     *
+     * console.log(el === document.body);
+     * // => false
+     * console.log(el.nodeName);
+     * // => 'BODY'
+     * console.log(el.childNodes.length);
+     * // => 20
+     */function cloneDeepWith(value,customizer){customizer=typeof customizer=='function'?customizer:undefined$1;return baseClone(value,CLONE_DEEP_FLAG|CLONE_SYMBOLS_FLAG,customizer);}/**
+     * Checks if `object` conforms to `source` by invoking the predicate
+     * properties of `source` with the corresponding property values of `object`.
+     *
+     * **Note:** This method is equivalent to `_.conforms` when `source` is
+     * partially applied.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.14.0
+     * @category Lang
+     * @param {Object} object The object to inspect.
+     * @param {Object} source The object of property predicates to conform to.
+     * @returns {boolean} Returns `true` if `object` conforms, else `false`.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': 2 };
+     *
+     * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
+     * // => true
+     *
+     * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
+     * // => false
+     */function conformsTo(object,source){return source==null||baseConformsTo(object,source,keys(source));}/**
+     * Performs a
+     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
+     * comparison between two values to determine if they are equivalent.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+     * @example
+     *
+     * var object = { 'a': 1 };
+     * var other = { 'a': 1 };
+     *
+     * _.eq(object, object);
+     * // => true
+     *
+     * _.eq(object, other);
+     * // => false
+     *
+     * _.eq('a', 'a');
+     * // => true
+     *
+     * _.eq('a', Object('a'));
+     * // => false
+     *
+     * _.eq(NaN, NaN);
+     * // => true
+     */function eq(value,other){return value===other||value!==value&&other!==other;}/**
+     * Checks if `value` is greater than `other`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.9.0
+     * @category Lang
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is greater than `other`,
+     *  else `false`.
+     * @see _.lt
+     * @example
+     *
+     * _.gt(3, 1);
+     * // => true
+     *
+     * _.gt(3, 3);
+     * // => false
+     *
+     * _.gt(1, 3);
+     * // => false
+     */var gt=createRelationalOperation(baseGt);/**
+     * Checks if `value` is greater than or equal to `other`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.9.0
+     * @category Lang
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is greater than or equal to
+     *  `other`, else `false`.
+     * @see _.lte
+     * @example
+     *
+     * _.gte(3, 1);
+     * // => true
+     *
+     * _.gte(3, 3);
+     * // => true
+     *
+     * _.gte(1, 3);
+     * // => false
+     */var gte=createRelationalOperation(function(value,other){return value>=other;});/**
+     * Checks if `value` is likely an `arguments` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
+     *  else `false`.
+     * @example
+     *
+     * _.isArguments(function() { return arguments; }());
+     * // => true
+     *
+     * _.isArguments([1, 2, 3]);
+     * // => false
+     */var isArguments=baseIsArguments(function(){return arguments;}())?baseIsArguments:function(value){return isObjectLike(value)&&hasOwnProperty.call(value,'callee')&&!propertyIsEnumerable.call(value,'callee');};/**
+     * Checks if `value` is classified as an `Array` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an array, else `false`.
+     * @example
+     *
+     * _.isArray([1, 2, 3]);
+     * // => true
+     *
+     * _.isArray(document.body.children);
+     * // => false
+     *
+     * _.isArray('abc');
+     * // => false
+     *
+     * _.isArray(_.noop);
+     * // => false
+     */var isArray=Array.isArray;/**
+     * Checks if `value` is classified as an `ArrayBuffer` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.3.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
+     * @example
+     *
+     * _.isArrayBuffer(new ArrayBuffer(2));
+     * // => true
+     *
+     * _.isArrayBuffer(new Array(2));
+     * // => false
+     */var isArrayBuffer=nodeIsArrayBuffer?baseUnary(nodeIsArrayBuffer):baseIsArrayBuffer;/**
+     * Checks if `value` is array-like. A value is considered array-like if it's
+     * not a function and has a `value.length` that's an integer greater than or
+     * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+     * @example
+     *
+     * _.isArrayLike([1, 2, 3]);
+     * // => true
+     *
+     * _.isArrayLike(document.body.children);
+     * // => true
+     *
+     * _.isArrayLike('abc');
+     * // => true
+     *
+     * _.isArrayLike(_.noop);
+     * // => false
+     */function isArrayLike(value){return value!=null&&isLength(value.length)&&!isFunction(value);}/**
+     * This method is like `_.isArrayLike` except that it also checks if `value`
+     * is an object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an array-like object,
+     *  else `false`.
+     * @example
+     *
+     * _.isArrayLikeObject([1, 2, 3]);
+     * // => true
+     *
+     * _.isArrayLikeObject(document.body.children);
+     * // => true
+     *
+     * _.isArrayLikeObject('abc');
+     * // => false
+     *
+     * _.isArrayLikeObject(_.noop);
+     * // => false
+     */function isArrayLikeObject(value){return isObjectLike(value)&&isArrayLike(value);}/**
+     * Checks if `value` is classified as a boolean primitive or object.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
+     * @example
+     *
+     * _.isBoolean(false);
+     * // => true
+     *
+     * _.isBoolean(null);
+     * // => false
+     */function isBoolean(value){return value===true||value===false||isObjectLike(value)&&baseGetTag(value)==boolTag;}/**
+     * Checks if `value` is a buffer.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.3.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
+     * @example
+     *
+     * _.isBuffer(new Buffer(2));
+     * // => true
+     *
+     * _.isBuffer(new Uint8Array(2));
+     * // => false
+     */var isBuffer=nativeIsBuffer||stubFalse;/**
+     * Checks if `value` is classified as a `Date` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
+     * @example
+     *
+     * _.isDate(new Date);
+     * // => true
+     *
+     * _.isDate('Mon April 23 2012');
+     * // => false
+     */var isDate=nodeIsDate?baseUnary(nodeIsDate):baseIsDate;/**
+     * Checks if `value` is likely a DOM element.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
+     * @example
+     *
+     * _.isElement(document.body);
+     * // => true
+     *
+     * _.isElement('<body>');
+     * // => false
+     */function isElement(value){return isObjectLike(value)&&value.nodeType===1&&!isPlainObject(value);}/**
+     * Checks if `value` is an empty object, collection, map, or set.
+     *
+     * Objects are considered empty if they have no own enumerable string keyed
+     * properties.
+     *
+     * Array-like values such as `arguments` objects, arrays, buffers, strings, or
+     * jQuery-like collections are considered empty if they have a `length` of `0`.
+     * Similarly, maps and sets are considered empty if they have a `size` of `0`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is empty, else `false`.
+     * @example
+     *
+     * _.isEmpty(null);
+     * // => true
+     *
+     * _.isEmpty(true);
+     * // => true
+     *
+     * _.isEmpty(1);
+     * // => true
+     *
+     * _.isEmpty([1, 2, 3]);
+     * // => false
+     *
+     * _.isEmpty({ 'a': 1 });
+     * // => false
+     */function isEmpty(value){if(value==null){return true;}if(isArrayLike(value)&&(isArray(value)||typeof value=='string'||typeof value.splice=='function'||isBuffer(value)||isTypedArray(value)||isArguments(value))){return !value.length;}var tag=getTag(value);if(tag==mapTag||tag==setTag){return !value.size;}if(isPrototype(value)){return !baseKeys(value).length;}for(var key in value){if(hasOwnProperty.call(value,key)){return false;}}return true;}/**
+     * Performs a deep comparison between two values to determine if they are
+     * equivalent.
+     *
+     * **Note:** This method supports comparing arrays, array buffers, booleans,
+     * date objects, error objects, maps, numbers, `Object` objects, regexes,
+     * sets, strings, symbols, and typed arrays. `Object` objects are compared
+     * by their own, not inherited, enumerable properties. Functions and DOM
+     * nodes are compared by strict equality, i.e. `===`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+     * @example
+     *
+     * var object = { 'a': 1 };
+     * var other = { 'a': 1 };
+     *
+     * _.isEqual(object, other);
+     * // => true
+     *
+     * object === other;
+     * // => false
+     */function isEqual(value,other){return baseIsEqual(value,other);}/**
+     * This method is like `_.isEqual` except that it accepts `customizer` which
+     * is invoked to compare values. If `customizer` returns `undefined`, comparisons
+     * are handled by the method instead. The `customizer` is invoked with up to
+     * six arguments: (objValue, othValue [, index|key, object, other, stack]).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @param {Function} [customizer] The function to customize comparisons.
+     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+     * @example
+     *
+     * function isGreeting(value) {
+     *   return /^h(?:i|ello)$/.test(value);
+     * }
+     *
+     * function customizer(objValue, othValue) {
+     *   if (isGreeting(objValue) && isGreeting(othValue)) {
+     *     return true;
+     *   }
+     * }
+     *
+     * var array = ['hello', 'goodbye'];
+     * var other = ['hi', 'goodbye'];
+     *
+     * _.isEqualWith(array, other, customizer);
+     * // => true
+     */function isEqualWith(value,other,customizer){customizer=typeof customizer=='function'?customizer:undefined$1;var result=customizer?customizer(value,other):undefined$1;return result===undefined$1?baseIsEqual(value,other,undefined$1,customizer):!!result;}/**
+     * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
+     * `SyntaxError`, `TypeError`, or `URIError` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
+     * @example
+     *
+     * _.isError(new Error);
+     * // => true
+     *
+     * _.isError(Error);
+     * // => false
+     */function isError(value){if(!isObjectLike(value)){return false;}var tag=baseGetTag(value);return tag==errorTag||tag==domExcTag||typeof value.message=='string'&&typeof value.name=='string'&&!isPlainObject(value);}/**
+     * Checks if `value` is a finite primitive number.
+     *
+     * **Note:** This method is based on
+     * [`Number.isFinite`](https://mdn.io/Number/isFinite).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
+     * @example
+     *
+     * _.isFinite(3);
+     * // => true
+     *
+     * _.isFinite(Number.MIN_VALUE);
+     * // => true
+     *
+     * _.isFinite(Infinity);
+     * // => false
+     *
+     * _.isFinite('3');
+     * // => false
+     */function isFinite(value){return typeof value=='number'&&nativeIsFinite(value);}/**
+     * Checks if `value` is classified as a `Function` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a function, else `false`.
+     * @example
+     *
+     * _.isFunction(_);
+     * // => true
+     *
+     * _.isFunction(/abc/);
+     * // => false
+     */function isFunction(value){if(!isObject(value)){return false;}// The use of `Object#toString` avoids issues with the `typeof` operator
+// in Safari 9 which returns 'object' for typed arrays and other constructors.
+var tag=baseGetTag(value);return tag==funcTag||tag==genTag||tag==asyncTag||tag==proxyTag;}/**
+     * Checks if `value` is an integer.
+     *
+     * **Note:** This method is based on
+     * [`Number.isInteger`](https://mdn.io/Number/isInteger).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
+     * @example
+     *
+     * _.isInteger(3);
+     * // => true
+     *
+     * _.isInteger(Number.MIN_VALUE);
+     * // => false
+     *
+     * _.isInteger(Infinity);
+     * // => false
+     *
+     * _.isInteger('3');
+     * // => false
+     */function isInteger(value){return typeof value=='number'&&value==toInteger(value);}/**
+     * Checks if `value` is a valid array-like length.
+     *
+     * **Note:** This method is loosely based on
+     * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+     * @example
+     *
+     * _.isLength(3);
+     * // => true
+     *
+     * _.isLength(Number.MIN_VALUE);
+     * // => false
+     *
+     * _.isLength(Infinity);
+     * // => false
+     *
+     * _.isLength('3');
+     * // => false
+     */function isLength(value){return typeof value=='number'&&value>-1&&value%1==0&&value<=MAX_SAFE_INTEGER;}/**
+     * Checks if `value` is the
+     * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
+     * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+     * @example
+     *
+     * _.isObject({});
+     * // => true
+     *
+     * _.isObject([1, 2, 3]);
+     * // => true
+     *
+     * _.isObject(_.noop);
+     * // => true
+     *
+     * _.isObject(null);
+     * // => false
+     */function isObject(value){var type=typeof value;return value!=null&&(type=='object'||type=='function');}/**
+     * Checks if `value` is object-like. A value is object-like if it's not `null`
+     * and has a `typeof` result of "object".
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+     * @example
+     *
+     * _.isObjectLike({});
+     * // => true
+     *
+     * _.isObjectLike([1, 2, 3]);
+     * // => true
+     *
+     * _.isObjectLike(_.noop);
+     * // => false
+     *
+     * _.isObjectLike(null);
+     * // => false
+     */function isObjectLike(value){return value!=null&&typeof value=='object';}/**
+     * Checks if `value` is classified as a `Map` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.3.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
+     * @example
+     *
+     * _.isMap(new Map);
+     * // => true
+     *
+     * _.isMap(new WeakMap);
+     * // => false
+     */var isMap=nodeIsMap?baseUnary(nodeIsMap):baseIsMap;/**
+     * Performs a partial deep comparison between `object` and `source` to
+     * determine if `object` contains equivalent property values.
+     *
+     * **Note:** This method is equivalent to `_.matches` when `source` is
+     * partially applied.
+     *
+     * Partial comparisons will match empty array and empty object `source`
+     * values against any array or object value, respectively. See `_.isEqual`
+     * for a list of supported value comparisons.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Lang
+     * @param {Object} object The object to inspect.
+     * @param {Object} source The object of property values to match.
+     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': 2 };
+     *
+     * _.isMatch(object, { 'b': 2 });
+     * // => true
+     *
+     * _.isMatch(object, { 'b': 1 });
+     * // => false
+     */function isMatch(object,source){return object===source||baseIsMatch(object,source,getMatchData(source));}/**
+     * This method is like `_.isMatch` except that it accepts `customizer` which
+     * is invoked to compare values. If `customizer` returns `undefined`, comparisons
+     * are handled by the method instead. The `customizer` is invoked with five
+     * arguments: (objValue, srcValue, index|key, object, source).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {Object} object The object to inspect.
+     * @param {Object} source The object of property values to match.
+     * @param {Function} [customizer] The function to customize comparisons.
+     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
+     * @example
+     *
+     * function isGreeting(value) {
+     *   return /^h(?:i|ello)$/.test(value);
+     * }
+     *
+     * function customizer(objValue, srcValue) {
+     *   if (isGreeting(objValue) && isGreeting(srcValue)) {
+     *     return true;
+     *   }
+     * }
+     *
+     * var object = { 'greeting': 'hello' };
+     * var source = { 'greeting': 'hi' };
+     *
+     * _.isMatchWith(object, source, customizer);
+     * // => true
+     */function isMatchWith(object,source,customizer){customizer=typeof customizer=='function'?customizer:undefined$1;return baseIsMatch(object,source,getMatchData(source),customizer);}/**
+     * Checks if `value` is `NaN`.
+     *
+     * **Note:** This method is based on
+     * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
+     * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
+     * `undefined` and other non-number values.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
+     * @example
+     *
+     * _.isNaN(NaN);
+     * // => true
+     *
+     * _.isNaN(new Number(NaN));
+     * // => true
+     *
+     * isNaN(undefined);
+     * // => true
+     *
+     * _.isNaN(undefined);
+     * // => false
+     */function isNaN(value){// An `NaN` primitive is the only value that is not equal to itself.
+// Perform the `toStringTag` check first to avoid errors with some
+// ActiveX objects in IE.
+return isNumber(value)&&value!=+value;}/**
+     * Checks if `value` is a pristine native function.
+     *
+     * **Note:** This method can't reliably detect native functions in the presence
+     * of the core-js package because core-js circumvents this kind of detection.
+     * Despite multiple requests, the core-js maintainer has made it clear: any
+     * attempt to fix the detection will be obstructed. As a result, we're left
+     * with little choice but to throw an error. Unfortunately, this also affects
+     * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
+     * which rely on core-js.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a native function,
+     *  else `false`.
+     * @example
+     *
+     * _.isNative(Array.prototype.push);
+     * // => true
+     *
+     * _.isNative(_);
+     * // => false
+     */function isNative(value){if(isMaskable(value)){throw new Error(CORE_ERROR_TEXT);}return baseIsNative(value);}/**
+     * Checks if `value` is `null`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
+     * @example
+     *
+     * _.isNull(null);
+     * // => true
+     *
+     * _.isNull(void 0);
+     * // => false
+     */function isNull(value){return value===null;}/**
+     * Checks if `value` is `null` or `undefined`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
+     * @example
+     *
+     * _.isNil(null);
+     * // => true
+     *
+     * _.isNil(void 0);
+     * // => true
+     *
+     * _.isNil(NaN);
+     * // => false
+     */function isNil(value){return value==null;}/**
+     * Checks if `value` is classified as a `Number` primitive or object.
+     *
+     * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
+     * classified as numbers, use the `_.isFinite` method.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a number, else `false`.
+     * @example
+     *
+     * _.isNumber(3);
+     * // => true
+     *
+     * _.isNumber(Number.MIN_VALUE);
+     * // => true
+     *
+     * _.isNumber(Infinity);
+     * // => true
+     *
+     * _.isNumber('3');
+     * // => false
+     */function isNumber(value){return typeof value=='number'||isObjectLike(value)&&baseGetTag(value)==numberTag;}/**
+     * Checks if `value` is a plain object, that is, an object created by the
+     * `Object` constructor or one with a `[[Prototype]]` of `null`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.8.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     * }
+     *
+     * _.isPlainObject(new Foo);
+     * // => false
+     *
+     * _.isPlainObject([1, 2, 3]);
+     * // => false
+     *
+     * _.isPlainObject({ 'x': 0, 'y': 0 });
+     * // => true
+     *
+     * _.isPlainObject(Object.create(null));
+     * // => true
+     */function isPlainObject(value){if(!isObjectLike(value)||baseGetTag(value)!=objectTag){return false;}var proto=getPrototype(value);if(proto===null){return true;}var Ctor=hasOwnProperty.call(proto,'constructor')&&proto.constructor;return typeof Ctor=='function'&&Ctor instanceof Ctor&&funcToString.call(Ctor)==objectCtorString;}/**
+     * Checks if `value` is classified as a `RegExp` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.1.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
+     * @example
+     *
+     * _.isRegExp(/abc/);
+     * // => true
+     *
+     * _.isRegExp('/abc/');
+     * // => false
+     */var isRegExp=nodeIsRegExp?baseUnary(nodeIsRegExp):baseIsRegExp;/**
+     * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
+     * double precision number which isn't the result of a rounded unsafe integer.
+     *
+     * **Note:** This method is based on
+     * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
+     * @example
+     *
+     * _.isSafeInteger(3);
+     * // => true
+     *
+     * _.isSafeInteger(Number.MIN_VALUE);
+     * // => false
+     *
+     * _.isSafeInteger(Infinity);
+     * // => false
+     *
+     * _.isSafeInteger('3');
+     * // => false
+     */function isSafeInteger(value){return isInteger(value)&&value>=-MAX_SAFE_INTEGER&&value<=MAX_SAFE_INTEGER;}/**
+     * Checks if `value` is classified as a `Set` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.3.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
+     * @example
+     *
+     * _.isSet(new Set);
+     * // => true
+     *
+     * _.isSet(new WeakSet);
+     * // => false
+     */var isSet=nodeIsSet?baseUnary(nodeIsSet):baseIsSet;/**
+     * Checks if `value` is classified as a `String` primitive or object.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a string, else `false`.
+     * @example
+     *
+     * _.isString('abc');
+     * // => true
+     *
+     * _.isString(1);
+     * // => false
+     */function isString(value){return typeof value=='string'||!isArray(value)&&isObjectLike(value)&&baseGetTag(value)==stringTag;}/**
+     * Checks if `value` is classified as a `Symbol` primitive or object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
+     * @example
+     *
+     * _.isSymbol(Symbol.iterator);
+     * // => true
+     *
+     * _.isSymbol('abc');
+     * // => false
+     */function isSymbol(value){return typeof value=='symbol'||isObjectLike(value)&&baseGetTag(value)==symbolTag;}/**
+     * Checks if `value` is classified as a typed array.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
+     * @example
+     *
+     * _.isTypedArray(new Uint8Array);
+     * // => true
+     *
+     * _.isTypedArray([]);
+     * // => false
+     */var isTypedArray=nodeIsTypedArray?baseUnary(nodeIsTypedArray):baseIsTypedArray;/**
+     * Checks if `value` is `undefined`.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
+     * @example
+     *
+     * _.isUndefined(void 0);
+     * // => true
+     *
+     * _.isUndefined(null);
+     * // => false
+     */function isUndefined(value){return value===undefined$1;}/**
+     * Checks if `value` is classified as a `WeakMap` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.3.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
+     * @example
+     *
+     * _.isWeakMap(new WeakMap);
+     * // => true
+     *
+     * _.isWeakMap(new Map);
+     * // => false
+     */function isWeakMap(value){return isObjectLike(value)&&getTag(value)==weakMapTag;}/**
+     * Checks if `value` is classified as a `WeakSet` object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.3.0
+     * @category Lang
+     * @param {*} value The value to check.
+     * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
+     * @example
+     *
+     * _.isWeakSet(new WeakSet);
+     * // => true
+     *
+     * _.isWeakSet(new Set);
+     * // => false
+     */function isWeakSet(value){return isObjectLike(value)&&baseGetTag(value)==weakSetTag;}/**
+     * Checks if `value` is less than `other`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.9.0
+     * @category Lang
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is less than `other`,
+     *  else `false`.
+     * @see _.gt
+     * @example
+     *
+     * _.lt(1, 3);
+     * // => true
+     *
+     * _.lt(3, 3);
+     * // => false
+     *
+     * _.lt(3, 1);
+     * // => false
+     */var lt=createRelationalOperation(baseLt);/**
+     * Checks if `value` is less than or equal to `other`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.9.0
+     * @category Lang
+     * @param {*} value The value to compare.
+     * @param {*} other The other value to compare.
+     * @returns {boolean} Returns `true` if `value` is less than or equal to
+     *  `other`, else `false`.
+     * @see _.gte
+     * @example
+     *
+     * _.lte(1, 3);
+     * // => true
+     *
+     * _.lte(3, 3);
+     * // => true
+     *
+     * _.lte(3, 1);
+     * // => false
+     */var lte=createRelationalOperation(function(value,other){return value<=other;});/**
+     * Converts `value` to an array.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Lang
+     * @param {*} value The value to convert.
+     * @returns {Array} Returns the converted array.
+     * @example
+     *
+     * _.toArray({ 'a': 1, 'b': 2 });
+     * // => [1, 2]
+     *
+     * _.toArray('abc');
+     * // => ['a', 'b', 'c']
+     *
+     * _.toArray(1);
+     * // => []
+     *
+     * _.toArray(null);
+     * // => []
+     */function toArray(value){if(!value){return [];}if(isArrayLike(value)){return isString(value)?stringToArray(value):copyArray(value);}if(symIterator&&value[symIterator]){return iteratorToArray(value[symIterator]());}var tag=getTag(value),func=tag==mapTag?mapToArray:tag==setTag?setToArray:values;return func(value);}/**
+     * Converts `value` to a finite number.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.12.0
+     * @category Lang
+     * @param {*} value The value to convert.
+     * @returns {number} Returns the converted number.
+     * @example
+     *
+     * _.toFinite(3.2);
+     * // => 3.2
+     *
+     * _.toFinite(Number.MIN_VALUE);
+     * // => 5e-324
+     *
+     * _.toFinite(Infinity);
+     * // => 1.7976931348623157e+308
+     *
+     * _.toFinite('3.2');
+     * // => 3.2
+     */function toFinite(value){if(!value){return value===0?value:0;}value=toNumber(value);if(value===INFINITY||value===-INFINITY){var sign=value<0?-1:1;return sign*MAX_INTEGER;}return value===value?value:0;}/**
+     * Converts `value` to an integer.
+     *
+     * **Note:** This method is loosely based on
+     * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to convert.
+     * @returns {number} Returns the converted integer.
+     * @example
+     *
+     * _.toInteger(3.2);
+     * // => 3
+     *
+     * _.toInteger(Number.MIN_VALUE);
+     * // => 0
+     *
+     * _.toInteger(Infinity);
+     * // => 1.7976931348623157e+308
+     *
+     * _.toInteger('3.2');
+     * // => 3
+     */function toInteger(value){var result=toFinite(value),remainder=result%1;return result===result?remainder?result-remainder:result:0;}/**
+     * Converts `value` to an integer suitable for use as the length of an
+     * array-like object.
+     *
+     * **Note:** This method is based on
+     * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to convert.
+     * @returns {number} Returns the converted integer.
+     * @example
+     *
+     * _.toLength(3.2);
+     * // => 3
+     *
+     * _.toLength(Number.MIN_VALUE);
+     * // => 0
+     *
+     * _.toLength(Infinity);
+     * // => 4294967295
+     *
+     * _.toLength('3.2');
+     * // => 3
+     */function toLength(value){return value?baseClamp(toInteger(value),0,MAX_ARRAY_LENGTH):0;}/**
+     * Converts `value` to a number.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to process.
+     * @returns {number} Returns the number.
+     * @example
+     *
+     * _.toNumber(3.2);
+     * // => 3.2
+     *
+     * _.toNumber(Number.MIN_VALUE);
+     * // => 5e-324
+     *
+     * _.toNumber(Infinity);
+     * // => Infinity
+     *
+     * _.toNumber('3.2');
+     * // => 3.2
+     */function toNumber(value){if(typeof value=='number'){return value;}if(isSymbol(value)){return NAN;}if(isObject(value)){var other=typeof value.valueOf=='function'?value.valueOf():value;value=isObject(other)?other+'':other;}if(typeof value!='string'){return value===0?value:+value;}value=baseTrim(value);var isBinary=reIsBinary.test(value);return isBinary||reIsOctal.test(value)?freeParseInt(value.slice(2),isBinary?2:8):reIsBadHex.test(value)?NAN:+value;}/**
+     * Converts `value` to a plain object flattening inherited enumerable string
+     * keyed properties of `value` to own properties of the plain object.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Lang
+     * @param {*} value The value to convert.
+     * @returns {Object} Returns the converted plain object.
+     * @example
+     *
+     * function Foo() {
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.assign({ 'a': 1 }, new Foo);
+     * // => { 'a': 1, 'b': 2 }
+     *
+     * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
+     * // => { 'a': 1, 'b': 2, 'c': 3 }
+     */function toPlainObject(value){return copyObject(value,keysIn(value));}/**
+     * Converts `value` to a safe integer. A safe integer can be compared and
+     * represented correctly.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to convert.
+     * @returns {number} Returns the converted integer.
+     * @example
+     *
+     * _.toSafeInteger(3.2);
+     * // => 3
+     *
+     * _.toSafeInteger(Number.MIN_VALUE);
+     * // => 0
+     *
+     * _.toSafeInteger(Infinity);
+     * // => 9007199254740991
+     *
+     * _.toSafeInteger('3.2');
+     * // => 3
+     */function toSafeInteger(value){return value?baseClamp(toInteger(value),-MAX_SAFE_INTEGER,MAX_SAFE_INTEGER):value===0?value:0;}/**
+     * Converts `value` to a string. An empty string is returned for `null`
+     * and `undefined` values. The sign of `-0` is preserved.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Lang
+     * @param {*} value The value to convert.
+     * @returns {string} Returns the converted string.
+     * @example
+     *
+     * _.toString(null);
+     * // => ''
+     *
+     * _.toString(-0);
+     * // => '-0'
+     *
+     * _.toString([1, 2, 3]);
+     * // => '1,2,3'
+     */function toString(value){return value==null?'':baseToString(value);}/*------------------------------------------------------------------------*/ /**
+     * Assigns own enumerable string keyed properties of source objects to the
+     * destination object. Source objects are applied from left to right.
+     * Subsequent sources overwrite property assignments of previous sources.
+     *
+     * **Note:** This method mutates `object` and is loosely based on
+     * [`Object.assign`](https://mdn.io/Object/assign).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.10.0
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} [sources] The source objects.
+     * @returns {Object} Returns `object`.
+     * @see _.assignIn
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     * }
+     *
+     * function Bar() {
+     *   this.c = 3;
+     * }
+     *
+     * Foo.prototype.b = 2;
+     * Bar.prototype.d = 4;
+     *
+     * _.assign({ 'a': 0 }, new Foo, new Bar);
+     * // => { 'a': 1, 'c': 3 }
+     */var assign=createAssigner(function(object,source){if(isPrototype(source)||isArrayLike(source)){copyObject(source,keys(source),object);return;}for(var key in source){if(hasOwnProperty.call(source,key)){assignValue(object,key,source[key]);}}});/**
+     * This method is like `_.assign` except that it iterates over own and
+     * inherited source properties.
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @alias extend
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} [sources] The source objects.
+     * @returns {Object} Returns `object`.
+     * @see _.assign
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     * }
+     *
+     * function Bar() {
+     *   this.c = 3;
+     * }
+     *
+     * Foo.prototype.b = 2;
+     * Bar.prototype.d = 4;
+     *
+     * _.assignIn({ 'a': 0 }, new Foo, new Bar);
+     * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
+     */var assignIn=createAssigner(function(object,source){copyObject(source,keysIn(source),object);});/**
+     * This method is like `_.assignIn` except that it accepts `customizer`
+     * which is invoked to produce the assigned values. If `customizer` returns
+     * `undefined`, assignment is handled by the method instead. The `customizer`
+     * is invoked with five arguments: (objValue, srcValue, key, object, source).
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @alias extendWith
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} sources The source objects.
+     * @param {Function} [customizer] The function to customize assigned values.
+     * @returns {Object} Returns `object`.
+     * @see _.assignWith
+     * @example
+     *
+     * function customizer(objValue, srcValue) {
+     *   return _.isUndefined(objValue) ? srcValue : objValue;
+     * }
+     *
+     * var defaults = _.partialRight(_.assignInWith, customizer);
+     *
+     * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
+     * // => { 'a': 1, 'b': 2 }
+     */var assignInWith=createAssigner(function(object,source,srcIndex,customizer){copyObject(source,keysIn(source),object,customizer);});/**
+     * This method is like `_.assign` except that it accepts `customizer`
+     * which is invoked to produce the assigned values. If `customizer` returns
+     * `undefined`, assignment is handled by the method instead. The `customizer`
+     * is invoked with five arguments: (objValue, srcValue, key, object, source).
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} sources The source objects.
+     * @param {Function} [customizer] The function to customize assigned values.
+     * @returns {Object} Returns `object`.
+     * @see _.assignInWith
+     * @example
+     *
+     * function customizer(objValue, srcValue) {
+     *   return _.isUndefined(objValue) ? srcValue : objValue;
+     * }
+     *
+     * var defaults = _.partialRight(_.assignWith, customizer);
+     *
+     * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
+     * // => { 'a': 1, 'b': 2 }
+     */var assignWith=createAssigner(function(object,source,srcIndex,customizer){copyObject(source,keys(source),object,customizer);});/**
+     * Creates an array of values corresponding to `paths` of `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.0.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {...(string|string[])} [paths] The property paths to pick.
+     * @returns {Array} Returns the picked values.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
+     *
+     * _.at(object, ['a[0].b.c', 'a[1]']);
+     * // => [3, 4]
+     */var at=flatRest(baseAt);/**
+     * Creates an object that inherits from the `prototype` object. If a
+     * `properties` object is given, its own enumerable string keyed properties
+     * are assigned to the created object.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.3.0
+     * @category Object
+     * @param {Object} prototype The object to inherit from.
+     * @param {Object} [properties] The properties to assign to the object.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * function Shape() {
+     *   this.x = 0;
+     *   this.y = 0;
+     * }
+     *
+     * function Circle() {
+     *   Shape.call(this);
+     * }
+     *
+     * Circle.prototype = _.create(Shape.prototype, {
+     *   'constructor': Circle
+     * });
+     *
+     * var circle = new Circle;
+     * circle instanceof Circle;
+     * // => true
+     *
+     * circle instanceof Shape;
+     * // => true
+     */function create(prototype,properties){var result=baseCreate(prototype);return properties==null?result:baseAssign(result,properties);}/**
+     * Assigns own and inherited enumerable string keyed properties of source
+     * objects to the destination object for all destination properties that
+     * resolve to `undefined`. Source objects are applied from left to right.
+     * Once a property is set, additional values of the same property are ignored.
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} [sources] The source objects.
+     * @returns {Object} Returns `object`.
+     * @see _.defaultsDeep
+     * @example
+     *
+     * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
+     * // => { 'a': 1, 'b': 2 }
+     */var defaults=baseRest(function(object,sources){object=Object(object);var index=-1;var length=sources.length;var guard=length>2?sources[2]:undefined$1;if(guard&&isIterateeCall(sources[0],sources[1],guard)){length=1;}while(++index<length){var source=sources[index];var props=keysIn(source);var propsIndex=-1;var propsLength=props.length;while(++propsIndex<propsLength){var key=props[propsIndex];var value=object[key];if(value===undefined$1||eq(value,objectProto[key])&&!hasOwnProperty.call(object,key)){object[key]=source[key];}}}return object;});/**
+     * This method is like `_.defaults` except that it recursively assigns
+     * default properties.
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.10.0
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} [sources] The source objects.
+     * @returns {Object} Returns `object`.
+     * @see _.defaults
+     * @example
+     *
+     * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
+     * // => { 'a': { 'b': 2, 'c': 3 } }
+     */var defaultsDeep=baseRest(function(args){args.push(undefined$1,customDefaultsMerge);return apply(mergeWith,undefined$1,args);});/**
+     * This method is like `_.find` except that it returns the key of the first
+     * element `predicate` returns truthy for instead of the element itself.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.1.0
+     * @category Object
+     * @param {Object} object The object to inspect.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {string|undefined} Returns the key of the matched element,
+     *  else `undefined`.
+     * @example
+     *
+     * var users = {
+     *   'barney':  { 'age': 36, 'active': true },
+     *   'fred':    { 'age': 40, 'active': false },
+     *   'pebbles': { 'age': 1,  'active': true }
+     * };
+     *
+     * _.findKey(users, function(o) { return o.age < 40; });
+     * // => 'barney' (iteration order is not guaranteed)
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.findKey(users, { 'age': 1, 'active': true });
+     * // => 'pebbles'
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.findKey(users, ['active', false]);
+     * // => 'fred'
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.findKey(users, 'active');
+     * // => 'barney'
+     */function findKey(object,predicate){return baseFindKey(object,getIteratee(predicate,3),baseForOwn);}/**
+     * This method is like `_.findKey` except that it iterates over elements of
+     * a collection in the opposite order.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Object
+     * @param {Object} object The object to inspect.
+     * @param {Function} [predicate=_.identity] The function invoked per iteration.
+     * @returns {string|undefined} Returns the key of the matched element,
+     *  else `undefined`.
+     * @example
+     *
+     * var users = {
+     *   'barney':  { 'age': 36, 'active': true },
+     *   'fred':    { 'age': 40, 'active': false },
+     *   'pebbles': { 'age': 1,  'active': true }
+     * };
+     *
+     * _.findLastKey(users, function(o) { return o.age < 40; });
+     * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.findLastKey(users, { 'age': 36, 'active': true });
+     * // => 'barney'
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.findLastKey(users, ['active', false]);
+     * // => 'fred'
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.findLastKey(users, 'active');
+     * // => 'pebbles'
+     */function findLastKey(object,predicate){return baseFindKey(object,getIteratee(predicate,3),baseForOwnRight);}/**
+     * Iterates over own and inherited enumerable string keyed properties of an
+     * object and invokes `iteratee` for each property. The iteratee is invoked
+     * with three arguments: (value, key, object). Iteratee functions may exit
+     * iteration early by explicitly returning `false`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.3.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     * @see _.forInRight
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.forIn(new Foo, function(value, key) {
+     *   console.log(key);
+     * });
+     * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
+     */function forIn(object,iteratee){return object==null?object:baseFor(object,getIteratee(iteratee,3),keysIn);}/**
+     * This method is like `_.forIn` except that it iterates over properties of
+     * `object` in the opposite order.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     * @see _.forIn
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.forInRight(new Foo, function(value, key) {
+     *   console.log(key);
+     * });
+     * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
+     */function forInRight(object,iteratee){return object==null?object:baseForRight(object,getIteratee(iteratee,3),keysIn);}/**
+     * Iterates over own enumerable string keyed properties of an object and
+     * invokes `iteratee` for each property. The iteratee is invoked with three
+     * arguments: (value, key, object). Iteratee functions may exit iteration
+     * early by explicitly returning `false`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.3.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     * @see _.forOwnRight
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.forOwn(new Foo, function(value, key) {
+     *   console.log(key);
+     * });
+     * // => Logs 'a' then 'b' (iteration order is not guaranteed).
+     */function forOwn(object,iteratee){return object&&baseForOwn(object,getIteratee(iteratee,3));}/**
+     * This method is like `_.forOwn` except that it iterates over properties of
+     * `object` in the opposite order.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.0.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Object} Returns `object`.
+     * @see _.forOwn
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.forOwnRight(new Foo, function(value, key) {
+     *   console.log(key);
+     * });
+     * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
+     */function forOwnRight(object,iteratee){return object&&baseForOwnRight(object,getIteratee(iteratee,3));}/**
+     * Creates an array of function property names from own enumerable properties
+     * of `object`.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The object to inspect.
+     * @returns {Array} Returns the function names.
+     * @see _.functionsIn
+     * @example
+     *
+     * function Foo() {
+     *   this.a = _.constant('a');
+     *   this.b = _.constant('b');
+     * }
+     *
+     * Foo.prototype.c = _.constant('c');
+     *
+     * _.functions(new Foo);
+     * // => ['a', 'b']
+     */function functions(object){return object==null?[]:baseFunctions(object,keys(object));}/**
+     * Creates an array of function property names from own and inherited
+     * enumerable properties of `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The object to inspect.
+     * @returns {Array} Returns the function names.
+     * @see _.functions
+     * @example
+     *
+     * function Foo() {
+     *   this.a = _.constant('a');
+     *   this.b = _.constant('b');
+     * }
+     *
+     * Foo.prototype.c = _.constant('c');
+     *
+     * _.functionsIn(new Foo);
+     * // => ['a', 'b', 'c']
+     */function functionsIn(object){return object==null?[]:baseFunctions(object,keysIn(object));}/**
+     * Gets the value at `path` of `object`. If the resolved value is
+     * `undefined`, the `defaultValue` is returned in its place.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.7.0
+     * @category Object
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path of the property to get.
+     * @param {*} [defaultValue] The value returned for `undefined` resolved values.
+     * @returns {*} Returns the resolved value.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+     *
+     * _.get(object, 'a[0].b.c');
+     * // => 3
+     *
+     * _.get(object, ['a', '0', 'b', 'c']);
+     * // => 3
+     *
+     * _.get(object, 'a.b.c', 'default');
+     * // => 'default'
+     */function get(object,path,defaultValue){var result=object==null?undefined$1:baseGet(object,path);return result===undefined$1?defaultValue:result;}/**
+     * Checks if `path` is a direct property of `object`.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path to check.
+     * @returns {boolean} Returns `true` if `path` exists, else `false`.
+     * @example
+     *
+     * var object = { 'a': { 'b': 2 } };
+     * var other = _.create({ 'a': _.create({ 'b': 2 }) });
+     *
+     * _.has(object, 'a');
+     * // => true
+     *
+     * _.has(object, 'a.b');
+     * // => true
+     *
+     * _.has(object, ['a', 'b']);
+     * // => true
+     *
+     * _.has(other, 'a');
+     * // => false
+     */function has(object,path){return object!=null&&hasPath(object,path,baseHas);}/**
+     * Checks if `path` is a direct or inherited property of `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path to check.
+     * @returns {boolean} Returns `true` if `path` exists, else `false`.
+     * @example
+     *
+     * var object = _.create({ 'a': _.create({ 'b': 2 }) });
+     *
+     * _.hasIn(object, 'a');
+     * // => true
+     *
+     * _.hasIn(object, 'a.b');
+     * // => true
+     *
+     * _.hasIn(object, ['a', 'b']);
+     * // => true
+     *
+     * _.hasIn(object, 'b');
+     * // => false
+     */function hasIn(object,path){return object!=null&&hasPath(object,path,baseHasIn);}/**
+     * Creates an object composed of the inverted keys and values of `object`.
+     * If `object` contains duplicate values, subsequent values overwrite
+     * property assignments of previous values.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.7.0
+     * @category Object
+     * @param {Object} object The object to invert.
+     * @returns {Object} Returns the new inverted object.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': 2, 'c': 1 };
+     *
+     * _.invert(object);
+     * // => { '1': 'c', '2': 'b' }
+     */var invert=createInverter(function(result,value,key){if(value!=null&&typeof value.toString!='function'){value=nativeObjectToString.call(value);}result[value]=key;},constant(identity));/**
+     * This method is like `_.invert` except that the inverted object is generated
+     * from the results of running each element of `object` thru `iteratee`. The
+     * corresponding inverted value of each inverted key is an array of keys
+     * responsible for generating the inverted value. The iteratee is invoked
+     * with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.1.0
+     * @category Object
+     * @param {Object} object The object to invert.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {Object} Returns the new inverted object.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': 2, 'c': 1 };
+     *
+     * _.invertBy(object);
+     * // => { '1': ['a', 'c'], '2': ['b'] }
+     *
+     * _.invertBy(object, function(value) {
+     *   return 'group' + value;
+     * });
+     * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
+     */var invertBy=createInverter(function(result,value,key){if(value!=null&&typeof value.toString!='function'){value=nativeObjectToString.call(value);}if(hasOwnProperty.call(result,value)){result[value].push(key);}else {result[value]=[key];}},getIteratee);/**
+     * Invokes the method at `path` of `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path of the method to invoke.
+     * @param {...*} [args] The arguments to invoke the method with.
+     * @returns {*} Returns the result of the invoked method.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
+     *
+     * _.invoke(object, 'a[0].b.c.slice', 1, 3);
+     * // => [2, 3]
+     */var invoke=baseRest(baseInvoke);/**
+     * Creates an array of the own enumerable property names of `object`.
+     *
+     * **Note:** Non-object values are coerced to objects. See the
+     * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
+     * for more details.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names.
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.keys(new Foo);
+     * // => ['a', 'b'] (iteration order is not guaranteed)
+     *
+     * _.keys('hi');
+     * // => ['0', '1']
+     */function keys(object){return isArrayLike(object)?arrayLikeKeys(object):baseKeys(object);}/**
+     * Creates an array of the own and inherited enumerable property names of `object`.
+     *
+     * **Note:** Non-object values are coerced to objects.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Object
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property names.
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.keysIn(new Foo);
+     * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+     */function keysIn(object){return isArrayLike(object)?arrayLikeKeys(object,true):baseKeysIn(object);}/**
+     * The opposite of `_.mapValues`; this method creates an object with the
+     * same values as `object` and keys generated by running each own enumerable
+     * string keyed property of `object` thru `iteratee`. The iteratee is invoked
+     * with three arguments: (value, key, object).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.8.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Object} Returns the new mapped object.
+     * @see _.mapValues
+     * @example
+     *
+     * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
+     *   return key + value;
+     * });
+     * // => { 'a1': 1, 'b2': 2 }
+     */function mapKeys(object,iteratee){var result={};iteratee=getIteratee(iteratee,3);baseForOwn(object,function(value,key,object){baseAssignValue(result,iteratee(value,key,object),value);});return result;}/**
+     * Creates an object with the same keys as `object` and values generated
+     * by running each own enumerable string keyed property of `object` thru
+     * `iteratee`. The iteratee is invoked with three arguments:
+     * (value, key, object).
+     *
+     * @static
+     * @memberOf _
+     * @since 2.4.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Object} Returns the new mapped object.
+     * @see _.mapKeys
+     * @example
+     *
+     * var users = {
+     *   'fred':    { 'user': 'fred',    'age': 40 },
+     *   'pebbles': { 'user': 'pebbles', 'age': 1 }
+     * };
+     *
+     * _.mapValues(users, function(o) { return o.age; });
+     * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.mapValues(users, 'age');
+     * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
+     */function mapValues(object,iteratee){var result={};iteratee=getIteratee(iteratee,3);baseForOwn(object,function(value,key,object){baseAssignValue(result,key,iteratee(value,key,object));});return result;}/**
+     * This method is like `_.assign` except that it recursively merges own and
+     * inherited enumerable string keyed properties of source objects into the
+     * destination object. Source properties that resolve to `undefined` are
+     * skipped if a destination value exists. Array and plain object properties
+     * are merged recursively. Other objects and value types are overridden by
+     * assignment. Source objects are applied from left to right. Subsequent
+     * sources overwrite property assignments of previous sources.
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.5.0
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} [sources] The source objects.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * var object = {
+     *   'a': [{ 'b': 2 }, { 'd': 4 }]
+     * };
+     *
+     * var other = {
+     *   'a': [{ 'c': 3 }, { 'e': 5 }]
+     * };
+     *
+     * _.merge(object, other);
+     * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
+     */var merge=createAssigner(function(object,source,srcIndex){baseMerge(object,source,srcIndex);});/**
+     * This method is like `_.merge` except that it accepts `customizer` which
+     * is invoked to produce the merged values of the destination and source
+     * properties. If `customizer` returns `undefined`, merging is handled by the
+     * method instead. The `customizer` is invoked with six arguments:
+     * (objValue, srcValue, key, object, source, stack).
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The destination object.
+     * @param {...Object} sources The source objects.
+     * @param {Function} customizer The function to customize assigned values.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * function customizer(objValue, srcValue) {
+     *   if (_.isArray(objValue)) {
+     *     return objValue.concat(srcValue);
+     *   }
+     * }
+     *
+     * var object = { 'a': [1], 'b': [2] };
+     * var other = { 'a': [3], 'b': [4] };
+     *
+     * _.mergeWith(object, other, customizer);
+     * // => { 'a': [1, 3], 'b': [2, 4] }
+     */var mergeWith=createAssigner(function(object,source,srcIndex,customizer){baseMerge(object,source,srcIndex,customizer);});/**
+     * The opposite of `_.pick`; this method creates an object composed of the
+     * own and inherited enumerable property paths of `object` that are not omitted.
+     *
+     * **Note:** This method is considerably slower than `_.pick`.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The source object.
+     * @param {...(string|string[])} [paths] The property paths to omit.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': '2', 'c': 3 };
+     *
+     * _.omit(object, ['a', 'c']);
+     * // => { 'b': '2' }
+     */var omit=flatRest(function(object,paths){var result={};if(object==null){return result;}var isDeep=false;paths=arrayMap(paths,function(path){path=castPath(path,object);isDeep||(isDeep=path.length>1);return path;});copyObject(object,getAllKeysIn(object),result);if(isDeep){result=baseClone(result,CLONE_DEEP_FLAG|CLONE_FLAT_FLAG|CLONE_SYMBOLS_FLAG,customOmitClone);}var length=paths.length;while(length--){baseUnset(result,paths[length]);}return result;});/**
+     * The opposite of `_.pickBy`; this method creates an object composed of
+     * the own and inherited enumerable string keyed properties of `object` that
+     * `predicate` doesn't return truthy for. The predicate is invoked with two
+     * arguments: (value, key).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The source object.
+     * @param {Function} [predicate=_.identity] The function invoked per property.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': '2', 'c': 3 };
+     *
+     * _.omitBy(object, _.isNumber);
+     * // => { 'b': '2' }
+     */function omitBy(object,predicate){return pickBy(object,negate(getIteratee(predicate)));}/**
+     * Creates an object composed of the picked `object` properties.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The source object.
+     * @param {...(string|string[])} [paths] The property paths to pick.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': '2', 'c': 3 };
+     *
+     * _.pick(object, ['a', 'c']);
+     * // => { 'a': 1, 'c': 3 }
+     */var pick=flatRest(function(object,paths){return object==null?{}:basePick(object,paths);});/**
+     * Creates an object composed of the `object` properties `predicate` returns
+     * truthy for. The predicate is invoked with two arguments: (value, key).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The source object.
+     * @param {Function} [predicate=_.identity] The function invoked per property.
+     * @returns {Object} Returns the new object.
+     * @example
+     *
+     * var object = { 'a': 1, 'b': '2', 'c': 3 };
+     *
+     * _.pickBy(object, _.isNumber);
+     * // => { 'a': 1, 'c': 3 }
+     */function pickBy(object,predicate){if(object==null){return {};}var props=arrayMap(getAllKeysIn(object),function(prop){return [prop];});predicate=getIteratee(predicate);return basePickBy(object,props,function(value,path){return predicate(value,path[0]);});}/**
+     * This method is like `_.get` except that if the resolved value is a
+     * function it's invoked with the `this` binding of its parent object and
+     * its result is returned.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The object to query.
+     * @param {Array|string} path The path of the property to resolve.
+     * @param {*} [defaultValue] The value returned for `undefined` resolved values.
+     * @returns {*} Returns the resolved value.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
+     *
+     * _.result(object, 'a[0].b.c1');
+     * // => 3
+     *
+     * _.result(object, 'a[0].b.c2');
+     * // => 4
+     *
+     * _.result(object, 'a[0].b.c3', 'default');
+     * // => 'default'
+     *
+     * _.result(object, 'a[0].b.c3', _.constant('default'));
+     * // => 'default'
+     */function result(object,path,defaultValue){path=castPath(path,object);var index=-1,length=path.length;// Ensure the loop is entered when path is empty.
+if(!length){length=1;object=undefined$1;}while(++index<length){var value=object==null?undefined$1:object[toKey(path[index])];if(value===undefined$1){index=length;value=defaultValue;}object=isFunction(value)?value.call(object):value;}return object;}/**
+     * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
+     * it's created. Arrays are created for missing index properties while objects
+     * are created for all other missing properties. Use `_.setWith` to customize
+     * `path` creation.
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.7.0
+     * @category Object
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to set.
+     * @param {*} value The value to set.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+     *
+     * _.set(object, 'a[0].b.c', 4);
+     * console.log(object.a[0].b.c);
+     * // => 4
+     *
+     * _.set(object, ['x', '0', 'y', 'z'], 5);
+     * console.log(object.x[0].y.z);
+     * // => 5
+     */function set(object,path,value){return object==null?object:baseSet(object,path,value);}/**
+     * This method is like `_.set` except that it accepts `customizer` which is
+     * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
+     * path creation is handled by the method instead. The `customizer` is invoked
+     * with three arguments: (nsValue, key, nsObject).
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to set.
+     * @param {*} value The value to set.
+     * @param {Function} [customizer] The function to customize assigned values.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * var object = {};
+     *
+     * _.setWith(object, '[0][1]', 'a', Object);
+     * // => { '0': { '1': 'a' } }
+     */function setWith(object,path,value,customizer){customizer=typeof customizer=='function'?customizer:undefined$1;return object==null?object:baseSet(object,path,value,customizer);}/**
+     * Creates an array of own enumerable string keyed-value pairs for `object`
+     * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
+     * entries are returned.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @alias entries
+     * @category Object
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the key-value pairs.
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.toPairs(new Foo);
+     * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
+     */var toPairs=createToPairs(keys);/**
+     * Creates an array of own and inherited enumerable string keyed-value pairs
+     * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
+     * or set, its entries are returned.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @alias entriesIn
+     * @category Object
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the key-value pairs.
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.toPairsIn(new Foo);
+     * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
+     */var toPairsIn=createToPairs(keysIn);/**
+     * An alternative to `_.reduce`; this method transforms `object` to a new
+     * `accumulator` object which is the result of running each of its own
+     * enumerable string keyed properties thru `iteratee`, with each invocation
+     * potentially mutating the `accumulator` object. If `accumulator` is not
+     * provided, a new object with the same `[[Prototype]]` will be used. The
+     * iteratee is invoked with four arguments: (accumulator, value, key, object).
+     * Iteratee functions may exit iteration early by explicitly returning `false`.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.3.0
+     * @category Object
+     * @param {Object} object The object to iterate over.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @param {*} [accumulator] The custom accumulator value.
+     * @returns {*} Returns the accumulated value.
+     * @example
+     *
+     * _.transform([2, 3, 4], function(result, n) {
+     *   result.push(n *= n);
+     *   return n % 2 == 0;
+     * }, []);
+     * // => [4, 9]
+     *
+     * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
+     *   (result[value] || (result[value] = [])).push(key);
+     * }, {});
+     * // => { '1': ['a', 'c'], '2': ['b'] }
+     */function transform(object,iteratee,accumulator){var isArr=isArray(object),isArrLike=isArr||isBuffer(object)||isTypedArray(object);iteratee=getIteratee(iteratee,4);if(accumulator==null){var Ctor=object&&object.constructor;if(isArrLike){accumulator=isArr?new Ctor():[];}else if(isObject(object)){accumulator=isFunction(Ctor)?baseCreate(getPrototype(object)):{};}else {accumulator={};}}(isArrLike?arrayEach:baseForOwn)(object,function(value,index,object){return iteratee(accumulator,value,index,object);});return accumulator;}/**
+     * Removes the property at `path` of `object`.
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Object
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to unset.
+     * @returns {boolean} Returns `true` if the property is deleted, else `false`.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c': 7 } }] };
+     * _.unset(object, 'a[0].b.c');
+     * // => true
+     *
+     * console.log(object);
+     * // => { 'a': [{ 'b': {} }] };
+     *
+     * _.unset(object, ['a', '0', 'b', 'c']);
+     * // => true
+     *
+     * console.log(object);
+     * // => { 'a': [{ 'b': {} }] };
+     */function unset(object,path){return object==null?true:baseUnset(object,path);}/**
+     * This method is like `_.set` except that accepts `updater` to produce the
+     * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
+     * is invoked with one argument: (value).
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.6.0
+     * @category Object
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to set.
+     * @param {Function} updater The function to produce the updated value.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
+     *
+     * _.update(object, 'a[0].b.c', function(n) { return n * n; });
+     * console.log(object.a[0].b.c);
+     * // => 9
+     *
+     * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
+     * console.log(object.x[0].y.z);
+     * // => 0
+     */function update(object,path,updater){return object==null?object:baseUpdate(object,path,castFunction(updater));}/**
+     * This method is like `_.update` except that it accepts `customizer` which is
+     * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
+     * path creation is handled by the method instead. The `customizer` is invoked
+     * with three arguments: (nsValue, key, nsObject).
+     *
+     * **Note:** This method mutates `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.6.0
+     * @category Object
+     * @param {Object} object The object to modify.
+     * @param {Array|string} path The path of the property to set.
+     * @param {Function} updater The function to produce the updated value.
+     * @param {Function} [customizer] The function to customize assigned values.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * var object = {};
+     *
+     * _.updateWith(object, '[0][1]', _.constant('a'), Object);
+     * // => { '0': { '1': 'a' } }
+     */function updateWith(object,path,updater,customizer){customizer=typeof customizer=='function'?customizer:undefined$1;return object==null?object:baseUpdate(object,path,castFunction(updater),customizer);}/**
+     * Creates an array of the own enumerable string keyed property values of `object`.
+     *
+     * **Note:** Non-object values are coerced to objects.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Object
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property values.
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.values(new Foo);
+     * // => [1, 2] (iteration order is not guaranteed)
+     *
+     * _.values('hi');
+     * // => ['h', 'i']
+     */function values(object){return object==null?[]:baseValues(object,keys(object));}/**
+     * Creates an array of the own and inherited enumerable string keyed property
+     * values of `object`.
+     *
+     * **Note:** Non-object values are coerced to objects.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Object
+     * @param {Object} object The object to query.
+     * @returns {Array} Returns the array of property values.
+     * @example
+     *
+     * function Foo() {
+     *   this.a = 1;
+     *   this.b = 2;
+     * }
+     *
+     * Foo.prototype.c = 3;
+     *
+     * _.valuesIn(new Foo);
+     * // => [1, 2, 3] (iteration order is not guaranteed)
+     */function valuesIn(object){return object==null?[]:baseValues(object,keysIn(object));}/*------------------------------------------------------------------------*/ /**
+     * Clamps `number` within the inclusive `lower` and `upper` bounds.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Number
+     * @param {number} number The number to clamp.
+     * @param {number} [lower] The lower bound.
+     * @param {number} upper The upper bound.
+     * @returns {number} Returns the clamped number.
+     * @example
+     *
+     * _.clamp(-10, -5, 5);
+     * // => -5
+     *
+     * _.clamp(10, -5, 5);
+     * // => 5
+     */function clamp(number,lower,upper){if(upper===undefined$1){upper=lower;lower=undefined$1;}if(upper!==undefined$1){upper=toNumber(upper);upper=upper===upper?upper:0;}if(lower!==undefined$1){lower=toNumber(lower);lower=lower===lower?lower:0;}return baseClamp(toNumber(number),lower,upper);}/**
+     * Checks if `n` is between `start` and up to, but not including, `end`. If
+     * `end` is not specified, it's set to `start` with `start` then set to `0`.
+     * If `start` is greater than `end` the params are swapped to support
+     * negative ranges.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.3.0
+     * @category Number
+     * @param {number} number The number to check.
+     * @param {number} [start=0] The start of the range.
+     * @param {number} end The end of the range.
+     * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
+     * @see _.range, _.rangeRight
+     * @example
+     *
+     * _.inRange(3, 2, 4);
+     * // => true
+     *
+     * _.inRange(4, 8);
+     * // => true
+     *
+     * _.inRange(4, 2);
+     * // => false
+     *
+     * _.inRange(2, 2);
+     * // => false
+     *
+     * _.inRange(1.2, 2);
+     * // => true
+     *
+     * _.inRange(5.2, 4);
+     * // => false
+     *
+     * _.inRange(-3, -2, -6);
+     * // => true
+     */function inRange(number,start,end){start=toFinite(start);if(end===undefined$1){end=start;start=0;}else {end=toFinite(end);}number=toNumber(number);return baseInRange(number,start,end);}/**
+     * Produces a random number between the inclusive `lower` and `upper` bounds.
+     * If only one argument is provided a number between `0` and the given number
+     * is returned. If `floating` is `true`, or either `lower` or `upper` are
+     * floats, a floating-point number is returned instead of an integer.
+     *
+     * **Note:** JavaScript follows the IEEE-754 standard for resolving
+     * floating-point values which can produce unexpected results.
+     *
+     * @static
+     * @memberOf _
+     * @since 0.7.0
+     * @category Number
+     * @param {number} [lower=0] The lower bound.
+     * @param {number} [upper=1] The upper bound.
+     * @param {boolean} [floating] Specify returning a floating-point number.
+     * @returns {number} Returns the random number.
+     * @example
+     *
+     * _.random(0, 5);
+     * // => an integer between 0 and 5
+     *
+     * _.random(5);
+     * // => also an integer between 0 and 5
+     *
+     * _.random(5, true);
+     * // => a floating-point number between 0 and 5
+     *
+     * _.random(1.2, 5.2);
+     * // => a floating-point number between 1.2 and 5.2
+     */function random(lower,upper,floating){if(floating&&typeof floating!='boolean'&&isIterateeCall(lower,upper,floating)){upper=floating=undefined$1;}if(floating===undefined$1){if(typeof upper=='boolean'){floating=upper;upper=undefined$1;}else if(typeof lower=='boolean'){floating=lower;lower=undefined$1;}}if(lower===undefined$1&&upper===undefined$1){lower=0;upper=1;}else {lower=toFinite(lower);if(upper===undefined$1){upper=lower;lower=0;}else {upper=toFinite(upper);}}if(lower>upper){var temp=lower;lower=upper;upper=temp;}if(floating||lower%1||upper%1){var rand=nativeRandom();return nativeMin(lower+rand*(upper-lower+freeParseFloat('1e-'+((rand+'').length-1))),upper);}return baseRandom(lower,upper);}/*------------------------------------------------------------------------*/ /**
+     * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the camel cased string.
+     * @example
+     *
+     * _.camelCase('Foo Bar');
+     * // => 'fooBar'
+     *
+     * _.camelCase('--foo-bar--');
+     * // => 'fooBar'
+     *
+     * _.camelCase('__FOO_BAR__');
+     * // => 'fooBar'
+     */var camelCase=createCompounder(function(result,word,index){word=word.toLowerCase();return result+(index?capitalize(word):word);});/**
+     * Converts the first character of `string` to upper case and the remaining
+     * to lower case.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to capitalize.
+     * @returns {string} Returns the capitalized string.
+     * @example
+     *
+     * _.capitalize('FRED');
+     * // => 'Fred'
+     */function capitalize(string){return upperFirst(toString(string).toLowerCase());}/**
+     * Deburrs `string` by converting
+     * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
+     * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
+     * letters to basic Latin letters and removing
+     * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to deburr.
+     * @returns {string} Returns the deburred string.
+     * @example
+     *
+     * _.deburr('d茅j脿 vu');
+     * // => 'deja vu'
+     */function deburr(string){string=toString(string);return string&&string.replace(reLatin,deburrLetter).replace(reComboMark,'');}/**
+     * Checks if `string` ends with the given target string.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to inspect.
+     * @param {string} [target] The string to search for.
+     * @param {number} [position=string.length] The position to search up to.
+     * @returns {boolean} Returns `true` if `string` ends with `target`,
+     *  else `false`.
+     * @example
+     *
+     * _.endsWith('abc', 'c');
+     * // => true
+     *
+     * _.endsWith('abc', 'b');
+     * // => false
+     *
+     * _.endsWith('abc', 'b', 2);
+     * // => true
+     */function endsWith(string,target,position){string=toString(string);target=baseToString(target);var length=string.length;position=position===undefined$1?length:baseClamp(toInteger(position),0,length);var end=position;position-=target.length;return position>=0&&string.slice(position,end)==target;}/**
+     * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
+     * corresponding HTML entities.
+     *
+     * **Note:** No other characters are escaped. To escape additional
+     * characters use a third-party library like [_he_](https://mths.be/he).
+     *
+     * Though the ">" character is escaped for symmetry, characters like
+     * ">" and "/" don't need escaping in HTML and have no special meaning
+     * unless they're part of a tag or unquoted attribute value. See
+     * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
+     * (under "semi-related fun fact") for more details.
+     *
+     * When working with HTML you should always
+     * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
+     * XSS vectors.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category String
+     * @param {string} [string=''] The string to escape.
+     * @returns {string} Returns the escaped string.
+     * @example
+     *
+     * _.escape('fred, barney, & pebbles');
+     * // => 'fred, barney, &amp; pebbles'
+     */function escape(string){string=toString(string);return string&&reHasUnescapedHtml.test(string)?string.replace(reUnescapedHtml,escapeHtmlChar):string;}/**
+     * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
+     * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to escape.
+     * @returns {string} Returns the escaped string.
+     * @example
+     *
+     * _.escapeRegExp('[lodash](https://lodash.com/)');
+     * // => '\[lodash\]\(https://lodash\.com/\)'
+     */function escapeRegExp(string){string=toString(string);return string&&reHasRegExpChar.test(string)?string.replace(reRegExpChar,'\\$&'):string;}/**
+     * Converts `string` to
+     * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the kebab cased string.
+     * @example
+     *
+     * _.kebabCase('Foo Bar');
+     * // => 'foo-bar'
+     *
+     * _.kebabCase('fooBar');
+     * // => 'foo-bar'
+     *
+     * _.kebabCase('__FOO_BAR__');
+     * // => 'foo-bar'
+     */var kebabCase=createCompounder(function(result,word,index){return result+(index?'-':'')+word.toLowerCase();});/**
+     * Converts `string`, as space separated words, to lower case.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the lower cased string.
+     * @example
+     *
+     * _.lowerCase('--Foo-Bar--');
+     * // => 'foo bar'
+     *
+     * _.lowerCase('fooBar');
+     * // => 'foo bar'
+     *
+     * _.lowerCase('__FOO_BAR__');
+     * // => 'foo bar'
+     */var lowerCase=createCompounder(function(result,word,index){return result+(index?' ':'')+word.toLowerCase();});/**
+     * Converts the first character of `string` to lower case.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the converted string.
+     * @example
+     *
+     * _.lowerFirst('Fred');
+     * // => 'fred'
+     *
+     * _.lowerFirst('FRED');
+     * // => 'fRED'
+     */var lowerFirst=createCaseFirst('toLowerCase');/**
+     * Pads `string` on the left and right sides if it's shorter than `length`.
+     * Padding characters are truncated if they can't be evenly divided by `length`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to pad.
+     * @param {number} [length=0] The padding length.
+     * @param {string} [chars=' '] The string used as padding.
+     * @returns {string} Returns the padded string.
+     * @example
+     *
+     * _.pad('abc', 8);
+     * // => '  abc   '
+     *
+     * _.pad('abc', 8, '_-');
+     * // => '_-abc_-_'
+     *
+     * _.pad('abc', 3);
+     * // => 'abc'
+     */function pad(string,length,chars){string=toString(string);length=toInteger(length);var strLength=length?stringSize(string):0;if(!length||strLength>=length){return string;}var mid=(length-strLength)/2;return createPadding(nativeFloor(mid),chars)+string+createPadding(nativeCeil(mid),chars);}/**
+     * Pads `string` on the right side if it's shorter than `length`. Padding
+     * characters are truncated if they exceed `length`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to pad.
+     * @param {number} [length=0] The padding length.
+     * @param {string} [chars=' '] The string used as padding.
+     * @returns {string} Returns the padded string.
+     * @example
+     *
+     * _.padEnd('abc', 6);
+     * // => 'abc   '
+     *
+     * _.padEnd('abc', 6, '_-');
+     * // => 'abc_-_'
+     *
+     * _.padEnd('abc', 3);
+     * // => 'abc'
+     */function padEnd(string,length,chars){string=toString(string);length=toInteger(length);var strLength=length?stringSize(string):0;return length&&strLength<length?string+createPadding(length-strLength,chars):string;}/**
+     * Pads `string` on the left side if it's shorter than `length`. Padding
+     * characters are truncated if they exceed `length`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to pad.
+     * @param {number} [length=0] The padding length.
+     * @param {string} [chars=' '] The string used as padding.
+     * @returns {string} Returns the padded string.
+     * @example
+     *
+     * _.padStart('abc', 6);
+     * // => '   abc'
+     *
+     * _.padStart('abc', 6, '_-');
+     * // => '_-_abc'
+     *
+     * _.padStart('abc', 3);
+     * // => 'abc'
+     */function padStart(string,length,chars){string=toString(string);length=toInteger(length);var strLength=length?stringSize(string):0;return length&&strLength<length?createPadding(length-strLength,chars)+string:string;}/**
+     * Converts `string` to an integer of the specified radix. If `radix` is
+     * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
+     * hexadecimal, in which case a `radix` of `16` is used.
+     *
+     * **Note:** This method aligns with the
+     * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
+     *
+     * @static
+     * @memberOf _
+     * @since 1.1.0
+     * @category String
+     * @param {string} string The string to convert.
+     * @param {number} [radix=10] The radix to interpret `value` by.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {number} Returns the converted integer.
+     * @example
+     *
+     * _.parseInt('08');
+     * // => 8
+     *
+     * _.map(['6', '08', '10'], _.parseInt);
+     * // => [6, 8, 10]
+     */function parseInt(string,radix,guard){if(guard||radix==null){radix=0;}else if(radix){radix=+radix;}return nativeParseInt(toString(string).replace(reTrimStart,''),radix||0);}/**
+     * Repeats the given string `n` times.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to repeat.
+     * @param {number} [n=1] The number of times to repeat the string.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {string} Returns the repeated string.
+     * @example
+     *
+     * _.repeat('*', 3);
+     * // => '***'
+     *
+     * _.repeat('abc', 2);
+     * // => 'abcabc'
+     *
+     * _.repeat('abc', 0);
+     * // => ''
+     */function repeat(string,n,guard){if(guard?isIterateeCall(string,n,guard):n===undefined$1){n=1;}else {n=toInteger(n);}return baseRepeat(toString(string),n);}/**
+     * Replaces matches for `pattern` in `string` with `replacement`.
+     *
+     * **Note:** This method is based on
+     * [`String#replace`](https://mdn.io/String/replace).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to modify.
+     * @param {RegExp|string} pattern The pattern to replace.
+     * @param {Function|string} replacement The match replacement.
+     * @returns {string} Returns the modified string.
+     * @example
+     *
+     * _.replace('Hi Fred', 'Fred', 'Barney');
+     * // => 'Hi Barney'
+     */function replace(){var args=arguments,string=toString(args[0]);return args.length<3?string:string.replace(args[1],args[2]);}/**
+     * Converts `string` to
+     * [snake case](https://en.wikipedia.org/wiki/Snake_case).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the snake cased string.
+     * @example
+     *
+     * _.snakeCase('Foo Bar');
+     * // => 'foo_bar'
+     *
+     * _.snakeCase('fooBar');
+     * // => 'foo_bar'
+     *
+     * _.snakeCase('--FOO-BAR--');
+     * // => 'foo_bar'
+     */var snakeCase=createCompounder(function(result,word,index){return result+(index?'_':'')+word.toLowerCase();});/**
+     * Splits `string` by `separator`.
+     *
+     * **Note:** This method is based on
+     * [`String#split`](https://mdn.io/String/split).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to split.
+     * @param {RegExp|string} separator The separator pattern to split by.
+     * @param {number} [limit] The length to truncate results to.
+     * @returns {Array} Returns the string segments.
+     * @example
+     *
+     * _.split('a-b-c', '-', 2);
+     * // => ['a', 'b']
+     */function split(string,separator,limit){if(limit&&typeof limit!='number'&&isIterateeCall(string,separator,limit)){separator=limit=undefined$1;}limit=limit===undefined$1?MAX_ARRAY_LENGTH:limit>>>0;if(!limit){return [];}string=toString(string);if(string&&(typeof separator=='string'||separator!=null&&!isRegExp(separator))){separator=baseToString(separator);if(!separator&&hasUnicode(string)){return castSlice(stringToArray(string),0,limit);}}return string.split(separator,limit);}/**
+     * Converts `string` to
+     * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
+     *
+     * @static
+     * @memberOf _
+     * @since 3.1.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the start cased string.
+     * @example
+     *
+     * _.startCase('--foo-bar--');
+     * // => 'Foo Bar'
+     *
+     * _.startCase('fooBar');
+     * // => 'Foo Bar'
+     *
+     * _.startCase('__FOO_BAR__');
+     * // => 'FOO BAR'
+     */var startCase=createCompounder(function(result,word,index){return result+(index?' ':'')+upperFirst(word);});/**
+     * Checks if `string` starts with the given target string.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to inspect.
+     * @param {string} [target] The string to search for.
+     * @param {number} [position=0] The position to search from.
+     * @returns {boolean} Returns `true` if `string` starts with `target`,
+     *  else `false`.
+     * @example
+     *
+     * _.startsWith('abc', 'a');
+     * // => true
+     *
+     * _.startsWith('abc', 'b');
+     * // => false
+     *
+     * _.startsWith('abc', 'b', 1);
+     * // => true
+     */function startsWith(string,target,position){string=toString(string);position=position==null?0:baseClamp(toInteger(position),0,string.length);target=baseToString(target);return string.slice(position,position+target.length)==target;}/**
+     * Creates a compiled template function that can interpolate data properties
+     * in "interpolate" delimiters, HTML-escape interpolated data properties in
+     * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
+     * properties may be accessed as free variables in the template. If a setting
+     * object is given, it takes precedence over `_.templateSettings` values.
+     *
+     * **Note:** In the development build `_.template` utilizes
+     * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
+     * for easier debugging.
+     *
+     * For more information on precompiling templates see
+     * [lodash's custom builds documentation](https://lodash.com/custom-builds).
+     *
+     * For more information on Chrome extension sandboxes see
+     * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category String
+     * @param {string} [string=''] The template string.
+     * @param {Object} [options={}] The options object.
+     * @param {RegExp} [options.escape=_.templateSettings.escape]
+     *  The HTML "escape" delimiter.
+     * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
+     *  The "evaluate" delimiter.
+     * @param {Object} [options.imports=_.templateSettings.imports]
+     *  An object to import into the template as free variables.
+     * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
+     *  The "interpolate" delimiter.
+     * @param {string} [options.sourceURL='lodash.templateSources[n]']
+     *  The sourceURL of the compiled template.
+     * @param {string} [options.variable='obj']
+     *  The data object variable name.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Function} Returns the compiled template function.
+     * @example
+     *
+     * // Use the "interpolate" delimiter to create a compiled template.
+     * var compiled = _.template('hello <%= user %>!');
+     * compiled({ 'user': 'fred' });
+     * // => 'hello fred!'
+     *
+     * // Use the HTML "escape" delimiter to escape data property values.
+     * var compiled = _.template('<b><%- value %></b>');
+     * compiled({ 'value': '<script>' });
+     * // => '<b>&lt;script&gt;</b>'
+     *
+     * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
+     * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
+     * compiled({ 'users': ['fred', 'barney'] });
+     * // => '<li>fred</li><li>barney</li>'
+     *
+     * // Use the internal `print` function in "evaluate" delimiters.
+     * var compiled = _.template('<% print("hello " + user); %>!');
+     * compiled({ 'user': 'barney' });
+     * // => 'hello barney!'
+     *
+     * // Use the ES template literal delimiter as an "interpolate" delimiter.
+     * // Disable support by replacing the "interpolate" delimiter.
+     * var compiled = _.template('hello ${ user }!');
+     * compiled({ 'user': 'pebbles' });
+     * // => 'hello pebbles!'
+     *
+     * // Use backslashes to treat delimiters as plain text.
+     * var compiled = _.template('<%= "\\<%- value %\\>" %>');
+     * compiled({ 'value': 'ignored' });
+     * // => '<%- value %>'
+     *
+     * // Use the `imports` option to import `jQuery` as `jq`.
+     * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
+     * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
+     * compiled({ 'users': ['fred', 'barney'] });
+     * // => '<li>fred</li><li>barney</li>'
+     *
+     * // Use the `sourceURL` option to specify a custom sourceURL for the template.
+     * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
+     * compiled(data);
+     * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
+     *
+     * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
+     * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
+     * compiled.source;
+     * // => function(data) {
+     * //   var __t, __p = '';
+     * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
+     * //   return __p;
+     * // }
+     *
+     * // Use custom template delimiters.
+     * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
+     * var compiled = _.template('hello {{ user }}!');
+     * compiled({ 'user': 'mustache' });
+     * // => 'hello mustache!'
+     *
+     * // Use the `source` property to inline compiled templates for meaningful
+     * // line numbers in error messages and stack traces.
+     * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
+     *   var JST = {\
+     *     "main": ' + _.template(mainText).source + '\
+     *   };\
+     * ');
+     */function template(string,options,guard){// Based on John Resig's `tmpl` implementation
+// (http://ejohn.org/blog/javascript-micro-templating/)
+// and Laura Doktorova's doT.js (https://github.com/olado/doT).
+var settings=lodash.templateSettings;if(guard&&isIterateeCall(string,options,guard)){options=undefined$1;}string=toString(string);options=assignInWith({},options,settings,customDefaultsAssignIn);var imports=assignInWith({},options.imports,settings.imports,customDefaultsAssignIn),importsKeys=keys(imports),importsValues=baseValues(imports,importsKeys);var isEscaping,isEvaluating,index=0,interpolate=options.interpolate||reNoMatch,source="__p += '";// Compile the regexp to match each delimiter.
+var reDelimiters=RegExp((options.escape||reNoMatch).source+'|'+interpolate.source+'|'+(interpolate===reInterpolate?reEsTemplate:reNoMatch).source+'|'+(options.evaluate||reNoMatch).source+'|$','g');// Use a sourceURL for easier debugging.
+// The sourceURL gets injected into the source that's eval-ed, so be careful
+// to normalize all kinds of whitespace, so e.g. newlines (and unicode versions of it) can't sneak in
+// and escape the comment, thus injecting code that gets evaled.
+var sourceURL='//# sourceURL='+(hasOwnProperty.call(options,'sourceURL')?(options.sourceURL+'').replace(/\s/g,' '):'lodash.templateSources['+ ++templateCounter+']')+'\n';string.replace(reDelimiters,function(match,escapeValue,interpolateValue,esTemplateValue,evaluateValue,offset){interpolateValue||(interpolateValue=esTemplateValue);// Escape characters that can't be included in string literals.
+source+=string.slice(index,offset).replace(reUnescapedString,escapeStringChar);// Replace delimiters with snippets.
+if(escapeValue){isEscaping=true;source+="' +\n__e("+escapeValue+") +\n'";}if(evaluateValue){isEvaluating=true;source+="';\n"+evaluateValue+";\n__p += '";}if(interpolateValue){source+="' +\n((__t = ("+interpolateValue+")) == null ? '' : __t) +\n'";}index=offset+match.length;// The JS engine embedded in Adobe products needs `match` returned in
+// order to produce the correct `offset` value.
+return match;});source+="';\n";// If `variable` is not specified wrap a with-statement around the generated
+// code to add the data object to the top of the scope chain.
+var variable=hasOwnProperty.call(options,'variable')&&options.variable;if(!variable){source='with (obj) {\n'+source+'\n}\n';}// Throw an error if a forbidden character was found in `variable`, to prevent
+// potential command injection attacks.
+else if(reForbiddenIdentifierChars.test(variable)){throw new Error(INVALID_TEMPL_VAR_ERROR_TEXT);}// Cleanup code by stripping empty strings.
+source=(isEvaluating?source.replace(reEmptyStringLeading,''):source).replace(reEmptyStringMiddle,'$1').replace(reEmptyStringTrailing,'$1;');// Frame code as the function body.
+source='function('+(variable||'obj')+') {\n'+(variable?'':'obj || (obj = {});\n')+"var __t, __p = ''"+(isEscaping?', __e = _.escape':'')+(isEvaluating?', __j = Array.prototype.join;\n'+"function print() { __p += __j.call(arguments, '') }\n":';\n')+source+'return __p\n}';var result=attempt(function(){return Function(importsKeys,sourceURL+'return '+source).apply(undefined$1,importsValues);});// Provide the compiled function's source by its `toString` method or
+// the `source` property as a convenience for inlining compiled templates.
+result.source=source;if(isError(result)){throw result;}return result;}/**
+     * Converts `string`, as a whole, to lower case just like
+     * [String#toLowerCase](https://mdn.io/toLowerCase).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the lower cased string.
+     * @example
+     *
+     * _.toLower('--Foo-Bar--');
+     * // => '--foo-bar--'
+     *
+     * _.toLower('fooBar');
+     * // => 'foobar'
+     *
+     * _.toLower('__FOO_BAR__');
+     * // => '__foo_bar__'
+     */function toLower(value){return toString(value).toLowerCase();}/**
+     * Converts `string`, as a whole, to upper case just like
+     * [String#toUpperCase](https://mdn.io/toUpperCase).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the upper cased string.
+     * @example
+     *
+     * _.toUpper('--foo-bar--');
+     * // => '--FOO-BAR--'
+     *
+     * _.toUpper('fooBar');
+     * // => 'FOOBAR'
+     *
+     * _.toUpper('__foo_bar__');
+     * // => '__FOO_BAR__'
+     */function toUpper(value){return toString(value).toUpperCase();}/**
+     * Removes leading and trailing whitespace or specified characters from `string`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to trim.
+     * @param {string} [chars=whitespace] The characters to trim.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {string} Returns the trimmed string.
+     * @example
+     *
+     * _.trim('  abc  ');
+     * // => 'abc'
+     *
+     * _.trim('-_-abc-_-', '_-');
+     * // => 'abc'
+     *
+     * _.map(['  foo  ', '  bar  '], _.trim);
+     * // => ['foo', 'bar']
+     */function trim(string,chars,guard){string=toString(string);if(string&&(guard||chars===undefined$1)){return baseTrim(string);}if(!string||!(chars=baseToString(chars))){return string;}var strSymbols=stringToArray(string),chrSymbols=stringToArray(chars),start=charsStartIndex(strSymbols,chrSymbols),end=charsEndIndex(strSymbols,chrSymbols)+1;return castSlice(strSymbols,start,end).join('');}/**
+     * Removes trailing whitespace or specified characters from `string`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to trim.
+     * @param {string} [chars=whitespace] The characters to trim.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {string} Returns the trimmed string.
+     * @example
+     *
+     * _.trimEnd('  abc  ');
+     * // => '  abc'
+     *
+     * _.trimEnd('-_-abc-_-', '_-');
+     * // => '-_-abc'
+     */function trimEnd(string,chars,guard){string=toString(string);if(string&&(guard||chars===undefined$1)){return string.slice(0,trimmedEndIndex(string)+1);}if(!string||!(chars=baseToString(chars))){return string;}var strSymbols=stringToArray(string),end=charsEndIndex(strSymbols,stringToArray(chars))+1;return castSlice(strSymbols,0,end).join('');}/**
+     * Removes leading whitespace or specified characters from `string`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to trim.
+     * @param {string} [chars=whitespace] The characters to trim.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {string} Returns the trimmed string.
+     * @example
+     *
+     * _.trimStart('  abc  ');
+     * // => 'abc  '
+     *
+     * _.trimStart('-_-abc-_-', '_-');
+     * // => 'abc-_-'
+     */function trimStart(string,chars,guard){string=toString(string);if(string&&(guard||chars===undefined$1)){return string.replace(reTrimStart,'');}if(!string||!(chars=baseToString(chars))){return string;}var strSymbols=stringToArray(string),start=charsStartIndex(strSymbols,stringToArray(chars));return castSlice(strSymbols,start).join('');}/**
+     * Truncates `string` if it's longer than the given maximum string length.
+     * The last characters of the truncated string are replaced with the omission
+     * string which defaults to "...".
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to truncate.
+     * @param {Object} [options={}] The options object.
+     * @param {number} [options.length=30] The maximum string length.
+     * @param {string} [options.omission='...'] The string to indicate text is omitted.
+     * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
+     * @returns {string} Returns the truncated string.
+     * @example
+     *
+     * _.truncate('hi-diddly-ho there, neighborino');
+     * // => 'hi-diddly-ho there, neighbo...'
+     *
+     * _.truncate('hi-diddly-ho there, neighborino', {
+     *   'length': 24,
+     *   'separator': ' '
+     * });
+     * // => 'hi-diddly-ho there,...'
+     *
+     * _.truncate('hi-diddly-ho there, neighborino', {
+     *   'length': 24,
+     *   'separator': /,? +/
+     * });
+     * // => 'hi-diddly-ho there...'
+     *
+     * _.truncate('hi-diddly-ho there, neighborino', {
+     *   'omission': ' [...]'
+     * });
+     * // => 'hi-diddly-ho there, neig [...]'
+     */function truncate(string,options){var length=DEFAULT_TRUNC_LENGTH,omission=DEFAULT_TRUNC_OMISSION;if(isObject(options)){var separator='separator'in options?options.separator:separator;length='length'in options?toInteger(options.length):length;omission='omission'in options?baseToString(options.omission):omission;}string=toString(string);var strLength=string.length;if(hasUnicode(string)){var strSymbols=stringToArray(string);strLength=strSymbols.length;}if(length>=strLength){return string;}var end=length-stringSize(omission);if(end<1){return omission;}var result=strSymbols?castSlice(strSymbols,0,end).join(''):string.slice(0,end);if(separator===undefined$1){return result+omission;}if(strSymbols){end+=result.length-end;}if(isRegExp(separator)){if(string.slice(end).search(separator)){var match,substring=result;if(!separator.global){separator=RegExp(separator.source,toString(reFlags.exec(separator))+'g');}separator.lastIndex=0;while(match=separator.exec(substring)){var newEnd=match.index;}result=result.slice(0,newEnd===undefined$1?end:newEnd);}}else if(string.indexOf(baseToString(separator),end)!=end){var index=result.lastIndexOf(separator);if(index>-1){result=result.slice(0,index);}}return result+omission;}/**
+     * The inverse of `_.escape`; this method converts the HTML entities
+     * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
+     * their corresponding characters.
+     *
+     * **Note:** No other HTML entities are unescaped. To unescape additional
+     * HTML entities use a third-party library like [_he_](https://mths.be/he).
+     *
+     * @static
+     * @memberOf _
+     * @since 0.6.0
+     * @category String
+     * @param {string} [string=''] The string to unescape.
+     * @returns {string} Returns the unescaped string.
+     * @example
+     *
+     * _.unescape('fred, barney, &amp; pebbles');
+     * // => 'fred, barney, & pebbles'
+     */function unescape(string){string=toString(string);return string&&reHasEscapedHtml.test(string)?string.replace(reEscapedHtml,unescapeHtmlChar):string;}/**
+     * Converts `string`, as space separated words, to upper case.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the upper cased string.
+     * @example
+     *
+     * _.upperCase('--foo-bar');
+     * // => 'FOO BAR'
+     *
+     * _.upperCase('fooBar');
+     * // => 'FOO BAR'
+     *
+     * _.upperCase('__foo_bar__');
+     * // => 'FOO BAR'
+     */var upperCase=createCompounder(function(result,word,index){return result+(index?' ':'')+word.toUpperCase();});/**
+     * Converts the first character of `string` to upper case.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category String
+     * @param {string} [string=''] The string to convert.
+     * @returns {string} Returns the converted string.
+     * @example
+     *
+     * _.upperFirst('fred');
+     * // => 'Fred'
+     *
+     * _.upperFirst('FRED');
+     * // => 'FRED'
+     */var upperFirst=createCaseFirst('toUpperCase');/**
+     * Splits `string` into an array of its words.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category String
+     * @param {string} [string=''] The string to inspect.
+     * @param {RegExp|string} [pattern] The pattern to match words.
+     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
+     * @returns {Array} Returns the words of `string`.
+     * @example
+     *
+     * _.words('fred, barney, & pebbles');
+     * // => ['fred', 'barney', 'pebbles']
+     *
+     * _.words('fred, barney, & pebbles', /[^, ]+/g);
+     * // => ['fred', 'barney', '&', 'pebbles']
+     */function words(string,pattern,guard){string=toString(string);pattern=guard?undefined$1:pattern;if(pattern===undefined$1){return hasUnicodeWord(string)?unicodeWords(string):asciiWords(string);}return string.match(pattern)||[];}/*------------------------------------------------------------------------*/ /**
+     * Attempts to invoke `func`, returning either the result or the caught error
+     * object. Any additional arguments are provided to `func` when it's invoked.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Util
+     * @param {Function} func The function to attempt.
+     * @param {...*} [args] The arguments to invoke `func` with.
+     * @returns {*} Returns the `func` result or error object.
+     * @example
+     *
+     * // Avoid throwing errors for invalid selectors.
+     * var elements = _.attempt(function(selector) {
+     *   return document.querySelectorAll(selector);
+     * }, '>_>');
+     *
+     * if (_.isError(elements)) {
+     *   elements = [];
+     * }
+     */var attempt=baseRest(function(func,args){try{return apply(func,undefined$1,args);}catch(e){return isError(e)?e:new Error(e);}});/**
+     * Binds methods of an object to the object itself, overwriting the existing
+     * method.
+     *
+     * **Note:** This method doesn't set the "length" property of bound functions.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Util
+     * @param {Object} object The object to bind and assign the bound methods to.
+     * @param {...(string|string[])} methodNames The object method names to bind.
+     * @returns {Object} Returns `object`.
+     * @example
+     *
+     * var view = {
+     *   'label': 'docs',
+     *   'click': function() {
+     *     console.log('clicked ' + this.label);
+     *   }
+     * };
+     *
+     * _.bindAll(view, ['click']);
+     * jQuery(element).on('click', view.click);
+     * // => Logs 'clicked docs' when clicked.
+     */var bindAll=flatRest(function(object,methodNames){arrayEach(methodNames,function(key){key=toKey(key);baseAssignValue(object,key,bind(object[key],object));});return object;});/**
+     * Creates a function that iterates over `pairs` and invokes the corresponding
+     * function of the first predicate to return truthy. The predicate-function
+     * pairs are invoked with the `this` binding and arguments of the created
+     * function.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {Array} pairs The predicate-function pairs.
+     * @returns {Function} Returns the new composite function.
+     * @example
+     *
+     * var func = _.cond([
+     *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
+     *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
+     *   [_.stubTrue,                      _.constant('no match')]
+     * ]);
+     *
+     * func({ 'a': 1, 'b': 2 });
+     * // => 'matches A'
+     *
+     * func({ 'a': 0, 'b': 1 });
+     * // => 'matches B'
+     *
+     * func({ 'a': '1', 'b': '2' });
+     * // => 'no match'
+     */function cond(pairs){var length=pairs==null?0:pairs.length,toIteratee=getIteratee();pairs=!length?[]:arrayMap(pairs,function(pair){if(typeof pair[1]!='function'){throw new TypeError(FUNC_ERROR_TEXT);}return [toIteratee(pair[0]),pair[1]];});return baseRest(function(args){var index=-1;while(++index<length){var pair=pairs[index];if(apply(pair[0],this,args)){return apply(pair[1],this,args);}}});}/**
+     * Creates a function that invokes the predicate properties of `source` with
+     * the corresponding property values of a given object, returning `true` if
+     * all predicates return truthy, else `false`.
+     *
+     * **Note:** The created function is equivalent to `_.conformsTo` with
+     * `source` partially applied.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {Object} source The object of property predicates to conform to.
+     * @returns {Function} Returns the new spec function.
+     * @example
+     *
+     * var objects = [
+     *   { 'a': 2, 'b': 1 },
+     *   { 'a': 1, 'b': 2 }
+     * ];
+     *
+     * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
+     * // => [{ 'a': 1, 'b': 2 }]
+     */function conforms(source){return baseConforms(baseClone(source,CLONE_DEEP_FLAG));}/**
+     * Creates a function that returns `value`.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.4.0
+     * @category Util
+     * @param {*} value The value to return from the new function.
+     * @returns {Function} Returns the new constant function.
+     * @example
+     *
+     * var objects = _.times(2, _.constant({ 'a': 1 }));
+     *
+     * console.log(objects);
+     * // => [{ 'a': 1 }, { 'a': 1 }]
+     *
+     * console.log(objects[0] === objects[1]);
+     * // => true
+     */function constant(value){return function(){return value;};}/**
+     * Checks `value` to determine whether a default value should be returned in
+     * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
+     * or `undefined`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.14.0
+     * @category Util
+     * @param {*} value The value to check.
+     * @param {*} defaultValue The default value.
+     * @returns {*} Returns the resolved value.
+     * @example
+     *
+     * _.defaultTo(1, 10);
+     * // => 1
+     *
+     * _.defaultTo(undefined, 10);
+     * // => 10
+     */function defaultTo(value,defaultValue){return value==null||value!==value?defaultValue:value;}/**
+     * Creates a function that returns the result of invoking the given functions
+     * with the `this` binding of the created function, where each successive
+     * invocation is supplied the return value of the previous.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Util
+     * @param {...(Function|Function[])} [funcs] The functions to invoke.
+     * @returns {Function} Returns the new composite function.
+     * @see _.flowRight
+     * @example
+     *
+     * function square(n) {
+     *   return n * n;
+     * }
+     *
+     * var addSquare = _.flow([_.add, square]);
+     * addSquare(1, 2);
+     * // => 9
+     */var flow=createFlow();/**
+     * This method is like `_.flow` except that it creates a function that
+     * invokes the given functions from right to left.
+     *
+     * @static
+     * @since 3.0.0
+     * @memberOf _
+     * @category Util
+     * @param {...(Function|Function[])} [funcs] The functions to invoke.
+     * @returns {Function} Returns the new composite function.
+     * @see _.flow
+     * @example
+     *
+     * function square(n) {
+     *   return n * n;
+     * }
+     *
+     * var addSquare = _.flowRight([square, _.add]);
+     * addSquare(1, 2);
+     * // => 9
+     */var flowRight=createFlow(true);/**
+     * This method returns the first argument it receives.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Util
+     * @param {*} value Any value.
+     * @returns {*} Returns `value`.
+     * @example
+     *
+     * var object = { 'a': 1 };
+     *
+     * console.log(_.identity(object) === object);
+     * // => true
+     */function identity(value){return value;}/**
+     * Creates a function that invokes `func` with the arguments of the created
+     * function. If `func` is a property name, the created function returns the
+     * property value for a given element. If `func` is an array or object, the
+     * created function returns `true` for elements that contain the equivalent
+     * source properties, otherwise it returns `false`.
+     *
+     * @static
+     * @since 4.0.0
+     * @memberOf _
+     * @category Util
+     * @param {*} [func=_.identity] The value to convert to a callback.
+     * @returns {Function} Returns the callback.
+     * @example
+     *
+     * var users = [
+     *   { 'user': 'barney', 'age': 36, 'active': true },
+     *   { 'user': 'fred',   'age': 40, 'active': false }
+     * ];
+     *
+     * // The `_.matches` iteratee shorthand.
+     * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
+     * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
+     *
+     * // The `_.matchesProperty` iteratee shorthand.
+     * _.filter(users, _.iteratee(['user', 'fred']));
+     * // => [{ 'user': 'fred', 'age': 40 }]
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.map(users, _.iteratee('user'));
+     * // => ['barney', 'fred']
+     *
+     * // Create custom iteratee shorthands.
+     * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
+     *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
+     *     return func.test(string);
+     *   };
+     * });
+     *
+     * _.filter(['abc', 'def'], /ef/);
+     * // => ['def']
+     */function iteratee(func){return baseIteratee(typeof func=='function'?func:baseClone(func,CLONE_DEEP_FLAG));}/**
+     * Creates a function that performs a partial deep comparison between a given
+     * object and `source`, returning `true` if the given object has equivalent
+     * property values, else `false`.
+     *
+     * **Note:** The created function is equivalent to `_.isMatch` with `source`
+     * partially applied.
+     *
+     * Partial comparisons will match empty array and empty object `source`
+     * values against any array or object value, respectively. See `_.isEqual`
+     * for a list of supported value comparisons.
+     *
+     * **Note:** Multiple values can be checked by combining several matchers
+     * using `_.overSome`
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Util
+     * @param {Object} source The object of property values to match.
+     * @returns {Function} Returns the new spec function.
+     * @example
+     *
+     * var objects = [
+     *   { 'a': 1, 'b': 2, 'c': 3 },
+     *   { 'a': 4, 'b': 5, 'c': 6 }
+     * ];
+     *
+     * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
+     * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
+     *
+     * // Checking for several possible values
+     * _.filter(objects, _.overSome([_.matches({ 'a': 1 }), _.matches({ 'a': 4 })]));
+     * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
+     */function matches(source){return baseMatches(baseClone(source,CLONE_DEEP_FLAG));}/**
+     * Creates a function that performs a partial deep comparison between the
+     * value at `path` of a given object to `srcValue`, returning `true` if the
+     * object value is equivalent, else `false`.
+     *
+     * **Note:** Partial comparisons will match empty array and empty object
+     * `srcValue` values against any array or object value, respectively. See
+     * `_.isEqual` for a list of supported value comparisons.
+     *
+     * **Note:** Multiple values can be checked by combining several matchers
+     * using `_.overSome`
+     *
+     * @static
+     * @memberOf _
+     * @since 3.2.0
+     * @category Util
+     * @param {Array|string} path The path of the property to get.
+     * @param {*} srcValue The value to match.
+     * @returns {Function} Returns the new spec function.
+     * @example
+     *
+     * var objects = [
+     *   { 'a': 1, 'b': 2, 'c': 3 },
+     *   { 'a': 4, 'b': 5, 'c': 6 }
+     * ];
+     *
+     * _.find(objects, _.matchesProperty('a', 4));
+     * // => { 'a': 4, 'b': 5, 'c': 6 }
+     *
+     * // Checking for several possible values
+     * _.filter(objects, _.overSome([_.matchesProperty('a', 1), _.matchesProperty('a', 4)]));
+     * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
+     */function matchesProperty(path,srcValue){return baseMatchesProperty(path,baseClone(srcValue,CLONE_DEEP_FLAG));}/**
+     * Creates a function that invokes the method at `path` of a given object.
+     * Any additional arguments are provided to the invoked method.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.7.0
+     * @category Util
+     * @param {Array|string} path The path of the method to invoke.
+     * @param {...*} [args] The arguments to invoke the method with.
+     * @returns {Function} Returns the new invoker function.
+     * @example
+     *
+     * var objects = [
+     *   { 'a': { 'b': _.constant(2) } },
+     *   { 'a': { 'b': _.constant(1) } }
+     * ];
+     *
+     * _.map(objects, _.method('a.b'));
+     * // => [2, 1]
+     *
+     * _.map(objects, _.method(['a', 'b']));
+     * // => [2, 1]
+     */var method=baseRest(function(path,args){return function(object){return baseInvoke(object,path,args);};});/**
+     * The opposite of `_.method`; this method creates a function that invokes
+     * the method at a given path of `object`. Any additional arguments are
+     * provided to the invoked method.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.7.0
+     * @category Util
+     * @param {Object} object The object to query.
+     * @param {...*} [args] The arguments to invoke the method with.
+     * @returns {Function} Returns the new invoker function.
+     * @example
+     *
+     * var array = _.times(3, _.constant),
+     *     object = { 'a': array, 'b': array, 'c': array };
+     *
+     * _.map(['a[2]', 'c[0]'], _.methodOf(object));
+     * // => [2, 0]
+     *
+     * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
+     * // => [2, 0]
+     */var methodOf=baseRest(function(object,args){return function(path){return baseInvoke(object,path,args);};});/**
+     * Adds all own enumerable string keyed function properties of a source
+     * object to the destination object. If `object` is a function, then methods
+     * are added to its prototype as well.
+     *
+     * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
+     * avoid conflicts caused by modifying the original.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Util
+     * @param {Function|Object} [object=lodash] The destination object.
+     * @param {Object} source The object of functions to add.
+     * @param {Object} [options={}] The options object.
+     * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
+     * @returns {Function|Object} Returns `object`.
+     * @example
+     *
+     * function vowels(string) {
+     *   return _.filter(string, function(v) {
+     *     return /[aeiou]/i.test(v);
+     *   });
+     * }
+     *
+     * _.mixin({ 'vowels': vowels });
+     * _.vowels('fred');
+     * // => ['e']
+     *
+     * _('fred').vowels().value();
+     * // => ['e']
+     *
+     * _.mixin({ 'vowels': vowels }, { 'chain': false });
+     * _('fred').vowels();
+     * // => ['e']
+     */function mixin(object,source,options){var props=keys(source),methodNames=baseFunctions(source,props);if(options==null&&!(isObject(source)&&(methodNames.length||!props.length))){options=source;source=object;object=this;methodNames=baseFunctions(source,keys(source));}var chain=!(isObject(options)&&'chain'in options)||!!options.chain,isFunc=isFunction(object);arrayEach(methodNames,function(methodName){var func=source[methodName];object[methodName]=func;if(isFunc){object.prototype[methodName]=function(){var chainAll=this.__chain__;if(chain||chainAll){var result=object(this.__wrapped__),actions=result.__actions__=copyArray(this.__actions__);actions.push({'func':func,'args':arguments,'thisArg':object});result.__chain__=chainAll;return result;}return func.apply(object,arrayPush([this.value()],arguments));};}});return object;}/**
+     * Reverts the `_` variable to its previous value and returns a reference to
+     * the `lodash` function.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Util
+     * @returns {Function} Returns the `lodash` function.
+     * @example
+     *
+     * var lodash = _.noConflict();
+     */function noConflict(){if(root._===this){root._=oldDash;}return this;}/**
+     * This method returns `undefined`.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.3.0
+     * @category Util
+     * @example
+     *
+     * _.times(2, _.noop);
+     * // => [undefined, undefined]
+     */function noop(){// No operation performed.
+}/**
+     * Creates a function that gets the argument at index `n`. If `n` is negative,
+     * the nth argument from the end is returned.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {number} [n=0] The index of the argument to return.
+     * @returns {Function} Returns the new pass-thru function.
+     * @example
+     *
+     * var func = _.nthArg(1);
+     * func('a', 'b', 'c', 'd');
+     * // => 'b'
+     *
+     * var func = _.nthArg(-2);
+     * func('a', 'b', 'c', 'd');
+     * // => 'c'
+     */function nthArg(n){n=toInteger(n);return baseRest(function(args){return baseNth(args,n);});}/**
+     * Creates a function that invokes `iteratees` with the arguments it receives
+     * and returns their results.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {...(Function|Function[])} [iteratees=[_.identity]]
+     *  The iteratees to invoke.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var func = _.over([Math.max, Math.min]);
+     *
+     * func(1, 2, 3, 4);
+     * // => [4, 1]
+     */var over=createOver(arrayMap);/**
+     * Creates a function that checks if **all** of the `predicates` return
+     * truthy when invoked with the arguments it receives.
+     *
+     * Following shorthands are possible for providing predicates.
+     * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
+     * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {...(Function|Function[])} [predicates=[_.identity]]
+     *  The predicates to check.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var func = _.overEvery([Boolean, isFinite]);
+     *
+     * func('1');
+     * // => true
+     *
+     * func(null);
+     * // => false
+     *
+     * func(NaN);
+     * // => false
+     */var overEvery=createOver(arrayEvery);/**
+     * Creates a function that checks if **any** of the `predicates` return
+     * truthy when invoked with the arguments it receives.
+     *
+     * Following shorthands are possible for providing predicates.
+     * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
+     * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {...(Function|Function[])} [predicates=[_.identity]]
+     *  The predicates to check.
+     * @returns {Function} Returns the new function.
+     * @example
+     *
+     * var func = _.overSome([Boolean, isFinite]);
+     *
+     * func('1');
+     * // => true
+     *
+     * func(null);
+     * // => true
+     *
+     * func(NaN);
+     * // => false
+     *
+     * var matchesFunc = _.overSome([{ 'a': 1 }, { 'a': 2 }])
+     * var matchesPropertyFunc = _.overSome([['a', 1], ['a', 2]])
+     */var overSome=createOver(arraySome);/**
+     * Creates a function that returns the value at `path` of a given object.
+     *
+     * @static
+     * @memberOf _
+     * @since 2.4.0
+     * @category Util
+     * @param {Array|string} path The path of the property to get.
+     * @returns {Function} Returns the new accessor function.
+     * @example
+     *
+     * var objects = [
+     *   { 'a': { 'b': 2 } },
+     *   { 'a': { 'b': 1 } }
+     * ];
+     *
+     * _.map(objects, _.property('a.b'));
+     * // => [2, 1]
+     *
+     * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
+     * // => [1, 2]
+     */function property(path){return isKey(path)?baseProperty(toKey(path)):basePropertyDeep(path);}/**
+     * The opposite of `_.property`; this method creates a function that returns
+     * the value at a given path of `object`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.0.0
+     * @category Util
+     * @param {Object} object The object to query.
+     * @returns {Function} Returns the new accessor function.
+     * @example
+     *
+     * var array = [0, 1, 2],
+     *     object = { 'a': array, 'b': array, 'c': array };
+     *
+     * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
+     * // => [2, 0]
+     *
+     * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
+     * // => [2, 0]
+     */function propertyOf(object){return function(path){return object==null?undefined$1:baseGet(object,path);};}/**
+     * Creates an array of numbers (positive and/or negative) progressing from
+     * `start` up to, but not including, `end`. A step of `-1` is used if a negative
+     * `start` is specified without an `end` or `step`. If `end` is not specified,
+     * it's set to `start` with `start` then set to `0`.
+     *
+     * **Note:** JavaScript follows the IEEE-754 standard for resolving
+     * floating-point values which can produce unexpected results.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Util
+     * @param {number} [start=0] The start of the range.
+     * @param {number} end The end of the range.
+     * @param {number} [step=1] The value to increment or decrement by.
+     * @returns {Array} Returns the range of numbers.
+     * @see _.inRange, _.rangeRight
+     * @example
+     *
+     * _.range(4);
+     * // => [0, 1, 2, 3]
+     *
+     * _.range(-4);
+     * // => [0, -1, -2, -3]
+     *
+     * _.range(1, 5);
+     * // => [1, 2, 3, 4]
+     *
+     * _.range(0, 20, 5);
+     * // => [0, 5, 10, 15]
+     *
+     * _.range(0, -4, -1);
+     * // => [0, -1, -2, -3]
+     *
+     * _.range(1, 4, 0);
+     * // => [1, 1, 1]
+     *
+     * _.range(0);
+     * // => []
+     */var range=createRange();/**
+     * This method is like `_.range` except that it populates values in
+     * descending order.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {number} [start=0] The start of the range.
+     * @param {number} end The end of the range.
+     * @param {number} [step=1] The value to increment or decrement by.
+     * @returns {Array} Returns the range of numbers.
+     * @see _.inRange, _.range
+     * @example
+     *
+     * _.rangeRight(4);
+     * // => [3, 2, 1, 0]
+     *
+     * _.rangeRight(-4);
+     * // => [-3, -2, -1, 0]
+     *
+     * _.rangeRight(1, 5);
+     * // => [4, 3, 2, 1]
+     *
+     * _.rangeRight(0, 20, 5);
+     * // => [15, 10, 5, 0]
+     *
+     * _.rangeRight(0, -4, -1);
+     * // => [-3, -2, -1, 0]
+     *
+     * _.rangeRight(1, 4, 0);
+     * // => [1, 1, 1]
+     *
+     * _.rangeRight(0);
+     * // => []
+     */var rangeRight=createRange(true);/**
+     * This method returns a new empty array.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.13.0
+     * @category Util
+     * @returns {Array} Returns the new empty array.
+     * @example
+     *
+     * var arrays = _.times(2, _.stubArray);
+     *
+     * console.log(arrays);
+     * // => [[], []]
+     *
+     * console.log(arrays[0] === arrays[1]);
+     * // => false
+     */function stubArray(){return [];}/**
+     * This method returns `false`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.13.0
+     * @category Util
+     * @returns {boolean} Returns `false`.
+     * @example
+     *
+     * _.times(2, _.stubFalse);
+     * // => [false, false]
+     */function stubFalse(){return false;}/**
+     * This method returns a new empty object.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.13.0
+     * @category Util
+     * @returns {Object} Returns the new empty object.
+     * @example
+     *
+     * var objects = _.times(2, _.stubObject);
+     *
+     * console.log(objects);
+     * // => [{}, {}]
+     *
+     * console.log(objects[0] === objects[1]);
+     * // => false
+     */function stubObject(){return {};}/**
+     * This method returns an empty string.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.13.0
+     * @category Util
+     * @returns {string} Returns the empty string.
+     * @example
+     *
+     * _.times(2, _.stubString);
+     * // => ['', '']
+     */function stubString(){return '';}/**
+     * This method returns `true`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.13.0
+     * @category Util
+     * @returns {boolean} Returns `true`.
+     * @example
+     *
+     * _.times(2, _.stubTrue);
+     * // => [true, true]
+     */function stubTrue(){return true;}/**
+     * Invokes the iteratee `n` times, returning an array of the results of
+     * each invocation. The iteratee is invoked with one argument; (index).
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Util
+     * @param {number} n The number of times to invoke `iteratee`.
+     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
+     * @returns {Array} Returns the array of results.
+     * @example
+     *
+     * _.times(3, String);
+     * // => ['0', '1', '2']
+     *
+     *  _.times(4, _.constant(0));
+     * // => [0, 0, 0, 0]
+     */function times(n,iteratee){n=toInteger(n);if(n<1||n>MAX_SAFE_INTEGER){return [];}var index=MAX_ARRAY_LENGTH,length=nativeMin(n,MAX_ARRAY_LENGTH);iteratee=getIteratee(iteratee);n-=MAX_ARRAY_LENGTH;var result=baseTimes(length,iteratee);while(++index<n){iteratee(index);}return result;}/**
+     * Converts `value` to a property path array.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Util
+     * @param {*} value The value to convert.
+     * @returns {Array} Returns the new property path array.
+     * @example
+     *
+     * _.toPath('a.b.c');
+     * // => ['a', 'b', 'c']
+     *
+     * _.toPath('a[0].b.c');
+     * // => ['a', '0', 'b', 'c']
+     */function toPath(value){if(isArray(value)){return arrayMap(value,toKey);}return isSymbol(value)?[value]:copyArray(stringToPath(toString(value)));}/**
+     * Generates a unique ID. If `prefix` is given, the ID is appended to it.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Util
+     * @param {string} [prefix=''] The value to prefix the ID with.
+     * @returns {string} Returns the unique ID.
+     * @example
+     *
+     * _.uniqueId('contact_');
+     * // => 'contact_104'
+     *
+     * _.uniqueId();
+     * // => '105'
+     */function uniqueId(prefix){var id=++idCounter;return toString(prefix)+id;}/*------------------------------------------------------------------------*/ /**
+     * Adds two numbers.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.4.0
+     * @category Math
+     * @param {number} augend The first number in an addition.
+     * @param {number} addend The second number in an addition.
+     * @returns {number} Returns the total.
+     * @example
+     *
+     * _.add(6, 4);
+     * // => 10
+     */var add=createMathOperation(function(augend,addend){return augend+addend;},0);/**
+     * Computes `number` rounded up to `precision`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.10.0
+     * @category Math
+     * @param {number} number The number to round up.
+     * @param {number} [precision=0] The precision to round up to.
+     * @returns {number} Returns the rounded up number.
+     * @example
+     *
+     * _.ceil(4.006);
+     * // => 5
+     *
+     * _.ceil(6.004, 2);
+     * // => 6.01
+     *
+     * _.ceil(6040, -2);
+     * // => 6100
+     */var ceil=createRound('ceil');/**
+     * Divide two numbers.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.7.0
+     * @category Math
+     * @param {number} dividend The first number in a division.
+     * @param {number} divisor The second number in a division.
+     * @returns {number} Returns the quotient.
+     * @example
+     *
+     * _.divide(6, 4);
+     * // => 1.5
+     */var divide=createMathOperation(function(dividend,divisor){return dividend/divisor;},1);/**
+     * Computes `number` rounded down to `precision`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.10.0
+     * @category Math
+     * @param {number} number The number to round down.
+     * @param {number} [precision=0] The precision to round down to.
+     * @returns {number} Returns the rounded down number.
+     * @example
+     *
+     * _.floor(4.006);
+     * // => 4
+     *
+     * _.floor(0.046, 2);
+     * // => 0.04
+     *
+     * _.floor(4060, -2);
+     * // => 4000
+     */var floor=createRound('floor');/**
+     * Computes the maximum value of `array`. If `array` is empty or falsey,
+     * `undefined` is returned.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @returns {*} Returns the maximum value.
+     * @example
+     *
+     * _.max([4, 2, 8, 6]);
+     * // => 8
+     *
+     * _.max([]);
+     * // => undefined
+     */function max(array){return array&&array.length?baseExtremum(array,identity,baseGt):undefined$1;}/**
+     * This method is like `_.max` except that it accepts `iteratee` which is
+     * invoked for each element in `array` to generate the criterion by which
+     * the value is ranked. The iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {*} Returns the maximum value.
+     * @example
+     *
+     * var objects = [{ 'n': 1 }, { 'n': 2 }];
+     *
+     * _.maxBy(objects, function(o) { return o.n; });
+     * // => { 'n': 2 }
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.maxBy(objects, 'n');
+     * // => { 'n': 2 }
+     */function maxBy(array,iteratee){return array&&array.length?baseExtremum(array,getIteratee(iteratee,2),baseGt):undefined$1;}/**
+     * Computes the mean of the values in `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @returns {number} Returns the mean.
+     * @example
+     *
+     * _.mean([4, 2, 8, 6]);
+     * // => 5
+     */function mean(array){return baseMean(array,identity);}/**
+     * This method is like `_.mean` except that it accepts `iteratee` which is
+     * invoked for each element in `array` to generate the value to be averaged.
+     * The iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.7.0
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {number} Returns the mean.
+     * @example
+     *
+     * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
+     *
+     * _.meanBy(objects, function(o) { return o.n; });
+     * // => 5
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.meanBy(objects, 'n');
+     * // => 5
+     */function meanBy(array,iteratee){return baseMean(array,getIteratee(iteratee,2));}/**
+     * Computes the minimum value of `array`. If `array` is empty or falsey,
+     * `undefined` is returned.
+     *
+     * @static
+     * @since 0.1.0
+     * @memberOf _
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @returns {*} Returns the minimum value.
+     * @example
+     *
+     * _.min([4, 2, 8, 6]);
+     * // => 2
+     *
+     * _.min([]);
+     * // => undefined
+     */function min(array){return array&&array.length?baseExtremum(array,identity,baseLt):undefined$1;}/**
+     * This method is like `_.min` except that it accepts `iteratee` which is
+     * invoked for each element in `array` to generate the criterion by which
+     * the value is ranked. The iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {*} Returns the minimum value.
+     * @example
+     *
+     * var objects = [{ 'n': 1 }, { 'n': 2 }];
+     *
+     * _.minBy(objects, function(o) { return o.n; });
+     * // => { 'n': 1 }
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.minBy(objects, 'n');
+     * // => { 'n': 1 }
+     */function minBy(array,iteratee){return array&&array.length?baseExtremum(array,getIteratee(iteratee,2),baseLt):undefined$1;}/**
+     * Multiply two numbers.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.7.0
+     * @category Math
+     * @param {number} multiplier The first number in a multiplication.
+     * @param {number} multiplicand The second number in a multiplication.
+     * @returns {number} Returns the product.
+     * @example
+     *
+     * _.multiply(6, 4);
+     * // => 24
+     */var multiply=createMathOperation(function(multiplier,multiplicand){return multiplier*multiplicand;},1);/**
+     * Computes `number` rounded to `precision`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.10.0
+     * @category Math
+     * @param {number} number The number to round.
+     * @param {number} [precision=0] The precision to round to.
+     * @returns {number} Returns the rounded number.
+     * @example
+     *
+     * _.round(4.006);
+     * // => 4
+     *
+     * _.round(4.006, 2);
+     * // => 4.01
+     *
+     * _.round(4060, -2);
+     * // => 4100
+     */var round=createRound('round');/**
+     * Subtract two numbers.
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Math
+     * @param {number} minuend The first number in a subtraction.
+     * @param {number} subtrahend The second number in a subtraction.
+     * @returns {number} Returns the difference.
+     * @example
+     *
+     * _.subtract(6, 4);
+     * // => 2
+     */var subtract=createMathOperation(function(minuend,subtrahend){return minuend-subtrahend;},0);/**
+     * Computes the sum of the values in `array`.
+     *
+     * @static
+     * @memberOf _
+     * @since 3.4.0
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @returns {number} Returns the sum.
+     * @example
+     *
+     * _.sum([4, 2, 8, 6]);
+     * // => 20
+     */function sum(array){return array&&array.length?baseSum(array,identity):0;}/**
+     * This method is like `_.sum` except that it accepts `iteratee` which is
+     * invoked for each element in `array` to generate the value to be summed.
+     * The iteratee is invoked with one argument: (value).
+     *
+     * @static
+     * @memberOf _
+     * @since 4.0.0
+     * @category Math
+     * @param {Array} array The array to iterate over.
+     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
+     * @returns {number} Returns the sum.
+     * @example
+     *
+     * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
+     *
+     * _.sumBy(objects, function(o) { return o.n; });
+     * // => 20
+     *
+     * // The `_.property` iteratee shorthand.
+     * _.sumBy(objects, 'n');
+     * // => 20
+     */function sumBy(array,iteratee){return array&&array.length?baseSum(array,getIteratee(iteratee,2)):0;}/*------------------------------------------------------------------------*/ // Add methods that return wrapped values in chain sequences.
+lodash.after=after;lodash.ary=ary;lodash.assign=assign;lodash.assignIn=assignIn;lodash.assignInWith=assignInWith;lodash.assignWith=assignWith;lodash.at=at;lodash.before=before;lodash.bind=bind;lodash.bindAll=bindAll;lodash.bindKey=bindKey;lodash.castArray=castArray;lodash.chain=chain;lodash.chunk=chunk;lodash.compact=compact;lodash.concat=concat;lodash.cond=cond;lodash.conforms=conforms;lodash.constant=constant;lodash.countBy=countBy;lodash.create=create;lodash.curry=curry;lodash.curryRight=curryRight;lodash.debounce=debounce;lodash.defaults=defaults;lodash.defaultsDeep=defaultsDeep;lodash.defer=defer;lodash.delay=delay;lodash.difference=difference;lodash.differenceBy=differenceBy;lodash.differenceWith=differenceWith;lodash.drop=drop;lodash.dropRight=dropRight;lodash.dropRightWhile=dropRightWhile;lodash.dropWhile=dropWhile;lodash.fill=fill;lodash.filter=filter;lodash.flatMap=flatMap;lodash.flatMapDeep=flatMapDeep;lodash.flatMapDepth=flatMapDepth;lodash.flatten=flatten;lodash.flattenDeep=flattenDeep;lodash.flattenDepth=flattenDepth;lodash.flip=flip;lodash.flow=flow;lodash.flowRight=flowRight;lodash.fromPairs=fromPairs;lodash.functions=functions;lodash.functionsIn=functionsIn;lodash.groupBy=groupBy;lodash.initial=initial;lodash.intersection=intersection;lodash.intersectionBy=intersectionBy;lodash.intersectionWith=intersectionWith;lodash.invert=invert;lodash.invertBy=invertBy;lodash.invokeMap=invokeMap;lodash.iteratee=iteratee;lodash.keyBy=keyBy;lodash.keys=keys;lodash.keysIn=keysIn;lodash.map=map;lodash.mapKeys=mapKeys;lodash.mapValues=mapValues;lodash.matches=matches;lodash.matchesProperty=matchesProperty;lodash.memoize=memoize;lodash.merge=merge;lodash.mergeWith=mergeWith;lodash.method=method;lodash.methodOf=methodOf;lodash.mixin=mixin;lodash.negate=negate;lodash.nthArg=nthArg;lodash.omit=omit;lodash.omitBy=omitBy;lodash.once=once;lodash.orderBy=orderBy;lodash.over=over;lodash.overArgs=overArgs;lodash.overEvery=overEvery;lodash.overSome=overSome;lodash.partial=partial;lodash.partialRight=partialRight;lodash.partition=partition;lodash.pick=pick;lodash.pickBy=pickBy;lodash.property=property;lodash.propertyOf=propertyOf;lodash.pull=pull;lodash.pullAll=pullAll;lodash.pullAllBy=pullAllBy;lodash.pullAllWith=pullAllWith;lodash.pullAt=pullAt;lodash.range=range;lodash.rangeRight=rangeRight;lodash.rearg=rearg;lodash.reject=reject;lodash.remove=remove;lodash.rest=rest;lodash.reverse=reverse;lodash.sampleSize=sampleSize;lodash.set=set;lodash.setWith=setWith;lodash.shuffle=shuffle;lodash.slice=slice;lodash.sortBy=sortBy;lodash.sortedUniq=sortedUniq;lodash.sortedUniqBy=sortedUniqBy;lodash.split=split;lodash.spread=spread;lodash.tail=tail;lodash.take=take;lodash.takeRight=takeRight;lodash.takeRightWhile=takeRightWhile;lodash.takeWhile=takeWhile;lodash.tap=tap;lodash.throttle=throttle;lodash.thru=thru;lodash.toArray=toArray;lodash.toPairs=toPairs;lodash.toPairsIn=toPairsIn;lodash.toPath=toPath;lodash.toPlainObject=toPlainObject;lodash.transform=transform;lodash.unary=unary;lodash.union=union;lodash.unionBy=unionBy;lodash.unionWith=unionWith;lodash.uniq=uniq;lodash.uniqBy=uniqBy;lodash.uniqWith=uniqWith;lodash.unset=unset;lodash.unzip=unzip;lodash.unzipWith=unzipWith;lodash.update=update;lodash.updateWith=updateWith;lodash.values=values;lodash.valuesIn=valuesIn;lodash.without=without;lodash.words=words;lodash.wrap=wrap;lodash.xor=xor;lodash.xorBy=xorBy;lodash.xorWith=xorWith;lodash.zip=zip;lodash.zipObject=zipObject;lodash.zipObjectDeep=zipObjectDeep;lodash.zipWith=zipWith;// Add aliases.
+lodash.entries=toPairs;lodash.entriesIn=toPairsIn;lodash.extend=assignIn;lodash.extendWith=assignInWith;// Add methods to `lodash.prototype`.
+mixin(lodash,lodash);/*------------------------------------------------------------------------*/ // Add methods that return unwrapped values in chain sequences.
+lodash.add=add;lodash.attempt=attempt;lodash.camelCase=camelCase;lodash.capitalize=capitalize;lodash.ceil=ceil;lodash.clamp=clamp;lodash.clone=clone;lodash.cloneDeep=cloneDeep;lodash.cloneDeepWith=cloneDeepWith;lodash.cloneWith=cloneWith;lodash.conformsTo=conformsTo;lodash.deburr=deburr;lodash.defaultTo=defaultTo;lodash.divide=divide;lodash.endsWith=endsWith;lodash.eq=eq;lodash.escape=escape;lodash.escapeRegExp=escapeRegExp;lodash.every=every;lodash.find=find;lodash.findIndex=findIndex;lodash.findKey=findKey;lodash.findLast=findLast;lodash.findLastIndex=findLastIndex;lodash.findLastKey=findLastKey;lodash.floor=floor;lodash.forEach=forEach;lodash.forEachRight=forEachRight;lodash.forIn=forIn;lodash.forInRight=forInRight;lodash.forOwn=forOwn;lodash.forOwnRight=forOwnRight;lodash.get=get;lodash.gt=gt;lodash.gte=gte;lodash.has=has;lodash.hasIn=hasIn;lodash.head=head;lodash.identity=identity;lodash.includes=includes;lodash.indexOf=indexOf;lodash.inRange=inRange;lodash.invoke=invoke;lodash.isArguments=isArguments;lodash.isArray=isArray;lodash.isArrayBuffer=isArrayBuffer;lodash.isArrayLike=isArrayLike;lodash.isArrayLikeObject=isArrayLikeObject;lodash.isBoolean=isBoolean;lodash.isBuffer=isBuffer;lodash.isDate=isDate;lodash.isElement=isElement;lodash.isEmpty=isEmpty;lodash.isEqual=isEqual;lodash.isEqualWith=isEqualWith;lodash.isError=isError;lodash.isFinite=isFinite;lodash.isFunction=isFunction;lodash.isInteger=isInteger;lodash.isLength=isLength;lodash.isMap=isMap;lodash.isMatch=isMatch;lodash.isMatchWith=isMatchWith;lodash.isNaN=isNaN;lodash.isNative=isNative;lodash.isNil=isNil;lodash.isNull=isNull;lodash.isNumber=isNumber;lodash.isObject=isObject;lodash.isObjectLike=isObjectLike;lodash.isPlainObject=isPlainObject;lodash.isRegExp=isRegExp;lodash.isSafeInteger=isSafeInteger;lodash.isSet=isSet;lodash.isString=isString;lodash.isSymbol=isSymbol;lodash.isTypedArray=isTypedArray;lodash.isUndefined=isUndefined;lodash.isWeakMap=isWeakMap;lodash.isWeakSet=isWeakSet;lodash.join=join;lodash.kebabCase=kebabCase;lodash.last=last;lodash.lastIndexOf=lastIndexOf;lodash.lowerCase=lowerCase;lodash.lowerFirst=lowerFirst;lodash.lt=lt;lodash.lte=lte;lodash.max=max;lodash.maxBy=maxBy;lodash.mean=mean;lodash.meanBy=meanBy;lodash.min=min;lodash.minBy=minBy;lodash.stubArray=stubArray;lodash.stubFalse=stubFalse;lodash.stubObject=stubObject;lodash.stubString=stubString;lodash.stubTrue=stubTrue;lodash.multiply=multiply;lodash.nth=nth;lodash.noConflict=noConflict;lodash.noop=noop;lodash.now=now;lodash.pad=pad;lodash.padEnd=padEnd;lodash.padStart=padStart;lodash.parseInt=parseInt;lodash.random=random;lodash.reduce=reduce;lodash.reduceRight=reduceRight;lodash.repeat=repeat;lodash.replace=replace;lodash.result=result;lodash.round=round;lodash.runInContext=runInContext;lodash.sample=sample;lodash.size=size;lodash.snakeCase=snakeCase;lodash.some=some;lodash.sortedIndex=sortedIndex;lodash.sortedIndexBy=sortedIndexBy;lodash.sortedIndexOf=sortedIndexOf;lodash.sortedLastIndex=sortedLastIndex;lodash.sortedLastIndexBy=sortedLastIndexBy;lodash.sortedLastIndexOf=sortedLastIndexOf;lodash.startCase=startCase;lodash.startsWith=startsWith;lodash.subtract=subtract;lodash.sum=sum;lodash.sumBy=sumBy;lodash.template=template;lodash.times=times;lodash.toFinite=toFinite;lodash.toInteger=toInteger;lodash.toLength=toLength;lodash.toLower=toLower;lodash.toNumber=toNumber;lodash.toSafeInteger=toSafeInteger;lodash.toString=toString;lodash.toUpper=toUpper;lodash.trim=trim;lodash.trimEnd=trimEnd;lodash.trimStart=trimStart;lodash.truncate=truncate;lodash.unescape=unescape;lodash.uniqueId=uniqueId;lodash.upperCase=upperCase;lodash.upperFirst=upperFirst;// Add aliases.
+lodash.each=forEach;lodash.eachRight=forEachRight;lodash.first=head;mixin(lodash,function(){var source={};baseForOwn(lodash,function(func,methodName){if(!hasOwnProperty.call(lodash.prototype,methodName)){source[methodName]=func;}});return source;}(),{'chain':false});/*------------------------------------------------------------------------*/ /**
+     * The semantic version number.
+     *
+     * @static
+     * @memberOf _
+     * @type {string}
+     */lodash.VERSION=VERSION;// Assign default placeholders.
+arrayEach(['bind','bindKey','curry','curryRight','partial','partialRight'],function(methodName){lodash[methodName].placeholder=lodash;});// Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
+arrayEach(['drop','take'],function(methodName,index){LazyWrapper.prototype[methodName]=function(n){n=n===undefined$1?1:nativeMax(toInteger(n),0);var result=this.__filtered__&&!index?new LazyWrapper(this):this.clone();if(result.__filtered__){result.__takeCount__=nativeMin(n,result.__takeCount__);}else {result.__views__.push({'size':nativeMin(n,MAX_ARRAY_LENGTH),'type':methodName+(result.__dir__<0?'Right':'')});}return result;};LazyWrapper.prototype[methodName+'Right']=function(n){return this.reverse()[methodName](n).reverse();};});// Add `LazyWrapper` methods that accept an `iteratee` value.
+arrayEach(['filter','map','takeWhile'],function(methodName,index){var type=index+1,isFilter=type==LAZY_FILTER_FLAG||type==LAZY_WHILE_FLAG;LazyWrapper.prototype[methodName]=function(iteratee){var result=this.clone();result.__iteratees__.push({'iteratee':getIteratee(iteratee,3),'type':type});result.__filtered__=result.__filtered__||isFilter;return result;};});// Add `LazyWrapper` methods for `_.head` and `_.last`.
+arrayEach(['head','last'],function(methodName,index){var takeName='take'+(index?'Right':'');LazyWrapper.prototype[methodName]=function(){return this[takeName](1).value()[0];};});// Add `LazyWrapper` methods for `_.initial` and `_.tail`.
+arrayEach(['initial','tail'],function(methodName,index){var dropName='drop'+(index?'':'Right');LazyWrapper.prototype[methodName]=function(){return this.__filtered__?new LazyWrapper(this):this[dropName](1);};});LazyWrapper.prototype.compact=function(){return this.filter(identity);};LazyWrapper.prototype.find=function(predicate){return this.filter(predicate).head();};LazyWrapper.prototype.findLast=function(predicate){return this.reverse().find(predicate);};LazyWrapper.prototype.invokeMap=baseRest(function(path,args){if(typeof path=='function'){return new LazyWrapper(this);}return this.map(function(value){return baseInvoke(value,path,args);});});LazyWrapper.prototype.reject=function(predicate){return this.filter(negate(getIteratee(predicate)));};LazyWrapper.prototype.slice=function(start,end){start=toInteger(start);var result=this;if(result.__filtered__&&(start>0||end<0)){return new LazyWrapper(result);}if(start<0){result=result.takeRight(-start);}else if(start){result=result.drop(start);}if(end!==undefined$1){end=toInteger(end);result=end<0?result.dropRight(-end):result.take(end-start);}return result;};LazyWrapper.prototype.takeRightWhile=function(predicate){return this.reverse().takeWhile(predicate).reverse();};LazyWrapper.prototype.toArray=function(){return this.take(MAX_ARRAY_LENGTH);};// Add `LazyWrapper` methods to `lodash.prototype`.
+baseForOwn(LazyWrapper.prototype,function(func,methodName){var checkIteratee=/^(?:filter|find|map|reject)|While$/.test(methodName),isTaker=/^(?:head|last)$/.test(methodName),lodashFunc=lodash[isTaker?'take'+(methodName=='last'?'Right':''):methodName],retUnwrapped=isTaker||/^find/.test(methodName);if(!lodashFunc){return;}lodash.prototype[methodName]=function(){var value=this.__wrapped__,args=isTaker?[1]:arguments,isLazy=value instanceof LazyWrapper,iteratee=args[0],useLazy=isLazy||isArray(value);var interceptor=function(value){var result=lodashFunc.apply(lodash,arrayPush([value],args));return isTaker&&chainAll?result[0]:result;};if(useLazy&&checkIteratee&&typeof iteratee=='function'&&iteratee.length!=1){// Avoid lazy use if the iteratee has a "length" value other than `1`.
+isLazy=useLazy=false;}var chainAll=this.__chain__,isHybrid=!!this.__actions__.length,isUnwrapped=retUnwrapped&&!chainAll,onlyLazy=isLazy&&!isHybrid;if(!retUnwrapped&&useLazy){value=onlyLazy?value:new LazyWrapper(this);var result=func.apply(value,args);result.__actions__.push({'func':thru,'args':[interceptor],'thisArg':undefined$1});return new LodashWrapper(result,chainAll);}if(isUnwrapped&&onlyLazy){return func.apply(this,args);}result=this.thru(interceptor);return isUnwrapped?isTaker?result.value()[0]:result.value():result;};});// Add `Array` methods to `lodash.prototype`.
+arrayEach(['pop','push','shift','sort','splice','unshift'],function(methodName){var func=arrayProto[methodName],chainName=/^(?:push|sort|unshift)$/.test(methodName)?'tap':'thru',retUnwrapped=/^(?:pop|shift)$/.test(methodName);lodash.prototype[methodName]=function(){var args=arguments;if(retUnwrapped&&!this.__chain__){var value=this.value();return func.apply(isArray(value)?value:[],args);}return this[chainName](function(value){return func.apply(isArray(value)?value:[],args);});};});// Map minified method names to their real names.
+baseForOwn(LazyWrapper.prototype,function(func,methodName){var lodashFunc=lodash[methodName];if(lodashFunc){var key=lodashFunc.name+'';if(!hasOwnProperty.call(realNames,key)){realNames[key]=[];}realNames[key].push({'name':methodName,'func':lodashFunc});}});realNames[createHybrid(undefined$1,WRAP_BIND_KEY_FLAG).name]=[{'name':'wrapper','func':undefined$1}];// Add methods to `LazyWrapper`.
+LazyWrapper.prototype.clone=lazyClone;LazyWrapper.prototype.reverse=lazyReverse;LazyWrapper.prototype.value=lazyValue;// Add chain sequence methods to the `lodash` wrapper.
+lodash.prototype.at=wrapperAt;lodash.prototype.chain=wrapperChain;lodash.prototype.commit=wrapperCommit;lodash.prototype.next=wrapperNext;lodash.prototype.plant=wrapperPlant;lodash.prototype.reverse=wrapperReverse;lodash.prototype.toJSON=lodash.prototype.valueOf=lodash.prototype.value=wrapperValue;// Add lazy aliases.
+lodash.prototype.first=lodash.prototype.head;if(symIterator){lodash.prototype[symIterator]=wrapperToIterator;}return lodash;};/*--------------------------------------------------------------------------*/ // Export lodash.
+var _=runInContext();// Some AMD build optimizers, like r.js, check for condition patterns like:
+if(freeModule){// Export for Node.js.
+(freeModule.exports=_)._=_;// Export for CommonJS support.
+freeExports._=_;}else {// Export to the global object.
+root._=_;}}).call(commonjsGlobal);
+});
+
+/* eslint-disable valid-jsdoc */
+
+/** insertAfter */
+function insertAfter(newElement, targetElement) {
+  var parent = targetElement.parentNode;
+
+  if (parent.lastChild == targetElement) {
+    parent.appendChild(newElement);
+  } else {
+    parent.insertBefore(newElement, targetElement.nextSibling);
+  }
+}
+
+var Status = /*#__PURE__*/function () {
+  function Status(jSPlugin, id) {
+    _classCallCheck$1(this, Status);
+
+    this.id = id;
+    this.jSPlugin = jSPlugin;
+    this.state = {
+      play: false,
+      loading: false
+    };
+  }
+
+  _createClass$1(Status, [{
+    key: "toString",
+    value: function toString() {
+      return "".concat(this.coreX, "-").concat(this.coreY);
+    }
+  }, {
+    key: "setPlayStatus",
+    value: function setPlayStatus(options) {
+      this.state = Object.assign(this.state, options);
+    }
+  }, {
+    key: "loadingStart",
+    value: function loadingStart(id) {
+      var oS = document.createElement('style');
+      document.getElementsByTagName("head")[0].appendChild(oS);
+      oS.innerHTML = '@keyframes antRotate {to {transform: rotate(400deg);transform-origin:50% 50%;}} .loading {display: inline-block;z-index: 1000;-webkit-animation: antRotate 1s infinite linear;animation: antRotate 1s infinite linear;}';
+      var domId = id;
+      var domElement = document.getElementById(domId);
+      var windowWidth = domElement.offsetWidth;
+      var windowHeight = domElement.offsetHeight;
+      var offsetTop = 0; //`calc(50% - ${(domElement.offsetTop / 2)}px)`;//domElement.offsetTop; // `calc(50% - ${domElement.offsetTop / 2}px)`
+
+      var offsetLeft = domElement.offsetLeft; // 鍏堟墽琛屾竻绌簂oading
+
+      if (document.getElementById("".concat(id, "-loading-id-0"))) {
+        document.getElementById("".concat(id, "-loading-id-0")).parentNode.removeChild(document.getElementById("".concat(id, "-loading-id-0")));
+      }
+
+      var loadingContainerDOM = document.createElement('div');
+      loadingContainerDOM.setAttribute('id', "".concat(id, "-loading-id-0"));
+      var style = 'position:absolute;outline:none;pointer-events:none;';
+      console.log("this.jSPlugin", this.jSPlugin);
+      style += 'width: 100%;background-size: cover; background-repeat:no-repeat;';
+      style += 'height: 100%;';
+      style += 'top:' + offsetTop + ';';
+      style += 'left:' + offsetLeft + 'px;';
+      loadingContainerDOM.setAttribute('style', style);
+      loadingContainerDOM.style.height = windowHeight;
+      loadingContainerDOM.setAttribute('class', 'loading-container'); // loadingContainerDOM.innerHTML= loading;
+
+      insertAfter(loadingContainerDOM, domElement);
+      var splitBasis = 1;
+      var loadingItemContainer = document.createElement('div');
+      var loadingStatusDOM = document.createElement('div');
+      loadingItemContainer.setAttribute('class', 'loading-item');
+      loadingItemContainer.setAttribute('id', "".concat(id, "-loading-item-0")); //loadingContainer.setAttribute('style','display:inline-flex;flex-direction:column;justify-content:center;align-items: center;width:'+(windowWidth / splitBasis)+'px;height:'+(windowHeight /splitBasis )+'px;outline:none;vertical-align: top;position:absolute');
+
+      var style = 'display:inline-flex;pointer-events:none;flex-direction:column;justify-content:center;align-items: center;width:100%;height:' + windowHeight + 'px;outline:none;vertical-align: top;position:absolute;';
+      style += 'left:' + calLoadingPostion(windowHeight, windowWidth, splitBasis, 0).left + 'px;';
+      style += 'top:' + calLoadingPostion(windowHeight, windowWidth, splitBasis, 0).top + 'px;';
+      loadingItemContainer.setAttribute('style', style);
+
+      function calLoadingPostion(windowHeight, windowWidth, splitBasis, i) {
+        var top = parseInt(i / splitBasis, 10) * (windowHeight / splitBasis);
+        var left = i % splitBasis * (windowWidth / splitBasis);
+        return {
+          top: top,
+          left: left
+        };
+      }
+
+      var loadingDOM = document.createElement('div');
+      loadingStatusDOM.innerHTML = "";
+      loadingStatusDOM.style.color = "#fff";
+      loadingDOM.setAttribute('class', 'loading');
+      var loading = '<svg t="1567069979438" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2399" width="32" height="32"><path d="M538.5344 266.4448a133.12 133.12 0 1 1 133.12-133.12 133.4272 133.4272 0 0 1-133.12 133.12zM255.0144 372.1984a121.6768 121.6768 0 1 1 121.6768-121.6768 121.856 121.856 0 0 1-121.6768 121.6768zM134.72 647.424a107.3664 107.3664 0 1 1 107.3664-107.264A107.52 107.52 0 0 1 134.72 647.424z m120.32 272.4608a90.9824 90.9824 0 1 1 90.9824-90.9824A91.1616 91.1616 0 0 1 255.04 919.8848zM538.5344 1024a79.36 79.36 0 1 1 79.36-79.36 79.36 79.36 0 0 1-79.36 79.36z m287.6928-134.144a64.1792 64.1792 0 1 1 64.1792-64.1792 64.3584 64.3584 0 0 1-64.1792 64.1792z m117.76-296.704a52.6336 52.6336 0 1 1 52.6592-52.6336 52.608 52.608 0 0 1-52.6336 52.6336z m-158.72-338.7136a40.96 40.96 0 1 1 12.0064 28.8512 40.5248 40.5248 0 0 1-12.0064-28.8512z" fill="#ffffff" p-id="2400"></path></svg>';
+      loadingDOM.innerHTML = loading;
+      loadingItemContainer.appendChild(loadingDOM); // loadingContainer.appendChild(loading);
+
+      loadingItemContainer.appendChild(loadingStatusDOM);
+      loadingContainerDOM.appendChild(loadingItemContainer);
+    }
+  }, {
+    key: "loadingSetText",
+    value: function loadingSetText(opt) {
+      this.loadingClearText();
+
+      if (document.getElementById("".concat(this.id, "-loading-item-0"))) {
+        var textElement = document.getElementById("".concat(this.id, "-loading-item-0")).childNodes[1];
+
+        if (!textElement) {
+          var loadingItemContainer = document.getElementById("".concat(this.id, "-loading-item-0"));
+          textElement = document.createElement('div');
+          textElement.innerHTML = opt.text;
+          loadingItemContainer.appendChild(textElement);
+        }
+
+        textElement.innerHTML = opt.text;
+        textElement.style.fontSize = "14px";
+        textElement.style.color = opt.color || "#FFFFFF";
+      }
+    }
+  }, {
+    key: "loadingClearText",
+    value: function loadingClearText() {
+      if (document.getElementById("".concat(this.id, "-loading-item-0"))) {
+        var elements = document.getElementById("".concat(this.id, "-loading-item-0")).childNodes;
+
+        if (elements.length > 1) {
+          elements[1].parentNode.removeChild(elements[1]);
+        } else {
+          elements[0] && elements[0].parentNode.removeChild(elements[0]);
+        }
+      }
+    }
+  }, {
+    key: "loadingClear",
+    value: function loadingClear() {
+      if (document.getElementById("".concat(this.id, "-loading-item-0"))) {
+        var elements = document.getElementById("".concat(this.id, "-loading-item-0")).childNodes;
+
+        for (var i = elements.length - 1; i >= 0; i--) {
+          elements[i].parentNode.removeChild(elements[i]);
+        }
+
+        if (document.getElementById("".concat(this.id, "-loading-id-0"))) {
+          document.getElementById("".concat(this.id, "-loading-id-0")).style.background = 'none';
+        }
+      }
+    }
+  }, {
+    key: "loadingEnd",
+    value: function loadingEnd() {
+      var loadingItemContainerDOM = document.getElementById("".concat(this.id, "-loading-item-0"));
+
+      if (loadingItemContainerDOM) {
+        loadingItemContainerDOM.parentNode.removeChild(loadingItemContainerDOM);
+        var loadingContainerDOM = document.getElementById("".concat(this.id, "-loading-id-0"));
+
+        if (loadingContainerDOM && loadingContainerDOM.children.length === 0) {
+          loadingContainerDOM.parentNode.removeChild(loadingContainerDOM);
+        }
+      }
+
+      document.getElementById("".concat(this.id, "-loading-item-0")).style.background = 'none';
+    }
+  }]);
+
+  return Status;
+}();
+
+var Message = /*#__PURE__*/function () {
+  function Message(jSPlugin, id) {
+    _classCallCheck$1(this, Message);
+
+    this.id = id;
+    this.jSPlugin = jSPlugin;
+    this.timer = null;
+    this.state = {
+      play: false,
+      loading: false
+    };
+  }
+
+  _createClass$1(Message, [{
+    key: "default",
+    value: function _default(msg) {
+      var _this = this;
+
+      var msgId = "msgId";
+
+      if (document.getElementById("".concat(this.id, "-").concat(msgId))) {
+        document.getElementById("".concat(this.id, "-wrap")).removeChild(document.getElementById("".concat(this.id, "-").concat(msgId)));
+      }
+
+      var messageDOM = document.createElement('div');
+      messageDOM.id = "".concat(this.id, "-").concat(msgId);
+      messageDOM.style = "position: absolute;top: 50%;left:calc(50% - ".concat(msg.length * 14 / 2, "px);padding: 4px 16px;background: #00000080;color: #FFFFFF;font-size: 14px");
+      messageDOM.innerHTML = msg;
+      document.getElementById("".concat(this.id, "-wrap")).appendChild(messageDOM);
+
+      if (this.timer) {
+        clearTimeout(this.timer);
+      }
+
+      this.timer = setTimeout(function () {
+        document.getElementById("".concat(_this.id, "-wrap")).removeChild(document.getElementById("".concat(_this.id, "-").concat(msgId)));
+      }, 2000);
+    }
+  }]);
+
+  return Message;
+}();
+
+var data$8 = [
+	{
+		moduleCode: "",
+		detailCode: "405984",
+		description: "",
+		solution: "",
+		updateTime: 1559564188000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10035",
+		description: "鑾峰彇瀛愯处鎴稟ccessToken寮傚父,瀛愯处鎴蜂笉瀛樺湪鎴栧瓙璐︽埛涓嶅睘浜庤寮�鍙戣��",
+		solution: "",
+		updateTime: 1559551958000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1052674",
+		description: "鑾峰彇鏈湴褰曞儚澶辫触",
+		solution: "",
+		updateTime: 1558579653000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395547",
+		description: "",
+		solution: "",
+		updateTime: 1557367296000
+	},
+	{
+		moduleCode: "",
+		detailCode: "12",
+		description: "",
+		solution: "",
+		updateTime: 1557229476000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10052",
+		description: "浣欓涓嶈冻",
+		solution: "",
+		updateTime: 1557121463000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20108",
+		description: "褰撳墠鐢ㄦ埛鍜屾墍娣诲姞鐢ㄦ埛涓嶆槸濂藉弸鍏崇郴",
+		solution: "",
+		updateTime: 1556541725000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10009",
+		description: "",
+		solution: "",
+		updateTime: 1556422452000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320001",
+		description: "閫氶亾涓嶅瓨鍦�",
+		solution: "璇锋鏌ュ綍鍍忔満鐨勫叧鑱旂姸鎬佹槸鍚︽甯革紝娌℃湁鎽勫儚澶寸殑閫氶亾鏃犳硶鎾斁",
+		updateTime: 1556419044000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120001",
+		description: "閫氶亾涓嶅瓨鍦�",
+		solution: "璇锋鏌ュ綍鍍忔満鐨勫叧鑱旂姸鎬佹槸鍚︽甯革紝娌℃湁鎽勫儚澶寸殑閫氶亾鏃犳硶鎾斁",
+		updateTime: 1556419030000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320049",
+		description: "",
+		solution: "",
+		updateTime: 1556272984000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380227",
+		description: "",
+		solution: "",
+		updateTime: 1556264379000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10033",
+		description: "policy鍙傛暟淇℃伅寮傚父",
+		solution: "",
+		updateTime: 1555922124000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10065",
+		description: "weakAppKey 涓嶅睘浜巃ccessToken瀵瑰簲鐨勭敤鎴�",
+		solution: "",
+		updateTime: 1555497522000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395416",
+		description: "璁惧杈惧埌鏈�澶ц繛鎺ユ暟锛屾棤娉曞缓绔嬭繛鎺�",
+		solution: "璇峰崌绾ц澶囧浐浠剁増鏈�",
+		updateTime: 1555394722000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100001",
+		description: "",
+		solution: "",
+		updateTime: 1555141776000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395558",
+		description: "",
+		solution: "",
+		updateTime: 1554987121000
+	},
+	{
+		moduleCode: "",
+		detailCode: "70001",
+		description: "鏅鸿兘瀹跺眳涔版柇鐢ㄦ埛璁惧鍙楀埌闄愬埗,寤鸿鍚堢悊閫夋嫨pagestart鍜宲ageSize",
+		solution: "",
+		updateTime: 1554691023000
+	},
+	{
+		moduleCode: "",
+		detailCode: "170001",
+		description: "",
+		solution: "",
+		updateTime: 1554691023000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1012",
+		description: "閲嶇疆澶辫触",
+		solution: "",
+		updateTime: 1554645841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1043",
+		description: "閲嶇疆澶辫触",
+		solution: "",
+		updateTime: 1554645834000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60060",
+		description: "鐩存挱鍔熻兘鏈紑閫�",
+		solution: "閫氶亾鏈紑閫氱洿鎾姛鑳斤紝璇峰厛寮�閫氱洿鎾�",
+		updateTime: 1554346018000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380203",
+		description: "",
+		solution: "",
+		updateTime: 1554093666000
+	},
+	{
+		moduleCode: "",
+		detailCode: "399048",
+		description: "鍏嶈垂鐗堝苟鍙戞暟杈惧埌涓婇檺锛岃鍗囩骇浼佷笟鐗堜娇鐢ㄥ骞跺彂鑳藉姏",
+		solution: "鍗囩骇鎴愪负浼佷笟鐗堝椁愬嵆鍙彇娑堝苟鍙戞暟闄愬埗",
+		updateTime: 1553839878000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60007",
+		description: "棰勭疆鐐逛釜鏁拌秴杩囨渶澶у��",
+		solution: "",
+		updateTime: 1553671316000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1005",
+		description: "",
+		solution: "",
+		updateTime: 1553513701000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20605",
+		description: "鍏朵粬鐢ㄦ埛姝e湪璁よ瘉涓�",
+		solution: "",
+		updateTime: 1552976317000
+	},
+	{
+		moduleCode: "",
+		detailCode: "90004",
+		description: "褰撳墠鍨嬪彿璁惧鏆傛椂涓嶆敮鎸丄I浠诲姟锛欳S-C3W-3B1WFR-YGL",
+		solution: "",
+		updateTime: 1552898525000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60046",
+		description: "娣诲姞鐨勮澶囩殑IP鍜屾湰璁惧鐨処P鍐茬獊",
+		solution: "",
+		updateTime: 1552872372000
+	},
+	{
+		moduleCode: "",
+		detailCode: "3",
+		description: "淇敼瑙嗛娓呮櫚搴﹀け璐�!",
+		solution: "",
+		updateTime: 1552440229000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1013",
+		description: "",
+		solution: "",
+		updateTime: 1552035069000
+	},
+	{
+		moduleCode: "",
+		detailCode: "370007",
+		description: "",
+		solution: "",
+		updateTime: 1551852327000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1",
+		description: "",
+		solution: "",
+		updateTime: 1551752889000
+	},
+	{
+		moduleCode: "",
+		detailCode: "30005",
+		description: "寮辫处鎴蜂笉瀛樺湪",
+		solution: "",
+		updateTime: 1551422358000
+	},
+	{
+		moduleCode: "",
+		detailCode: "90006",
+		description: "鐢ㄦ埛鎿嶄綔AI浠诲姟鍙楅檺",
+		solution: "",
+		updateTime: 1551073320000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60203",
+		description: "鏈紑閫氱浉鍏虫湇鍔�",
+		solution: "",
+		updateTime: 1550623070000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10002",
+		description: "accessToken杩囨湡鎴栧紓甯�",
+		solution: "",
+		updateTime: 1550300346000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380339",
+		description: "",
+		solution: "",
+		updateTime: 1549889458000
+	},
+	{
+		moduleCode: "",
+		detailCode: "90002",
+		description: "AI浠诲姟璁惧閰嶇疆鏁拌揪鍒颁笂闄愶細3",
+		solution: "",
+		updateTime: 1549071664000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380008",
+		description: "",
+		solution: "",
+		updateTime: 1549005979000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320227",
+		description: "",
+		solution: "",
+		updateTime: 1548739731000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60059",
+		description: "ezopen鍦板潃鍧囦笉鍙敤",
+		solution: "",
+		updateTime: 1548395350000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10005",
+		description: "appKey寮傚父",
+		solution: "",
+		updateTime: 1548317858000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60045",
+		description: "娣诲姞鐨勮澶囩殑IP鍜屽叾浠栭�氶亾鐨処P鍐茬獊",
+		solution: "",
+		updateTime: 1548155085000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60047",
+		description: "鐮佹祦绫诲瀷涓嶆敮鎸�",
+		solution: "",
+		updateTime: 1547962108000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60041",
+		description: "娣诲姞鐨勮澶囪鍏朵粬璁惧鍏宠仈鎴栧搷搴旇秴鏃�",
+		solution: "",
+		updateTime: 1547960980000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110029",
+		description: "涓汉鐢ㄦ埛鎺ュ彛璋冪敤棰戠巼瓒呴檺",
+		solution: "璇峰崌绾т紒涓氱増锛歨ttps://open.ys7.com/price.html",
+		updateTime: 1547606859000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380355",
+		description: "璁惧鐩磋繛鎺ㄦ祦寮傚父缁撴潫",
+		solution: "",
+		updateTime: 1547106294000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320081",
+		description: "",
+		solution: "",
+		updateTime: 1547106279000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60035",
+		description: "璐拱浜戝瓨鍌ㄦ湇鍔″け璐�",
+		solution: "",
+		updateTime: 1547026959000
+	},
+	{
+		moduleCode: "",
+		detailCode: "90005",
+		description: "璁惧宸插瓨鍦細C75714141",
+		solution: "",
+		updateTime: 1546940622000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1053445",
+		description: "璇ユ椂闂存娌℃湁褰曞儚鐗囨",
+		solution: "",
+		updateTime: 1546935727000
+	},
+	{
+		moduleCode: "",
+		detailCode: "90007",
+		description: "璁惧鏈姞鍏ュ埌AI浠诲姟",
+		solution: "",
+		updateTime: 1546932948000
+	},
+	{
+		moduleCode: "",
+		detailCode: "326000",
+		description: "",
+		solution: "",
+		updateTime: 1546823143000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1021",
+		description: "閲嶇疆澶辫触",
+		solution: "",
+		updateTime: 1546781152000
+	},
+	{
+		moduleCode: "",
+		detailCode: "2001",
+		description: "鍒犻櫎璁惧澶辫触!",
+		solution: "",
+		updateTime: 1546422886000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380425",
+		description: "",
+		solution: "",
+		updateTime: 1546407694000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120097",
+		description: "",
+		solution: "",
+		updateTime: 1546085995000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10059",
+		description: "requestId宸插瓨鍦�",
+		solution: "",
+		updateTime: 1545824509000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1154723",
+		description: "",
+		solution: "",
+		updateTime: 1545795209000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60043",
+		description: "娣诲姞鐨勮澶囪秴鍑烘渶澶ф暟閲�",
+		solution: "",
+		updateTime: 1545493607000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1152677",
+		description: "",
+		solution: "",
+		updateTime: 1545313404000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20097",
+		description: "璁惧娣诲姞寮傚父,璁惧楠岃瘉鐮佷负ABCDEF鎴栬澶囪N1锛孯1鍏宠仈",
+		solution: "",
+		updateTime: 1545310795000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10060",
+		description: "璁惧涓嶆敮鎸佽浜戝瓨鍌ㄧ被鍨�",
+		solution: "",
+		updateTime: 1545309064000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20102",
+		description: "鏃犵浉搴旈個璇蜂俊鎭紝鏃犳硶鎺ュ彈閭�璇�",
+		solution: "",
+		updateTime: 1545204966000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10053",
+		description: "浜戝瓨鍌ㄥ紑閫氫腑",
+		solution: "",
+		updateTime: 1545100293000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20401",
+		description: "鐢ㄦ埛浜戠┖闂翠俊鎭笉瀛樺湪",
+		solution: "",
+		updateTime: 1545017880000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20600",
+		description: "涓存椂瀵嗙爜鏁板凡杈句笂闄�",
+		solution: "",
+		updateTime: 1544873457000
+	},
+	{
+		moduleCode: "",
+		detailCode: "901",
+		description: "",
+		solution: "",
+		updateTime: 1544693519000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60210",
+		description: "鍥剧墖鏁版嵁閿欒",
+		solution: "",
+		updateTime: 1544604457000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10013",
+		description: "鎮ㄧ殑搴旂敤娌℃湁鏉冮檺璋冪敤",
+		solution: "",
+		updateTime: 1544416237000
+	},
+	{
+		moduleCode: "",
+		detailCode: "70007",
+		description: "鎺堟潈鐮佷笉瀛樺湪",
+		solution: "",
+		updateTime: 1544179533000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10015",
+		description: "鎺堟潈鍦板潃涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1544163240000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320423",
+		description: "",
+		solution: "",
+		updateTime: 1544100685000
+	},
+	{
+		moduleCode: "",
+		detailCode: "370009",
+		description: "",
+		solution: "",
+		updateTime: 1544077151000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10031",
+		description: "瀛愯处鎴锋垨钀ょ煶鐢ㄦ埛娌℃湁鏉冮檺",
+		solution: "",
+		updateTime: 1543990462000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10055",
+		description: "璁惧涓嶆敮鎸佽瘯鐢ㄤ簯瀛樺偍鏈嶅姟",
+		solution: "",
+		updateTime: 1543986292000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60042",
+		description: "娣诲姞鐨勮澶囧瘑鐮侀敊璇�",
+		solution: "",
+		updateTime: 1543710913000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60082",
+		description: "璁惧姝e湪鍝嶅簲鏈澹版簮瀹氫綅",
+		solution: "",
+		updateTime: 1543647426000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10056",
+		description: "璁惧涓嶆敮鎸佷簯瀛樺偍鏈嶅姟杞嚭",
+		solution: "",
+		updateTime: 1543558342000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20104",
+		description: "濂藉弸涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1543492403000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20111",
+		description: "濂藉弸涓嶆槸绛夊緟楠岃瘉鐘舵�侊紝鏃犳硶鎺ュ彈閭�璇�",
+		solution: "",
+		updateTime: 1543492365000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20107",
+		description: "涓嶈兘娣诲姞鑷繁涓哄ソ鍙�",
+		solution: "",
+		updateTime: 1543480986000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1",
+		description: "璁惧杩斿洖鍏朵粬閿欒",
+		solution: "",
+		updateTime: 1543459921000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60084",
+		description: "褰撳墠姝e湪鍏抽棴闅愮閬斀",
+		solution: "",
+		updateTime: 1543456515000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380255",
+		description: "",
+		solution: "",
+		updateTime: 1543411652000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20015",
+		description: "璁惧涓嶆敮鎸�",
+		solution: "",
+		updateTime: 1543390936000
+	},
+	{
+		moduleCode: "",
+		detailCode: "30003",
+		description: "鎵嬫満楠岃瘉鐮侀敊璇�",
+		solution: "",
+		updateTime: 1543389137000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20615",
+		description: "閿佺敤鎴峰凡瀛樺湪",
+		solution: "",
+		updateTime: 1543388325000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60061",
+		description: "璐︽埛娴侀噺宸茶秴鍑烘垨鏈喘涔帮紝闄愬埗寮�閫�",
+		solution: "",
+		updateTime: 1543372581000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60020",
+		description: "璁惧涓嶆敮鎸佽淇′护",
+		solution: "",
+		updateTime: 1543321636000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320146",
+		description: "",
+		solution: "",
+		updateTime: 1543318472000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60018",
+		description: "璁惧鍗囩骇澶辫触",
+		solution: "",
+		updateTime: 1543304928000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60044",
+		description: "娣诲姞鐨勮澶囩綉缁滀笉鍙揪瓒呮椂",
+		solution: "",
+		updateTime: 1543304102000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20619",
+		description: "涓荤敤鎴锋棤娉曞垹闄�",
+		solution: "",
+		updateTime: 1543290219000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20608",
+		description: "閿佺敤鎴蜂笉瀛樺湪",
+		solution: "",
+		updateTime: 1543281950000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20609",
+		description: "璁惧鍝嶅簲瓒呮椂,闂ㄩ攣閫氫俊鏁呴殰鎴栬�呯數閲忎笉瓒�,璇烽噸璇�.",
+		solution: "",
+		updateTime: 1543281601000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1049954",
+		description: "鍗囩骇璁惧澶辫触",
+		solution: "",
+		updateTime: 1543279264000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60009",
+		description: "姝e湪璋冪敤棰勭疆鐐�",
+		solution: "",
+		updateTime: 1543238114000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1052677",
+		description: "鑾峰彇鏈湴褰曞儚澶辫触",
+		solution: "",
+		updateTime: 1543207604000
+	},
+	{
+		moduleCode: "",
+		detailCode: "327000",
+		description: "",
+		solution: "",
+		updateTime: 1543196609000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20021",
+		description: "璁惧鍦ㄧ嚎锛屾湭琚敤鎴锋坊鍔�",
+		solution: "",
+		updateTime: 1543193436000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20202",
+		description: "鎿嶄綔鐣欒█淇℃伅澶辫触",
+		solution: "",
+		updateTime: 1543191562000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1052678",
+		description: "鑾峰彇鏈湴褰曞儚澶辫触",
+		solution: "",
+		updateTime: 1543132218000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1054723",
+		description: "鏍煎紡鍖栬澶囧け璐�",
+		solution: "",
+		updateTime: 1543129833000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20109",
+		description: "瀵瑰簲鍒嗕韩涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1543129111000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60026",
+		description: "璁惧澶勪簬闅愮閬斀鐘舵��",
+		solution: "",
+		updateTime: 1543110403000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60083",
+		description: "褰撳墠姝e湪寮�鍚殣绉侀伄钄�",
+		solution: "",
+		updateTime: 1543071148000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60001",
+		description: "鐢ㄦ埛鏃犱簯鍙版帶鍒舵潈闄�",
+		solution: "",
+		updateTime: 1543059167000
+	},
+	{
+		moduleCode: "",
+		detailCode: "2003",
+		description: "璁惧涓嶅湪绾�",
+		solution: "",
+		updateTime: 1543051046000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-24",
+		description: "璁剧疆璁惧enable閿欒",
+		solution: "",
+		updateTime: 1543042701000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10018",
+		description: "",
+		solution: "",
+		updateTime: 1543041564000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20103",
+		description: "濂藉弸宸插瓨鍦�",
+		solution: "",
+		updateTime: 1543038430000
+	},
+	{
+		moduleCode: "",
+		detailCode: "70010",
+		description: "鎺堟潈寮傚父璇烽噸璇�",
+		solution: "",
+		updateTime: 1543035590000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60056",
+		description: "鍒犻櫎璁惧澶辫触",
+		solution: "",
+		updateTime: 1543031275000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60040",
+		description: "娣诲姞鐨勮澶囦笉鍦ㄥ悓涓�灞�鍩熺綉",
+		solution: "",
+		updateTime: 1543031210000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60019",
+		description: "鍔犲瘑宸插紑鍚�",
+		solution: "",
+		updateTime: 1543029931000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1054722",
+		description: "鏍煎紡鍖栬澶囧け璐�",
+		solution: "",
+		updateTime: 1543028537000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20016",
+		description: "褰撳墠璁惧姝e湪鏍煎紡鍖�",
+		solution: "",
+		updateTime: 1543028537000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10024",
+		description: "閫忔槑閫氶亾鏉冮檺鏍¢獙涓嶉�氳繃",
+		solution: "",
+		updateTime: 1543025540000
+	},
+	{
+		moduleCode: "",
+		detailCode: "6002",
+		description: "鍒犻櫎璁惧澶辫触!",
+		solution: "",
+		updateTime: 1543025026000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1011",
+		description: "楠岃瘉鐮侀敊璇紒",
+		solution: "",
+		updateTime: 1543016865000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60032",
+		description: "鍗″瘑宸蹭娇鐢�",
+		solution: "",
+		updateTime: 1543006668000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10034",
+		description: "瀛愯处鍙峰凡瀛樺湪",
+		solution: "",
+		updateTime: 1542989194000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20301",
+		description: "鏍规嵁uuid鏌ヨ鑱斿姩淇℃伅涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1542988651000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1041",
+		description: "鑾峰彇楠岃瘉鐮佽繃浜庨绻�",
+		solution: "",
+		updateTime: 1542980953000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10012",
+		description: "璇ppkey涓嬪凡缁戝畾閲嶅鐨刾hone锛�",
+		solution: "",
+		updateTime: 1542980800000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1008",
+		description: "phone涓嶅悎娉曪紒",
+		solution: "",
+		updateTime: 1542979812000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60023",
+		description: "璁㈤槄鎿嶄綔澶辫触",
+		solution: "",
+		updateTime: 1542979006000
+	},
+	{
+		moduleCode: "",
+		detailCode: "5",
+		description: "璁惧杩斿洖鍏朵粬閿欒",
+		solution: "",
+		updateTime: 1542977828000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60006",
+		description: "浜戝彴褰撳墠鎿嶄綔澶辫触",
+		solution: "",
+		updateTime: 1542977598000
+	},
+	{
+		moduleCode: "",
+		detailCode: "131",
+		description: "淇敼瑙嗛娓呮櫚搴﹀け璐�!",
+		solution: "",
+		updateTime: 1542977246000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10019",
+		description: "瀵嗙爜閿欒",
+		solution: "",
+		updateTime: 1542976628000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10004",
+		description: "鐢ㄦ埛涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1542976268000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20201",
+		description: "鎿嶄綔鎶ヨ淇℃伅澶辫触",
+		solution: "",
+		updateTime: 1542975906000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20024",
+		description: "璁惧涓嶅湪绾匡紝宸茬粡琚埆鐨勭敤鎴锋坊鍔�",
+		solution: "",
+		updateTime: 1542975858000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60004",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌宸﹂檺浣�",
+		solution: "",
+		updateTime: 1542975207000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1052679",
+		description: "淇敼瑙嗛娓呮櫚搴﹀け璐�!",
+		solution: "",
+		updateTime: 1542974886000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20031",
+		description: "璇峰湪钀ょ煶瀹㈡埛绔叧闂粓绔粦瀹�",
+		solution: "",
+		updateTime: 1542974756000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1053825",
+		description: "鑾峰彇鏈湴褰曞儚澶辫触",
+		solution: "",
+		updateTime: 1542974692000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60011",
+		description: "棰勭疆鐐逛笉瀛樺湪",
+		solution: "",
+		updateTime: 1542974414000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1052936",
+		description: "淇敼瑙嗛娓呮櫚搴﹀け璐�!",
+		solution: "",
+		updateTime: 1542974390000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1016",
+		description: "",
+		solution: "",
+		updateTime: 1542974273000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10032",
+		description: "瀛愯处鍙蜂笉瀛樺湪",
+		solution: "",
+		updateTime: 1542973906000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20013",
+		description: "璁惧宸茶鍒汉娣诲姞",
+		solution: "",
+		updateTime: 1542973817000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50000",
+		description: "鏈嶅姟鍣ㄩ敊璇�!",
+		solution: "",
+		updateTime: 1542973801000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60010",
+		description: "璇ラ缃偣宸茬粡鏄綋鍓嶄綅缃�",
+		solution: "",
+		updateTime: 1542973800000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60003",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌涓嬮檺浣�",
+		solution: "",
+		updateTime: 1542973770000
+	},
+	{
+		moduleCode: "",
+		detailCode: "4",
+		description: "璁惧杩斿洖鍏朵粬閿欒",
+		solution: "",
+		updateTime: 1542973755000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60016",
+		description: "鍔犲瘑鏈紑鍚紝鏃犻渶鍏抽棴",
+		solution: "",
+		updateTime: 1542973753000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60002",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌涓婇檺浣�",
+		solution: "",
+		updateTime: 1542973742000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20023",
+		description: "璁惧涓嶅湪绾匡紝鏈鐢ㄦ埛娣诲姞",
+		solution: "",
+		updateTime: 1542973685000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10008",
+		description: "",
+		solution: "",
+		updateTime: 1542973676000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20010",
+		description: "璁惧楠岃瘉鐮侀敊璇�",
+		solution: "",
+		updateTime: 1542973658000
+	},
+	{
+		moduleCode: "",
+		detailCode: "60005",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌鍙抽檺浣�",
+		solution: "",
+		updateTime: 1542973657000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20017",
+		description: "璁惧宸茬粡琚嚜宸辨坊鍔�",
+		solution: "",
+		updateTime: 1542973648000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20020",
+		description: "璁惧鍦ㄧ嚎锛屽凡缁忚鑷繁娣诲姞",
+		solution: "",
+		updateTime: 1542973533000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20029",
+		description: "璁惧涓嶅湪绾匡紝宸茬粡琚嚜宸辨坊鍔�",
+		solution: "",
+		updateTime: 1542973530000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10014",
+		description: "APPKEY涓嬪搴旂殑绗笁鏂箄serId鍜宲hone鏈粦瀹氾紒",
+		solution: "",
+		updateTime: 1542973499000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20002",
+		description: "璁惧涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1542973499000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10030",
+		description: "appkey鍜宎ppsecret涓嶅尮閰�",
+		solution: "",
+		updateTime: 1542973490000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20022",
+		description: "璁惧鍦ㄧ嚎锛屽凡缁忚鍒殑鐢ㄦ埛娣诲姞",
+		solution: "",
+		updateTime: 1542973486000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20008",
+		description: "璁惧鍝嶅簲瓒呮椂",
+		solution: "",
+		updateTime: 1542973484000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20032",
+		description: "璇ョ敤鎴蜂笅閫氶亾涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1542973481000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20006",
+		description: "缃戠粶寮傚父",
+		solution: "",
+		updateTime: 1542973475000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20014",
+		description: "deviceSerial涓嶅悎娉�!",
+		solution: "",
+		updateTime: 1542973454000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20007",
+		description: "璁惧涓嶅湪绾�",
+		solution: "",
+		updateTime: 1542973454000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20018",
+		description: "璇ョ敤鎴蜂笉鎷ユ湁璇ヨ澶�",
+		solution: "",
+		updateTime: 1542973453000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10010",
+		description: "",
+		solution: "",
+		updateTime: 1542973453000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10011",
+		description: "鏈粦瀹氾紒",
+		solution: "",
+		updateTime: 1542973453000
+	},
+	{
+		moduleCode: "",
+		detailCode: "20001",
+		description: "閫氶亾涓嶅瓨鍦�!",
+		solution: "",
+		updateTime: 1542973452000
+	},
+	{
+		moduleCode: "",
+		detailCode: "10017",
+		description: "appKey涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1542973451000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400259",
+		description: "",
+		solution: "",
+		updateTime: 1542875643000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400004",
+		description: "",
+		solution: "",
+		updateTime: 1542873364000
+	},
+	{
+		moduleCode: "",
+		detailCode: "3840",
+		description: "",
+		solution: "",
+		updateTime: 1541860000000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1017",
+		description: "",
+		solution: "",
+		updateTime: 1541733663000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320025",
+		description: "",
+		solution: "",
+		updateTime: 1541078281000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320024",
+		description: "",
+		solution: "",
+		updateTime: 1540801374000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321002",
+		description: "",
+		solution: "",
+		updateTime: 1540631734000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321000",
+		description: "",
+		solution: "",
+		updateTime: 1540609178000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321022",
+		description: "",
+		solution: "",
+		updateTime: 1540548345000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321016",
+		description: "",
+		solution: "",
+		updateTime: 1540287187000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320023",
+		description: "",
+		solution: "",
+		updateTime: 1539825993000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1016",
+		description: "",
+		solution: "",
+		updateTime: 1539584931000
+	},
+	{
+		moduleCode: "",
+		detailCode: "8",
+		description: "",
+		solution: "",
+		updateTime: 1539391812000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1075127593",
+		description: "",
+		solution: "",
+		updateTime: 1538959251000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380421",
+		description: "",
+		solution: "",
+		updateTime: 1537288465000
+	},
+	{
+		moduleCode: "",
+		detailCode: "322000",
+		description: "楹﹀厠椋庢潈闄愭湭寮�鍚�",
+		solution: "",
+		updateTime: 1536820136000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1152678",
+		description: "",
+		solution: "",
+		updateTime: 1536738348000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320047",
+		description: "",
+		solution: "",
+		updateTime: 1536664472000
+	},
+	{
+		moduleCode: "",
+		detailCode: "327006",
+		description: "",
+		solution: "",
+		updateTime: 1536136120000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1074807593",
+		description: "",
+		solution: "",
+		updateTime: 1536135035000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320291",
+		description: "",
+		solution: "",
+		updateTime: 1536110836000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320045",
+		description: "",
+		solution: "",
+		updateTime: 1535963775000
+	},
+	{
+		moduleCode: "",
+		detailCode: "370004",
+		description: "",
+		solution: "",
+		updateTime: 1535883699000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1149954",
+		description: "",
+		solution: "",
+		updateTime: 1535700674000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320053",
+		description: "",
+		solution: "",
+		updateTime: 1535681079000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400000",
+		description: "",
+		solution: "",
+		updateTime: 1535532332000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110028",
+		description: "涓汉鐗堟姄鍥炬帴鍙f棩璋冪敤娆℃暟瓒呭嚭闄愬埗",
+		solution: "璇峰崌绾т紒涓氱増锛歨ttps://open.ys7.com/price.html",
+		updateTime: 1535348756000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110027",
+		description: "涓汉鐗堝笎鍙锋暟閲忚秴鍑哄畨鍏ㄩ檺鍒讹紝鏃犳硶璋冪敤",
+		solution: "璇峰崌绾т紒涓氱増锛歨ttps://open.ys7.com/price.html",
+		updateTime: 1535348734000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110026",
+		description: "璁惧鏁伴噺瓒呭嚭涓汉鐗堥檺鍒讹紝褰撳墠璁惧鏃犳硶鎿嶄綔",
+		solution: "璇峰崌绾т紒涓氱増锛歨ttps://open.ys7.com/price.html",
+		updateTime: 1535348588000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100000",
+		description: "",
+		solution: "",
+		updateTime: 1534980008000
+	},
+	{
+		moduleCode: "",
+		detailCode: "324004",
+		description: "",
+		solution: "",
+		updateTime: 1534927762000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360104",
+		description: "",
+		solution: "",
+		updateTime: 1534761006000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320204",
+		description: "",
+		solution: "",
+		updateTime: 1534584221000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380001",
+		description: "",
+		solution: "",
+		updateTime: 1534404715000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380204",
+		description: "",
+		solution: "",
+		updateTime: 1534401682000
+	},
+	{
+		moduleCode: "",
+		detailCode: "328006",
+		description: "",
+		solution: "",
+		updateTime: 1534144407000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321703",
+		description: "",
+		solution: "",
+		updateTime: 1534127274000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321510",
+		description: "",
+		solution: "",
+		updateTime: 1533428892000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321006",
+		description: "",
+		solution: "",
+		updateTime: 1533036916000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50009",
+		description: "",
+		solution: "",
+		updateTime: 1532078548000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50007",
+		description: "",
+		solution: "",
+		updateTime: 1531991720000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50018",
+		description: "",
+		solution: "",
+		updateTime: 1531912829000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380451",
+		description: "",
+		solution: "",
+		updateTime: 1531615700000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380336",
+		description: "",
+		solution: "",
+		updateTime: 1531231721000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360020",
+		description: "",
+		solution: "",
+		updateTime: 1531117554000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380418",
+		description: "",
+		solution: "",
+		updateTime: 1531107070000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1153445",
+		description: "璁惧鍦ㄨ鏃堕棿娈靛唴娌℃湁褰曞儚",
+		solution: "",
+		updateTime: 1530944007000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110007",
+		description: "璋冪敤鎺ュ彛鎬绘鏁拌揪鍒颁笂闄�",
+		solution: "璇峰崌绾т紒涓氱増锛岃幏鍙栨洿楂樿兘鍔�",
+		updateTime: 1530935584000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360019",
+		description: "",
+		solution: "",
+		updateTime: 1530869771000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360100",
+		description: "",
+		solution: "",
+		updateTime: 1530786188000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380042",
+		description: "",
+		solution: "",
+		updateTime: 1530775199000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320355",
+		description: "",
+		solution: "",
+		updateTime: 1530716074000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100003",
+		description: "",
+		solution: "",
+		updateTime: 1530232541000
+	},
+	{
+		moduleCode: "",
+		detailCode: "371026",
+		description: "",
+		solution: "",
+		updateTime: 1530192600000
+	},
+	{
+		moduleCode: "",
+		detailCode: "102",
+		description: "",
+		solution: "",
+		updateTime: 1529895641000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380201",
+		description: "",
+		solution: "",
+		updateTime: 1529740929000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320054",
+		description: "",
+		solution: "",
+		updateTime: 1529544875000
+	},
+	{
+		moduleCode: "",
+		detailCode: "500101",
+		description: "",
+		solution: "",
+		updateTime: 1529485953000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321001",
+		description: "",
+		solution: "",
+		updateTime: 1529411048000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321508",
+		description: "",
+		solution: "",
+		updateTime: 1529393279000
+	},
+	{
+		moduleCode: "",
+		detailCode: "405991",
+		description: "",
+		solution: "",
+		updateTime: 1529380238000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380461",
+		description: "",
+		solution: "",
+		updateTime: 1529130941000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1019",
+		description: "",
+		solution: "",
+		updateTime: 1529057245000
+	},
+	{
+		moduleCode: "",
+		detailCode: "322009",
+		description: "",
+		solution: "",
+		updateTime: 1528965717000
+	},
+	{
+		moduleCode: "",
+		detailCode: "324005",
+		description: "",
+		solution: "",
+		updateTime: 1528950153000
+	},
+	{
+		moduleCode: "",
+		detailCode: "325000",
+		description: "",
+		solution: "",
+		updateTime: 1528947143000
+	},
+	{
+		moduleCode: "",
+		detailCode: "326032",
+		description: "",
+		solution: "",
+		updateTime: 1528872971000
+	},
+	{
+		moduleCode: "",
+		detailCode: "325032",
+		description: "",
+		solution: "",
+		updateTime: 1528863189000
+	},
+	{
+		moduleCode: "",
+		detailCode: "328000",
+		description: "",
+		solution: "",
+		updateTime: 1528794505000
+	},
+	{
+		moduleCode: "",
+		detailCode: "53",
+		description: "",
+		solution: "",
+		updateTime: 1528693249000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1020",
+		description: "",
+		solution: "",
+		updateTime: 1528499440000
+	},
+	{
+		moduleCode: "",
+		detailCode: "329032",
+		description: "",
+		solution: "",
+		updateTime: 1528446301000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1202",
+		description: "",
+		solution: "",
+		updateTime: 1528439820000
+	},
+	{
+		moduleCode: "",
+		detailCode: "2",
+		description: "",
+		solution: "",
+		updateTime: 1528434175000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1152936",
+		description: "",
+		solution: "",
+		updateTime: 1528345986000
+	},
+	{
+		moduleCode: "",
+		detailCode: "328011",
+		description: "",
+		solution: "",
+		updateTime: 1528338600000
+	},
+	{
+		moduleCode: "",
+		detailCode: "28",
+		description: "",
+		solution: "",
+		updateTime: 1528337530000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320356",
+		description: "",
+		solution: "",
+		updateTime: 1528188693000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320357",
+		description: "",
+		solution: "",
+		updateTime: 1528188517000
+	},
+	{
+		moduleCode: "",
+		detailCode: "405800",
+		description: "",
+		solution: "",
+		updateTime: 1528168732000
+	},
+	{
+		moduleCode: "",
+		detailCode: "405996",
+		description: "",
+		solution: "",
+		updateTime: 1528168686000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380357",
+		description: "",
+		solution: "",
+		updateTime: 1528011565000
+	},
+	{
+		moduleCode: "",
+		detailCode: "328022",
+		description: "",
+		solution: "",
+		updateTime: 1527929065000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380003",
+		description: "",
+		solution: "",
+		updateTime: 1527927819000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50004",
+		description: "",
+		solution: "",
+		updateTime: 1527770643000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50011",
+		description: "",
+		solution: "",
+		updateTime: 1527770635000
+	},
+	{
+		moduleCode: "",
+		detailCode: "370017",
+		description: "",
+		solution: "",
+		updateTime: 1527739514000
+	},
+	{
+		moduleCode: "",
+		detailCode: "327032",
+		description: "",
+		solution: "",
+		updateTime: 1527726704000
+	},
+	{
+		moduleCode: "",
+		detailCode: "324001",
+		description: "",
+		solution: "",
+		updateTime: 1527681892000
+	},
+	{
+		moduleCode: "",
+		detailCode: "405997",
+		description: "",
+		solution: "",
+		updateTime: 1527653408000
+	},
+	{
+		moduleCode: "",
+		detailCode: "405995",
+		description: "",
+		solution: "",
+		updateTime: 1527647283000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1153825",
+		description: "",
+		solution: "",
+		updateTime: 1527601747000
+	},
+	{
+		moduleCode: "",
+		detailCode: "328002",
+		description: "",
+		solution: "",
+		updateTime: 1527495292000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1152679",
+		description: "",
+		solution: "",
+		updateTime: 1527486665000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380356",
+		description: "",
+		solution: "",
+		updateTime: 1527125669000
+	},
+	{
+		moduleCode: "",
+		detailCode: "328032",
+		description: "",
+		solution: "",
+		updateTime: 1527069382000
+	},
+	{
+		moduleCode: "",
+		detailCode: "22",
+		description: "",
+		solution: "",
+		updateTime: 1527049826000
+	},
+	{
+		moduleCode: "",
+		detailCode: "9",
+		description: "",
+		solution: "",
+		updateTime: 1527006778000
+	},
+	{
+		moduleCode: "",
+		detailCode: "89",
+		description: "",
+		solution: "",
+		updateTime: 1526622784000
+	},
+	{
+		moduleCode: "",
+		detailCode: "328016",
+		description: "",
+		solution: "",
+		updateTime: 1526452365000
+	},
+	{
+		moduleCode: "",
+		detailCode: "368005",
+		description: "",
+		solution: "",
+		updateTime: 1525921264000
+	},
+	{
+		moduleCode: "",
+		detailCode: "0",
+		description: "",
+		solution: "",
+		updateTime: 1525920242000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380006",
+		description: "",
+		solution: "",
+		updateTime: 1525918868000
+	},
+	{
+		moduleCode: "",
+		detailCode: "310",
+		description: "",
+		solution: "",
+		updateTime: 1525834436000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360011",
+		description: "",
+		solution: "",
+		updateTime: 1525681552000
+	},
+	{
+		moduleCode: "",
+		detailCode: "170005",
+		description: "",
+		solution: "",
+		updateTime: 1525433900000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50023",
+		description: "",
+		solution: "",
+		updateTime: 1525403338000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100131",
+		description: "",
+		solution: "",
+		updateTime: 1525229691000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1018",
+		description: "",
+		solution: "",
+		updateTime: 1525142341000
+	},
+	{
+		moduleCode: "",
+		detailCode: "362026",
+		description: "",
+		solution: "",
+		updateTime: 1524882677000
+	},
+	{
+		moduleCode: "",
+		detailCode: "368007",
+		description: "",
+		solution: "",
+		updateTime: 1524832269000
+	},
+	{
+		moduleCode: "",
+		detailCode: "54",
+		description: "",
+		solution: "",
+		updateTime: 1524793646000
+	},
+	{
+		moduleCode: "",
+		detailCode: "1154722",
+		description: "",
+		solution: "",
+		updateTime: 1524620807000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320229",
+		description: "",
+		solution: "",
+		updateTime: 1524551682000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360012",
+		description: "",
+		solution: "",
+		updateTime: 1524472094000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380229",
+		description: "",
+		solution: "",
+		updateTime: 1524110755000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360016",
+		description: "",
+		solution: "",
+		updateTime: 1523933518000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1003",
+		description: "",
+		solution: "",
+		updateTime: 1523584804000
+	},
+	{
+		moduleCode: "",
+		detailCode: "410026",
+		description: "",
+		solution: "",
+		updateTime: 1523517430000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360102",
+		description: "TTS鍒濆鍖栧け璐�",
+		solution: "",
+		updateTime: 1523503528000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360013",
+		description: "璁惧寮�鍚簡闅愮淇濇姢",
+		solution: "",
+		updateTime: 1523503507000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360010",
+		description: "璁惧姝e湪瀵硅涓�",
+		solution: "",
+		updateTime: 1523503491000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360007",
+		description: "TTS鍏抽棴浜嗕笌瀹㈡埛绔殑杩炴帴",
+		solution: "",
+		updateTime: 1523503475000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360006",
+		description: "瀹㈡埛绔帴鏀跺彂鐢熼敊璇�",
+		solution: "",
+		updateTime: 1523503457000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360005",
+		description: "瀹㈡埛绔彂閫佺殑娑堟伅閿欒",
+		solution: "",
+		updateTime: 1523503437000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360004",
+		description: "TTS鍐呴儴鍙戠敓閿欒",
+		solution: "",
+		updateTime: 1523503421000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360003",
+		description: "TTS鐨勮澶囩鍙戠敓閿欒",
+		solution: "",
+		updateTime: 1523503397000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360002",
+		description: "瀵硅鍙戣捣瓒呮椂",
+		solution: "",
+		updateTime: 1523503376000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360001",
+		description: "瀹㈡埛绔姹傝秴鏃�",
+		solution: "",
+		updateTime: 1523503357000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320077",
+		description: "",
+		solution: "",
+		updateTime: 1523444274000
+	},
+	{
+		moduleCode: "",
+		detailCode: "370047",
+		description: "",
+		solution: "",
+		updateTime: 1523440480000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100002",
+		description: "",
+		solution: "",
+		updateTime: 1523413964000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1004",
+		description: "",
+		solution: "",
+		updateTime: 1523336653000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380000",
+		description: "",
+		solution: "",
+		updateTime: 1523180856000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380213",
+		description: "",
+		solution: "",
+		updateTime: 1523180623000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380101",
+		description: "",
+		solution: "",
+		updateTime: 1522834231000
+	},
+	{
+		moduleCode: "",
+		detailCode: "50047",
+		description: "",
+		solution: "",
+		updateTime: 1522833243000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-999",
+		description: "",
+		solution: "",
+		updateTime: 1522831034000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320418",
+		description: "",
+		solution: "",
+		updateTime: 1522829072000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1009",
+		description: "",
+		solution: "",
+		updateTime: 1522746247000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320209",
+		description: "",
+		solution: "",
+		updateTime: 1522744395000
+	},
+	{
+		moduleCode: "",
+		detailCode: "368006",
+		description: "",
+		solution: "",
+		updateTime: 1522744300000
+	},
+	{
+		moduleCode: "",
+		detailCode: "369003",
+		description: "",
+		solution: "",
+		updateTime: 1522736355000
+	},
+	{
+		moduleCode: "",
+		detailCode: "405989",
+		description: "",
+		solution: "",
+		updateTime: 1522726571000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1012",
+		description: "",
+		solution: "",
+		updateTime: 1522726203000
+	},
+	{
+		moduleCode: "",
+		detailCode: "322016",
+		description: "",
+		solution: "",
+		updateTime: 1522722918000
+	},
+	{
+		moduleCode: "",
+		detailCode: "500103",
+		description: "",
+		solution: "",
+		updateTime: 1522655556000
+	},
+	{
+		moduleCode: "",
+		detailCode: "405999",
+		description: "",
+		solution: "",
+		updateTime: 1522654716000
+	},
+	{
+		moduleCode: "",
+		detailCode: "321032",
+		description: "",
+		solution: "",
+		updateTime: 1522647732000
+	},
+	{
+		moduleCode: "",
+		detailCode: "381101",
+		description: "",
+		solution: "",
+		updateTime: 1522392414000
+	},
+	{
+		moduleCode: "",
+		detailCode: "399999",
+		description: "",
+		solution: "",
+		updateTime: 1522379834000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380103",
+		description: "",
+		solution: "",
+		updateTime: 1522312724000
+	},
+	{
+		moduleCode: "",
+		detailCode: "360014",
+		description: "",
+		solution: "",
+		updateTime: 1522304341000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1005",
+		description: "",
+		solution: "",
+		updateTime: 1522288195000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395454",
+		description: "",
+		solution: "",
+		updateTime: 1522220180000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100005",
+		description: "",
+		solution: "",
+		updateTime: 1522218849000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100004",
+		description: "",
+		solution: "",
+		updateTime: 1522209053000
+	},
+	{
+		moduleCode: "",
+		detailCode: "106002",
+		description: "",
+		solution: "",
+		updateTime: 1522206200000
+	},
+	{
+		moduleCode: "",
+		detailCode: "410030",
+		description: "",
+		solution: "",
+		updateTime: 1522162252000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1002",
+		description: "",
+		solution: "",
+		updateTime: 1522150690000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1200",
+		description: "",
+		solution: "",
+		updateTime: 1522139025000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1001",
+		description: "",
+		solution: "",
+		updateTime: 1522046436000
+	},
+	{
+		moduleCode: "",
+		detailCode: "-1011",
+		description: "",
+		solution: "",
+		updateTime: 1522045931000
+	},
+	{
+		moduleCode: "",
+		detailCode: "381102",
+		description: "",
+		solution: "",
+		updateTime: 1522044953000
+	},
+	{
+		moduleCode: "",
+		detailCode: "381103",
+		description: "",
+		solution: "",
+		updateTime: 1522044953000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391205",
+		description: "vtdu瑙f瀽鏈嶅姟鍣╥p澶辫触",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391206",
+		description: "vtdu鎻忚堪绗elect澶辫触",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391207",
+		description: "vtdu鏂囦欢鎻忚堪绗︿笉鍦ㄥ彲璇讳腑",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391208",
+		description: "vtdu缃戠粶鍙戠敓閿欒getsockopt",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391209",
+		description: "vtdu鎻忚堪绗elect瓒呮椂",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395000",
+		description: "cas鍥炲淇′护锛屽彂鐜板唴瀛樺凡缁忛噴鏀撅紙鍜岃澶囦箣闂村紓甯告柇寮�锛�",
+		solution: "妫�鏌ヨ澶囩綉缁滐紱鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395400",
+		description: "绉佹湁鍖栧崗璁畍tm妫�娴嬬鏈夊寲鍗忚涓爜娴佺被鍨嬪皬浜�0鎴栬�呰澶囧簭鍒楀彿涓虹┖绛夐潪娉曞弬鏁板満鏅繑鍥�(app涓嶉噸璇曞彇娴�)",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395402",
+		description: "鍥炴斁鎵句笉鍒板綍鍍忔枃浠�",
+		solution: "妫�鏌ユ槸鍚︽湁瀛樺偍鍗″苟涓旀帴瑙﹁壇濂�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395403",
+		description: "鎿嶄綔鐮佹垨淇′护瀵嗛挜涓庤澶囦笉鍖归厤",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395404",
+		description: "璁惧涓嶅湪绾�",
+		solution: "妫�鏌ヨ澶囩綉缁滐紱閲嶅惎璁惧鎺ュ叆钀ょ煶浜�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395405",
+		description: "娴佸獟浣撳悜璁惧鍙戦�佹垨鎺ュ彈淇′护瓒呮椂/cas鍝嶅簲瓒呮椂",
+		solution: "妫�鏌ヨ澶囩綉缁滐紱閲嶅惎璁惧",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395406",
+		description: "token澶辨晥",
+		solution: "鍒锋柊閲嶈瘯鎴栬�呴噸鍚澶�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395407",
+		description: "瀹㈡埛绔殑URL鏍煎紡閿欒",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395409",
+		description: "棰勮寮�鍚殣绉佷繚鎶�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395410",
+		description: "璁惧杈惧埌鏈�澶ц繛鎺ユ暟",
+		solution: "璇峰崌绾ц澶囧浐浠剁増鏈�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395411",
+		description: "token鏃犳潈闄�",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395412",
+		description: "session涓嶅瓨鍦� ",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395413",
+		description: "楠岃瘉token鐨勪粬寮傚父锛堜笉鍏蜂綋锛� ",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395415",
+		description: "璁惧閫氶亾閿�",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395451",
+		description: "璁惧涓嶆敮鎸佺殑鐮佹祦绫诲瀷",
+		solution: "鍒锋柊閲嶈瘯鎴栬�呭垏鎹㈠埌楂樻竻妯″紡",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395452",
+		description: "璁惧閾炬帴娴佸獟浣撴湇鍔″櫒澶辫触 ",
+		solution: "妫�鏌ヨ澶囩綉缁滐紝閲嶅惎璁惧锛屽埛鏂伴噸璇�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395500",
+		description: "鏈嶅姟鍣ㄥ鐞嗗け璐� ",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395501",
+		description: "娴佸獟浣搗tdu杈惧埌鏈�澶ц礋杞斤紝璇锋墿瀹�",
+		solution: "鏈嶅姟鍣ㄨ礋杞借揪鍒颁笂闄愶紝璇风◢鍚庨噸璇�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395503",
+		description: "vtm杩斿洖鍒嗛厤vtdu澶辫触",
+		solution: "鏈嶅姟鍣ㄨ礋杞借揪鍒颁笂闄愶紝璇风◢鍚庨噸璇�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395544",
+		description: "璁惧杩斿洖鏃犺棰戞簮 ",
+		solution: "璁惧鏄惁鎺ヨЕ鑹ソ锛�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395545",
+		description: "瑙嗛鍒嗕韩鏃堕棿宸茬粡缁撴潫",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395546",
+		description: "vtdu杩斿洖杈惧埌鍙栨祦骞跺彂璺暟闄愬埗",
+		solution: "璇峰崌绾т负浼佷笟鐗堬紝鏀惧紑骞跺彂闄愬埗",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395560",
+		description: "铓佸叺浠g悊涓嶆敮鎸佺殑鐢ㄦ埛鍙栨祦绫诲瀷锛屼細閲嶅畾鍚戝埌vtdu鍙栨祦",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395557",
+		description: "鍥炴斁鏈嶅姟鍣ㄧ瓑寰呮祦澶磋秴鏃�",
+		solution: "鍒锋柊閲嶈瘯锛屾娴嬭澶囩綉缁滐紝閲嶅惎璁惧",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395600",
+		description: "鍒嗕韩璁惧涓嶅湪鍒嗕韩鏃堕棿鍐�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395601",
+		description: "缇ょ粍鍒嗕韩鐢ㄦ埛娌℃潈闄�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395602",
+		description: "缇ょ粍鍒嗕韩鏉冮檺鍙樻洿",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395556",
+		description: "ticket鍙栨祦楠岃瘉澶辫触",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395530",
+		description: "鏈烘埧鏁呴殰涓嶅彲鐢�",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "395701",
+		description: "cas淇′护杩斿洖鏍煎紡閿欒",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396001",
+		description: "瀹㈡埛绔弬鏁板嚭閿�",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396099",
+		description: "瀹㈡埛绔粯璁ら敊璇�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396101",
+		description: "涓嶆敮鎸佺殑鍛戒护",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396102",
+		description: "璁惧娴佸ご鍙戦�佸け璐�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396103",
+		description: "cas/璁惧杩斿洖閿欒1",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396104",
+		description: "cas/璁惧杩斿洖閿欒-1",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396105",
+		description: "璁惧杩斿洖閿欒鐮�3",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396106",
+		description: "璁惧杩斿洖閿欒鐮�4",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396107",
+		description: "璁惧杩斿洖閿欒鐮�5",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396108",
+		description: "cas淇′护鍥炲簲閲嶅",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396109",
+		description: "瑙嗛骞垮満鍙栨秷鍒嗕韩",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396110",
+		description: "璁惧淇′护榛樿閿欒",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396501",
+		description: "璁惧鏁版嵁閾捐矾鍜屽疄闄呴摼璺笉鍖归厤",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396502",
+		description: "璁惧鏁版嵁閾捐矾閲嶅寤虹珛杩炴帴",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396503",
+		description: "璁惧鏁版嵁閾捐矾绔彛涓嶅尮閰�",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396504",
+		description: "缂撳瓨璁惧鏁版嵁閾捐矾澶辫触(鍐呭瓨鍧椾笉瓒�)",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396505",
+		description: "璁惧鍙戦�佺‘璁ゅご娑堟伅閲嶅",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396506",
+		description: "璁惧鏁版嵁鍏堜簬纭畾澶撮儴鍒拌揪",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396508",
+		description: "璁惧鏁版嵁澶撮儴闀垮害闈炴硶",
+		solution: "鍒锋柊閲嶈瘯锛屾垨鑰呴噸鍚澶�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396509",
+		description: "绱㈠紩鎵句笉鍒拌澶囨暟鎹鐞嗗潡",
+		solution: "鍒锋柊閲嶈瘯",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396510",
+		description: "璁惧鏁版嵁閾捐矾vtdu鍐呭瓨鍧楀崗璁姸鎬佷笉鍖归厤",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396511",
+		description: "璁惧鏁版嵁澶撮儴娌℃湁streamkey閿欒",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396512",
+		description: "璁惧鏁版嵁澶撮儴闈炴硶(杈冪缁�)",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396513",
+		description: "璁惧鏁版嵁闀垮害杩囧皬",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396514",
+		description: "璁惧鑰佸崗璁帹娴佸ご閮ㄦ病鏈塻treamkey閿欒",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396515",
+		description: "璁惧鑰佸崗璁帹娴佹暟鎹潪娉�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396516",
+		description: "璁惧鑰佸崗璁储寮曟壘涓嶅埌鍐呭瓨绠$悊鍧�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396517",
+		description: "璁惧鑰佸崗璁帹娴佹暟鎹潪娉�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396518",
+		description: "璁惧鏁版嵁鍖呰繃澶�",
+		solution: "鍒锋柊閲嶈瘯锛屾垨鑰呴噸鍚澶�",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396519",
+		description: "璁惧鎺ㄦ祦閾捐矾缃戠粶涓嶇ǔ瀹�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "396520",
+		description: "璁惧鎺ㄦ祦閾捐矾缃戠粶涓嶇ǔ瀹�(榛樿)",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "170003",
+		description: "refreshToken涓嶅瓨鍦�",
+		solution: "寤鸿鐢ㄦ埛閲嶆柊璋冪敤logout鎺ュ彛锛岀劧鍚庤皟鐢╫penLoginPage鎺ュ彛閲嶆柊鍚姩鐧诲綍椤甸潰鐧诲綍",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "170004",
+		description: "refreshToken宸茶繃鏈�",
+		solution: "寤鸿鐢ㄦ埛閲嶆柊璋冪敤logout鎺ュ彛锛岀劧鍚庤皟鐢╫penLoginPage鎺ュ彛閲嶆柊鍚姩鐧诲綍椤甸潰鐧诲綍",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380011",
+		description: "璁惧闅愮淇濇姢涓�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380045",
+		description: "璁惧鐩磋繛鍙栨祦杩炴帴鏁伴噺杩囧ぇ",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380047",
+		description: "璁惧涓嶆敮鎸佽鍛戒护",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380077",
+		description: "璁惧姝e湪瀵硅涓�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380102",
+		description: "鏁版嵁鎺ユ敹寮傚父",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380205",
+		description: "璁惧妫�娴嬪叆鍙傚紓甯�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380209",
+		description: "缃戠粶杩炴帴瓒呮椂",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380212",
+		description: "璁惧绔綉缁滆繛鎺ヨ秴鏃�",
+		solution: "",
+		updateTime: 1522034841000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101007",
+		description: "鎵嬫満鍙锋湭娉ㄥ唽",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120503",
+		description: "姝e湪鍝嶉搩",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390016",
+		description: "vtdu鎴愬姛鍝嶅簲鏈惡甯︽祦澶�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101008",
+		description: "鎵嬫満鍙风爜涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120504",
+		description: "瀹ゅ唴鏈烘鍦ㄩ�氳瘽",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390017",
+		description: "鏃犳暟鎹祦锛屽皻鏈娇鐢�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101009",
+		description: "鐢ㄦ埛鍚嶄笌鎵嬫満涓嶅尮閰�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120505",
+		description: "璁惧鎿嶄綔澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390018",
+		description: "淇′护娑堟伅浣揚B瑙f瀽澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101010",
+		description: "鑾峰彇楠岃瘉鐮佸け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120506",
+		description: "闈炴硶鍛戒护",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390019",
+		description: "淇′护娑堟伅浣揚B灏佽澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101011",
+		description: "楠岃瘉鐮侀敊璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120507",
+		description: "鏅鸿兘閿佸瘑鐮侀敊璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390020",
+		description: "鐢宠绯荤粺鍐呭瓨璧勬簮澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101012",
+		description: "楠岃瘉鐮佸け鏁�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120508",
+		description: "寮�鍏抽攣澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390021",
+		description: "vtdu鍦板潃灏氭湭鑾峰彇鍒�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101013",
+		description: "鐢ㄦ埛涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120509",
+		description: "寮�鍏抽攣瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390022",
+		description: "瀹㈡埛绔皻鏈敮鎸�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101014",
+		description: "瀵嗙爜涓嶆纭垨鑰卆ppKey涓嶆纭�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120510",
+		description: "鏅鸿兘閿佽澶囩箒蹇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390023",
+		description: "鑾峰彇绯荤粺socket璧勬簮澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101015",
+		description: "鐢ㄦ埛琚攣浣�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120511",
+		description: "杩滅▼寮�閿佸姛鑳芥湭鎵撳紑",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390024",
+		description: "涓婂眰濉厖鐨凷treamSsnId涓嶅尮閰�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101021",
+		description: "楠岃瘉鍙傛暟寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120600",
+		description: "涓存椂瀵嗙爜鏁板凡杈句笂闄�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390025",
+		description: "閾炬帴鏈嶅姟鍣ㄥけ璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101026",
+		description: "閭宸茬粡琚敞鍐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120601",
+		description: "娣诲姞涓存椂瀵嗙爜澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390026",
+		description: "瀹㈡埛绔姹傛湭鏀跺埌鏈嶅姟绔簲绛�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101031",
+		description: "閭鏈敞鍐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120602",
+		description: "鍒犻櫎涓存椂瀵嗙爜澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390027",
+		description: "閾捐矾鏂紑",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101032",
+		description: "閭涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120603",
+		description: "璇ヤ复鏃跺瘑鐮佷笉瀛樺湪",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390028",
+		description: "娌℃湁鍙栨祦閾炬帴",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101041",
+		description: "鑾峰彇楠岃瘉鐮佽繃浜庨绻�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120604",
+		description: "鎸囩汗閿佸皠棰戦�氫俊澶辫触,璇风◢鍚庡啀璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390029",
+		description: "娴佹垚鍔熷仠姝�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101043",
+		description: "鎵嬫満楠岃瘉鐮佽緭鍏ラ敊璇秴杩囪瀹氭鏁�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120605",
+		description: "鍏朵粬鐢ㄦ埛姝e湪璁よ瘉涓�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390030",
+		description: "瀹㈡埛绔槻涓叉祦鏍¢獙澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "102000",
+		description: "璁惧涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120606",
+		description: "楠岃瘉宸插惎鍔�,璇峰湪120s鍐呰繘琛屾湰鍦伴獙璇佸拰璋冪敤娣诲姞璁惧鎺ュ彛",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390031",
+		description: "搴旂敤灞倀cp绮樺寘澶勭悊缂撳啿鍖烘弧",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "102001",
+		description: "鎽勫儚鏈轰笉瀛樺湪",
+		solution: "鎽勫儚鏈烘湭娉ㄥ唽鍒拌悿鐭充簯骞冲彴锛岃浠旂粏妫�鏌ユ憚鍍忔満鐨勭綉缁滈厤缃紝纭繚杩炴帴鍒扮綉缁�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120607",
+		description: "鍒犻櫎鐢ㄦ埛澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390032",
+		description: "鏃犳晥鐘舵�佽縼绉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "102003",
+		description: "璁惧涓嶅湪绾�",
+		solution: "鍙傝�冩湇鍔′腑蹇冩帓鏌ユ柟娉�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120608",
+		description: "鐢ㄦ埛涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390033",
+		description: "鏃犳晥瀹㈡埛绔姸鎬�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "102004",
+		description: "璁惧寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120609",
+		description: "璁惧鍝嶅簲瓒呮椂,闂ㄩ攣閫氫俊鏁呴殰鎴栬�呯數閲忎笉瓒�,璇烽噸璇�.",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390034",
+		description: "鍚憊tm鍙栨祦娴佸獟浣撲俊鎭姹傝秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "102007",
+		description: "璁惧搴忓垪鍙蜂笉姝g‘",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120610",
+		description: "鑾峰彇涓存椂瀵嗙爜鍒楄〃澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390035",
+		description: "鍚戜唬鐞嗗彇娴佽姹傝秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "102009",
+		description: "璁惧璇锋眰鍝嶅簲瓒呮椂寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "130001",
+		description: "鐢ㄦ埛涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390036",
+		description: "鍚戜唬鐞嗕繚娲诲彇娴佽姹傝秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "105000",
+		description: "璁惧宸茶鑷繁娣诲姞",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "130002",
+		description: "鎵嬫満鍙风爜宸茬粡娉ㄥ唽",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390037",
+		description: "鍚憊tdu鍙栨祦璇锋眰瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "105001",
+		description: "璁惧宸茶鍒汉娣诲姞",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "130003",
+		description: "鎵嬫満楠岃瘉鐮侀敊璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390038",
+		description: "鍚憊tdu淇濇椿鍙栨祦璇锋眰瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "105002",
+		description: "璁惧楠岃瘉鐮侀敊璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "130004",
+		description: "缁堢缁戝畾鎿嶄綔澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391001",
+		description: "vtm鍦板潃鎴栫鍙i潪娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "107001",
+		description: "閭�璇蜂笉瀛樺湪",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "149999",
+		description: "鏁版嵁寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391002",
+		description: "vtm鐢熸垚鏂囦欢鎻忚堪绗﹀け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "107002",
+		description: "閭�璇烽獙璇佸け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "150000",
+		description: "鏈嶅姟鍣ㄥ紓甯�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391003",
+		description: "vtm璁剧疆鏂囦欢鎻忚堪绗﹂潪闃诲澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "107003",
+		description: "閭�璇风敤鎴蜂笉鍖归厤",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160000",
+		description: "璁惧涓嶆敮鎸佷簯鍙版帶鍒�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391004",
+		description: "vtm璁剧疆鏂囦欢鎻忚堪绗﹂樆濉炲け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "107004",
+		description: "浜戝瓨鍌ㄨ繛鎺ュけ璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160001",
+		description: "鐢ㄦ埛鏃犱簯鍙版帶鍒舵潈闄�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391005",
+		description: "vtm瑙f瀽鏈嶅姟鍣╥p澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "7005",
+		description: "VTDU涓诲姩鏂紑杩炴帴",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "107005",
+		description: "VTDU涓诲姩鏂紑杩炴帴",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160002",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌涓婇檺浣�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391006",
+		description: "vtm鎻忚堪绗elect澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "107006",
+		description: "涓嶈兘閭�璇疯嚜宸�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160003",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌涓嬮檺浣�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391007",
+		description: "vtm鏂囦欢鎻忚堪绗︿笉鍦ㄥ彲璇讳腑",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "107007",
+		description: "閲嶅閭�璇�",
+		solution: "鍒嗕韩鍜屽垹闄ゅ垎浜繀椤诲叏閮ㄧ敱鎺ュ彛褰㈠紡鎿嶄綔锛屽鏋滀笌钀ょ煶瀹㈡埛绔贩鐢ㄤ細閫犳垚杩欎釜闂锛岃В鍐冲姙娉曪細鍦ㄨ悿鐭冲鎴风娓呯┖鎵�鏈夌浉鍏冲垎浜暟鎹苟閲嶆柊娣诲姞璁惧锛屽啀閫氳繃鎺ュ彛鎿嶄綔鍗冲彲",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160004",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌宸﹂檺浣�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391008",
+		description: "vtm缃戠粶鍙戠敓閿欒getsockopt",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110001",
+		description: "鍙傛暟閿欒",
+		solution: "鍙傛暟涓虹┖鎴栬�呮牸寮忎笉瀵�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160005",
+		description: "璁惧浜戝彴鏃嬭浆杈惧埌鍙抽檺浣�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391009",
+		description: "vtm鎻忚堪绗elect瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110002",
+		description: "accessToken寮傚父鎴栬繃鏈�",
+		solution: "accessToken鏈夋晥鏈熶负涓冨ぉ锛屽缓璁湪accessToken鍗冲皢杩囨湡鎴栬�呭嚭鐜�10002閿欒鐮佺殑鏃跺�欓噸鏂拌幏鍙朼ccessToken",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160006",
+		description: "浜戝彴褰撳墠鎿嶄綔澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391101",
+		description: "proxy鍦板潃鎴栫鍙i潪娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110004",
+		description: "鐢ㄦ埛涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160007",
+		description: "棰勭疆鐐逛釜鏁拌秴杩囨渶澶у��",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391102",
+		description: "proxy鐢熸垚鏂囦欢鎻忚堪绗﹀け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110005",
+		description: "appKey寮傚父",
+		solution: "纭appKey鐘舵�侊紝涓嶉�氳繃鎴栬�呭喕缁撶姸鎬佷細杩斿洖璇ラ敊璇爜",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160009",
+		description: "姝e湪璋冪敤棰勭疆鐐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391103",
+		description: "proxy璁剧疆鏂囦欢鎻忚堪绗﹂潪闃诲澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110006",
+		description: "ip鍙楅檺",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160010",
+		description: "璇ラ缃偣宸茬粡鏄綋鍓嶄綅缃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391104",
+		description: "proxy璁剧疆鏂囦欢鎻忚堪绗﹂樆濉炲け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160011",
+		description: "棰勭疆鐐逛笉瀛樺湪",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391105",
+		description: "proxy瑙f瀽鏈嶅姟鍣╥p澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110008",
+		description: "绛惧悕閿欒",
+		solution: "鈶犺幏鍙栫鍚嶆柟寮忚瑙乤pidemo鍙奫鏃API鏂囨。 鈶℃敞鎰忕紪鐮佹牸寮忎负UTF-8",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160013",
+		description: "璁惧鐗堟湰宸叉槸鏈�鏂�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391106",
+		description: "proxy鎻忚堪绗elect澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110009",
+		description: "绛惧悕鍙傛暟閿欒",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160014",
+		description: "璁惧姝e湪鍗囩骇",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391107",
+		description: "proxy鏂囦欢鎻忚堪绗︿笉鍦ㄥ彲璇讳腑",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110010",
+		description: "绛惧悕瓒呮椂",
+		solution: "璇疯皟鐢ㄥ悓姝ユ湇鍔″櫒鏃堕棿鎺ュ彛杩涜鏍℃椂",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160015",
+		description: "璁惧姝e湪閲嶅惎",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391108",
+		description: "proxy缃戠粶鍙戠敓閿欒getsockopt",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110011",
+		description: "鏈紑閫氳悿鐭充簯鏈嶅姟",
+		solution: "鍙傜収缁戝畾娴佺▼",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160016",
+		description: "鍔犲瘑鏈紑鍚紝鏃犻』鍏抽棴",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391109",
+		description: "proxy鎻忚堪绗elect瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110012",
+		description: "绗笁鏂硅处鎴蜂笌钀ょ煶璐﹀彿宸茬粡缁戝畾",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160017",
+		description: "璁惧鎶撳浘澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391201",
+		description: "vtdu鍦板潃鎴栫鍙i潪娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110013",
+		description: "搴旂敤娌℃湁鏉冮檺璋冪敤姝ゆ帴鍙�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160018",
+		description: "璁惧鍗囩骇澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391202",
+		description: "vtdu鐢熸垚鏂囦欢鎻忚堪绗﹀け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110014",
+		description: "APPKEY涓嬪搴旂殑绗笁鏂箄serId鍜宲hone鏈粦瀹�",
+		solution: "鑾峰彇AccessToken鏃舵墍鐢╝ppKey涓嶴DK鎵�鐢╝ppKey涓嶄竴鑷�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160019",
+		description: "鍔犲瘑宸插紑鍚�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391203",
+		description: "vtdu璁剧疆鏂囦欢鎻忚堪绗﹂潪闃诲澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110017",
+		description: "appKey涓嶅瓨鍦�",
+		solution: "璇峰~鍐欏湪瀹樼綉鐢宠鐨勫簲鐢ㄧ閽�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160020",
+		description: "涓嶆敮鎸佽鍛戒护",
+		solution: "璇风‘璁よ澶囨槸鍚︽敮鎸佽鍛戒护",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "391204",
+		description: "vtdu璁剧疆鏂囦欢鎻忚堪绗﹂樆濉炲け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110018",
+		description: "AccessToken涓嶢ppkey涓嶅尮閰�",
+		solution: "璇锋鏌ヨ幏鍙朼ccessToken瀵瑰簲鐨刟ppKey鍜孲DK涓缃殑appKey鏄惁涓�鑷�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160023",
+		description: "璁㈤槄鎿嶄綔澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110019",
+		description: "瀵嗙爜閿欒",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160024",
+		description: "鍙栨秷璁㈤槄鎿嶄綔澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110020",
+		description: "璇锋眰鏂规硶涓虹┖",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160025",
+		description: "瀹㈡祦缁熻閰嶇疆澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110021",
+		description: "ticket鏍¢獙澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160026",
+		description: "璁惧澶勪簬闅愮閬斀鐘舵��",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110022",
+		description: "閫忎紶鐩殑鍦伴潪娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160027",
+		description: "璁惧姝e湪闀滃儚鎿嶄綔",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110024",
+		description: "鏃犻�忎紶鏉冮檺",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160028",
+		description: "璁惧姝e湪閿帶鍔ㄤ綔",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110025",
+		description: "appKey琚姝娇鐢ㄩ�氭槑閫氶亾",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160029",
+		description: "璁惧澶勪簬璇煶瀵硅鐘舵��",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160030",
+		description: "鍗″瘑杈撳叆閿欒娆℃暟杩囧锛�24灏忔椂鍚庡啀杈撳叆",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160031",
+		description: "鍗″瘑淇℃伅涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160032",
+		description: "鍗″瘑鐘舵�佷笉瀵规垨宸茶繃鏈�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160033",
+		description: "鍗″瘑闈炲崠鍝侊紝鍙兘寮�閫氬搴旂殑缁戝畾璁惧",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110030",
+		description: "appKey鍜宎ppSecret涓嶅尮閰�",
+		solution: "璇锋鏌ppKey鍜宎ppSecret鏄惁瀵瑰簲",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160035",
+		description: "璐拱浜戝瓨鍌ㄦ湇鍔″け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110031",
+		description: "瀛愯处鎴锋垨钀ょ煶鐢ㄦ埛娌℃湁鏉冮檺",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160040",
+		description: "娣诲姞鐨勮澶囦笉鍦ㄥ悓涓�灞�鍩熺綉",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110032",
+		description: "瀛愯处鎴蜂笉瀛樺湪",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160041",
+		description: "娣诲姞鐨勮澶囪鍏朵粬璁惧鍏宠仈鎴栧搷搴旇秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110033",
+		description: "瀛愯处鎴锋湭璁剧疆鎺堟潈绛栫暐",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160042",
+		description: "娣诲姞鐨勮澶囧瘑鐮侀敊璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110034",
+		description: "瀛愯处鎴峰凡瀛樺湪",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160043",
+		description: "娣诲姞鐨勮澶囪秴鍑烘渶澶ф暟閲�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110035",
+		description: "鑾峰彇瀛愯处鎴稟ccessToken寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160044",
+		description: "娣诲姞鐨勮澶囩綉缁滀笉鍙揪瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110036",
+		description: "瀛愯处鎴疯绂佺敤",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160045",
+		description: "娣诲姞鐨勮澶囩殑IP鍜屽叾浠栭�氶亾鐨処P鍐茬獊",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "110051",
+		description: "鏃犳潈闄愯繘琛屾姄鍥�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160046",
+		description: "娣诲姞鐨勮澶囩殑IP鍜屾湰璁惧鐨処P鍐茬獊",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160047",
+		description: "鐮佹祦绫诲瀷涓嶆敮鎸�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120002",
+		description: "璁惧涓嶅瓨鍦�",
+		solution: "鈶犺澶囨病鏈夋敞鍐屽埌钀ょ煶浜戝钩鍙帮紝璇锋鏌ヤ笅璁惧缃戠粶鍙傛暟锛岀‘淇濊兘姝e父杩炴帴缃戠粶鈶¤澶囧簭鍒楀彿涓嶅瓨鍦�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160048",
+		description: "甯﹀瓒呭嚭绯荤粺鎺ュ叆甯﹀",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120003",
+		description: "鍙傛暟寮傚父锛孲DK鐗堟湰杩囦綆",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160049",
+		description: "IP鎴栬�呯鍙d笉鍚堟硶",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120004",
+		description: "鍙傛暟寮傚父锛孲DK鐗堟湰杩囦綆",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160050",
+		description: "娣诲姞鐨勮澶囩増鏈笉鏀寔闇�瑕佸崌绾ф墠鑳芥帴鍏�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120005",
+		description: "瀹夊叏璁よ瘉澶辫触锛岄渶杩涜SDK瀹夊叏璁よ瘉",
+		solution: "宸插幓鎺夊畨鍏ㄩ獙璇�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160051",
+		description: "娣诲姞鐨勮澶囦笉鏀寔鎺ュ叆",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120006",
+		description: "缃戠粶寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160052",
+		description: "娣诲姞鐨勮澶囬�氶亾鍙峰嚭閿�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120007",
+		description: "璁惧涓嶅湪绾�",
+		solution: "鍙傝�冩湇鍔′腑蹇冩帓鏌ユ柟娉�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160053",
+		description: "娣诲姞鐨勮澶囧垎杈ㄧ巼涓嶆敮鎸�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120008",
+		description: "璁惧鍝嶅簲瓒呮椂",
+		solution: "璁惧鍝嶅簲瓒呮椂锛岃妫�娴嬭澶囩綉缁滄垨閲嶈瘯",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160054",
+		description: "娣诲姞鐨勮澶囪处鍙疯閿佸畾",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120009",
+		description: "瀛愯处鍙蜂笉鑳芥坊鍔犺澶�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160055",
+		description: "娣诲姞鐨勮澶囧彇鐮佹祦鍑洪敊",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120010",
+		description: "璁惧楠岃瘉鐮侀敊璇�",
+		solution: "楠岃瘉鐮佸湪璁惧鏍囩涓婏紝鍏綅澶у啓瀛楁瘝锛屾敞鎰忓ぇ灏忓啓",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160056",
+		description: "鍒犻櫎璁惧澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120012",
+		description: "璁惧娣诲姞澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160057",
+		description: "鍒犻櫎鐨勮澶囨湭鍏宠仈",
+		solution: "妫�鏌PC涓嶯VR鏄惁鏈夊叧鑱斿叧绯�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120013",
+		description: "璁惧宸茶鍒汉娣诲姞",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160060",
+		description: "鍦板潃鏈粦瀹�",
+		solution: "璇峰墠寰�瀹樼綉璁剧疆鐩存挱",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120014",
+		description: "璁惧搴忓垪鍙蜂笉姝g‘",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160061",
+		description: "璐︽埛娴侀噺宸茶秴鍑烘垨鏈喘涔帮紝闄愬埗寮�閫�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120015",
+		description: "璁惧涓嶆敮鎸佽鍔熻兘",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160062",
+		description: "璇ラ�氶亾鐩存挱宸插紑閫�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120016",
+		description: "褰撳墠璁惧姝e湪鏍煎紡鍖�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160063",
+		description: "鐩存挱鏈娇鐢ㄦ垨鐩存挱宸插叧闂�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120017",
+		description: "璁惧宸茶鑷繁娣诲姞",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160070",
+		description: "璁惧涓嶈兘杞Щ缁欒嚜宸�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120018",
+		description: "璇ョ敤鎴蜂笉鎷ユ湁璇ヨ澶�",
+		solution: "纭璁惧鏄惁灞炰簬鐢ㄦ埛",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160071",
+		description: "璁惧涓嶈兘杞Щ锛岃澶囦笌鍏朵粬璁惧瀛樺湪鍏宠仈鍏崇郴",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400001",
+		description: "鍙傛暟涓虹┖",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120019",
+		description: "璁惧涓嶆敮鎸佷簯瀛樺偍鏈嶅姟",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160072",
+		description: "璁惧涓嶈兘杞Щ锛岄�氶亾琚垎浜粰鍏朵粬鐢ㄦ埛鎴栬�呭垎浜埌瑙嗛骞垮満",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400002",
+		description: "鍙傛暟閿欒",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120020",
+		description: "璁惧鍦ㄧ嚎锛岃鑷繁娣诲姞",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160073",
+		description: "浜戝瓨鍌ㄨ浆绉诲け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400025",
+		description: "璁惧涓嶆敮鎸佸璁�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120021",
+		description: "璁惧鍦ㄧ嚎锛屼絾鏄湭琚敤鎴锋坊鍔�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160080",
+		description: "褰撳墠姝e湪澹版簮瀹氫綅",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400029",
+		description: "娌℃湁鍒濆鍖栨垨璧勬簮琚噴鏀�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120022",
+		description: "璁惧鍦ㄧ嚎锛屼絾鏄凡缁忚鍒殑鐢ㄦ埛娣诲姞",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160081",
+		description: "褰撳墠姝e湪杞ㄨ抗宸¤埅",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400030",
+		description: "json瑙f瀽寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120023",
+		description: "璁惧涓嶅湪绾匡紝鏈鐢ㄦ埛娣诲姞",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160082",
+		description: "璁惧姝e湪鍝嶅簲鏈澹版簮瀹氫綅",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400031",
+		description: "缃戠粶寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120024",
+		description: "璁惧涓嶅湪绾匡紝浣嗘槸宸茬粡琚埆鐨勭敤鎴锋坊鍔�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160083",
+		description: "褰撳墠姝e湪寮�鍚殣绉侀伄钄�",
+		solution: "璁惧姝e湪鎿嶄綔闅愮閬斀锛屾棤娉曡繘琛屽綋鍓嶆搷浣�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400032",
+		description: "璁惧淇℃伅寮傚父涓虹┖",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120025",
+		description: "閲嶅鐢宠鍒嗕韩",
+		solution: "纭璁惧鏄惁鐢辨坊鍔犺繃璇ヨ澶囦笖鐢宠杩囧垎浜殑璐︽埛涓嬫槸鍚﹁繕瀛樺湪鍒嗕韩璁板綍",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "160084",
+		description: "褰撳墠姝e湪鍏抽棴闅愮閬斀",
+		solution: "璁惧姝e湪鎿嶄綔闅愮閬斀锛屾棤娉曡繘琛屽綋鍓嶆搷浣�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400034",
+		description: "鍙栨祦瓒呮椂",
+		solution: "涓�鑸槸鐢变簬缃戠粶鐘跺喌涓嶅ソ瀵艰嚧锛屽彲浠ュ皾璇曚笅璁╃敤鎴烽噸鏂版挱鏀�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120026",
+		description: "瑙嗛骞垮満涓嶅瓨鍦ㄨ瑙嗛",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "380290",
+		description: "銆�杩炴帴CAS鏈嶅姟鍣ㄥけ璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400035",
+		description: "璁惧宸插姞瀵嗭紝闇�瑕佽緭鍏ラ獙璇佺爜",
+		solution: "鏀跺埌姝ら敊璇爜锛岄渶瑕佽鐢ㄦ埛杈撳叆楠岃瘉鐮佸悗锛岃皟鐢‥ZPlayer.setPlayKey浼犲叆楠岃瘉鐮侊紝骞堕噸鏂拌皟鐢ㄦ挱鏀惧嚱鏁�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120027",
+		description: "瑙嗛杞爜澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361001",
+		description: "瀵硅鏈嶅姟绔帓闃熻秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400036",
+		description: "鎾斁楠岃瘉鐮侀敊璇�",
+		solution: "鏀跺埌姝ら敊璇爜锛岄渶瑕佽鐢ㄦ埛杈撳叆楠岃瘉鐮佸悗锛岃皟鐢‥ZPlayer.setPlayKey浼犲叆楠岃瘉鐮侊紝骞堕噸鏂拌皟鐢ㄦ挱鏀惧嚱鏁�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120028",
+		description: "璁惧鍥轰欢鍗囩骇鍖呬笉瀛樺湪",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361002",
+		description: "瀵硅鏈嶅姟绔鐞嗚秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400037",
+		description: "surfacehold閿欒",
+		solution: "璇锋鏌ユ槸鍚︽槸鎾斁涔嬪墠閿�姣佷簡surface锛屾敹鍒版閿欒涔熷彲浠ラ噸鏂板缓绔媠urface鍚庢挱鏀�",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120029",
+		description: "璁惧涓嶅湪绾匡紝浣嗘槸宸茬粡琚嚜宸辨坊鍔�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361003",
+		description: "璁惧閾炬帴瀵硅鏈嶅姟鍣ㄨ秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400100",
+		description: "鏈煡閿欒",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120030",
+		description: "璇ョ敤鎴蜂笉鎷ユ湁璇ヨ棰戝箍鍦鸿棰�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361004",
+		description: "鏈嶅姟鍣ㄥ唴閮ㄩ敊璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400200",
+		description: "player sdk鍑洪敊锛岃繖绉嶉敊璇竴鑸紑鍙戣�呬篃鏄棤娉曡В鍐筹紝涓嶅叿浣撳垎绫讳紶鍑猴紝浼犱竴涓粺涓�鐨刬nner閿欒鐮佸嚭鍘�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120031",
+		description: "寮�鍚粓绔粦瀹氾紝纭欢鐗瑰緛鐮侀獙璇佸け璐�",
+		solution: "璇峰湪钀ょ煶瀹㈡埛绔叧闂粓绔粦瀹氾紝鍙傝�冩姝ラ",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361005",
+		description: "瑙f瀽娑堟伅澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400300",
+		description: "鍐呭瓨婧㈠嚭",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120032",
+		description: "璇ョ敤鎴蜂笅閫氶亾涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361006",
+		description: "璇锋眰閲嶅畾鍚�--闇�瑕佸悜鍏朵粬鏈嶅姟鐢宠瀵硅",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400901",
+		description: "璁惧涓嶅湪绾匡紝鍙互鎻愮ず鐢ㄦ埛",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120033",
+		description: "鏃犳硶鏀惰棌鑷繁鍒嗕韩鐨勮棰�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361007",
+		description: "璇锋眰url闈炴硶",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400902",
+		description: "accesstoken寮傚父鎴栧け鏁堬紝闇�瑕侀噸鏂拌幏鍙朼ccesstoken锛屽苟浼犲叆鍒皊dk",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120034",
+		description: "璇ョ敤鎴蜂笅鏃犺澶�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361008",
+		description: "token澶辨晥",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400903",
+		description: "褰撳墠璐﹀彿寮�鍚簡缁堢缁戝畾锛屽彧鍏佽鎸囧畾璁惧鐧诲綍鎿嶄綔锛屾彁绀虹敤鎴风櫥褰昳.ys7.com瑙i櫎缁堢缁戝畾",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120090",
+		description: "鐢ㄦ埛鍙嶉澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361009",
+		description: "璁惧楠岃瘉鐮佹垨鑰呴�氫俊绉橀挜涓嶅尮閰�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400904",
+		description: "璁惧姝e湪瀵硅涓�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120095",
+		description: "APP鍖呬笅杞藉け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361010",
+		description: "璁惧宸茬粡鍦ㄥ璁�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "400905",
+		description: "璁惧寮�鍚簡闅愮淇濇姢锛屼笉鍏佽棰勮銆佸璁茬瓑",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120096",
+		description: "APP鍖呬俊鎭垹闄ゅけ璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361011",
+		description: "璁惧10s鍝嶅簲瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120101",
+		description: "瑙嗛涓嶆敮鎸佸垎浜粰鏈汉",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361012",
+		description: "璁惧涓嶅湪绾�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320002",
+		description: "鍙傛暟鏃犳晥",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120102",
+		description: "鏃犵浉搴旈個璇蜂俊鎭�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361013",
+		description: "璁惧寮�鍚殣绉佷繚鎶ゆ嫆缁濆璁�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320003",
+		description: "鏆備笉鏀寔姝ゆ搷浣�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120103",
+		description: "濂藉弸宸插瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361014",
+		description: "token鏃犳潈闄�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320004",
+		description: "鍐呭瓨婧㈠嚭",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120104",
+		description: "濂藉弸涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361015",
+		description: "璁惧杩斿洖session涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320005",
+		description: "鍒涘缓CAS session澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120105",
+		description: "濂藉弸鐘舵�侀敊璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361016",
+		description: "楠岃瘉token鍏朵粬寮傚父閿欒",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320006",
+		description: "鍒涘缓cloud session澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120106",
+		description: "瀵瑰簲缇ょ粍涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361017",
+		description: "鏈嶅姟绔洃鍚澶囧缓绔嬬鍙h秴鏃�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320007",
+		description: "token澶辨晥",
+		solution: "閲嶆柊璁剧疆token鍚庡啀閲嶈瘯",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120107",
+		description: "涓嶈兘娣诲姞鑷繁涓哄ソ鍙�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361018",
+		description: "璁惧閾捐矾寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320008",
+		description: "token姹犻噷闈㈡病鏈塼oken,璇蜂紶鍏oken",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120108",
+		description: "褰撳墠鐢ㄦ埛鍜屾墍娣诲姞鐢ㄦ埛涓嶆槸濂藉弸鍏崇郴",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361019",
+		description: "瀵硅鏈嶅姟绔笉鏀寔鐨勪俊浠ゆ秷鎭�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320009",
+		description: "浼犲叆鏂扮殑INIT_PARAM骞秗eset(淇濈暀锛岀洰鍓嶆湭鐢�)",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120109",
+		description: "瀵瑰簲鍒嗕韩涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361020",
+		description: "瀵硅鏈嶅姟绔В鏋愬璁茶姹傛湭鎼哄甫浼氳瘽鎻忚堪鑳藉姏闆�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320010",
+		description: "璇烽噸璇�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120110",
+		description: "濂藉弸缇ょ粍涓嶅睘浜庡綋鍓嶇敤鎴�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361021",
+		description: "瀵硅鏈嶅姟绔紭鍏堣兘鍔涢泦缁撴灉涓虹┖",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320011",
+		description: "500姣鍚庤閲嶈瘯",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120111",
+		description: "濂藉弸涓嶆槸绛夊緟楠岃瘉鐘舵��",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361022",
+		description: "cas閾捐矾寮傚父",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320012",
+		description: "token姹犲凡婊�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120112",
+		description: "娣诲姞搴旂敤涓嬬殑鐢ㄦ埛涓哄ソ鍙嬪け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361023",
+		description: "瀵硅鏈嶅姟绔垎閰嶅璁蹭細璇濊祫婧愬け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320013",
+		description: "P2P client瓒呰繃闄愬埗",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120201",
+		description: "鎿嶄綔鎶ヨ淇℃伅澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "361024",
+		description: "瀵硅鏈嶅姟绔В鏋愪俊浠ゆ秷鎭け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320014",
+		description: "sdk鏈垵濮嬪寲",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120202",
+		description: "鎿嶄綔鐣欒█淇℃伅澶辫触",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390001",
+		description: "閫氱敤閿欒杩斿洖",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320015",
+		description: "瓒呮椂",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120301",
+		description: "鏍规嵁UUID鏌ヨ鎶ヨ娑堟伅涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390002",
+		description: "鍏ュ弬涓虹┖鎸囬拡",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320016",
+		description: "姝e湪鎵撴礊涓�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120302",
+		description: "鏍规嵁UUID鏌ヨ鍥剧墖涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390003",
+		description: "鍏ュ弬鍊兼棤鏁�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320017",
+		description: "娌℃湁瑙嗛鏂囦欢澶�(鎾斁鍣ㄥ眰闈骇鐢熷拰澶勭悊姝ら敊璇�)",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120303",
+		description: "鏍规嵁FID鏌ヨ鍥剧墖涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390004",
+		description: "淇′护娑堟伅瑙f瀽闈炴硶",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320018",
+		description: "瑙g爜閿欒/瓒呮椂(鎾斁鍣ㄥ眰闈骇鐢熷拰澶勭悊姝ら敊璇�)",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120305",
+		description: "璁惧ip瑙f瀽閿欒",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390005",
+		description: "鍐呭瓨璧勬簮涓嶈冻",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320019",
+		description: "鍙栨秷(淇濈暀锛岀敤鎴蜂笉鐢ㄥ鐞�)",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120401",
+		description: "鐢ㄦ埛浜戠┖闂翠俊鎭笉瀛樺湪",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390006",
+		description: "鍗忚鏍煎紡涓嶅鎴栬�呮秷鎭綋闀垮害瓒呰繃STREAM_MAX_MSGBODY_LEN",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320020",
+		description: "鎾斁杩囩▼涓杩炴帴琚敤鎴锋竻闄ら鎿嶄綔淇℃伅",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120402",
+		description: "浜戠┖闂存搷浣滃け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390007",
+		description: "璁惧搴忓垪鍙烽暱搴︿笉鍚堟硶",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320021",
+		description: "娴佸姞瀵嗙爜涓嶅",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120403",
+		description: "鐢ㄦ埛鐩綍涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390008",
+		description: "鍙栨祦url闀垮害涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "320022",
+		description: "鏈紶鍏ユ挱鏀剧獥鍙�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120404",
+		description: "瑕佹搷浣滅殑鐩爣鐩綍涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390009",
+		description: "瑙f瀽vtm杩斿洖vtdu鍦板潃涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "100200",
+		description: "鎿嶄綔鎴愬姛",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120405",
+		description: "瑕佸垹闄ょ殑鏂囦欢淇℃伅涓嶅瓨鍦�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390010",
+		description: "瑙f瀽vtm杩斿洖绾ц仈vtdu鍦板潃涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101001",
+		description: "鐢ㄦ埛鍚嶄笉鍚堟硶",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120406",
+		description: "宸插紑閫氫簯瀛樺偍",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390011",
+		description: "瑙f瀽vtm杩斿洖浼氳瘽鏍囪瘑闀垮害涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101002",
+		description: "鐢ㄦ埛鍚嶅凡琚崰鐢�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120407",
+		description: "寮�閫氳褰曞け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390012",
+		description: "vtdu杩斿洖娴佸ご闀垮害涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101003",
+		description: "瀵嗙爜涓嶅悎娉�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120500",
+		description: "鑾峰彇鏁版嵁閿欒",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390013",
+		description: "vtdu浼氳瘽闀垮害闈炴硶",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101004",
+		description: "瀵嗙爜涓哄悓涓�瀛楃",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120501",
+		description: "寮�閿佸け璐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390014",
+		description: "鍥炶皟鍑芥暟鏈敞鍐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "101006",
+		description: "鎵嬫満鍙风爜宸茬粡琚敞鍐�",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "120502",
+		description: "瀹ゅ唴鏈烘湭鏀跺埌鍛煎彨",
+		solution: "",
+		updateTime: 1522034840000
+	},
+	{
+		moduleCode: "",
+		detailCode: "390015",
+		description: "vtdu鎴愬姛鍝嶅簲鏈惡甯︿細璇濇爣璇�",
+		solution: "",
+		updateTime: 1522034840000
+	}
+];
+var code = "200";
+var msg$1 = "鎿嶄綔鎴愬姛!";
+var errorCode = {
+	data: data$8,
+	code: code,
+	msg: msg$1
+};
+
+var Code = /*#__PURE__*/function () {
+  function Code(x, y) {
+    _classCallCheck$1(this, Code);
+
+    this.coreX = x;
+    this.coreY = y;
+    console.log("ErrorCode", errorCode);
+  }
+
+  _createClass$1(Code, [{
+    key: "toString",
+    value: function toString() {
+      return "".concat(this.coreX, "-").concat(this.coreY);
+    }
+  }, {
+    key: "matchErrorInfo",
+    value: function matchErrorInfo(code) {
+      return errorCode.data.find(function (item) {
+        return item.detailCode.substr(-4) == code;
+      });
+    }
+  }]);
+
+  return Code;
+}();
+
+var header = {
+	color: "red",
+	backgroundColor: "red",
+	activeColor: "red",
+	btnList: [
+		{
+			btnKey: "ade5d065a113432e8091a1c5bc819c57-934f270c08b14e928bf0c2ae8e1a937d-header-0",
+			iconId: "deviceID",
+			part: "left",
+			defaultActive: 1,
+			isrender: 1,
+			themeId: "934f270c08b14e928bf0c2ae8e1a937d"
+		},
+		{
+			btnKey: "ade5d065a113432e8091a1c5bc819c57-934f270c08b14e928bf0c2ae8e1a937d-header-1",
+			iconId: "deviceName",
+			part: "left",
+			defaultActive: 1,
+			isrender: 1,
+			themeId: "934f270c08b14e928bf0c2ae8e1a937d"
+		}
+	]
+};
+var footer = {
+	color: "blue",
+	backgroundColor: "blue",
+	activeColor: "blue",
+	btnList: [
+		{
+			btnKey: "ade5d065a113432e8091a1c5bc819c57-934f270c08b14e928bf0c2ae8e1a937d-footer-0",
+			iconId: "play",
+			part: "left",
+			defaultActive: 0,
+			isrender: 0,
+			themeId: "934f270c08b14e928bf0c2ae8e1a937d"
+		}
+	]
+};
+var defaultTheme = {
+	header: header,
+	footer: footer
+};
+
+// 閫氱敤璇锋眰鏂规硶
+
+var TimeLine$1 = function TimeLine(jsPlugin) {
+  this.jsPlugin = jsPlugin;
+  var status = {
+    isMouseDown: false,
+    // 榧犳爣鏄惁鎸変笅
+    isOver: false,
+    // 榧犳爣鏄惁鎮诞鍦ㄨ繘搴︽潯涓�
+    mousePosition: null,
+    oldTime: null,
+    nowTime: null,
+    moved: null,
+    hoverTime: '2018-12-07 12:00:00',
+    hoverLeft: 0,
+    timeTipShow: false,
+    randomNum: 123,
+    timeWidthTbls: [60, 1800, 3600, 86400],
+    // 鏃堕棿瀹藉害鍗曚綅锛堢锛�
+    timeUnits: ['鑼冨洿: 1鍒嗛挓; 鍗曚綅: 绉�', '鑼冨洿: 30鍒嗛挓; 鍗曚綅: 鍒嗛挓', '鑼冨洿: 1灏忔椂; 鍗曚綅: 鍒嗛挓', '鑼冨洿: 1澶�; 鍗曚綅: 灏忔椂', '鑼冨洿: 3澶�; 鍗曚綅: 灏忔椂'],
+    // 鏃堕棿鍗曚綅
+    drawPen: null,
+    timeSection: [],
+    canvasWidth: null,
+    canvasHeight: null,
+    timeTips: null
+  }; // Object.keys(status).forEach(element => {
+  //     this[element] = status[element];
+  // });
+
+  var _this = this;
+
+  Object.keys(status).forEach(function (element) {
+    _this[element] = status[element];
+  });
+  this.options = {
+    width: this.canvasWidth,
+    height: 48,
+    time: new Date().getTime(),
+    //new Date("2019-10-31 00:00:00"),//
+    timeSection: [],
+    timeWidth: 0 // 0-3
+
+  };
+
+  TimeLine.prototype.subTime = function (time) {
+    if (time < 10) {
+      return '0' + time;
+    } else {
+      return time;
+    }
+  };
+
+  TimeLine.prototype.tranTime = function (time) {
+    var stringTime = time;
+
+    if (time) {
+      var newDate = new Date(time);
+      stringTime = newDate.getFullYear() + '/' + (newDate.getMonth() + 1) + '/' + newDate.getDate() + ' ' + this.subTime(newDate.getHours()) + ':' + this.subTime(newDate.getMinutes()) + ':' + this.subTime(newDate.getSeconds());
+    }
+
+    return stringTime;
+  };
+
+  TimeLine.prototype.init = function (params) {
+    // document.getElementsByTagName("html")[0].addEventListener("mouseup", this.mouseUpFn(e,params.));
+    if (params.width) {
+      document.getElementById(params.id).setAttribute("width", parseInt(params.width, 10) + 'px');
+    }
+
+    var that = this;
+    var opts = this.options;
+    that.randomNum = (Math.random() + '').split('.').join('');
+    that.timeWidthTblIndex = opts.timeWidth; // 褰撳墠浣跨敤鏃堕棿瀹藉害绱㈠紩
+    // 12-10
+    //that.drawPanal = this.$refs.drawPanal;
+
+    var canvas = document.querySelector("#".concat(this.jsPlugin.id, "-canvas"));
+    that.drawPen = canvas.getContext('2d');
+    that.nowTime = opts.time || Date.now(); // 褰撳墠鏃堕棿鐐�
+
+    that.timeSection = opts.timeSection || []; // 鏃堕棿娈佃褰曞尯闂�
+
+    that.canvasWidth = canvas.offsetWidth;
+    that.canvasHeight = canvas.offsetHeight;
+    that.updata(); // 灞曠ず杩涘害鏉�
+    // 浜嬩欢鐩戝惉
+
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).addEventListener('mousemove', function (e) {
+      if (that.options.readOnly) {
+        return;
+      }
+
+      that.mousemove(e);
+    });
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).addEventListener('mouseover', function (e) {
+      if (that.options.readOnly) {
+        return;
+      }
+
+      that.mouseover(e);
+    });
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).addEventListener('mouseleave', function (e) {
+      if (that.options.readOnly) {
+        return;
+      }
+
+      that.mouseleave(e);
+    });
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).addEventListener('mousedown', function (e) {
+      if (that.options.readOnly) {
+        return;
+      }
+
+      that.mousedown(e);
+    });
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).addEventListener('mouseup', function (e) {
+      if (that.options.readOnly) {
+        return;
+      } //debugger
+
+
+      var callback = params.onChange;
+      that.mouseUpFn(e, callback);
+    });
+  };
+
+  TimeLine.prototype.mousemove = function (e) {
+    //  console.log("榧犳爣绉诲姩",e)
+    if (this.isMouseDown && this.isOver) {
+      var mouseOffset = this.mousePosition - e.pageX; // fix鐐瑰嚮寮曡捣mousemove鐨勯棶棰�
+
+      if (mouseOffset === 0) {
+        return;
+      }
+
+      var timeOffsetUnit = 0;
+
+      switch (this.timeWidth) {
+        case 60:
+          timeOffsetUnit = 1 / 10;
+          break;
+
+        case 1800:
+          timeOffsetUnit = 1 / 20 * 60;
+          break;
+
+        case 3600:
+          timeOffsetUnit = 1 / 20 * 60;
+          break;
+
+        case 86400:
+          //timeOffset = 
+          timeOffsetUnit = 1 / 30 * 60 * 60;
+          break;
+      }
+
+      var currentTime = new Date(this.oldTime).getTime() + mouseOffset * timeOffsetUnit * 1000; //console.log("rurrentTime",this.oldTime,mouseOffset,currentTime,new Date(currentTime))
+      //console.log("currentTime", new Date(currentTime))
+      // var currentTime =
+      //     this.oldTime +
+      //     (mouseOffset / this.canvasWidth) *
+      //     this.timeWidth *
+      //     1000;
+      // console.log("currentTime",new Date(this.oldTime), new Date(currentTime))
+
+      this.updata({
+        time: currentTime
+      });
+      this.moved = true;
+    } else {
+      // 12-10
+      //var { left, top } = this.$utils.getOffset(this.$refs.drawPanal);
+      var left = parseInt(document.getElementById("".concat(this.jsPlugin.id, "-canvas-container")).offsetLeft, 10); //12 -10
+
+      this.mousePosition = e.pageX - left;
+      this.updata(); // 鏇存柊鐢婚潰
+    }
+  };
+
+  TimeLine.prototype.mousedown = function (e) {
+    this.isMouseDown = true;
+    this.mousePosition = e.pageX;
+    this.oldTime = this.nowTime; // this.$emit('drag', true);
+  };
+
+  TimeLine.prototype.mouseover = function (e) {
+    this.isOver = true;
+  };
+
+  TimeLine.prototype.mouseleave = function (e) {
+    this.isOver = false;
+    this.isMouseDown = false;
+    this.updata();
+  };
+
+  TimeLine.prototype.changeSize = function (timeWidth) {
+    console.log("changeSize", timeWidth); // if (w) {
+    //     this.options.width = w;
+    //     this.canvasWidth = w;
+    // }
+    // if (h) {
+    //     this.options.height = h;
+    //     this.canvasHeight = h;
+    // }
+    // console.log("tehis.optiosn",this.options)
+
+    this.options.timeWidth = timeWidth;
+    this.updata({
+      timeWidth: timeWidth
+    }); // this.$nextTick(() => {
+    //     this.updata();
+    // });
+  };
+
+  TimeLine.prototype.mouseUpFn = function (e, callback) {
+    if (this.isMouseDown) {
+      this.isMouseDown = false;
+
+      if (this.moved) {
+        this.moved = false; // 闄愬埗鎷栧姩鍙洿鏀规椂鍒嗙
+
+        var newStringTime = // new Date(this.nowTime).getFullYear() +
+        // '/' +
+        // ( new Date(this.nowTime).getMonth() + 1) +
+        // '/' +
+        // new Date(this.nowTime).getDate() +
+        // ' ' +
+        this.subTime(new Date(this.nowTime).getHours()) + ':' + this.subTime(new Date(this.nowTime).getMinutes()) + ':' + this.subTime(new Date(this.nowTime).getSeconds());
+        var oldStringTime = new Date(this.oldTime).getFullYear() + '/' + (new Date(this.oldTime).getMonth() + 1) + '/' + new Date(this.oldTime).getDate(); // ' ' +
+        // this.subTime(new Date(this.oldTime).getHours()) +
+        // ':' +
+        // this.subTime( new Date(this.oldTime).getMinutes()) +
+        // ':' +
+        // this.subTime( new Date(this.oldTime).getSeconds());
+        // this.nowTime = new Date(`${oldStringTime.substring(0,11) + newStringTime.substring(11,19)}`).getTime();
+
+        this.nowTime = new Date("".concat(oldStringTime, " ").concat(newStringTime));
+        this.updata({
+          time: this.nowTime
+        });
+        this.oldTime = this.nowTime;
+        console.log("nowTime", new Date(this.nowTime), "".concat(oldStringTime, " ").concat(newStringTime)); // 闄愬埗鍙兘鎷栧姩褰撳ぉ;
+
+        callback(this.nowTime);
+      }
+    }
+  };
+
+  TimeLine.prototype.readOnly = function (data) {
+    console.log("鏇存敼涓哄彧璇�");
+    this.options.readOnly = true;
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).style.cursor = "not-allowed";
+  };
+
+  TimeLine.prototype.unReadOnly = function (data) {
+    console.log("鏇存敼涓哄彧璇�");
+    this.options.readOnly = false;
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).style.cursor = "pointer";
+  };
+
+  TimeLine.prototype.run = function (data) {
+    if (!this.isMouseDown) {
+      this.updata(data);
+    }
+  };
+
+  TimeLine.prototype.getTime = function (data) {
+    console.log("this", this);
+    console.log("褰撳墠鏃堕棿", new Date(this.nowTime));
+  };
+
+  TimeLine.prototype.updata = function (data) {
+    var that = this;
+    data = data || {};
+    that.nowTime = data.time || that.nowTime;
+    that.timeSection = data.timeSection || that.timeSection;
+    that.timeWidthTblIndex = data.timeWidth || that.timeWidthTblIndex;
+    that.timeWidth = that.timeWidthTbls[data.timeWidth || that.timeWidthTblIndex];
+    that.timeUnit = that.timeUnits[data.timeWidth || that.timeWidthTblIndex];
+
+    if (data.timeWidth === 0) {
+      that.timeWidthTblIndex = 0;
+      that.timeWidth = that.timeWidthTbls[0];
+      that.timeUnit = that.timeUnits[0];
+    }
+
+    that.drawPen.fillStyle = '#000000';
+    that.drawPen.fillRect(0, 0, that.canvasWidth, that.canvasHeight);
+    that.drawScale(); // 鐢诲埢搴�
+
+    that.drawRecord(); // 鐢诲綍鍍忓尯闂�
+
+    that.drawOtherMsg(); // 鐢诲綍鍍忕殑鍏朵粬淇℃伅
+    // 12-10
+    //that.$emit('update-time', that.nowTime);
+
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas-container")).style.width = this.options.width + 'px';
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).style.width = this.options.width + 'px';
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas-container")).style.height = this.options.height + 'px';
+    document.getElementById("".concat(this.jsPlugin.id, "-canvas")).style.height = this.options.height + 'px';
+  };
+
+  TimeLine.prototype.drawSolidLine = function (startX, startY, endX, endY, lineWidth, color) {
+    this.drawPen.save();
+    this.drawPen.strokeStyle = color;
+    this.drawPen.lineWidth = lineWidth;
+    this.drawPen.beginPath();
+    this.drawPen.moveTo(startX, startY);
+    this.drawPen.lineTo(endX, endY);
+    this.drawPen.stroke();
+    this.drawPen.restore();
+  };
+
+  TimeLine.prototype.drawString = function (text, x, y, aling, color) {
+    this.drawPen.font = '12px serif';
+    this.drawPen.fillStyle = '#ffffff';
+    this.drawPen.textAlign = aling || 'left';
+    this.drawPen.fillText(text, x, y + 10);
+  };
+
+  TimeLine.prototype.drawScale = function () {
+    // console.log("drawScale",new Date(this.nowTime))
+    var that = this;
+    var lineColor = 'rgba(255,255,255)'; //that.nowTime = new Date("2019-12-31 01:50:00")
+
+    var startDate = new Date(that.nowTime); // 寮�濮嬫椂闂�
+
+    var startYears = startDate.getFullYear(); // 璧峰鐨勭鏁�
+
+    var starSecond = startDate.getSeconds(); // 璧峰鐨勭鏁�
+
+    var starMin = startDate.getMinutes(); // 璧峰鐨勫垎閽熸暟
+
+    var startHours = startDate.getHours(); // 璧峰鐨勫皬鏃�
+
+    var startDay = startDate.getDate(); // 璧峰鐨勬棩鏈�
+    // debugger;
+
+    var curScale = 0; // 璁$畻鏃堕棿鐐�
+
+    switch (that.timeWidth) {
+      case 60:
+        {
+          // debugger
+          var dotNum = parseInt(that.canvasWidth / 10); // 姣�10鍍忕礌涓�涓偣
+
+          startDate.setSeconds(startDate.getSeconds() - parseInt(dotNum / 2, 10)); // 浠庣幇鍦ㄦ椂闂寸殑涓�鍗婂紑濮嬬敾璧�
+
+          startDay = startDate.getDate();
+          startHours = startDate.getHours();
+          starMin = startDate.getMinutes();
+          starSecond = startDate.getSeconds(); // console.log("domNum",dotNum);
+          // console.log("starSecond",starSecond)
+
+          for (var i = 0; i < dotNum; i++) {
+            curScale = starSecond + i;
+            startDate.setSeconds(curScale); // debugger;
+            //debugger;
+            // console.log("startDate",startDate,curScale)
+            // 姣忎竴涓暣10绉掔敾涓�娆$嚎鍜屾枃瀛�
+
+            if (curScale % 10 === 0) {
+              that.drawSolidLine(i * that.canvasWidth / dotNum, 8, i * that.canvasWidth / dotNum, that.canvasHeight / 5 + 8, 1, lineColor);
+              var timeString = this.subTime(startDate.getHours()) + ':' + this.subTime(startDate.getMinutes()) + ':' + this.subTime(startDate.getSeconds());
+              that.drawString(timeString, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 2.5, 'center', 'rgba(255,255,255,0.3)'); // console.log("timeString",timeString)
+            } else {
+              // console.log("鐢荤煭绾�",(i * that.canvasWidth) / 60,0,(i * that.canvasWidth) / 60,(that.canvasHeight / 5) * 0.5,1)
+              // 鍙敾涓�娆$嚎
+              that.drawSolidLine(i * that.canvasWidth / dotNum, 8, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 0.5 + 8, 1, lineColor);
+            }
+            /**
+             * 鍋忕Щ璺濈瓒呰繃60锛宻etSeconds浼氭瘡娆$疮鍔�1鍒板垎閽燂紝鍥犳缁樺浘瀹屾垚鍚庨渶瑕佸鍘熷埌褰撳墠鍒嗛挓锛屽啀娆¤绠楀亸绉�
+             */
+
+
+            startDate.setDate(startDay);
+            startDate.setHours(startHours);
+            startDate.setMinutes(starMin);
+          }
+
+          break;
+        }
+
+      case 1800:
+        {
+          // 30鍒嗛挓
+          var dotNum = parseInt(that.canvasWidth / 20); // 姣�10鍍忕礌涓�涓偣
+
+          startDate.setMinutes(startDate.getMinutes() - parseInt(dotNum / 2, 10)); // starSecond = startDate.getSeconds();
+
+          startHours = startDate.getHours();
+          starMin = startDate.getMinutes(); //console.log("dotNum",dotNum,starMin)
+
+          for (var i = 0; i <= dotNum; i++) {
+            curScale = starMin + i;
+            startDate.setMinutes(curScale);
+
+            if (curScale % 5 === 0) {
+              that.drawSolidLine(i * that.canvasWidth / dotNum, 8, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 1.5 + 8, 1, lineColor);
+              var timeString = this.subTime(startDate.getHours()) + ':' + this.subTime(startDate.getMinutes());
+              that.drawString(timeString, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 2.5, 'center', 'rgba(255,255,255,0.3)');
+            } else {
+              // console.log("鐢荤煭绾�",((i - starMin) * that.canvasWidth) / dotNum)
+              that.drawSolidLine(i * that.canvasWidth / dotNum, 8, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 0.5 + 8, 1, lineColor);
+            }
+
+            startDate.setHours(startHours);
+          }
+
+          break;
+        }
+
+      case 3600:
+        {
+          // 60鍒嗛挓
+          var dotNum = parseInt(that.canvasWidth / 20); // 姣�10鍍忕礌涓�涓偣
+
+          startDate.setMinutes(startDate.getMinutes() - parseInt(dotNum / 2, 10));
+          startHours = startDate.getHours();
+          starMin = startDate.getMinutes();
+
+          for (var i = 0; i <= dotNum; i++) {
+            curScale = starMin + i; // if (curScale > 60) {
+            //     curScale = curScale - 60;
+            // }
+
+            startDate.setMinutes(curScale);
+
+            if (curScale % 10 === 0) {
+              that.drawSolidLine(i * that.canvasWidth / dotNum, 8, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 1.5 + 8, 1, lineColor);
+              var timeString = this.subTime(startDate.getHours()) + ':' + this.subTime(startDate.getMinutes());
+              that.drawString(timeString, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 2.5, 'center', 'rgba(255,255,255,0.3)');
+            } else {
+              that.drawSolidLine(i * that.canvasWidth / dotNum, 8, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 0.5 + 8, 1, lineColor);
+            }
+
+            startDate.setHours(startHours);
+          }
+
+          break;
+        }
+
+      case 86400:
+        {
+          var dotNum = parseInt(that.canvasWidth / 30); // 姣�10鍍忕礌涓�涓偣
+          // 1澶╋紝24灏忔椂
+          //console.log("dotNum",dotNum);
+          //startDate.setDate(startDay  - parseInt(dotNum / 2,10));
+
+          startDate.setHours(startDate.getHours() - parseInt(dotNum / 2, 10)); // console.log("startDat111e",startDate);
+          // debugger;
+
+          starSecond = startDate.getSeconds();
+          starMin = startDate.getMinutes();
+          startHours = startDate.getHours();
+          startDay = startDate.getDate();
+          startYears = startDate.getFullYear();
+
+          for (var i = 0; i <= dotNum; i++) {
+            curScale = startHours + i; // if (curScale >= 24) {
+            //     curScale = curScale - 24;
+            // }
+
+            startDate.setHours(curScale);
+            var timeString; // 涓嶇瓑浜�24鐨勬椂鍊欙紝鐢荤煭绾�
+            //console.log("curScale",curScale)
+            //if (curScale % 24 !=0) {
+            //  console.log("curScale",curScale)
+
+            timeString = this.subTime(startDate.getHours()) + ":00"; // timeString = startDate.toLocaleDateString();
+            // debugger
+
+            that.drawSolidLine(i * that.canvasWidth / dotNum, 8, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 0.5 + 8, 1, lineColor); // } else {
+            //     // debugger;
+            //     // console.log("鐢诲浘")
+            //     // 涓嶇瓑浜�24鐨勬椂鍊欙紝鐢婚暱绾�
+            //     timeString = startDate.toLocaleDateString();
+            //     // console.log("startDatestartDate",startDate,i)
+            //     // debugger;
+            //     that.drawSolidLine(
+            //         ((i ) * that.canvasWidth) /
+            //         dotNum,
+            //         8,
+            //         ((i) * that.canvasWidth) /
+            //         dotNum,
+            //         (that.canvasHeight / 5) * 1 + 8,
+            //         1,
+            //         lineColor
+            //     );
+            // }
+            // 姣�2涓皬鏃朵竴涓椂闂存枃瀛�
+
+            if (curScale % 2 === 0) {
+              that.drawString(timeString, i * that.canvasWidth / dotNum, that.canvasHeight / 5 * 2, 'center', 'rgba(255,255,255,0.3)');
+            }
+
+            startDate.setFullYear(startYears);
+            startDate.setDate(startDay);
+            startDate.setHours(startHours);
+          }
+
+          break;
+        }
+    }
+  };
+
+  TimeLine.prototype.getRecord = function (timeArr, startTime, endTime) {
+    this.timeSection = timeArr;
+    this.drawRecord();
+  };
+
+  TimeLine.prototype.drawRecord = function () {
+    var timeArr = this.timeSection || [];
+    var that = this;
+    var drawPen = that.drawPen; // var startDate = new Date(that.nowTime);
+    // var timeScale = that.canvasWidth / that.timeWidth;
+    // 鏍规嵁鏃堕棿鏌ユ壘褰撳墠浣嶇疆
+
+    for (var i = 0; i < timeArr.length; i++) {
+      //console.log("timeArr[i]",timeArr[i],findPosition(timeArr[i].startTime),findPosition(timeArr[i].endTime))
+      var startPosition = findPosition(timeArr[i].startTime);
+      var endPosition = findPosition(timeArr[i].endTime);
+      drawPen.fillStyle = '#1890ff80';
+      drawPen.fillRect(startPosition, 0, endPosition - startPosition, 48);
+    }
+
+    function findPosition(time) {
+      var scale = 10;
+
+      switch (that.timeWidth) {
+        case 60:
+          scale = 10;
+          break;
+
+        case 1800:
+          scale = 20 / 60;
+          break;
+
+        case 3600:
+          scale = 20 / 60;
+          break;
+
+        case 86400:
+          scale = 20 / 60 / 60;
+          break;
+      }
+
+      var nowTimePostion = that.canvasWidth / 2; //鎬诲搴︿竴鍗�
+
+      var position = nowTimePostion + (time - that.nowTime) / 1000 * scale;
+
+      if (position > that.canvasWidth) {
+        position = that.canvasWidth;
+      }
+
+      if (position <= 0) {
+        position = 0;
+      }
+
+      return position;
+    }
+  };
+
+  TimeLine.prototype.drawOtherMsg = function () {
+    // 鐢讳腑蹇冪嚎
+    this.drawSolidLine(this.canvasWidth / 2, 0, this.canvasWidth / 2, this.canvasHeight, 2, '#1890FF');
+    this.drawPen.shadowBlur = 0;
+
+    if (this.isOver && !this.isMouseDown) {
+      this.mouseTime = this.mousePosition / this.canvasWidth * this.timeWidth * 1000 + this.nowTime - this.timeWidth / 2 * 1000; // 榧犳爣鐨勬偓娴偣瀵瑰簲鐨勬椂闂�
+
+      this.mouseString = this.tranTime(this.mouseTime); // 榧犳爣鎮诞鐐规樉绀虹殑鏂囧瓧
+
+      this.hoverTime = this.mouseString;
+      this.hoverLeft = this.mousePosition - 60;
+      this.timeTipShow = true;
+    } else {
+      this.timeTipShow = false;
+    }
+  };
+};
+
+var Rec = /*#__PURE__*/function () {
+  function Rec(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, Rec);
+
+    this.jSPlugin = jSPlugin;
+
+    if (!document.getElementById("".concat(this.jSPlugin.id, "-audioControls"))) {
+      return false;
+    }
+
+    this.currentTimeWidth = 1; //鍥炴斁鏃堕棿杞村昂搴� 1~4
+
+    this.timer = null;
+    this.date = new Date();
+    this.datepickerVisible = false;
+    this.seekTimer = null;
+    this.disabled = false;
+    this.seekFrequency = 2000;
+
+    if (this.jSPlugin.params && this.jSPlugin.params.seekFrequency) {
+      this.seekFrequency = this.jSPlugin.params.seekFrequency;
+    }
+
+    var canvasItemWidth = parseInt(getComputedStyle(document.getElementById(jSPlugin.id)).width, 10) - 100;
+    var canvasContainer = document.createElement('div');
+    canvasContainer.style = "display:inline-block;height:48px;";
+    canvasContainer.id = this.jSPlugin.id + "-canvas-container";
+    var canvasItem = document.createElement('canvas');
+    canvasItem.id = this.jSPlugin.id + "-canvas";
+    canvasItem.className = "time-line-body";
+    canvasItem.height = "48";
+    canvasItem.width = canvasItemWidth;
+    canvasItem.style = "display:inline-block;";
+    canvasItem.innerHTML = "璇ユ祻瑙堝櫒涓嶆敮鎸乧anvas";
+    canvasContainer.appendChild(canvasItem);
+    insertAfter$1(canvasContainer, document.getElementById("".concat(this.jSPlugin.id, "-audioControls")));
+    var timeLineControlsContainer = document.createElement('div');
+    timeLineControlsContainer.className = "timeline-controls";
+    timeLineControlsContainer.style = "display:flex;width:100px;height:48px;text-align:center;line-height: 48px;vertical-align: top;background: #000000;";
+    var timeLineControls = "\n<div class=\"timeline-controls-scale\" style=\"display: inline-flex;flex-direction: column;justify-content: center;vertical-align: top;padding: 0 20px;\">\n  <span style=\"vertical-Align: middle;line-height: 14px;height: 18px; width: 18px;cursor:pointer;\" id=\"".concat(this.jSPlugin.id, "-timeline-scale-add\">\n    <svg fill=\"#2C2C2C\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\"\n      viewBox=\"0 0 20 20\">\n      <title>add</title>\n      <g>\n        <polygon points=\"0.1,0.5 15,0.5 15,15.4 0.1,15.4 \t\" />\n      </g>\n      <g>\n        <path\n          fill=\"#FFFFFF\";\n          d=\"M7.6,12.4c-0.3,0-0.5-0.2-0.5-0.5v-8c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5v8C8.1,12.2,7.9,12.4,7.6,12.4z\" />\n      </g>\n      <g>\n        <path\n          fill=\"#FFFFFF\";\n          d=\"M11.6,8.4h-8c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h8c0.3,0,0.5,0.2,0.5,0.5S11.8,8.4,11.6,8.4z\" />\n      </g>\n    </svg>\n  </span>\n  <span style=\"vertical-Align: middle;line-height: 14px;height: 18px; width: 18px;cursor:pointer;\" id=\"").concat(this.jSPlugin.id, "-timeline-scale-sub\">\n    <svg fill=\"#2C2C2C\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\"\n      viewBox=\"0 0 20 20\">\n      <title>reduce</title>\n      <g>\n        <polygon class=\"st0\" points=\"1,0.8 15.2,0.8 15.2,15 1,15 \t\" />\n      </g>\n      <g>\n        <path class=\"st1\"\n          fill=\"#FFFFFF\";\n          d=\"M12.1,8.4h-8c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h8c0.3,0,0.5,0.2,0.5,0.5S12.4,8.4,12.1,8.4z\" />\n      </g>\n    </svg>\n  </span>\n</div>\n<label for=\"").concat(this.jSPlugin.id, "-datepicker\">\n  <div class=\"timeline-controls-date\">\n    <span>\n      <svg fill=\"#2C2C2C\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\"\n        viewBox=\"0 0 20 20\">\n        <title>ifttt</title>\n        <g id=\"Rectangle\">\n          <rect x=\"0.6\" y=\"0.9\" class=\"st0\" width=\"20\" height=\"20\" />\n        </g>\n        <g id=\"Stroke-1\">\n          <path fill=\"#FFFFFF\"; class=\"st1\"\n            d=\"M14,7.2c-0.3,0-0.5-0.2-0.5-0.5V3.4c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5v3.3C14.5,7,14.2,7.2,14,7.2z\" />\n        </g>\n        <g id=\"Stroke-3\">\n          <path fill=\"#FFFFFF\"; class=\"st1\"\n            d=\"M7.3,7.2C7,7.2,6.8,7,6.8,6.7V3.4c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5v3.3C7.8,7,7.6,7.2,7.3,7.2z\" />\n        </g>\n        <g id=\"Stroke-5\">\n          <path fill=\"#FFFFFF\"; class=\"st1\"\n            d=\"M18.1,9.7h-15c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h15c0.3,0,0.5,0.2,0.5,0.5S18.4,9.7,18.1,9.7z\" />\n        </g>\n        <g id=\"Stroke-7\">\n          <path fill=\"#FFFFFF\"; class=\"st1\" d=\"M16.5,19.7H4.8c-1.2,0-2.2-1-2.2-2.2V6.7c0-1.2,1-2.2,2.2-2.2h11.7c1.2,0,2.2,1,2.2,2.2v10.8\nC18.6,18.8,17.7,19.7,16.5,19.7z M4.8,5.6c-0.6,0-1.2,0.5-1.2,1.2v10.8c0,0.6,0.5,1.2,1.2,1.2h11.7c0.6,0,1.2-0.5,1.2-1.2V6.7\nc0-0.6-0.5-1.2-1.2-1.2H4.8z\" />\n        </g>\n        <g id=\"Stroke-9\">\n          <path fill=\"#FFFFFF\"; class=\"st1\" d=\"M10.6,13.3c-0.4,0-0.7-0.3-0.7-0.7c0-0.2,0.1-0.4,0.2-0.5s0.3-0.2,0.5-0.2h0h0c0.4,0,0.7,0.3,0.7,0.7\nS11,13.3,10.6,13.3z\" />\n        </g>\n        <g id=\"Stroke-11\">\n          <path fill=\"#FFFFFF\"; class=\"st1\" d=\"M14.8,13.3c-0.4,0-0.7-0.3-0.7-0.7c0-0.2,0.1-0.4,0.2-0.5c0.1-0.1,0.3-0.2,0.5-0.2c0.4,0,0.7,0.3,0.7,0.7\nS15.2,13.3,14.8,13.3z M14.8,12.3c-0.2,0-0.3,0.1-0.3,0.3c0,0.2,0.3,0.4,0.5,0.2c0.1-0.1,0.1-0.1,0.1-0.2\nC15.1,12.4,15,12.3,14.8,12.3z\" />\n        </g>\n        <g id=\"Stroke-13\">\n          <path fill=\"#FFFFFF\"; class=\"st1\" d=\"M6.5,16.6c-0.4,0-0.7-0.3-0.7-0.7c0-0.2,0.1-0.4,0.2-0.5c0.1-0.1,0.3-0.2,0.5-0.2h0h0c0.4,0,0.7,0.3,0.7,0.7\nC7.2,16.3,6.9,16.6,6.5,16.6z\" />\n        </g>\n        <g id=\"Stroke-15\">\n          <path fill=\"#FFFFFF\"; class=\"st1\" d=\"M10.6,16.6c-0.4,0-0.7-0.3-0.7-0.7c0-0.2,0.1-0.4,0.2-0.5c0.1-0.1,0.3-0.2,0.5-0.2h0h0c0.4,0,0.7,0.3,0.7,0.7\nC11.4,16.3,11,16.6,10.6,16.6z\" />\n        </g>\n      </svg>\n    </span>\n  </div>\n</label>\n<input data-toggle=\"").concat(this.jSPlugin.id, "-datepicker\" id=\"").concat(this.jSPlugin.id, "-datepicker\" name=\"").concat(this.jSPlugin.id, "-datepicker\" style=\"opacity:0;width:24px;margin-left:-24px;cursor:pointer;\" />\n");
+    timeLineControlsContainer.innerHTML = timeLineControls;
+    insertAfter$1(timeLineControlsContainer, canvasContainer);
+    this.timeLine = new TimeLine$1(this.jSPlugin);
+    this.timeLine.init({
+      id: this.jSPlugin.id + '-canvas',
+      width: canvasItemWidth,
+      onChange: function onChange(time) {
+        console.log("time", time, new Date(time).Format('yyyyMMddhhmmss'));
+        var newBegin = new Date(time).Format('yyyyMMddhhmmss');
+
+        if (matchEzopenUrl(_this.jSPlugin.url).type === 'cloud.rec') {
+          var cloudSeek = function cloudSeek() {
+            _this.jSPlugin.seek(newBegin.substr(8, 6), "235959");
+
+            _this.unSyncTimeLine();
+
+            setTimeout(function () {
+              _this.syncTimeLine();
+            }, 6000);
+          };
+
+          if (_this.seekTimer) {
+            clearTimeout(_this.seekTimer);
+          } else {
+            cloudSeek();
+          } // 闄愬埗姣�2绉掑彧瑙﹀彂涓�娆℃嫋鍔�
+
+
+          _this.seekTimer = setTimeout(function () {
+            cloudSeek();
+            clearTimeout(_this.seekTimer);
+            _this.seekTimer = null;
+          }, _this.seekFrequency);
+        } else {
+          var callback = function callback() {
+            setTimeout(function () {
+              _this.disabled = false;
+            }, _this.seekFrequency);
+          };
+
+          var localRecSeek = function localRecSeek(callback) {
+            _this.disabled = true;
+
+            _this.jSPlugin.pause().then(function () {
+              console.log("鏆傚仠鎴愬姛");
+
+              _this.jSPlugin.resume(newBegin).then(function (data) {
+                console.log("鎭㈠鎴愬姛");
+
+                if (_this.jSPlugin.Theme) {
+                  _this.jSPlugin.Theme.setDecoderState({
+                    play: true
+                  });
+                }
+
+                if (callback) {
+                  callback();
+                }
+              })["catch"](function (err) {
+                console.log("鎭㈠澶辫触", err);
+              });
+            })["catch"](function () {
+              console.log("鏆傚仠澶辫触");
+
+              _this.jSPlugin.resume(newBegin).then(function (data) {
+                console.log("鎭㈠鎴愬姛");
+
+                if (_this.jSPlugin.Theme) {
+                  _this.jSPlugin.Theme.setDecoderState({
+                    play: true
+                  });
+                }
+
+                if (callback) {
+                  callback();
+                }
+              })["catch"](function (err) {
+                console.log("鎭㈠澶辫触", err);
+              });
+            });
+          };
+
+          if (_this.disabled) {
+            console.log("鎿嶄綔棰戠箒锛岀瓑寰�2绉掑悗鎵ц"); // 闄愬埗姣�2绉掑彧瑙﹀彂涓�娆℃嫋鍔�
+
+            if (_this.seekTimer) {
+              clearTimeout(_this.seekTimer);
+            }
+
+            _this.seekTimer = setTimeout(function () {
+              localRecSeek(callback);
+            }, _this.seekFrequency);
+          } else {
+            localRecSeek(callback);
+          }
+        }
+      }
+    });
+    this.syncTimeLine(); // 鍔犺浇鏃ユ湡閫夋嫨鍣�
+
+    addCss("".concat(this.jSPlugin.staticPath, "/rec/datepicker.min.css"));
+    addJs("".concat(this.jSPlugin.staticPath, "/rec/jquery.min.js"), function () {
+      addJs("".concat(_this.jSPlugin.staticPath, "/rec/datepicker.js"), function () {
+        addJs("".concat(_this.jSPlugin.staticPath, "/rec/datepicker.zh-CN.js"), function () {
+          // 鏃ユ湡閫夋嫨锛�
+          if (!document.getElementsByClassName("datepicker-container")[0]) {
+            $("#".concat(_this.jSPlugin.id, "-datepicker")).datepicker({
+              autoShow: false,
+              autoHide: true,
+              autoPick: true,
+              language: 'zh-CN',
+              defaultDate: new Date(),
+              format: 'yyyy-mm-dd',
+              endDate: new Date(),
+              inline: true,
+              container: document.getElementById("".concat(_this.jSPlugin.id, "-wrap"))
+            });
+          }
+
+          if (document.getElementsByClassName("datepicker-container")[0]) {
+            document.getElementsByClassName("datepicker-container")[0].style.display = "none";
+          }
+
+          _this.datepickerVisible = false;
+          $("#".concat(_this.jSPlugin.id, "-datepicker")).on('pick.datepicker', function (e) {
+            console.log("閲嶆柊閫夋嫨鏃ユ湡", e.date, new Date(e.date).Format('yyyyMMdd'), new Date(document.getElementById("".concat(_this.jSPlugin.id, "-datepicker")).value).Format('yyyyMMdd'));
+
+            if (e.date > new Date() || new Date(e.date).Format('yyyyMMdd') === new Date(document.getElementById("".concat(_this.jSPlugin.id, "-datepicker")).value).Format('yyyyMMdd')) {
+              e.preventDefault(); // Prevent to pick the date
+            } else {
+              _this.renderRec(e.date);
+
+              _this.jSPlugin.changePlayUrl({
+                begin: new Date(e.date).Format('yyyyMMdd')
+              });
+            }
+
+            if (document.getElementsByClassName("datepicker-container")[0]) {
+              document.getElementsByClassName("datepicker-container")[0].style.display = "none";
+            }
+
+            _this.datepickerVisible = false;
+          });
+          $("#".concat(_this.jSPlugin.id, "-datepicker")).off('click').on("click", function (e) {
+            console.log("鐐瑰嚮鏃ユ湡");
+
+            if (!_this.datepickerVisible) {
+              if (document.getElementsByClassName("datepicker-container")[0]) {
+                document.getElementsByClassName("datepicker-container")[0].style.display = "inline";
+              }
+            } else {
+              if (document.getElementsByClassName("datepicker-container")[0]) {
+                document.getElementsByClassName("datepicker-container")[0].style.display = "none";
+              }
+            }
+
+            _this.datepickerVisible = !_this.datepickerVisible;
+          });
+        });
+      });
+    }); // 灏哄害鍙樺寲鐩戝惉
+
+    document.getElementById("".concat(this.jSPlugin.id, "-timeline-scale-add")).onclick = function () {
+      var currentTimeWidth = _this.currentTimeWidth;
+
+      if (currentTimeWidth < 3) {
+        _this.timeLine.changeSize(++_this.currentTimeWidth);
+      }
+    };
+
+    document.getElementById("".concat(this.jSPlugin.id, "-timeline-scale-sub")).onclick = function () {
+      var currentTimeWidth = _this.currentTimeWidth;
+
+      if (currentTimeWidth > 0) {
+        _this.timeLine.changeSize(--_this.currentTimeWidth);
+      }
+    }; // 娓叉煋鍥炴斁
+
+
+    var initDate = getQueryString("begin", this.jSPlugin.url) || new Date().Format('yyyyMMdd');
+    this.renderRec("".concat(initDate.slice(0, 4), "-").concat(initDate.slice(4, 6), "-").concat(initDate.slice(6, 8)));
+    this.observer = new MutationObserver(function (mutations, observer) {
+      _this.recAutoSize();
+    });
+    var config = {
+      attributes: true,
+      attributeOldValue: true,
+      attributeFilter: ['style']
+    };
+    var el = document.getElementById("".concat(this.jSPlugin.id));
+    this.observer.observe(el, config);
+  }
+
+  _createClass$1(Rec, [{
+    key: "recAutoSize",
+    value: function recAutoSize() {
+      var _this2 = this;
+
+      if (document.getElementById("".concat(this.jSPlugin.id, "-canvas"))) {
+        var canvasItemWidth = parseInt(getComputedStyle(document.getElementById(this.jSPlugin.id)).width, 10) - 100;
+
+        if (canvasItemWidth !== parseInt(document.getElementById("".concat(this.jSPlugin.id, "-canvas")).width)) {
+          document.getElementById("".concat(this.jSPlugin.id, "-canvas")).width = canvasItemWidth;
+          this.timeLine.init({
+            id: "".concat(this.jSPlugin.id, "-canvas"),
+            width: canvasItemWidth,
+            onChange: function onChange(time) {
+              console.log("time", time, new Date(time).Format('yyyyMMddhhmmss'));
+              console.log("jSPlugin", _this2.jSPlugin);
+              var newBegin = new Date(time).Format('yyyyMMddhhmmss');
+
+              _this2.jSPlugin.changePlayUrl({
+                begin: newBegin
+              });
+            }
+          });
+          this.renderRec(this.date);
+        }
+      }
+    }
+  }, {
+    key: "renderRec",
+    value: function renderRec(date) {
+      var _this3 = this;
+
+      this.date = date;
+      var dateStart = new Date(new Date(date).Format('yyyy-MM-dd 00:00:00').replace(/-/g, "/")).getTime();
+      var dateEnd = new Date(new Date(date).Format('yyyy-MM-dd 23:59:59').replace(/-/g, "/")).getTime();
+      this.timeLine.getRecord([], dateStart, dateEnd);
+      var recSliceParams = {
+        accessToken: this.jSPlugin.accessToken,
+        recType: matchEzopenUrl(this.jSPlugin.url).type === 'cloud.rec' ? 1 : 2,
+        deviceSerial: matchEzopenUrl(this.jSPlugin.url).deviceSerial,
+        channelNo: matchEzopenUrl(this.jSPlugin.url).channelNo,
+        startTime: dateStart,
+        endTime: dateEnd,
+        version: '2.0'
+      };
+
+      var recAPISuccess = function recAPISuccess(data) {
+        if (data.data && data.data.files && data.data.files.length > 0) {
+          var dataArr = data.data.files;
+          var nextFileTime = new Date().getTime();
+          var isAll = data.data.isAll;
+
+          if (isAll) {
+            _this3.timeLine.getRecord(dataArr, dateStart, dateEnd);
+          } else {
+            // 浜戝瓨鍌ㄥ洖璋冧簨鍔�
+            var recTransaction = function recTransaction() {
+              function recAPIV2Success(data) {
+                if (data.data && data.data.files && data.data.files.length > 0) {
+                  if (data.data.isAll == false) {
+                    if (data.data.files) {
+                      dataArr = dataArr.concat(data.data.files);
+                    }
+
+                    nextFileTime = data.data.nextFileTime > 0 ? data.data.nextFileTime : new Date().getTime();
+                    recTransaction();
+                  } else {
+                    console.log("浜戝瓨鍌ㄦ墽琛屾覆鏌撶墖娈�");
+                    this.timeLine.getRecord(dataArr, dateStart, dateEnd);
+                  }
+                } else {
+                  this.timeLine.getRecord(dataArr, dateStart, dateEnd);
+                }
+              }
+
+              recSliceParams.startTime = nextFileTime;
+              request(this.jSPlugin.env.domain + "/api/lapp/video/by/time", 'POST', recSliceParams, '', recAPIV2Success);
+            };
+
+            recTransaction();
+          }
+
+          _this3.timeLine.run({
+            time: new Date(dateStart)
+          });
+        } else if (data.data && data.data.length > 0) {
+          console.log("鑾峰彇鏈湴褰曞儚鐗囨鎴愬姛", data);
+
+          _this3.timeLine.getRecord(data.data, dateStart, dateEnd);
+
+          _this3.timeLine.run({
+            time: new Date(dateStart)
+          });
+        } else ;
+      };
+
+      var recAPIUrl = this.jSPlugin.env.domain + "/api/lapp/video/by/time";
+      request(recAPIUrl, 'POST', recSliceParams, '', recAPISuccess);
+    }
+  }, {
+    key: "syncTimeLine",
+    value: function syncTimeLine() {
+      var _this4 = this;
+
+      if (this.timer) {
+        clearInterval(this.timer);
+      }
+
+      this.timer = setInterval(function () {
+        var getOSDTimePromise = _this4.jSPlugin.getOSDTime();
+
+        getOSDTimePromise.then(function (data) {
+          var v = data.data;
+
+          if (v === -1) {
+            console.log("鑾峰彇鎾斁鏃堕棿閿欒");
+          } else {
+            if (v > 0) {
+              //console.log("鑾峰彇鎾斁鏃堕棿", v, this.timeLine.run);
+              _this4.timeLine.run({
+                time: new Date(v > 1000000000000 ? v : v * 1000)
+              }); //$(".current-time").text(new Date(new Date(v > 1000000000000 ? v : v * 1000)).Format('yyyy-MM-dd hh:mm:ss'))
+
+            }
+          }
+        })["catch"](function (err) {});
+      }, 1000);
+    }
+  }, {
+    key: "unSyncTimeLine",
+    value: function unSyncTimeLine() {
+      if (this.timer) {
+        clearInterval(this.timer);
+      }
+    }
+  }]);
+
+  return Rec;
+}();
+
+var TimeLine = function TimeLine(params) {
+  console.log("鎵цTimeLine - params", params);
+  this.state = {
+    id: params.id,
+    start: '00:00:00',
+    // 浼犲叆鏈�杩戠墖娈佃捣濮嬫椂鍒�
+    end: '24:00:00',
+    // 浼犲叆鏈�杩戠墖娈电粨鏉熸椂鍒� 榛樿缁撴潫鏃堕棿涓�24锛�00锛�00, 1440  24
+    current: 0,
+    // 褰撳墠鎾斁鏃跺埢
+    // rate: 1, // 1锛�2灏忔椂锛� 2锛�1灏忔椂锛� 3锛氬崐灏忔椂锛� 4锛�10鍒嗛挓锛� 5锛�1鍒嗛挓
+    timelag: 30,
+    // 120: 2灏忔椂锛� 60锛�1灏忔椂锛� 30锛氬崐灏忔椂锛�10锛�10鍒嗛挓锛�1锛�1鍒嗛挓
+    timeArr: [],
+    // 鏃堕棿杞村垪琛�
+    availTimeLine: [],
+    // 鐢卞疄闄呭瓨鍦ㄨ棰戠墖娈电殑鏃堕棿缁勬垚锛孾{st: '', et: ''}, {st: '', et: ''}, ...]
+    scrollTop: 0,
+    // 椤甸潰婊氬姩鍋忕Щ閲� 椤甸潰鍋忕Щ閲忕敱浼犲叆鏃跺埢鍐冲畾
+    // currentTimer: '', // 鏃跺埢瀹氭椂鍣�
+    // timelineTimer: '', //鏃堕棿杞村畾鏃跺櫒,
+    index: 0,
+    // 鍒濆鏃跺埢鍦╝vailtimeLine涓殑index
+    // playCode: 0, // 褰撳墠鎾斁鐘舵�佸��
+    date: '',
+    noTimeLineTxt: '',
+    disabled: false // 绂佺敤鎷栧姩杞�
+
+  };
+
+  var _this = this;
+
+  this.setState = function (obj) {
+    Object.keys(obj).forEach(function (key) {
+      _this.state[key] = obj[key];
+
+      if (key === 'scrollTop') {
+        document.getElementById('time-line-item').parentNode.scrollTo(0, obj[key]);
+      }
+
+      if (key === 'current') {
+        document.getElementById('time-line-current').innerHTML = obj[key];
+      }
+    });
+  };
+
+  this.setDisabled = function (value) {
+    this.setState({
+      disabled: value
+    });
+    document.getElementById('time-line-item').parentNode.style.overflowY = value ? 'hidden' : 'scroll'; // console.log(" document.getElementById('time-line-item').parentNode.style", document.getElementById('time-line-item').parentNode)
+  };
+
+  this.timeToSecond = function (time) {
+    var e = time.split(':');
+    var h = Number(e[0]);
+    var m = Number(e[1]);
+    var s = Number(e[2]);
+    return h * 60 * 60 + m * 60 + (s ? s : 0);
+  };
+
+  this.minuteToTime = function (minute) {
+    var hour = Math.floor(minute / 60);
+    var m = minute % 60;
+    return (hour > 9 ? hour : '0' + hour) + ':' + (m > 9 ? m : '0' + m);
+  };
+
+  this.timeToMinute = function (time) {
+    var e = time.split(':');
+    var h = Number(e[0]);
+    var m = Number(e[1]); // const s = Number(e[2]);
+
+    return h * 60 + m;
+  };
+
+  this.getPalyParam = params.getPalyParam; // 鐩戝惉鎵嬪姩婊氬姩鏃堕棿杞存椂锛屽仠姝㈡椂闂磋酱婊氬姩锛屾椂鍒讳粛鐒跺彉鍖�
+
+  document.getElementById('time-line-item').parentNode.ontouchstart = function () {
+    if (_this.state.disabled) {
+      return false;
+    }
+
+    params.ontouchstart();
+  }; // 鐩戝惉鎵嬪姩婊氬姩鏃堕棿杞存椂锛屽仠姝㈡椂闂磋酱婊氬姩锛屾椂鍒讳粛鐒跺彉鍖�
+
+
+  document.getElementById('time-line-item').parentNode.ontouchmove = function () {
+    if (_this.state.disabled) {
+      return false;
+    }
+
+    params.ontouchmove();
+  }; // 鎵嬪姩婊氬姩鍋滄锛岄�夊畾鏃跺埢鑷姩鎾斁
+
+
+  document.getElementById('time-line-item').parentNode.ontouchend = function () {
+    // var _this = this;
+    if (_this.state.disabled) {
+      return false;
+    } //
+
+
+    var timer;
+    var scollPromise = new Promise(function (resolve, reject) {
+      var preTop = -1;
+      timer = setInterval(function () {
+        // debugger
+        var reactTop = document.getElementById('time-line-item').parentNode.scrollTop; // 瀹為檯鍋忕Щ楂樺害
+
+        if (reactTop !== preTop) {
+          console.log("scolling", reactTop, preTop);
+          preTop = reactTop;
+        } else {
+          console.log("scoll stop", reactTop, preTop);
+          clearInterval(timer);
+          resolve(reactTop);
+        }
+      }, 100);
+    }); //
+
+    scollPromise.then(function (reactTop) {
+      console.log("scollPromise: then", reactTop, _this);
+
+      _this.rectTopTotime(reactTop);
+
+      console.log('椤甸潰婊氬姩瀹為檯楂樺害', reactTop, _this.state);
+
+      _this.getPalyParam({
+        current: _this.state.current
+      });
+    });
+    params.ontouchend();
+  };
+
+  this.matchTimeDot();
+};
+
+TimeLine.prototype.changeScale = function (value) {
+  this.setState({
+    timelag: value // 120: 2灏忔椂锛� 60锛�1灏忔椂锛� 30锛氬崐灏忔椂锛�10锛�10鍒嗛挓锛�1锛�1鍒嗛挓
+
+  });
+  this.matchTimeDot();
+};
+
+TimeLine.prototype.setDateLine = function (news, defaultIndex) {
+  // if( news.length > 0 ){
+  //   if(!defaultIndex){
+  //     defaultIndex = 0;
+  //   }
+  //   this.setState({
+  //     availTimeLine: news,
+  //     start: news[defaultIndex].st,
+  //     end: news[defaultIndex].et,
+  //     current: news[defaultIndex].st,
+  //   })
+  //   console.log("this.state", this.state);
+  //   this.matchTimeDot();
+  //   this.primaryOffsetH();
+  //   // 灏嗗綋鍓嶆挱鏀炬椂闂寸墖娈典紶缁欑埗缁勪欢
+  //   this.getPalyParam(news[defaultIndex]);
+  // }
+  if (news.length > 0) {
+    if (typeof defaultIndex === 'undefined') {
+      defaultIndex = news.length - 1;
+    }
+
+    this.setState({
+      availTimeLine: news,
+      start: news[defaultIndex].st,
+      end: news[defaultIndex].et,
+      current: news[defaultIndex].st
+    });
+    console.log("this.state", this.state);
+    this.matchRecTimeDot();
+    this.primaryOffsetH(); // 灏嗗綋鍓嶆挱鏀炬椂闂寸墖娈典紶缁欑埗缁勪欢
+    //this.getPalyParam({ current: news[defaultIndex].st });
+  } else {
+    this.setState({
+      availTimeLine: []
+    });
+    console.log("this.state", this.state);
+    this.matchRecTimeDot();
+  }
+};
+
+TimeLine.prototype.matchTimeDot = function () {
+  var _this$state = this.state,
+      start = _this$state.start,
+      end = _this$state.end,
+      timelag = _this$state.timelag;
+      _this$state.availTimeLine;
+  console.log("start", start, 'end', end);
+  var timeArr = []; // // 鎾斁鏃堕棿鐗囨鏃跺埢杞垎閽�
+  // let availArr = [];
+  // let len = availTimeLine.length;
+  // for (let i = 0; i < len; i++) {
+  //   const temp = availTimeLine[i];
+  //   let st = this.timeToSecond(temp.st);
+  //   let et = this.timeToSecond(temp.et);
+  //   // console.log('st: ', st, 'et:', et);
+  //   let stminute;
+  //   let etminute;
+  //   let stAvailPercent = 0;
+  //   let etAvailPercent = 0;
+  //   stminute = Math.floor(st / (timelag * 60)) * timelag;
+  //   stAvailPercent = (st - (stminute * 60)) / timelag;
+  //   etminute = Math.floor(et / (timelag * 60)) * timelag;
+  //   etAvailPercent = (et - (etminute * 60)) / timelag;
+  //   availArr[i] = {
+  //     st: stminute,
+  //     et: etminute,
+  //     stAvailPercent: stAvailPercent,
+  //     etAvailPercent: etAvailPercent
+  //   }
+  // }
+  // console.log('availArr: ', availArr);
+  // 鏃堕棿杞垎閽�
+
+  var minute = this.timeToMinute(end); // // 妫�娴嬫槸鍚﹀寘鍚,鍒欏疄闄呭垎閽熷姞1
+  // const e = end.split(':');
+  // const s = Number(e[2]);
+  // if (s > 0) {
+  //   minute = minute + 1
+  // }
+
+  minute = Math.floor(minute / timelag) * timelag;
+
+  for (var i = minute; i >= 0;) {
+    var marginTop = 0;
+    var marginBottom = 0; // 瑙嗛鐗囨
+
+    var recArr = [];
+
+    if (i == minute) {
+      marginTop = 70;
+    }
+
+    if (i == 0) {
+      marginBottom = 230;
+    } // for (let j = 0; j < len; j++) {
+    //   if (i >= availArr[j].st && i <= availArr[j].et) {
+    //     // borderColor = '#f7a670';
+    //     // console.log("i",i,availArr[j])
+    //     if (i == availArr[j].st && i == availArr[j].et) {
+    //       var height = availArr[j].etAvailPercent - availArr[j].stAvailPercent;
+    //       var top = 60 - availArr[j].etAvailPercent;
+    //       recArr.push({
+    //         height: height,
+    //         top: top
+    //       })
+    //     } else {
+    //       if (i == availArr[j].st) {
+    //         recArr.push({
+    //           height: 60 - availArr[j].stAvailPercent,
+    //           top: 0
+    //         })
+    //       } else if (i == availArr[j].et) {
+    //         recArr.push({
+    //           height: availArr[j].etAvailPercent,
+    //           top: 60 - availArr[j].etAvailPercent,
+    //         })
+    //       } else if (i > availArr[j].st && i < availArr[j].et) {
+    //         // 璺ㄨ秺澶氫釜鍖哄煙
+    //         recArr.push({
+    //           height: 60,
+    //           top: 0,
+    //         })
+    //       }
+    //     }
+    //   }
+    // }
+
+
+    var time = this.minuteToTime(i);
+    timeArr.push({
+      id: i,
+      current: time,
+      label: "a" + i,
+      marginTop: marginTop,
+      marginBottom: marginBottom,
+      recArr: recArr
+    });
+    i = i - timelag;
+  }
+
+  this.setState({
+    timeArr: timeArr
+  });
+  this.renderDateLine();
+};
+
+TimeLine.prototype.matchRecTimeDot = function () {
+  var _this$state2 = this.state,
+      start = _this$state2.start,
+      end = _this$state2.end,
+      timelag = _this$state2.timelag,
+      availTimeLine = _this$state2.availTimeLine,
+      timeArr = _this$state2.timeArr;
+  console.log("start", start, 'end', end); // 鎾斁鏃堕棿鐗囨鏃跺埢杞垎閽�
+
+  var availArr = [];
+  var len = availTimeLine.length;
+
+  if (len === 0) {
+    for (var j = 0; j < timeArr.length; j++) {
+      timeArr[j].recArr = [];
+    }
+  } else {
+    for (var i = 0; i < len; i++) {
+      var temp = availTimeLine[i];
+      var st = this.timeToSecond(temp.st);
+      var et = this.timeToSecond(temp.et); // console.log('st: ', st, 'et:', et);
+
+      var stminute = void 0;
+      var etminute = void 0;
+      var stAvailPercent = 0;
+      var etAvailPercent = 0;
+      stminute = Math.floor(st / (timelag * 60)) * timelag;
+      stAvailPercent = (st - stminute * 60) / timelag;
+      etminute = Math.floor(et / (timelag * 60)) * timelag;
+      etAvailPercent = (et - etminute * 60) / timelag;
+      availArr[i] = {
+        st: stminute,
+        et: etminute,
+        stAvailPercent: stAvailPercent,
+        etAvailPercent: etAvailPercent
+      };
+
+      for (var j = 0; j < timeArr.length; j++) {
+        if (timeArr[j].id == stminute && timeArr[j].id == etminute) {
+          var height = etAvailPercent - stAvailPercent;
+          var top = 60 - etAvailPercent;
+          timeArr[j].recArr.push({
+            height: height,
+            top: top
+          });
+        } else {
+          if (timeArr[j].id == stminute) {
+            timeArr[j].recArr.push({
+              height: 60 - stAvailPercent,
+              top: 0
+            });
+          } else if (timeArr[j].id == etminute) {
+            timeArr[j].recArr.push({
+              height: etAvailPercent,
+              top: 60 - etAvailPercent
+            });
+          } else if (timeArr[j].id > stminute && timeArr[j].id < etminute) {
+            timeArr[j].recArr.push({
+              height: 60,
+              top: 0
+            });
+          }
+        }
+      }
+    }
+  }
+
+  console.log('availArr: ', availArr);
+  this.setState({
+    timeArr: timeArr
+  });
+  console.log('timeArr:', this.state);
+  this.renderDateLine();
+};
+
+TimeLine.prototype.renderDateLine = function () {
+  var _this$state3 = this.state,
+      id = _this$state3.id,
+      timeArr = _this$state3.timeArr;
+  console.log("id,timeArr", id, timeArr);
+  var container = document.getElementById("time-line-item");
+  container.innerHTML = "";
+  timeArr.forEach(function (item, index) {
+    var timeItemDOM = document.createElement('div');
+    timeItemDOM.setAttribute("class", "time-item");
+    timeItemDOM.style = "margin-top: ".concat(item.marginTop, "px; margin-bottom: ").concat(item.marginBottom, "px; border-right-color: ").concat(item.borderColor, ";");
+    var scaleDOM = document.createElement('div');
+    scaleDOM.setAttribute("class", "scale");
+    var timeItemHtml = '<div class="scale"></div><div class="scale"></div><div class="scale"></div><div class="scale"></div><div class="scale"></div><div class="scale" style="width:10px"></div>';
+    item.recArr.forEach(function (i, j) {
+      timeItemHtml += "<div class=\"item-unavail\" style=\"height: ".concat(i.height, "px;background-color:#A8B9ED; top: ").concat(i.top, "px\"></div>");
+    }); //timeItemHtml += `<div class="item-unavail" style="height: ${item.availPercent}px; top: ${item.availTop}px"></div>`
+
+    timeItemHtml += "<div id=".concat(item.label, " style=\"position: relative; top: 51px; left: 40%\"> ").concat(item.current, "</div>");
+    timeItemDOM.innerHTML = timeItemHtml;
+    container.appendChild(timeItemDOM);
+  });
+}; // 璁$畻鍒濆鍋忕Щ閲�
+
+
+TimeLine.prototype.primaryOffsetH = function () {
+  var _this$state4 = this.state,
+      start = _this$state4.start,
+      timelag = _this$state4.timelag,
+      timeArr = _this$state4.timeArr;
+  var currentItem = timeArr[0].current;
+  var currentTime = this.timeToSecond(currentItem);
+  var startSecond = this.timeToSecond(start);
+  var offsetS = currentTime - startSecond;
+  var offsetH = Math.ceil(offsetS / timelag) + 60; // offsetS / (timelag * 60) * 60
+
+  this.setState({
+    scrollTop: offsetH
+  });
+  console.log('璧峰鍋忕Щ閲�', offsetH);
+}; // 璁$畻褰撳墠鍋忕Щ閲�
+
+
+TimeLine.prototype.currentOffsetH = function () {
+  var _this$state5 = this.state,
+      current = _this$state5.current,
+      timelag = _this$state5.timelag,
+      timeArr = _this$state5.timeArr;
+  var startItem = timeArr[0].current;
+  var startSecond = this.timeToSecond(startItem);
+  var currentSecond = this.timeToSecond(current);
+  var offsetS = startSecond - currentSecond;
+  var offsetH = Math.ceil(offsetS / timelag) + 60; // offsetS / (timelag * 60) * 60
+
+  this.setState({
+    scrollTop: offsetH
+  });
+}; // 閫氳繃鏃堕棿杞翠綅缃幏鍙栧綋鍓嶆椂闂�
+
+
+TimeLine.prototype.rectTopTotime = function (reactTop) {
+  var timelag = this.state.timelag; // let rectTop = rect.top; // 鑾峰彇褰撳墠鍏冪礌璺濈鐖跺厓绱犻《閮ㄧ殑楂樺害
+  // let reactTop = 0 - rectTop; // 瀹為檯鍋忕Щ楂樺害
+
+  var index = Math.floor(reactTop / 60); // 浠ュ垎閽熶负鍒诲害鏃讹紝姣忎釜鍏冪礌鍒濆楂樺害涓�60px, 鍚戜笅鍙栨暣骞堕櫎浠ユ椂鍒诲�嶆暟寰楀嚭鍋忕Щitem;
+
+  var offsetH = reactTop - index * 60; // 鍋忕Щ楂樺害
+
+  var current;
+  var offsetSecond;
+  console.log('index锛�', index, 'offsetH:', offsetH);
+
+  if (offsetH == 0) {
+    current = this.state.timeArr[index - 1].current;
+    offsetSecond = 0;
+  } else {
+    // 褰搕imelag==120,timelag==60,timelag==30,timelag==10,timelag==1
+    var time = this.state.timeArr[index].current;
+    var minute = this.timeToMinute(time); // 鐩稿浜庝笅涓�鍏冪礌鍋忕Щ
+
+    var offsetY = 60 - offsetH;
+    var offsetS = offsetY * timelag; // offsetY / 60 * timelag * 60
+
+    var offsetM = Math.floor(offsetS / 60) + minute;
+    var second = Math.floor(offsetS / 60) * 60;
+    offsetSecond = Math.ceil(offsetS - second); // 淇濈暀涓や綅灏忔暟
+
+    current = this.minuteToTime(offsetM);
+  }
+
+  this.setState({
+    current: current + ':' + (offsetSecond > 9 ? offsetSecond : '0' + offsetSecond),
+    scrollTop: reactTop
+  }); // console.log("rectLeft", reactTop);
+  // console.log("currentTime", current + ':' + (offsetSecond > 9 ? offsetSecond : '0' + offsetSecond));
+}; // 鏃堕棿杞存粴鍔紝鏍规嵁浼犲弬鍙樺寲
+
+
+TimeLine.prototype.stepScrollTimeLine = function (time) {
+  this.setState({
+    current: time
+  });
+  this.currentOffsetH();
+};
+
+TimeLine.prototype.secondCountDown = function (time) {
+  var current = this.state.current; // console.log('currentTime', current);
+
+  var temp = current.split(':');
+  var hour = Number(temp[0]);
+  var minute = Number(temp[1]);
+  var second = Number(temp[2]);
+  var t = hour * 60 * 60 + minute * 60 + second + 1;
+  var h = Math.floor(t / 3600);
+  var m = Math.floor((t - h * 3600) / 60);
+  var s = t - h * 3600 - m * 60;
+  this.setState({
+    current: (h > 9 ? h : '0' + h) + ':' + (m > 9 ? m : '0' + m) + ':' + (s > 9 ? s : '0' + s)
+  });
+};
+
+var MobileTimeLine = TimeLine;
+
+Date.prototype.Format = function (fmt) {
+  //author: meizz
+  var o = {
+    "M+": this.getMonth() + 1,
+    //鏈堜唤
+    "d+": this.getDate(),
+    //鏃�
+    "h+": this.getHours(),
+    //灏忔椂
+    "m+": this.getMinutes(),
+    //鍒�
+    "s+": this.getSeconds(),
+    //绉�
+    "q+": Math.floor((this.getMonth() + 3) / 3),
+    //瀛e害
+    "S": this.getMilliseconds() //姣
+
+  };
+
+  if (/(y+)/.test(fmt)) {
+    fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+  }
+
+  for (var k in o) {
+    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
+  }
+
+  return fmt;
+};
+
+function format(now) {
+  var time = new Date(now);
+  var h = time.getHours(); //杩斿洖鏃ユ湡涓殑灏忔椂鏁帮紙0鍒�23锛�
+
+  var m = time.getMinutes(); //杩斿洖鏃ユ湡涓殑鍒嗛挓鏁帮紙0鍒�59锛�
+
+  var s = time.getSeconds(); //杩斿洖鏃ユ湡涓殑绉掓暟锛�0鍒�59锛�
+
+  return (h > 9 ? h : '0' + h) + ':' + (m > 9 ? m : '0' + m) + ':' + (s > 9 ? s : '0' + s);
+}
+
+var MobileRec = /*#__PURE__*/function () {
+  function MobileRec(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, MobileRec);
+
+    this.jSPlugin = jSPlugin;
+    this.timer = null;
+    this.date = new Date().Format('yyyy-MM-dd');
+    this.begin = (new Date().Format('yyyy-MM-dd') + ' 00:00:00').replace(/-/g, "/");
+    this.end = (new Date().Format('yyyy-MM-dd') + ' 23:59:59').replace(/-/g, "/");
+    this.initBegin = null;
+    this.initEnd = null;
+    this.type = matchEzopenUrl(this.jSPlugin.url).type;
+    this.operating = false;
+    this.seekTimer = null;
+    this.disabled = false;
+    this.seekFrequency = 2000;
+
+    if (this.jSPlugin.params && this.jSPlugin.params.seekFrequency) {
+      this.seekFrequency = this.jSPlugin.params.seekFrequency;
+    }
+
+    var oS = document.createElement('style');
+    oS.innerHTML = "\n    body{\n      padding: 0;\n      margin: 0;\n    }\n    .time-line-container {\n      text-align: left;\n      height: 300px;\n      /* outline: 1px solid red; */\n      /* background: gray; */\n      position: relative;\n      /* padding-top: 60px; */\n      margin-top: 20px;\n    }\n\n    .time-line-container .time-line-item-container {\n      display: inline-block;\n      /* height: 400px; */\n      width: 30%;\n      /* background: indianred; */\n      overflow-y: scroll;\n      overflow-x: hidden;\n      /* padding-top: 60px; */\n      height: 300px;\n      box-sizing: border-box;\n      white-space: nowrap;\n      position: relative;\n    }\n\n    .time-line-container .time-line-item-container::-webkit-scrollbar {\n      width: 0px;\n      /*\u6EDA\u52A8\u6761\u5BBD\u5EA6*/\n      height: 0px;\n      /*\u6EDA\u52A8\u6761\u9AD8\u5EA6*/\n    }\n\n    .time-line-item .time-item {\n      position: relative;\n      box-sizing: border-box;\n      height: 60px;\n      font-size: 12px;\n      color: rgb(150, 150, 150);\n      border-right: 6px solid;\n      border-right-color: #ddd;\n    }\n\n    .time-line-item .time-item .scale {\n      width: 6px;\n      height: 9px;\n      border-bottom: 1px solid #ccc;\n      float: right;\n      clear: both;\n    }\n\n    .time-line-item .time-item .item-unavail {\n      width: 6px;\n      position: absolute;\n      left: 100%;\n      background-color: #ddd;\n    }\n\n    .time-line-container .current-time {\n      position: absolute;\n      left: 0;\n      top: 40px;\n      height: 29px;\n      /* line-height: 58px; */\n      border-bottom: 1px solid #648FFC;\n      width: 60%;\n      margin-left: 26%;\n    }\n\n    .time-line-container .current-time .current-time-bg {\n      position: relative;\n      top: 15px;\n      width: 100px;\n      height: 29px;\n      line-height: 29px;\n      left: -70px;\n      font-size: 12px;\n      color: #2C2C2C;\n    }\n\n    .time-line-container .current-time .current-time-bg::before {\n      content: '';\n      display: inline-block;\n      width: 6px;\n      height: 6px;\n      border-radius: 100%;\n      background: #648FFC;\n      top: 11px;\n      position: absolute;\n      right: 30px;\n    }\n\n    .date-switch-container {\n      height: 40px;\n      position: relative;\n      text-align: center;\n      margin: 20px 10px;\n    }\n\n    .date-switch-container .current-date {\n      line-height: 40px;\n      height: 22px;\n      font-size: 16px;\n      color: #2C2C2C;\n      text-align: center;\n      font-weight: bold;\n    }\n\n    .date-container {\n      width: 40px;\n      height: 40px;\n      position: absolute;\n      right: 0;\n      top: 0;\n    }\n\n    .rec-type-container {\n      display: flex;\n      justify-content: space-between;\n    }\n\n    .rec-type-container .rec-type-text {\n      padding: 0 15px;\n      font-size: 12px;\n      color: #2C2C2C;\n    }\n\n    .rec-type-container .rec-type-switch {\n      padding: 0 20px;\n    }\n\n    .date-container input {\n      position: absolute;\n      opacity: 0;\n      display: inline-block;\n      width: 40px;\n      height: 40px;\n      z-index: 10;\n      left: 0;\n    }\n\n    .date-container label {\n      position: absolute;\n      left: 0;\n      top: 0;\n      /* display: none; */\n      z-index: 0;\n    }\n\n    .date-icon {\n      display: inline-block;\n      width: 40px;\n      height: 40px;\n      background: url('https://resource.eziot.com/group2/M00/00/6A/CtwQF2F6VieAQrU9AAABP-_Nsqo949.png') no-repeat 100% 100%;\n    }\n    .select-container {\n      padding: 10px;\n      display: flex;\n      justify-content: space-between;\n    }\n\n    .advice {\n      height: 24px;\n      width: 70px;\n      display: flex;\n      justify-content: space-between;\n      line-height: 24px;\n      background: #F8F8F8;\n      border-radius: 8px;\n    }\n\n    .advice span {\n      width: 40px;\n      display: inline-block;\n    }\n\n    input[type=\"checkbox\"]:not(:checked)+.advice span:first-child {\n      box-shadow: 0px 2px 5px 0px rgb(23 45 101 / 20%);\n      border-radius: 8px;\n      text-align: center;\n\n    }\n\n    input[type=\"checkbox\"]:checked+.advice span:last-child {\n      box-shadow: 0px 2px 5px 0px rgb(23 45 101 / 20%);\n      border-radius: 8px;\n      text-align: center;\n    }\n\n    input[type=\"checkbox\"]:not(:checked)+.advice span:first-child svg {\n      fill: #648FFC !important;\n    }\n\n    input[type=\"checkbox\"]:checked+.advice span:last-child svg {\n      fill: #648FFC !important;\n    }";
+    document.getElementsByTagName("head")[0].appendChild(oS);
+
+    if (getQueryString("begin", this.jSPlugin.url)) {
+      var begin = getQueryString("begin", this.jSPlugin.url);
+      this.date = begin.slice(0, 4) + '/' + begin.slice(4, 6) + '/' + begin.slice(6, 8);
+      this.begin = this.date + " ".concat(begin.slice(8, 10) || "00", ":").concat(begin.slice(10, 12) || "00", ":").concat(begin.slice(12, 14) || "00");
+      this.end = this.date + ' 23:59:59';
+      this.initBegin = this.begin;
+    }
+
+    if (getQueryString("end", this.jSPlugin.url)) {
+      var end = getQueryString("end", this.jSPlugin.url);
+      this.end = this.date + " ".concat(end.slice(8, 10) || "23", ":").concat(end.slice(10, 12) || "59", ":").concat(end.slice(12, 14) || "59");
+      this.initEnd = this.end;
+    } // 鍥炴斁鏃堕棿鏍囬
+
+
+    var mobileRecTitleWrap = document.createElement('div');
+    mobileRecTitleWrap.id = "date-switch-container-wrap";
+    mobileRecTitleWrap.className = "date-switch-container-wrap";
+    mobileRecTitleWrap.style = "";
+    mobileRecTitleWrap.innerHTML = "\n      <div class=\"date-switch-container\">\n      <div class=\"current-date\" id=\"current-date\">\u4ECA\u65E5\u5F55\u50CF</div>\n      <div class=\"date-container\">\n        <label for=\"date\">\n          <div class=\"date-icon\"></div>\n        </label>\n        <input type=\"date\" name=\"date\" id=\"date\" />\n      </div>\n    </div>\n        ";
+    insertAfter$1(mobileRecTitleWrap, document.getElementById("".concat(this.jSPlugin.id, "-wrap"))); // 鍥炴斁鏃堕棿绫诲瀷閫夋嫨
+
+    var mobileRecSwitchWrap = document.createElement('div');
+    mobileRecSwitchWrap.id = "rec-type-container-wrap";
+    mobileRecSwitchWrap.className = "rec-type-container-wrap";
+    mobileRecSwitchWrap.style = "";
+    mobileRecSwitchWrap.innerHTML = "\n    <div class=\"rec-type-container\">\n    <div class=\"rec-type-text\">\u5171\u4E2A<span id=\"recCount\">0</span>\u5F55\u50CF</div>\n    <div class=\"rec-type-switch\">\n      <label>\n        <input type=\"checkbox\" name=\"type\" id=\"cloudType\" value=\"1\" hidden />\n        <label for=\"cloudType\" class=\"advice\">\n          <span>\n          <svg fill=\"#CCCCCC\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"2 0 20 20\">\n            <path class=\"st0\" d=\"M12.6,5c-2.3,0.1-4.3,1.4-5.3,3.3L7.2,8.6c-2.4,0.5-4.1,2.5-4.1,4.9c0,2.8,2.4,5,5.2,5h9.9\n            c2.4,0,4.3-1.9,4.3-4.2l0-0.2c-0.1-2-1.6-3.5-3.5-3.9l-0.1,0l0-0.2c-0.4-2.8-3-5-6.1-5L12.6,5z\"/>\n          </svg>\n        </span>\n        <span>\n          <svg fill=\"#CCCCCC\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"2 0 20 20\">\n            <path id=\"\u5F62\u72B6\u7ED3\u5408\" class=\"st0\" d=\"M14.3,4c0.6,0,1.2,0.2,1.7,0.7l0,0L18.3,7C18.7,7.4,19,8,19,8.6l0,0v9c0,1.3-1.1,2.3-2.4,2.3\n\tl0,0H8.4C7.1,20,6,19,6,17.7l0,0V6.3C6,5,7.1,4,8.4,4l0,0H14.3z M9.7,7.2C9.3,7.2,8.9,7.6,8.9,8l0,0v2.5l0,0.1\n\tc0,0.4,0.4,0.6,0.7,0.6c0.4,0,0.8-0.3,0.8-0.8l0,0V8l0-0.1C10.4,7.5,10,7.2,9.7,7.2z M12.2,7.2c-0.4,0-0.8,0.3-0.8,0.8l0,0v2.5\n\tl0,0.1c0,0.4,0.4,0.6,0.7,0.6c0.4,0,0.8-0.3,0.8-0.8l0,0V8l0-0.1C12.9,7.5,12.5,7.2,12.2,7.2z M14.7,7.2c-0.4,0-0.8,0.3-0.8,0.8l0,0\n\tv2.5l0,0.1c0,0.4,0.4,0.6,0.7,0.6c0.4,0,0.8-0.3,0.8-0.8l0,0V8l0-0.1C15.4,7.5,15,7.2,14.7,7.2z\"/>\n          </svg>\n        </span>\n        </label>\n      </label>\n    </div>\n  </div>\n        ";
+    insertAfter$1(mobileRecSwitchWrap, mobileRecTitleWrap); // 鍥炴斁鏃堕棿杞�
+
+    var mobileRecWrap = document.createElement('div');
+    mobileRecWrap.id = "mobile-rec-wrap";
+    mobileRecWrap.className = "mobileRec-wrap";
+    mobileRecWrap.style = "";
+    mobileRecWrap.innerHTML = "\n    <div class=\"time-line-container\">\n    <div class=\"current-time\">\n      <div class=\"current-time-bg\" id=\"time-line-current\">2020-01-01 00:00:00</div>\n    </div>\n    <div class=\"time-line-item-container\">\n      <div class=\"time-line-item\" id=\"time-line-item\">\n      </div>\n    </div>\n    </div>\n      ";
+    insertAfter$1(mobileRecWrap, mobileRecSwitchWrap);
+
+    var getPalyParam = function getPalyParam(data) {
+      console.log("瀛愮粍浠朵紶鍊煎埌鐖剁粍浠�", data, data.current);
+      var st = data.current;
+      var date = new Date(_this.date).Format('yyyyMMdd').substr(0, 8) + (data.current ? st.replace(/:/g, "") : data.current.replace(/:/g, ""));
+
+      if (_this.initBegin && new Date("".concat(_this.date, " ").concat(data.current)).getTime() < new Date(_this.initBegin).getTime()) {
+        console.log("瓒呰繃闄愬埗鏈�浣庡��");
+        date = new Date(_this.initBegin).Format("yyyyMMddhhmmss");
+      }
+
+      if (_this.initEnd && new Date("".concat(_this.date, " ").concat(data.current)).getTime() > new Date(_this.initEnd).getTime()) {
+        console.log("瓒呰繃闄愬埗鏈�楂樺��");
+        date = new Date(_this.initBegin).Format("yyyyMMddhhmmss");
+      }
+
+      if (_this.type === 'cloud.rec') {
+        var cloudSeek = function cloudSeek() {
+          _this.jSPlugin.seek(date.substr(8, 6), "235959");
+
+          setTimeout(function () {
+            _this.syncTimeLine();
+          }, 6000);
+        };
+
+        if (_this.seekTimer) {
+          clearTimeout(_this.seekTimer);
+        } else {
+          cloudSeek();
+        }
+
+        console.log("this.jsPlug", _this.jSPlugin.params); // 闄愬埗姣�2绉掑彧瑙﹀彂涓�娆℃嫋鍔�
+
+        _this.seekTimer = setTimeout(function () {
+          cloudSeek();
+          clearTimeout(_this.seekTimer);
+          _this.seekTimer = null;
+        }, _this.seekFrequency);
+      } else {
+        var callback = function callback() {
+          setTimeout(function () {
+            _this.disabled = false;
+          }, _this.seekFrequency);
+        };
+
+        var localRecSeek = function localRecSeek(callback) {
+          _this.disabled = true;
+
+          _this.jSPlugin.pause().then(function () {
+            console.log("鏆傚仠鎴愬姛");
+
+            _this.jSPlugin.resume(date).then(function (data) {
+              console.log("鎭㈠鎴愬姛");
+
+              if (_this.jSPlugin.Theme) {
+                _this.jSPlugin.Theme.setDecoderState({
+                  play: true
+                });
+              }
+
+              _this.syncTimeLine();
+
+              if (callback) {
+                callback();
+              }
+            });
+          })["catch"](function () {
+            console.log("鏆傚仠澶辫触");
+
+            _this.jSPlugin.resume(date).then(function (data) {
+              console.log("鎭㈠鎴愬姛");
+
+              if (_this.jSPlugin.Theme) {
+                _this.jSPlugin.Theme.setDecoderState({
+                  play: true
+                });
+              }
+
+              _this.syncTimeLine();
+
+              if (callback) {
+                callback();
+              }
+            });
+          });
+        };
+
+        if (_this.disabled) {
+          console.log("鎿嶄綔棰戠箒锛岀瓑寰�2绉掑悗鎵ц");
+
+          if (_this.seekTimer) {
+            clearTimeout(_this.seekTimer);
+          }
+
+          _this.seekTimer = setTimeout(function () {
+            localRecSeek(callback);
+          }, _this.seekFrequency);
+        } else {
+          // 闄愬埗姣�2绉掑彧瑙﹀彂涓�娆℃嫋鍔�
+          localRecSeek(callback);
+        }
+      }
+    };
+
+    var ontouchstart = function ontouchstart() {
+      _this.operating = true;
+
+      _this.unSyncTimeLine(); // if (currentTimer) {
+      //   clearInterval(currentTimer)
+      // }
+      // if (decoder) {
+      //   var stopPromise = decoder.stop();
+      //   stopPromise.then(() => {
+      //     console.log("鍋滄鎴愬姛")
+      //   });
+      // }
+
+    };
+
+    var ontouchmove = function ontouchmove() {// if (currentTimer) {
+      //   clearInterval(currentTimer)
+      // }
+    };
+
+    var ontouchend = function ontouchend() {
+      _this.operating = false;
+      console.log("ontouchend"); // if (currentTimer) {
+      //   clearInterval(currentTimer)
+      // }
+    };
+
+    this.TimeLineOBJ = new MobileTimeLine({
+      id: "time-line-item",
+      getPalyParam: getPalyParam,
+      ontouchstart: ontouchstart,
+      ontouchmove: ontouchmove,
+      ontouchend: ontouchend
+    });
+    this.fetchDeviceRec(); // 鐩戝惉鏃ユ湡鍙樺寲
+
+    document.getElementById("date").addEventListener('change', function (e) {
+      console.log("鏃ユ湡鍙樺寲", e.target.value); // if(this.initBegin && new Date(`${e.target.value}`.replace(/-/g, "/")).getTime() < new Date(this.initBegin.slice(0, 10)).getTime()) {
+      //   console.log("瓒呰繃闄愬埗鏈�浣庡��")
+      //   return false;
+      // }
+      // if(this.initEnd && new Date(`${e.target.value}`.replace(/-/g, "/")).getTime() > new Date(this.initEnd.slice(0, 10)).getTime()) {
+      //   console.log("瓒呰繃闄愬埗鏈�楂樺��")
+      //   return false;
+      // }
+
+      if (_this.initBegin || _this.initEnd) {
+        console.log("鎮ㄥ紑鍚簡鏃堕棿闄愬埗锛屾棤娉曞垏鎹㈡棩鏈�");
+        return false;
+      }
+
+      _this.date = new Date(e.target.value).Format("yyyy/MM/dd");
+      _this.begin = _this.date + ' 00:00:00';
+      _this.end = _this.date + ' 23:59:59';
+
+      _this.fetchDeviceRec();
+
+      _this.jSPlugin.changePlayUrl({
+        type: _this.type,
+        begin: "".concat(new Date(_this.date).Format('yyyyMMdd'), "000000")
+      });
+    });
+    document.getElementById("cloudType").checked = this.type === 'rec';
+    document.getElementById("cloudType").addEventListener('change', function (e) {
+      var recType = e.target.checked ? 2 : 1;
+      _this.type = e.target.checked ? "rec" : 'cloud.rec';
+      console.log("recType", recType);
+
+      _this.fetchDeviceRec();
+
+      _this.jSPlugin.changePlayUrl({
+        type: _this.type,
+        begin: "".concat(new Date(_this.date).Format('yyyyMMdd'), "000000")
+      }).then(function () {
+        console.log("鍒囨崲绫诲瀷鎴愬姛");
+
+        _this.syncTimeLine();
+      }, function (err) {
+        console.log("err", err);
+      })["catch"](function (err) {
+        console.log(err);
+      }); // document.getElementById("cloudType").setAttribute("checked", true);
+      // $("#cloudType").attr("checked", recType == '2');
+      // $("#cloudType .device svg").attr("checked", recType == '2');
+
+    });
+    this.syncTimeLine();
+  }
+
+  _createClass$1(MobileRec, [{
+    key: "fetchDeviceRec",
+    value: function fetchDeviceRec() {
+      var _this2 = this;
+
+      var doRender = function doRender(result) {
+        var len = result.length;
+        document.getElementById("recCount").innerHTML = len;
+        var availArr = [];
+
+        for (var i = len - 1; i >= 0; i--) {
+          var res = result[i];
+          var et = format(res.endTime);
+          var st = format(res.startTime);
+
+          availArr.push({
+            st: st,
+            et: et
+          });
+        } // document.getElementById("time-line-item").style.display = "block";
+
+
+        {
+          _this2.TimeLineOBJ.setDateLine(availArr);
+        }
+      };
+
+      var data = new FormData();
+      data.append("deviceSerial", matchEzopenUrl(this.jSPlugin.url).deviceSerial);
+      data.append("channelNo", matchEzopenUrl(this.jSPlugin.url).channelNo);
+      data.append("accessToken", this.jSPlugin.accessToken);
+      data.append("recType", this.type === 'cloud.rec' ? 1 : 2);
+      data.append("startTime", new Date(this.begin).getTime());
+      data.append("endTime", new Date(this.end).getTime());
+      fetch(this.jSPlugin.env.domain + '/api/lapp/video/by/time', {
+        method: "POST",
+        body: data
+      }).then(function (response) {
+        return response.json();
+      }).then(function (res) {
+        // 鏈湴鍥炴斁
+        if (res.code == 200 && res.data) {
+          var result = [];
+          result = res.data;
+          doRender(result);
+        } else {
+          doRender([]);
+        }
+      });
+    }
+  }, {
+    key: "syncTimeLine",
+    value: function syncTimeLine() {
+      var _this3 = this;
+
+      var dateFormat = function dateFormat(now) {
+        var time = new Date(now);
+        var h = time.getHours(); //杩斿洖鏃ユ湡涓殑灏忔椂鏁帮紙0鍒�23锛�
+
+        var m = time.getMinutes(); //杩斿洖鏃ユ湡涓殑鍒嗛挓鏁帮紙0鍒�59锛�
+
+        var s = time.getSeconds(); //杩斿洖鏃ユ湡涓殑绉掓暟锛�0鍒�59锛�
+
+        return (h > 9 ? h : '0' + h) + ':' + (m > 9 ? m : '0' + m) + ':' + (s > 9 ? s : '0' + s);
+      };
+
+      if (this.timer) {
+        clearInterval(this.timer);
+      }
+
+      this.timer = setInterval(function () {
+        // 瀹氭椂鍣�
+        if (_this3.operating) {
+          console.log("鎿嶄綔涓�");
+          return false;
+        }
+
+        _this3.jSPlugin.getOSDTime().then(function (res) {
+          if (res.data > 0) {
+            _this3.TimeLineOBJ.stepScrollTimeLine(dateFormat(res.data * 1000));
+          } else {
+            console.log("鏈壘鍒板綋鍓嶈幏鍙栨挱鏀炬椂闂达紝绛夊緟涓�...");
+          }
+        })["catch"](function (err) {
+          console.log("鏈壘鍒板綋鍓嶈幏鍙栨挱鏀炬椂闂达紝绛夊緟涓�...");
+        });
+      }, 1000);
+    }
+  }, {
+    key: "unSyncTimeLine",
+    value: function unSyncTimeLine() {
+      if (this.timer) {
+        clearInterval(this.timer);
+      }
+    }
+  }]);
+
+  return MobileRec;
+}();
+
+var Ptz = /*#__PURE__*/function () {
+  function Ptz(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, Ptz);
+
+    this.jSPlugin = jSPlugin;
+    console.log("浜戝彴鍒濆鍖�");
+
+    if (document.getElementById(this.jSPlugin.id + "-ez-ptz-item")) {
+      return false;
+    }
+
+    var ptzWrap = document.createElement('div');
+    ptzWrap.id = this.jSPlugin.id + "-ez-ptz-item";
+    ptzWrap.className = "ez-ptz-wrap";
+    ptzWrap.style = "display:none";
+    var oS = document.createElement('style');
+    oS.innerHTML = "\n    .ez-ptz-container {\n      position: relative;\n      width: 80px;\n      height: 80px;\n      background: rgba(255, 255, 255, 0.80);\n      box-shadow: 0px 0px 33px 4px rgb(0 0 0 / 15%);\n      border: 1px solid rgba(255, 255, 255, 0.80);\n      border-radius: 100%;\n      cursor: pointer;\n      overflow: hidden;\n      user-select: none;\n    }\n    .ez-ptz-container .ez-ptz-icon.top {\n      width: 0;\n      height: 0;\n      border-left: 3px solid transparent;\n      border-right: 3px solid transparent;\n      border-bottom: 6px solid #333333;\n      position: absolute;\n      display: inline-block;\n      left: calc(50% - 3px);\n      top: 2px;\n    }\n\n    .ez-ptz-container .ez-ptz-icon.top.active {\n      border-bottom-color: #1890FF;\n    }\n\n    .ez-ptz-container .ez-ptz-icon.bottom {\n      width: 0;\n      height: 0;\n      border-left: 3px solid transparent;\n      border-right: 3px solid transparent;\n      border-top: 6px solid #333333;\n      position: absolute;\n      display: inline-block;\n      left: calc(50% - 3px);\n      bottom: 2px;\n    }\n\n    .ez-ptz-container .ez-ptz-icon.bottom.active {\n      border-top-color: #1890FF;\n    }\n\n    .ez-ptz-container .ez-ptz-icon.right {\n      width: 0;\n      height: 0;\n      border-top: 3px solid transparent;\n      border-bottom: 3px solid transparent;\n      border-left: 6px solid #333333;\n      position: absolute;\n      display: inline-block;\n      top: calc(50% - 3px);\n      right: 2px;\n    }\n\n    .ez-ptz-container .ez-ptz-icon.right.active {\n      border-left-color: #1890FF;\n    }\n\n    .ez-ptz-container .ez-ptz-icon.left {\n      width: 0;\n      height: 0;\n      border-top: 3px solid transparent;\n      border-bottom: 3px solid transparent;\n      border-right: 6px solid #333333;\n      position: absolute;\n      display: inline-block;\n      top: calc(50% - 3px);\n      left: 2px;\n    }\n\n    .ez-ptz-container .ez-ptz-icon.left.active {\n      border-right-color: #1890FF;\n    }\n\n    .ez-ptz-container .ez-ptz-main.center {\n      width: 23px;\n      height: 23px;\n      background: #1890FF;\n      border-radius: 100%;\n      top: calc(50% - 12.3px);\n      left: calc(50% - 12.3px);\n      position: absolute;\n    }\n\n    .ez-ptz-wrap {\n      position: absolute;\n      right: 20px;\n      top: calc(50% - 50px);\n      width: 100px;\n      height: 100px;\n      z-index: 999;\n    }\n\n    .ez-ptz-close {\n      position: absolute;\n      color: #FFFFFF;\n      top: 0;\n      right: 0px;\n    }";
+    document.getElementsByTagName("head")[0].appendChild(oS);
+    ptzWrap.innerHTML = "\n      <div class=\"ez-ptz-container\" id=\"".concat(this.jSPlugin.id, "-ez-ptz-container\" style=\"position: relative;width: 80px;height: 80px;background: rgba(255, 255, 255, 0.80);box-shadow: 0px 0px 33px 4px rgba(0, 0, 0, 0.15);border: 1px solid rgba(255, 255, 255, 0.80);border-radius: 100%;cursor: pointer;overflow: hidden;user-select: none;\">\n        <div class=\"ez-ptz-main center\"></div>\n        <div class=\"ez-ptz-icon top active\"></div>\n        <div class=\"ez-ptz-icon left active\"></div>\n        <div class=\"ez-ptz-icon bottom active\"></div>\n        <div class=\"ez-ptz-icon right active\"></div>\n      ");
+    document.getElementById("".concat(jSPlugin.id, "-wrap")).appendChild(ptzWrap); // 浜戝彴鎺у埗浜嬩欢缁戝畾
+    // 浜戝彴鎺у埗
+
+    document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-container")).onmousedown = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜寮�濮�");
+
+      _this._handlePtzTouch(e, 'start');
+    };
+
+    document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-container")).onmouseup = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜缁撴潫");
+
+      _this._handlePtzTouch(e, 'stop');
+    };
+
+    document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-container")).ontouchstart = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜寮�濮�");
+
+      _this._handlePtzTouch(e, 'start');
+    };
+
+    document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-container")).ontouchend = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜缁撴潫", e);
+
+      _this._handlePtzTouch(e, 'stop');
+    };
+  }
+
+  _createClass$1(Ptz, [{
+    key: "show",
+    value: function show() {
+      document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-item")).style = "display: inline-block";
+    }
+  }, {
+    key: "hide",
+    value: function hide() {
+      document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-item")).style = "display: none";
+    }
+  }, {
+    key: "_handlePtzTouch",
+    value: function _handlePtzTouch(e, type) {
+      var _this2 = this;
+
+      var container = document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-container")).getBoundingClientRect();
+      var containerCenterX = container.left + 41;
+      var containerCenterY = container.top + 41;
+      var eventX = e.x || e.changedTouches[0].clientX;
+      var eventY = e.y || e.changedTouches[0].clientY;
+      var left = eventX - containerCenterX;
+      var top = eventY - containerCenterY;
+      var direction = 0; //鎿嶄綔鍛戒护锛�0-涓婏紝1-涓嬶紝2-宸︼紝3-鍙筹紝4-宸︿笂锛�5-宸︿笅锛�6-鍙充笂锛�7-鍙充笅锛�8-鏀惧ぇ锛�9-缂╁皬锛�10-杩戠劍璺濓紝11-杩滅劍璺�
+
+      var url = this.jSPlugin.env.domain + "/api/lapp/device/ptz/start"; // var nextPtzImg = ptzNormalImg;
+      // var nextPtzImgFailed = ptzNormalImg;
+      // 鍒よ鏂逛綅
+
+      if (Math.abs(left) > Math.abs(top)) {
+        if (left > 0) {
+          direction = 3; // nextPtzImg = ptzRightImgSuccess;
+          // nextPtzImgFailed = ptzRightImgFailed;
+        } else {
+          direction = 2; // nextPtzImg = ptzLeftImgSuccess;
+          // nextPtzImgFailed = ptzLeftImgFailed;
+        }
+      } else {
+        if (top > 0) {
+          direction = 1; // nextPtzImg = ptzDownImgSuccess;
+          // nextPtzImgFailed = ptzDownImgFailed;
+        } else {
+          direction = 0; // nextPtzImg = ptzTopImgSuccess;
+          // nextPtzImgFailed = ptzTopImgFailed;
+        }
+      } // 鍏煎鐢婚潰鏃嬭浆90搴�
+
+
+      if (/^rotate\(90/.test(document.getElementById("".concat(this.jSPlugin.id, "-wrap")).style.transform)) {
+        switch (direction) {
+          case 0:
+            direction = 2; // 涓婅浆鍖栦负宸�
+
+            break;
+
+          case 1:
+            direction = 3; // 涓嬭浆鍖栦负鍙�
+
+            break;
+
+          case 2:
+            direction = 1; // 宸﹁浆鍖栦负涓�
+
+            break;
+
+          case 3:
+            direction = 0; // 鍙宠浆鍖栦负涓�
+
+            break;
+        }
+      }
+
+      document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-container")).style = "background-image:linear-gradient(".concat(direction === 0 ? 180 : direction === 1 ? 0 : direction === 2 ? 90 : 270, "deg, #1d8dd8 0%, rgba(100,143,252,0.00) 30%)");
+
+      if (type === 'stop') {
+        url = this.jSPlugin.env.domain + '/api/lapp/device/ptz/stop';
+        document.getElementById("".concat(this.jSPlugin.id, "-ez-ptz-container")).style = "";
+      }
+
+      var data = new FormData();
+      data.append("deviceSerial", matchEzopenUrl(this.jSPlugin.url).deviceSerial);
+      data.append("channelNo", matchEzopenUrl(this.jSPlugin.url).channelNo);
+      data.append("speed", 1);
+      data.append("direction", direction);
+      data.append("accessToken", this.jSPlugin.accessToken);
+      fetch(url, {
+        method: "POST",
+        body: data
+      }).then(function (response) {
+        return response.json();
+      }).then(function (rt) {
+        if (rt.code == 200) ; else {
+          //document.getElementById('ptz-img-container').childNodes[0].src = nextPtzImgFailed;
+          // layer.msg(data.msg);
+          if (rt.code == 60005 || rt.code == 60002 || rt.code == 60003 || rt.code == 60004) {
+            document.getElementById("".concat(_this2.jSPlugin.id, "-ez-ptz-container")).style = "background-image:linear-gradient(".concat(direction === 0 ? 180 : direction === 1 ? 0 : direction === 2 ? 90 : 270, "deg, #f45656 0%, rgba(100,143,252,0.00) 30%)");
+          }
+        }
+      })["catch"](function (err) {
+        console.log("浜戝彴璋冪敤寮傚父", err);
+      });
+    }
+  }]);
+
+  return Ptz;
+}();
+
+(function (f) {
+  if ((typeof exports === "undefined" ? "undefined" : _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 () {
+  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) {
+
+      var _adapter_factory = require('./adapter_factory.js');
+
+      var adapter = (0, _adapter_factory.adapterFactory)({
+        window: window
+      });
+      window.adapter = adapter;
+      module.exports = adapter; // this is the difference from adapter_core.
+    }, {
+      "./adapter_factory.js": 2
+    }],
+    2: [function (require, module, exports) {
+
+      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 _edge_shim = require('./edge/edge_shim');
+
+      var edgeShim = _interopRequireWildcard(_edge_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);
+
+      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,
+          shimEdge: 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
+        }; // 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;
+            }
+
+            logging('adapter.js shimming chrome.'); // Export to the adapter global object visible in the browser.
+
+            adapter.browserShim = chromeShim;
+            chromeShim.shimGetUserMedia(window);
+            chromeShim.shimMediaStream(window);
+            chromeShim.shimPeerConnection(window);
+            chromeShim.shimOnTrack(window);
+            chromeShim.shimAddTrackRemoveTrack(window);
+            chromeShim.shimGetSendersWithDtmf(window);
+            chromeShim.shimGetStats(window);
+            chromeShim.shimSenderReceiverGetStats(window);
+            chromeShim.fixNegotiationNeeded(window);
+            commonShim.shimRTCIceCandidate(window);
+            commonShim.shimConnectionState(window);
+            commonShim.shimMaxMessageSize(window);
+            commonShim.shimSendThrowTypeError(window);
+            commonShim.removeAllowExtmapMixed(window);
+            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;
+            firefoxShim.shimGetUserMedia(window);
+            firefoxShim.shimPeerConnection(window);
+            firefoxShim.shimOnTrack(window);
+            firefoxShim.shimRemoveStream(window);
+            firefoxShim.shimSenderGetStats(window);
+            firefoxShim.shimReceiverGetStats(window);
+            firefoxShim.shimRTCDataChannel(window);
+            firefoxShim.shimAddTransceiver(window);
+            firefoxShim.shimCreateOffer(window);
+            firefoxShim.shimCreateAnswer(window);
+            commonShim.shimRTCIceCandidate(window);
+            commonShim.shimConnectionState(window);
+            commonShim.shimMaxMessageSize(window);
+            commonShim.shimSendThrowTypeError(window);
+            break;
+
+          case 'edge':
+            if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) {
+              logging('MS edge shim is not included in this adapter release.');
+              return adapter;
+            }
+
+            logging('adapter.js shimming edge.'); // Export to the adapter global object visible in the browser.
+
+            adapter.browserShim = edgeShim;
+            edgeShim.shimGetUserMedia(window);
+            edgeShim.shimGetDisplayMedia(window);
+            edgeShim.shimPeerConnection(window);
+            edgeShim.shimReplaceTrack(window); // the edge shim implements the full RTCIceCandidate object.
+
+            commonShim.shimMaxMessageSize(window);
+            commonShim.shimSendThrowTypeError(window);
+            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;
+            safariShim.shimRTCIceServerUrls(window);
+            safariShim.shimCreateOfferLegacy(window);
+            safariShim.shimCallbacksAPI(window);
+            safariShim.shimLocalStreamsAPI(window);
+            safariShim.shimRemoteStreamsAPI(window);
+            safariShim.shimTrackEventTransceiver(window);
+            safariShim.shimGetUserMedia(window);
+            commonShim.shimRTCIceCandidate(window);
+            commonShim.shimMaxMessageSize(window);
+            commonShim.shimSendThrowTypeError(window);
+            commonShim.removeAllowExtmapMixed(window);
+            break;
+
+          default:
+            logging('Unsupported browser!');
+            break;
+        }
+
+        return adapter;
+      } // Browser shims.
+
+    }, {
+      "./chrome/chrome_shim": 3,
+      "./common_shim": 6,
+      "./edge/edge_shim": 7,
+      "./firefox/firefox_shim": 11,
+      "./safari/safari_shim": 14,
+      "./utils": 15
+    }],
+    3: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined;
+
+      var _typeof$1 = 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$1(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$1(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$1(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$1(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) {
+        if (!window.RTCPeerConnection) {
+          return;
+        }
+
+        var browserDetails = utils.detectBrowser(window); // 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) {
+        var browserDetails = utils.detectBrowser(window);
+
+        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];
+          });
+        } // support for addIceCandidate(null or undefined)
+
+
+        var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate;
+
+        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 planned for Chrome M77.
+
+
+          if (browserDetails.version < 78 && arguments[0] && arguments[0].candidate === '') {
+            return Promise.resolve();
+          }
+
+          return nativeAddIceCandidate.apply(this, arguments);
+        };
+      }
+
+      function fixNegotiationNeeded(window) {
+        utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) {
+          var pc = e.target;
+
+          if (pc.signalingState !== 'stable') {
+            return;
+          }
+
+          return e;
+        });
+      }
+    }, {
+      "../utils.js": 15,
+      "./getdisplaymedia": 4,
+      "./getusermedia": 5
+    }],
+    4: [function (require, module, exports) {
+
+      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) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+
+      var _typeof$1 = 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) {
+        var navigator = window && window.navigator;
+
+        if (!navigator.mediaDevices) {
+          return;
+        }
+
+        var browserDetails = utils.detectBrowser(window);
+
+        var constraintsToChrome_ = function constraintsToChrome_(c) {
+          if ((typeof c === 'undefined' ? 'undefined' : _typeof$1(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$1(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$1(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$1(constraints.video) === 'object') {
+            // Shim facingMode for mobile & surface pro.
+            var face = constraints.video.facingMode;
+            face = face && ((typeof face === 'undefined' ? 'undefined' : _typeof$1(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": 15
+    }],
+    6: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+
+      var _typeof$1 = 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.removeAllowExtmapMixed = removeAllowExtmapMixed;
+
+      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$1(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) {
+        if (!window.RTCPeerConnection) {
+          return;
+        }
+
+        var browserDetails = utils.detectBrowser(window);
+
+        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 removeAllowExtmapMixed(window) {
+        /* remove a=extmap-allow-mixed for Chrome < M71 */
+        if (!window.RTCPeerConnection) {
+          return;
+        }
+
+        var browserDetails = utils.detectBrowser(window);
+
+        if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) {
+          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) {
+            desc.sdp = desc.sdp.split('\n').filter(function (line) {
+              return line.trim() !== 'a=extmap-allow-mixed';
+            }).join('\n');
+          }
+
+          return nativeSRD.apply(this, arguments);
+        };
+      }
+    }, {
+      "./utils": 15,
+      "sdp": 17
+    }],
+    7: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined;
+
+      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.shimPeerConnection = shimPeerConnection;
+      exports.shimReplaceTrack = shimReplaceTrack;
+
+      var _utils = require('../utils');
+
+      var utils = _interopRequireWildcard(_utils);
+
+      var _filtericeservers = require('./filtericeservers');
+
+      var _rtcpeerconnectionShim = require('rtcpeerconnection-shim');
+
+      var _rtcpeerconnectionShim2 = _interopRequireDefault(_rtcpeerconnectionShim);
+
+      function _interopRequireDefault(obj) {
+        return obj && obj.__esModule ? obj : {
+          "default": obj
+        };
+      }
+
+      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 shimPeerConnection(window) {
+        var browserDetails = utils.detectBrowser(window);
+
+        if (window.RTCIceGatherer) {
+          if (!window.RTCIceCandidate) {
+            window.RTCIceCandidate = function RTCIceCandidate(args) {
+              return args;
+            };
+          }
+
+          if (!window.RTCSessionDescription) {
+            window.RTCSessionDescription = function RTCSessionDescription(args) {
+              return args;
+            };
+          } // this adds an additional event listener to MediaStrackTrack that signals
+          // when a tracks enabled property was changed. Workaround for a bug in
+          // addStream, see below. No longer required in 15025+
+
+
+          if (browserDetails.version < 15025) {
+            var origMSTEnabled = Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype, 'enabled');
+            Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', {
+              set: function set(value) {
+                origMSTEnabled.set.call(this, value);
+                var ev = new Event('enabled');
+                ev.enabled = value;
+                this.dispatchEvent(ev);
+              }
+            });
+          }
+        } // ORTC defines the DTMF sender a bit different.
+        // https://github.com/w3c/ortc/issues/714
+
+
+        if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) {
+          Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', {
+            get: function get() {
+              if (this._dtmf === undefined) {
+                if (this.track.kind === 'audio') {
+                  this._dtmf = new window.RTCDtmfSender(this);
+                } else if (this.track.kind === 'video') {
+                  this._dtmf = null;
+                }
+              }
+
+              return this._dtmf;
+            }
+          });
+        } // Edge currently only implements the RTCDtmfSender, not the
+        // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2*
+
+
+        if (window.RTCDtmfSender && !window.RTCDTMFSender) {
+          window.RTCDTMFSender = window.RTCDtmfSender;
+        }
+
+        var RTCPeerConnectionShim = (0, _rtcpeerconnectionShim2["default"])(window, browserDetails.version);
+
+        window.RTCPeerConnection = function RTCPeerConnection(config) {
+          if (config && config.iceServers) {
+            config.iceServers = (0, _filtericeservers.filterIceServers)(config.iceServers, browserDetails.version);
+            utils.log('ICE servers after filtering:', config.iceServers);
+          }
+
+          return new RTCPeerConnectionShim(config);
+        };
+
+        window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype;
+      }
+
+      function shimReplaceTrack(window) {
+        // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614
+        if (window.RTCRtpSender && !('replaceTrack' in window.RTCRtpSender.prototype)) {
+          window.RTCRtpSender.prototype.replaceTrack = window.RTCRtpSender.prototype.setTrack;
+        }
+      }
+    }, {
+      "../utils": 15,
+      "./filtericeservers": 8,
+      "./getdisplaymedia": 9,
+      "./getusermedia": 10,
+      "rtcpeerconnection-shim": 16
+    }],
+    8: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.filterIceServers = filterIceServers;
+
+      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;
+        }
+      } // Edge does not like
+      // 1) stun: filtered after 14393 unless ?transport=udp is present
+      // 2) turn: that does not have all of turn:host:port?transport=udp
+      // 3) turn: with ipv6 addresses
+      // 4) turn: occurring muliple times
+
+
+      function filterIceServers(iceServers, edgeVersion) {
+        var hasTurn = false;
+        iceServers = JSON.parse(JSON.stringify(iceServers));
+        return iceServers.filter(function (server) {
+          if (server && (server.urls || server.url)) {
+            var urls = server.urls || server.url;
+
+            if (server.url && !server.urls) {
+              utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls');
+            }
+
+            var isString = typeof urls === 'string';
+
+            if (isString) {
+              urls = [urls];
+            }
+
+            urls = urls.filter(function (url) {
+              // filter STUN unconditionally.
+              if (url.indexOf('stun:') === 0) {
+                return false;
+              }
+
+              var validTurn = url.startsWith('turn') && !url.startsWith('turn:[') && url.includes('transport=udp');
+
+              if (validTurn && !hasTurn) {
+                hasTurn = true;
+                return true;
+              }
+
+              return validTurn && !hasTurn;
+            });
+            delete server.url;
+            server.urls = isString ? urls[0] : urls;
+            return !!urls.length;
+          }
+        });
+      }
+    }, {
+      "../utils": 15
+    }],
+    9: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.shimGetDisplayMedia = shimGetDisplayMedia;
+
+      function shimGetDisplayMedia(window) {
+        if (!('getDisplayMedia' in window.navigator)) {
+          return;
+        }
+
+        if (!window.navigator.mediaDevices) {
+          return;
+        }
+
+        if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) {
+          return;
+        }
+
+        window.navigator.mediaDevices.getDisplayMedia = window.navigator.getDisplayMedia.bind(window.navigator);
+      }
+    }, {}],
+    10: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.shimGetUserMedia = shimGetUserMedia;
+
+      function shimGetUserMedia(window) {
+        var navigator = window && window.navigator;
+
+        var shimError_ = function shimError_(e) {
+          return {
+            name: {
+              PermissionDeniedError: 'NotAllowedError'
+            }[e.name] || e.name,
+            message: e.message,
+            constraint: e.constraint,
+            toString: function toString() {
+              return this.name;
+            }
+          };
+        }; // getUserMedia error shim.
+
+
+        var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);
+
+        navigator.mediaDevices.getUserMedia = function (c) {
+          return origGetUserMedia(c)["catch"](function (e) {
+            return Promise.reject(shimError_(e));
+          });
+        };
+      }
+    }, {}],
+    11: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+      exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined;
+
+      var _typeof$1 = 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.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$1(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) {
+        var browserDetails = utils.detectBrowser(window);
+
+        if ((typeof window === 'undefined' ? 'undefined' : _typeof$1(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];
+          });
+        } // support for addIceCandidate(null or undefined)
+        // as well as ignoring {sdpMid, candidate: ""}
+
+
+        if (browserDetails.version < 68) {
+          var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate;
+
+          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.
+
+
+            if (arguments[0] && arguments[0].candidate === '') {
+              return Promise.resolve();
+            }
+
+            return nativeAddIceCandidate.apply(this, arguments);
+          };
+        }
+
+        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$1(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$1(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$1(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)) {
+                params.encodings = initParameters.sendEncodings;
+                this.setParametersPromises.push(sender.setParameters(params)["catch"](function () {}));
+              }
+            }
+
+            return transceiver;
+          };
+        }
+      }
+
+      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$1(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$1(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": 15,
+      "./getdisplaymedia": 12,
+      "./getusermedia": 13
+    }],
+    12: [function (require, module, exports) {
+
+      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);
+        };
+      }
+    }, {}],
+    13: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+
+      var _typeof$1 = 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) {
+        var browserDetails = utils.detectBrowser(window);
+        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$1(c)) === 'object' && _typeof$1(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$1(c)) === 'object') {
+                c = JSON.parse(JSON.stringify(c));
+                remap(c, 'autoGainControl', 'mozAutoGainControl');
+                remap(c, 'noiseSuppression', 'mozNoiseSuppression');
+              }
+
+              return nativeApplyConstraints.apply(this, [c]);
+            };
+          }
+        }
+      }
+    }, {
+      "../utils": 15
+    }],
+    14: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+
+      var _typeof$1 = 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;
+
+      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$1(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 stream = arguments[1];
+
+            if (stream) {
+              if (!this._localStreams) {
+                this._localStreams = [stream];
+              } else if (!this._localStreams.includes(stream)) {
+                this._localStreams.push(stream);
+              }
+            }
+
+            return _addTrack.apply(this, arguments);
+          };
+        }
+
+        if (!('removeStream' in window.RTCPeerConnection.prototype)) {
+          window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) {
+            var _this2 = 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)) {
+                _this2.removeTrack(sender);
+              }
+            });
+          };
+        }
+      }
+
+      function shimRemoteStreamsAPI(window) {
+        if ((typeof window === 'undefined' ? 'undefined' : _typeof$1(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 _this3 = 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 (!_this3._remoteStreams) {
+                    _this3._remoteStreams = [];
+                  }
+
+                  if (_this3._remoteStreams.includes(stream)) {
+                    return;
+                  }
+
+                  _this3._remoteStreams.push(stream);
+
+                  var event = new Event('addstream');
+                  event.stream = stream;
+
+                  _this3.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$1(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) {
+        // 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 window.RTCPeerConnection) {
+          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$1(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);
+        };
+      }
+    }, {
+      "../utils": 15
+    }],
+    15: [function (require, module, exports) {
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true
+      });
+
+      var _typeof$1 = 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) {
+              cb(modifiedEvent);
+            }
+          };
+
+          this._eventMap = this._eventMap || {};
+          this._eventMap[cb] = wrappedCallback;
+          return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]);
+        };
+
+        var nativeRemoveEventListener = proto.removeEventListener;
+
+        proto.removeEventListener = function (nativeEventName, cb) {
+          if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[cb]) {
+            return nativeRemoveEventListener.apply(this, arguments);
+          }
+
+          var unwrappedCb = this._eventMap[cb];
+          delete this._eventMap[cb];
+          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$1(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$1(bool)) + '. Please use a boolean.');
+        }
+
+        deprecationWarnings_ = !bool;
+        return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled');
+      }
+
+      function log() {
+        if ((typeof window === 'undefined' ? 'undefined' : _typeof$1(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) {
+        var navigator = window.navigator; // 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;
+        }
+
+        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 (navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
+          // Edge.
+          result.browser = 'edge';
+          result.version = extractVersion(navigator.userAgent, /Edge\/(\d+).(\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;
+      }
+    }, {}],
+    16: [function (require, module, exports) {
+
+      var SDPUtils = require('sdp');
+
+      function fixStatsType(stat) {
+        return {
+          inboundrtp: 'inbound-rtp',
+          outboundrtp: 'outbound-rtp',
+          candidatepair: 'candidate-pair',
+          localcandidate: 'local-candidate',
+          remotecandidate: 'remote-candidate'
+        }[stat.type] || stat.type;
+      }
+
+      function writeMediaSection(transceiver, caps, type, stream, dtlsRole) {
+        var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); // Map ICE parameters (ufrag, pwd) to SDP.
+
+        sdp += SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters()); // Map DTLS parameters to SDP.
+
+        sdp += SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(), type === 'offer' ? 'actpass' : dtlsRole || 'active');
+        sdp += 'a=mid:' + transceiver.mid + '\r\n';
+
+        if (transceiver.rtpSender && transceiver.rtpReceiver) {
+          sdp += 'a=sendrecv\r\n';
+        } else if (transceiver.rtpSender) {
+          sdp += 'a=sendonly\r\n';
+        } else if (transceiver.rtpReceiver) {
+          sdp += 'a=recvonly\r\n';
+        } else {
+          sdp += 'a=inactive\r\n';
+        }
+
+        if (transceiver.rtpSender) {
+          var trackId = transceiver.rtpSender._initialTrackId || transceiver.rtpSender.track.id;
+          transceiver.rtpSender._initialTrackId = trackId; // spec.
+
+          var msid = 'msid:' + (stream ? stream.id : '-') + ' ' + trackId + '\r\n';
+          sdp += 'a=' + msid; // for Chrome. Legacy should no longer be required.
+
+          sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + ' ' + msid; // RTX
+
+          if (transceiver.sendEncodingParameters[0].rtx) {
+            sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + ' ' + msid;
+            sdp += 'a=ssrc-group:FID ' + transceiver.sendEncodingParameters[0].ssrc + ' ' + transceiver.sendEncodingParameters[0].rtx.ssrc + '\r\n';
+          }
+        } // FIXME: this should be written by writeRtpDescription.
+
+
+        sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + ' cname:' + SDPUtils.localCName + '\r\n';
+
+        if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {
+          sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + ' cname:' + SDPUtils.localCName + '\r\n';
+        }
+
+        return sdp;
+      } // Edge does not like
+      // 1) stun: filtered after 14393 unless ?transport=udp is present
+      // 2) turn: that does not have all of turn:host:port?transport=udp
+      // 3) turn: with ipv6 addresses
+      // 4) turn: occurring muliple times
+
+
+      function filterIceServers(iceServers, edgeVersion) {
+        var hasTurn = false;
+        iceServers = JSON.parse(JSON.stringify(iceServers));
+        return iceServers.filter(function (server) {
+          if (server && (server.urls || server.url)) {
+            var urls = server.urls || server.url;
+
+            if (server.url && !server.urls) {
+              console.warn('RTCIceServer.url is deprecated! Use urls instead.');
+            }
+
+            var isString = typeof urls === 'string';
+
+            if (isString) {
+              urls = [urls];
+            }
+
+            urls = urls.filter(function (url) {
+              var validTurn = url.indexOf('turn:') === 0 && url.indexOf('transport=udp') !== -1 && url.indexOf('turn:[') === -1 && !hasTurn;
+
+              if (validTurn) {
+                hasTurn = true;
+                return true;
+              }
+
+              return url.indexOf('stun:') === 0 && edgeVersion >= 14393 && url.indexOf('?transport=udp') === -1;
+            });
+            delete server.url;
+            server.urls = isString ? urls[0] : urls;
+            return !!urls.length;
+          }
+        });
+      } // Determines the intersection of local and remote capabilities.
+
+
+      function getCommonCapabilities(localCapabilities, remoteCapabilities) {
+        var commonCapabilities = {
+          codecs: [],
+          headerExtensions: [],
+          fecMechanisms: []
+        };
+
+        var findCodecByPayloadType = function findCodecByPayloadType(pt, codecs) {
+          pt = parseInt(pt, 10);
+
+          for (var i = 0; i < codecs.length; i++) {
+            if (codecs[i].payloadType === pt || codecs[i].preferredPayloadType === pt) {
+              return codecs[i];
+            }
+          }
+        };
+
+        var rtxCapabilityMatches = function rtxCapabilityMatches(lRtx, rRtx, lCodecs, rCodecs) {
+          var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs);
+          var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs);
+          return lCodec && rCodec && lCodec.name.toLowerCase() === rCodec.name.toLowerCase();
+        };
+
+        localCapabilities.codecs.forEach(function (lCodec) {
+          for (var i = 0; i < remoteCapabilities.codecs.length; i++) {
+            var rCodec = remoteCapabilities.codecs[i];
+
+            if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && lCodec.clockRate === rCodec.clockRate) {
+              if (lCodec.name.toLowerCase() === 'rtx' && lCodec.parameters && rCodec.parameters.apt) {
+                // for RTX we need to find the local rtx that has a apt
+                // which points to the same local codec as the remote one.
+                if (!rtxCapabilityMatches(lCodec, rCodec, localCapabilities.codecs, remoteCapabilities.codecs)) {
+                  continue;
+                }
+              }
+
+              rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy
+              // number of channels is the highest common number of channels
+
+              rCodec.numChannels = Math.min(lCodec.numChannels, rCodec.numChannels); // push rCodec so we reply with offerer payload type
+
+              commonCapabilities.codecs.push(rCodec); // determine common feedback mechanisms
+
+              rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function (fb) {
+                for (var j = 0; j < lCodec.rtcpFeedback.length; j++) {
+                  if (lCodec.rtcpFeedback[j].type === fb.type && lCodec.rtcpFeedback[j].parameter === fb.parameter) {
+                    return true;
+                  }
+                }
+
+                return false;
+              }); // FIXME: also need to determine .parameters
+              //  see https://github.com/openpeer/ortc/issues/569
+
+              break;
+            }
+          }
+        });
+        localCapabilities.headerExtensions.forEach(function (lHeaderExtension) {
+          for (var i = 0; i < remoteCapabilities.headerExtensions.length; i++) {
+            var rHeaderExtension = remoteCapabilities.headerExtensions[i];
+
+            if (lHeaderExtension.uri === rHeaderExtension.uri) {
+              commonCapabilities.headerExtensions.push(rHeaderExtension);
+              break;
+            }
+          }
+        }); // FIXME: fecMechanisms
+
+        return commonCapabilities;
+      } // is action=setLocalDescription with type allowed in signalingState
+
+
+      function isActionAllowedInSignalingState(action, type, signalingState) {
+        return {
+          offer: {
+            setLocalDescription: ['stable', 'have-local-offer'],
+            setRemoteDescription: ['stable', 'have-remote-offer']
+          },
+          answer: {
+            setLocalDescription: ['have-remote-offer', 'have-local-pranswer'],
+            setRemoteDescription: ['have-local-offer', 'have-remote-pranswer']
+          }
+        }[type][action].indexOf(signalingState) !== -1;
+      }
+
+      function maybeAddCandidate(iceTransport, candidate) {
+        // Edge's internal representation adds some fields therefore
+        // not all field褧 are taken into account.
+        var alreadyAdded = iceTransport.getRemoteCandidates().find(function (remoteCandidate) {
+          return candidate.foundation === remoteCandidate.foundation && candidate.ip === remoteCandidate.ip && candidate.port === remoteCandidate.port && candidate.priority === remoteCandidate.priority && candidate.protocol === remoteCandidate.protocol && candidate.type === remoteCandidate.type;
+        });
+
+        if (!alreadyAdded) {
+          iceTransport.addRemoteCandidate(candidate);
+        }
+
+        return !alreadyAdded;
+      }
+
+      function makeError(name, description) {
+        var e = new Error(description);
+        e.name = name; // legacy error codes from https://heycam.github.io/webidl/#idl-DOMException-error-names
+
+        e.code = {
+          NotSupportedError: 9,
+          InvalidStateError: 11,
+          InvalidAccessError: 15,
+          TypeError: undefined,
+          OperationError: undefined
+        }[name];
+        return e;
+      }
+
+      module.exports = function (window, edgeVersion) {
+        // https://w3c.github.io/mediacapture-main/#mediastream
+        // Helper function to add the track to the stream and
+        // dispatch the event ourselves.
+        function addTrackToStreamAndFireEvent(track, stream) {
+          stream.addTrack(track);
+          stream.dispatchEvent(new window.MediaStreamTrackEvent('addtrack', {
+            track: track
+          }));
+        }
+
+        function removeTrackFromStreamAndFireEvent(track, stream) {
+          stream.removeTrack(track);
+          stream.dispatchEvent(new window.MediaStreamTrackEvent('removetrack', {
+            track: track
+          }));
+        }
+
+        function fireAddTrack(pc, track, receiver, streams) {
+          var trackEvent = new Event('track');
+          trackEvent.track = track;
+          trackEvent.receiver = receiver;
+          trackEvent.transceiver = {
+            receiver: receiver
+          };
+          trackEvent.streams = streams;
+          window.setTimeout(function () {
+            pc._dispatchEvent('track', trackEvent);
+          });
+        }
+
+        var RTCPeerConnection = function RTCPeerConnection(config) {
+          var pc = this;
+
+          var _eventTarget = document.createDocumentFragment();
+
+          ['addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(function (method) {
+            pc[method] = _eventTarget[method].bind(_eventTarget);
+          });
+          this.canTrickleIceCandidates = null;
+          this.needNegotiation = false;
+          this.localStreams = [];
+          this.remoteStreams = [];
+          this._localDescription = null;
+          this._remoteDescription = null;
+          this.signalingState = 'stable';
+          this.iceConnectionState = 'new';
+          this.connectionState = 'new';
+          this.iceGatheringState = 'new';
+          config = JSON.parse(JSON.stringify(config || {}));
+          this.usingBundle = config.bundlePolicy === 'max-bundle';
+
+          if (config.rtcpMuxPolicy === 'negotiate') {
+            throw makeError('NotSupportedError', 'rtcpMuxPolicy \'negotiate\' is not supported');
+          } else if (!config.rtcpMuxPolicy) {
+            config.rtcpMuxPolicy = 'require';
+          }
+
+          switch (config.iceTransportPolicy) {
+            case 'all':
+            case 'relay':
+              break;
+
+            default:
+              config.iceTransportPolicy = 'all';
+              break;
+          }
+
+          switch (config.bundlePolicy) {
+            case 'balanced':
+            case 'max-compat':
+            case 'max-bundle':
+              break;
+
+            default:
+              config.bundlePolicy = 'balanced';
+              break;
+          }
+
+          config.iceServers = filterIceServers(config.iceServers || [], edgeVersion);
+          this._iceGatherers = [];
+
+          if (config.iceCandidatePoolSize) {
+            for (var i = config.iceCandidatePoolSize; i > 0; i--) {
+              this._iceGatherers.push(new window.RTCIceGatherer({
+                iceServers: config.iceServers,
+                gatherPolicy: config.iceTransportPolicy
+              }));
+            }
+          } else {
+            config.iceCandidatePoolSize = 0;
+          }
+
+          this._config = config; // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ...
+          // everything that is needed to describe a SDP m-line.
+
+          this.transceivers = [];
+          this._sdpSessionId = SDPUtils.generateSessionId();
+          this._sdpSessionVersion = 0;
+          this._dtlsRole = undefined; // role for a=setup to use in answers.
+
+          this._isClosed = false;
+        };
+
+        Object.defineProperty(RTCPeerConnection.prototype, 'localDescription', {
+          configurable: true,
+          get: function get() {
+            return this._localDescription;
+          }
+        });
+        Object.defineProperty(RTCPeerConnection.prototype, 'remoteDescription', {
+          configurable: true,
+          get: function get() {
+            return this._remoteDescription;
+          }
+        }); // set up event handlers on prototype
+
+        RTCPeerConnection.prototype.onicecandidate = null;
+        RTCPeerConnection.prototype.onaddstream = null;
+        RTCPeerConnection.prototype.ontrack = null;
+        RTCPeerConnection.prototype.onremovestream = null;
+        RTCPeerConnection.prototype.onsignalingstatechange = null;
+        RTCPeerConnection.prototype.oniceconnectionstatechange = null;
+        RTCPeerConnection.prototype.onconnectionstatechange = null;
+        RTCPeerConnection.prototype.onicegatheringstatechange = null;
+        RTCPeerConnection.prototype.onnegotiationneeded = null;
+        RTCPeerConnection.prototype.ondatachannel = null;
+
+        RTCPeerConnection.prototype._dispatchEvent = function (name, event) {
+          if (this._isClosed) {
+            return;
+          }
+
+          this.dispatchEvent(event);
+
+          if (typeof this['on' + name] === 'function') {
+            this['on' + name](event);
+          }
+        };
+
+        RTCPeerConnection.prototype._emitGatheringStateChange = function () {
+          var event = new Event('icegatheringstatechange');
+
+          this._dispatchEvent('icegatheringstatechange', event);
+        };
+
+        RTCPeerConnection.prototype.getConfiguration = function () {
+          return this._config;
+        };
+
+        RTCPeerConnection.prototype.getLocalStreams = function () {
+          return this.localStreams;
+        };
+
+        RTCPeerConnection.prototype.getRemoteStreams = function () {
+          return this.remoteStreams;
+        }; // internal helper to create a transceiver object.
+        // (which is not yet the same as the WebRTC 1.0 transceiver)
+
+
+        RTCPeerConnection.prototype._createTransceiver = function (kind, doNotAdd) {
+          var hasBundleTransport = this.transceivers.length > 0;
+          var transceiver = {
+            track: null,
+            iceGatherer: null,
+            iceTransport: null,
+            dtlsTransport: null,
+            localCapabilities: null,
+            remoteCapabilities: null,
+            rtpSender: null,
+            rtpReceiver: null,
+            kind: kind,
+            mid: null,
+            sendEncodingParameters: null,
+            recvEncodingParameters: null,
+            stream: null,
+            associatedRemoteMediaStreams: [],
+            wantReceive: true
+          };
+
+          if (this.usingBundle && hasBundleTransport) {
+            transceiver.iceTransport = this.transceivers[0].iceTransport;
+            transceiver.dtlsTransport = this.transceivers[0].dtlsTransport;
+          } else {
+            var transports = this._createIceAndDtlsTransports();
+
+            transceiver.iceTransport = transports.iceTransport;
+            transceiver.dtlsTransport = transports.dtlsTransport;
+          }
+
+          if (!doNotAdd) {
+            this.transceivers.push(transceiver);
+          }
+
+          return transceiver;
+        };
+
+        RTCPeerConnection.prototype.addTrack = function (track, stream) {
+          if (this._isClosed) {
+            throw makeError('InvalidStateError', 'Attempted to call addTrack on a closed peerconnection.');
+          }
+
+          var alreadyExists = this.transceivers.find(function (s) {
+            return s.track === track;
+          });
+
+          if (alreadyExists) {
+            throw makeError('InvalidAccessError', 'Track already exists.');
+          }
+
+          var transceiver;
+
+          for (var i = 0; i < this.transceivers.length; i++) {
+            if (!this.transceivers[i].track && this.transceivers[i].kind === track.kind) {
+              transceiver = this.transceivers[i];
+            }
+          }
+
+          if (!transceiver) {
+            transceiver = this._createTransceiver(track.kind);
+          }
+
+          this._maybeFireNegotiationNeeded();
+
+          if (this.localStreams.indexOf(stream) === -1) {
+            this.localStreams.push(stream);
+          }
+
+          transceiver.track = track;
+          transceiver.stream = stream;
+          transceiver.rtpSender = new window.RTCRtpSender(track, transceiver.dtlsTransport);
+          return transceiver.rtpSender;
+        };
+
+        RTCPeerConnection.prototype.addStream = function (stream) {
+          var pc = this;
+
+          if (edgeVersion >= 15025) {
+            stream.getTracks().forEach(function (track) {
+              pc.addTrack(track, stream);
+            });
+          } else {
+            // Clone is necessary for local demos mostly, attaching directly
+            // to two different senders does not work (build 10547).
+            // Fixed in 15025 (or earlier)
+            var clonedStream = stream.clone();
+            stream.getTracks().forEach(function (track, idx) {
+              var clonedTrack = clonedStream.getTracks()[idx];
+              track.addEventListener('enabled', function (event) {
+                clonedTrack.enabled = event.enabled;
+              });
+            });
+            clonedStream.getTracks().forEach(function (track) {
+              pc.addTrack(track, clonedStream);
+            });
+          }
+        };
+
+        RTCPeerConnection.prototype.removeTrack = function (sender) {
+          if (this._isClosed) {
+            throw makeError('InvalidStateError', 'Attempted to call removeTrack on a closed peerconnection.');
+          }
+
+          if (!(sender instanceof window.RTCRtpSender)) {
+            throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.');
+          }
+
+          var transceiver = this.transceivers.find(function (t) {
+            return t.rtpSender === sender;
+          });
+
+          if (!transceiver) {
+            throw makeError('InvalidAccessError', 'Sender was not created by this connection.');
+          }
+
+          var stream = transceiver.stream;
+          transceiver.rtpSender.stop();
+          transceiver.rtpSender = null;
+          transceiver.track = null;
+          transceiver.stream = null; // remove the stream from the set of local streams
+
+          var localStreams = this.transceivers.map(function (t) {
+            return t.stream;
+          });
+
+          if (localStreams.indexOf(stream) === -1 && this.localStreams.indexOf(stream) > -1) {
+            this.localStreams.splice(this.localStreams.indexOf(stream), 1);
+          }
+
+          this._maybeFireNegotiationNeeded();
+        };
+
+        RTCPeerConnection.prototype.removeStream = function (stream) {
+          var pc = this;
+          stream.getTracks().forEach(function (track) {
+            var sender = pc.getSenders().find(function (s) {
+              return s.track === track;
+            });
+
+            if (sender) {
+              pc.removeTrack(sender);
+            }
+          });
+        };
+
+        RTCPeerConnection.prototype.getSenders = function () {
+          return this.transceivers.filter(function (transceiver) {
+            return !!transceiver.rtpSender;
+          }).map(function (transceiver) {
+            return transceiver.rtpSender;
+          });
+        };
+
+        RTCPeerConnection.prototype.getReceivers = function () {
+          return this.transceivers.filter(function (transceiver) {
+            return !!transceiver.rtpReceiver;
+          }).map(function (transceiver) {
+            return transceiver.rtpReceiver;
+          });
+        };
+
+        RTCPeerConnection.prototype._createIceGatherer = function (sdpMLineIndex, usingBundle) {
+          var pc = this;
+
+          if (usingBundle && sdpMLineIndex > 0) {
+            return this.transceivers[0].iceGatherer;
+          } else if (this._iceGatherers.length) {
+            return this._iceGatherers.shift();
+          }
+
+          var iceGatherer = new window.RTCIceGatherer({
+            iceServers: this._config.iceServers,
+            gatherPolicy: this._config.iceTransportPolicy
+          });
+          Object.defineProperty(iceGatherer, 'state', {
+            value: 'new',
+            writable: true
+          });
+          this.transceivers[sdpMLineIndex].bufferedCandidateEvents = [];
+
+          this.transceivers[sdpMLineIndex].bufferCandidates = function (event) {
+            var end = !event.candidate || Object.keys(event.candidate).length === 0; // polyfill since RTCIceGatherer.state is not implemented in
+            // Edge 10547 yet.
+
+            iceGatherer.state = end ? 'completed' : 'gathering';
+
+            if (pc.transceivers[sdpMLineIndex].bufferedCandidateEvents !== null) {
+              pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event);
+            }
+          };
+
+          iceGatherer.addEventListener('localcandidate', this.transceivers[sdpMLineIndex].bufferCandidates);
+          return iceGatherer;
+        }; // start gathering from an RTCIceGatherer.
+
+
+        RTCPeerConnection.prototype._gather = function (mid, sdpMLineIndex) {
+          var pc = this;
+          var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer;
+
+          if (iceGatherer.onlocalcandidate) {
+            return;
+          }
+
+          var bufferedCandidateEvents = this.transceivers[sdpMLineIndex].bufferedCandidateEvents;
+          this.transceivers[sdpMLineIndex].bufferedCandidateEvents = null;
+          iceGatherer.removeEventListener('localcandidate', this.transceivers[sdpMLineIndex].bufferCandidates);
+
+          iceGatherer.onlocalcandidate = function (evt) {
+            if (pc.usingBundle && sdpMLineIndex > 0) {
+              // if we know that we use bundle we can drop candidates with
+              // 褧dpMLineIndex > 0. If we don't do this then our state gets
+              // confused since we dispose the extra ice gatherer.
+              return;
+            }
+
+            var event = new Event('icecandidate');
+            event.candidate = {
+              sdpMid: mid,
+              sdpMLineIndex: sdpMLineIndex
+            };
+            var cand = evt.candidate; // Edge emits an empty object for RTCIceCandidateComplete鈥�
+
+            var end = !cand || Object.keys(cand).length === 0;
+
+            if (end) {
+              // polyfill since RTCIceGatherer.state is not implemented in
+              // Edge 10547 yet.
+              if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') {
+                iceGatherer.state = 'completed';
+              }
+            } else {
+              if (iceGatherer.state === 'new') {
+                iceGatherer.state = 'gathering';
+              } // RTCIceCandidate doesn't have a component, needs to be added
+
+
+              cand.component = 1; // also the usernameFragment. TODO: update SDP to take both variants.
+
+              cand.ufrag = iceGatherer.getLocalParameters().usernameFragment;
+              var serializedCandidate = SDPUtils.writeCandidate(cand);
+              event.candidate = Object.assign(event.candidate, SDPUtils.parseCandidate(serializedCandidate));
+              event.candidate.candidate = serializedCandidate;
+
+              event.candidate.toJSON = function () {
+                return {
+                  candidate: event.candidate.candidate,
+                  sdpMid: event.candidate.sdpMid,
+                  sdpMLineIndex: event.candidate.sdpMLineIndex,
+                  usernameFragment: event.candidate.usernameFragment
+                };
+              };
+            } // update local description.
+
+
+            var sections = SDPUtils.getMediaSections(pc._localDescription.sdp);
+
+            if (!end) {
+              sections[event.candidate.sdpMLineIndex] += 'a=' + event.candidate.candidate + '\r\n';
+            } else {
+              sections[event.candidate.sdpMLineIndex] += 'a=end-of-candidates\r\n';
+            }
+
+            pc._localDescription.sdp = SDPUtils.getDescription(pc._localDescription.sdp) + sections.join('');
+            var complete = pc.transceivers.every(function (transceiver) {
+              return transceiver.iceGatherer && transceiver.iceGatherer.state === 'completed';
+            });
+
+            if (pc.iceGatheringState !== 'gathering') {
+              pc.iceGatheringState = 'gathering';
+
+              pc._emitGatheringStateChange();
+            } // Emit candidate. Also emit null candidate when all gatherers are
+            // complete.
+
+
+            if (!end) {
+              pc._dispatchEvent('icecandidate', event);
+            }
+
+            if (complete) {
+              pc._dispatchEvent('icecandidate', new Event('icecandidate'));
+
+              pc.iceGatheringState = 'complete';
+
+              pc._emitGatheringStateChange();
+            }
+          }; // emit already gathered candidates.
+
+
+          window.setTimeout(function () {
+            bufferedCandidateEvents.forEach(function (e) {
+              iceGatherer.onlocalcandidate(e);
+            });
+          }, 0);
+        }; // Create ICE transport and DTLS transport.
+
+
+        RTCPeerConnection.prototype._createIceAndDtlsTransports = function () {
+          var pc = this;
+          var iceTransport = new window.RTCIceTransport(null);
+
+          iceTransport.onicestatechange = function () {
+            pc._updateIceConnectionState();
+
+            pc._updateConnectionState();
+          };
+
+          var dtlsTransport = new window.RTCDtlsTransport(iceTransport);
+
+          dtlsTransport.ondtlsstatechange = function () {
+            pc._updateConnectionState();
+          };
+
+          dtlsTransport.onerror = function () {
+            // onerror does not set state to failed by itself.
+            Object.defineProperty(dtlsTransport, 'state', {
+              value: 'failed',
+              writable: true
+            });
+
+            pc._updateConnectionState();
+          };
+
+          return {
+            iceTransport: iceTransport,
+            dtlsTransport: dtlsTransport
+          };
+        }; // Destroy ICE gatherer, ICE transport and DTLS transport.
+        // Without triggering the callbacks.
+
+
+        RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function (sdpMLineIndex) {
+          var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer;
+
+          if (iceGatherer) {
+            delete iceGatherer.onlocalcandidate;
+            delete this.transceivers[sdpMLineIndex].iceGatherer;
+          }
+
+          var iceTransport = this.transceivers[sdpMLineIndex].iceTransport;
+
+          if (iceTransport) {
+            delete iceTransport.onicestatechange;
+            delete this.transceivers[sdpMLineIndex].iceTransport;
+          }
+
+          var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport;
+
+          if (dtlsTransport) {
+            delete dtlsTransport.ondtlsstatechange;
+            delete dtlsTransport.onerror;
+            delete this.transceivers[sdpMLineIndex].dtlsTransport;
+          }
+        }; // Start the RTP Sender and Receiver for a transceiver.
+
+
+        RTCPeerConnection.prototype._transceive = function (transceiver, send, recv) {
+          var params = getCommonCapabilities(transceiver.localCapabilities, transceiver.remoteCapabilities);
+
+          if (send && transceiver.rtpSender) {
+            params.encodings = transceiver.sendEncodingParameters;
+            params.rtcp = {
+              cname: SDPUtils.localCName,
+              compound: transceiver.rtcpParameters.compound
+            };
+
+            if (transceiver.recvEncodingParameters.length) {
+              params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc;
+            }
+
+            transceiver.rtpSender.send(params);
+          }
+
+          if (recv && transceiver.rtpReceiver && params.codecs.length > 0) {
+            // remove RTX field in Edge 14942
+            if (transceiver.kind === 'video' && transceiver.recvEncodingParameters && edgeVersion < 15019) {
+              transceiver.recvEncodingParameters.forEach(function (p) {
+                delete p.rtx;
+              });
+            }
+
+            if (transceiver.recvEncodingParameters.length) {
+              params.encodings = transceiver.recvEncodingParameters;
+            } else {
+              params.encodings = [{}];
+            }
+
+            params.rtcp = {
+              compound: transceiver.rtcpParameters.compound
+            };
+
+            if (transceiver.rtcpParameters.cname) {
+              params.rtcp.cname = transceiver.rtcpParameters.cname;
+            }
+
+            if (transceiver.sendEncodingParameters.length) {
+              params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc;
+            }
+
+            transceiver.rtpReceiver.receive(params);
+          }
+        };
+
+        RTCPeerConnection.prototype.setLocalDescription = function (description) {
+          var pc = this; // Note: pranswer is not supported.
+
+          if (['offer', 'answer'].indexOf(description.type) === -1) {
+            return Promise.reject(makeError('TypeError', 'Unsupported type "' + description.type + '"'));
+          }
+
+          if (!isActionAllowedInSignalingState('setLocalDescription', description.type, pc.signalingState) || pc._isClosed) {
+            return Promise.reject(makeError('InvalidStateError', 'Can not set local ' + description.type + ' in state ' + pc.signalingState));
+          }
+
+          var sections;
+          var sessionpart;
+
+          if (description.type === 'offer') {
+            // VERY limited support for SDP munging. Limited to:
+            // * changing the order of codecs
+            sections = SDPUtils.splitSections(description.sdp);
+            sessionpart = sections.shift();
+            sections.forEach(function (mediaSection, sdpMLineIndex) {
+              var caps = SDPUtils.parseRtpParameters(mediaSection);
+              pc.transceivers[sdpMLineIndex].localCapabilities = caps;
+            });
+            pc.transceivers.forEach(function (transceiver, sdpMLineIndex) {
+              pc._gather(transceiver.mid, sdpMLineIndex);
+            });
+          } else if (description.type === 'answer') {
+            sections = SDPUtils.splitSections(pc._remoteDescription.sdp);
+            sessionpart = sections.shift();
+            var isIceLite = SDPUtils.matchPrefix(sessionpart, 'a=ice-lite').length > 0;
+            sections.forEach(function (mediaSection, sdpMLineIndex) {
+              var transceiver = pc.transceivers[sdpMLineIndex];
+              var iceGatherer = transceiver.iceGatherer;
+              var iceTransport = transceiver.iceTransport;
+              var dtlsTransport = transceiver.dtlsTransport;
+              var localCapabilities = transceiver.localCapabilities;
+              var remoteCapabilities = transceiver.remoteCapabilities; // treat bundle-only as not-rejected.
+
+              var rejected = SDPUtils.isRejected(mediaSection) && SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0;
+
+              if (!rejected && !transceiver.rejected) {
+                var remoteIceParameters = SDPUtils.getIceParameters(mediaSection, sessionpart);
+                var remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, sessionpart);
+
+                if (isIceLite) {
+                  remoteDtlsParameters.role = 'server';
+                }
+
+                if (!pc.usingBundle || sdpMLineIndex === 0) {
+                  pc._gather(transceiver.mid, sdpMLineIndex);
+
+                  if (iceTransport.state === 'new') {
+                    iceTransport.start(iceGatherer, remoteIceParameters, isIceLite ? 'controlling' : 'controlled');
+                  }
+
+                  if (dtlsTransport.state === 'new') {
+                    dtlsTransport.start(remoteDtlsParameters);
+                  }
+                } // Calculate intersection of capabilities.
+
+
+                var params = getCommonCapabilities(localCapabilities, remoteCapabilities); // Start the RTCRtpSender. The RTCRtpReceiver for this
+                // transceiver has already been started in setRemoteDescription.
+
+                pc._transceive(transceiver, params.codecs.length > 0, false);
+              }
+            });
+          }
+
+          pc._localDescription = {
+            type: description.type,
+            sdp: description.sdp
+          };
+
+          if (description.type === 'offer') {
+            pc._updateSignalingState('have-local-offer');
+          } else {
+            pc._updateSignalingState('stable');
+          }
+
+          return Promise.resolve();
+        };
+
+        RTCPeerConnection.prototype.setRemoteDescription = function (description) {
+          var pc = this; // Note: pranswer is not supported.
+
+          if (['offer', 'answer'].indexOf(description.type) === -1) {
+            return Promise.reject(makeError('TypeError', 'Unsupported type "' + description.type + '"'));
+          }
+
+          if (!isActionAllowedInSignalingState('setRemoteDescription', description.type, pc.signalingState) || pc._isClosed) {
+            return Promise.reject(makeError('InvalidStateError', 'Can not set remote ' + description.type + ' in state ' + pc.signalingState));
+          }
+
+          var streams = {};
+          pc.remoteStreams.forEach(function (stream) {
+            streams[stream.id] = stream;
+          });
+          var receiverList = [];
+          var sections = SDPUtils.splitSections(description.sdp);
+          var sessionpart = sections.shift();
+          var isIceLite = SDPUtils.matchPrefix(sessionpart, 'a=ice-lite').length > 0;
+          var usingBundle = SDPUtils.matchPrefix(sessionpart, 'a=group:BUNDLE ').length > 0;
+          pc.usingBundle = usingBundle;
+          var iceOptions = SDPUtils.matchPrefix(sessionpart, 'a=ice-options:')[0];
+
+          if (iceOptions) {
+            pc.canTrickleIceCandidates = iceOptions.substr(14).split(' ').indexOf('trickle') >= 0;
+          } else {
+            pc.canTrickleIceCandidates = false;
+          }
+
+          sections.forEach(function (mediaSection, sdpMLineIndex) {
+            var lines = SDPUtils.splitLines(mediaSection);
+            var kind = SDPUtils.getKind(mediaSection); // treat bundle-only as not-rejected.
+
+            var rejected = SDPUtils.isRejected(mediaSection) && SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0;
+            var protocol = lines[0].substr(2).split(' ')[2];
+            var direction = SDPUtils.getDirection(mediaSection, sessionpart);
+            var remoteMsid = SDPUtils.parseMsid(mediaSection);
+            var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); // Reject datachannels which are not implemented yet.
+
+            if (rejected || kind === 'application' && (protocol === 'DTLS/SCTP' || protocol === 'UDP/DTLS/SCTP')) {
+              // TODO: this is dangerous in the case where a non-rejected m-line
+              //     becomes rejected.
+              pc.transceivers[sdpMLineIndex] = {
+                mid: mid,
+                kind: kind,
+                protocol: protocol,
+                rejected: true
+              };
+              return;
+            }
+
+            if (!rejected && pc.transceivers[sdpMLineIndex] && pc.transceivers[sdpMLineIndex].rejected) {
+              // recycle a rejected transceiver.
+              pc.transceivers[sdpMLineIndex] = pc._createTransceiver(kind, true);
+            }
+
+            var transceiver;
+            var iceGatherer;
+            var iceTransport;
+            var dtlsTransport;
+            var rtpReceiver;
+            var sendEncodingParameters;
+            var recvEncodingParameters;
+            var localCapabilities;
+            var track; // FIXME: ensure the mediaSection has rtcp-mux set.
+
+            var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection);
+            var remoteIceParameters;
+            var remoteDtlsParameters;
+
+            if (!rejected) {
+              remoteIceParameters = SDPUtils.getIceParameters(mediaSection, sessionpart);
+              remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, sessionpart);
+              remoteDtlsParameters.role = 'client';
+            }
+
+            recvEncodingParameters = SDPUtils.parseRtpEncodingParameters(mediaSection);
+            var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection);
+            var isComplete = SDPUtils.matchPrefix(mediaSection, 'a=end-of-candidates', sessionpart).length > 0;
+            var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:').map(function (cand) {
+              return SDPUtils.parseCandidate(cand);
+            }).filter(function (cand) {
+              return cand.component === 1;
+            }); // Check if we can use BUNDLE and dispose transports.
+
+            if ((description.type === 'offer' || description.type === 'answer') && !rejected && usingBundle && sdpMLineIndex > 0 && pc.transceivers[sdpMLineIndex]) {
+              pc._disposeIceAndDtlsTransports(sdpMLineIndex);
+
+              pc.transceivers[sdpMLineIndex].iceGatherer = pc.transceivers[0].iceGatherer;
+              pc.transceivers[sdpMLineIndex].iceTransport = pc.transceivers[0].iceTransport;
+              pc.transceivers[sdpMLineIndex].dtlsTransport = pc.transceivers[0].dtlsTransport;
+
+              if (pc.transceivers[sdpMLineIndex].rtpSender) {
+                pc.transceivers[sdpMLineIndex].rtpSender.setTransport(pc.transceivers[0].dtlsTransport);
+              }
+
+              if (pc.transceivers[sdpMLineIndex].rtpReceiver) {
+                pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport(pc.transceivers[0].dtlsTransport);
+              }
+            }
+
+            if (description.type === 'offer' && !rejected) {
+              transceiver = pc.transceivers[sdpMLineIndex] || pc._createTransceiver(kind);
+              transceiver.mid = mid;
+
+              if (!transceiver.iceGatherer) {
+                transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, usingBundle);
+              }
+
+              if (cands.length && transceiver.iceTransport.state === 'new') {
+                if (isComplete && (!usingBundle || sdpMLineIndex === 0)) {
+                  transceiver.iceTransport.setRemoteCandidates(cands);
+                } else {
+                  cands.forEach(function (candidate) {
+                    maybeAddCandidate(transceiver.iceTransport, candidate);
+                  });
+                }
+              }
+
+              localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); // filter RTX until additional stuff needed for RTX is implemented
+              // in adapter.js
+
+              if (edgeVersion < 15019) {
+                localCapabilities.codecs = localCapabilities.codecs.filter(function (codec) {
+                  return codec.name !== 'rtx';
+                });
+              }
+
+              sendEncodingParameters = transceiver.sendEncodingParameters || [{
+                ssrc: (2 * sdpMLineIndex + 2) * 1001
+              }]; // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams
+
+              var isNewTrack = false;
+
+              if (direction === 'sendrecv' || direction === 'sendonly') {
+                isNewTrack = !transceiver.rtpReceiver;
+                rtpReceiver = transceiver.rtpReceiver || new window.RTCRtpReceiver(transceiver.dtlsTransport, kind);
+
+                if (isNewTrack) {
+                  var stream;
+                  track = rtpReceiver.track; // FIXME: does not work with Plan B.
+
+                  if (remoteMsid && remoteMsid.stream === '-') ; else if (remoteMsid) {
+                    if (!streams[remoteMsid.stream]) {
+                      streams[remoteMsid.stream] = new window.MediaStream();
+                      Object.defineProperty(streams[remoteMsid.stream], 'id', {
+                        get: function get() {
+                          return remoteMsid.stream;
+                        }
+                      });
+                    }
+
+                    Object.defineProperty(track, 'id', {
+                      get: function get() {
+                        return remoteMsid.track;
+                      }
+                    });
+                    stream = streams[remoteMsid.stream];
+                  } else {
+                    if (!streams["default"]) {
+                      streams["default"] = new window.MediaStream();
+                    }
+
+                    stream = streams["default"];
+                  }
+
+                  if (stream) {
+                    addTrackToStreamAndFireEvent(track, stream);
+                    transceiver.associatedRemoteMediaStreams.push(stream);
+                  }
+
+                  receiverList.push([track, rtpReceiver, stream]);
+                }
+              } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) {
+                transceiver.associatedRemoteMediaStreams.forEach(function (s) {
+                  var nativeTrack = s.getTracks().find(function (t) {
+                    return t.id === transceiver.rtpReceiver.track.id;
+                  });
+
+                  if (nativeTrack) {
+                    removeTrackFromStreamAndFireEvent(nativeTrack, s);
+                  }
+                });
+                transceiver.associatedRemoteMediaStreams = [];
+              }
+
+              transceiver.localCapabilities = localCapabilities;
+              transceiver.remoteCapabilities = remoteCapabilities;
+              transceiver.rtpReceiver = rtpReceiver;
+              transceiver.rtcpParameters = rtcpParameters;
+              transceiver.sendEncodingParameters = sendEncodingParameters;
+              transceiver.recvEncodingParameters = recvEncodingParameters; // Start the RTCRtpReceiver now. The RTPSender is started in
+              // setLocalDescription.
+
+              pc._transceive(pc.transceivers[sdpMLineIndex], false, isNewTrack);
+            } else if (description.type === 'answer' && !rejected) {
+              transceiver = pc.transceivers[sdpMLineIndex];
+              iceGatherer = transceiver.iceGatherer;
+              iceTransport = transceiver.iceTransport;
+              dtlsTransport = transceiver.dtlsTransport;
+              rtpReceiver = transceiver.rtpReceiver;
+              sendEncodingParameters = transceiver.sendEncodingParameters;
+              localCapabilities = transceiver.localCapabilities;
+              pc.transceivers[sdpMLineIndex].recvEncodingParameters = recvEncodingParameters;
+              pc.transceivers[sdpMLineIndex].remoteCapabilities = remoteCapabilities;
+              pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters;
+
+              if (cands.length && iceTransport.state === 'new') {
+                if ((isIceLite || isComplete) && (!usingBundle || sdpMLineIndex === 0)) {
+                  iceTransport.setRemoteCandidates(cands);
+                } else {
+                  cands.forEach(function (candidate) {
+                    maybeAddCandidate(transceiver.iceTransport, candidate);
+                  });
+                }
+              }
+
+              if (!usingBundle || sdpMLineIndex === 0) {
+                if (iceTransport.state === 'new') {
+                  iceTransport.start(iceGatherer, remoteIceParameters, 'controlling');
+                }
+
+                if (dtlsTransport.state === 'new') {
+                  dtlsTransport.start(remoteDtlsParameters);
+                }
+              } // If the offer contained RTX but the answer did not,
+              // remove RTX from sendEncodingParameters.
+
+
+              var commonCapabilities = getCommonCapabilities(transceiver.localCapabilities, transceiver.remoteCapabilities);
+              var hasRtx = commonCapabilities.codecs.filter(function (c) {
+                return c.name.toLowerCase() === 'rtx';
+              }).length;
+
+              if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) {
+                delete transceiver.sendEncodingParameters[0].rtx;
+              }
+
+              pc._transceive(transceiver, direction === 'sendrecv' || direction === 'recvonly', direction === 'sendrecv' || direction === 'sendonly'); // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams
+
+
+              if (rtpReceiver && (direction === 'sendrecv' || direction === 'sendonly')) {
+                track = rtpReceiver.track;
+
+                if (remoteMsid) {
+                  if (!streams[remoteMsid.stream]) {
+                    streams[remoteMsid.stream] = new window.MediaStream();
+                  }
+
+                  addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]);
+                  receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]);
+                } else {
+                  if (!streams["default"]) {
+                    streams["default"] = new window.MediaStream();
+                  }
+
+                  addTrackToStreamAndFireEvent(track, streams["default"]);
+                  receiverList.push([track, rtpReceiver, streams["default"]]);
+                }
+              } else {
+                // FIXME: actually the receiver should be created later.
+                delete transceiver.rtpReceiver;
+              }
+            }
+          });
+
+          if (pc._dtlsRole === undefined) {
+            pc._dtlsRole = description.type === 'offer' ? 'active' : 'passive';
+          }
+
+          pc._remoteDescription = {
+            type: description.type,
+            sdp: description.sdp
+          };
+
+          if (description.type === 'offer') {
+            pc._updateSignalingState('have-remote-offer');
+          } else {
+            pc._updateSignalingState('stable');
+          }
+
+          Object.keys(streams).forEach(function (sid) {
+            var stream = streams[sid];
+
+            if (stream.getTracks().length) {
+              if (pc.remoteStreams.indexOf(stream) === -1) {
+                pc.remoteStreams.push(stream);
+                var event = new Event('addstream');
+                event.stream = stream;
+                window.setTimeout(function () {
+                  pc._dispatchEvent('addstream', event);
+                });
+              }
+
+              receiverList.forEach(function (item) {
+                var track = item[0];
+                var receiver = item[1];
+
+                if (stream.id !== item[2].id) {
+                  return;
+                }
+
+                fireAddTrack(pc, track, receiver, [stream]);
+              });
+            }
+          });
+          receiverList.forEach(function (item) {
+            if (item[2]) {
+              return;
+            }
+
+            fireAddTrack(pc, item[0], item[1], []);
+          }); // check whether addIceCandidate({}) was called within four seconds after
+          // setRemoteDescription.
+
+          window.setTimeout(function () {
+            if (!(pc && pc.transceivers)) {
+              return;
+            }
+
+            pc.transceivers.forEach(function (transceiver) {
+              if (transceiver.iceTransport && transceiver.iceTransport.state === 'new' && transceiver.iceTransport.getRemoteCandidates().length > 0) {
+                console.warn('Timeout for addRemoteCandidate. Consider sending ' + 'an end-of-candidates notification');
+                transceiver.iceTransport.addRemoteCandidate({});
+              }
+            });
+          }, 4000);
+          return Promise.resolve();
+        };
+
+        RTCPeerConnection.prototype.close = function () {
+          this.transceivers.forEach(function (transceiver) {
+            /* not yet
+            if (transceiver.iceGatherer) {
+              transceiver.iceGatherer.close();
+            }
+            */
+            if (transceiver.iceTransport) {
+              transceiver.iceTransport.stop();
+            }
+
+            if (transceiver.dtlsTransport) {
+              transceiver.dtlsTransport.stop();
+            }
+
+            if (transceiver.rtpSender) {
+              transceiver.rtpSender.stop();
+            }
+
+            if (transceiver.rtpReceiver) {
+              transceiver.rtpReceiver.stop();
+            }
+          }); // FIXME: clean up tracks, local streams, remote streams, etc
+
+          this._isClosed = true;
+
+          this._updateSignalingState('closed');
+        }; // Update the signaling state.
+
+
+        RTCPeerConnection.prototype._updateSignalingState = function (newState) {
+          this.signalingState = newState;
+          var event = new Event('signalingstatechange');
+
+          this._dispatchEvent('signalingstatechange', event);
+        }; // Determine whether to fire the negotiationneeded event.
+
+
+        RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function () {
+          var pc = this;
+
+          if (this.signalingState !== 'stable' || this.needNegotiation === true) {
+            return;
+          }
+
+          this.needNegotiation = true;
+          window.setTimeout(function () {
+            if (pc.needNegotiation) {
+              pc.needNegotiation = false;
+              var event = new Event('negotiationneeded');
+
+              pc._dispatchEvent('negotiationneeded', event);
+            }
+          }, 0);
+        }; // Update the ice connection state.
+
+
+        RTCPeerConnection.prototype._updateIceConnectionState = function () {
+          var newState;
+          var states = {
+            'new': 0,
+            closed: 0,
+            checking: 0,
+            connected: 0,
+            completed: 0,
+            disconnected: 0,
+            failed: 0
+          };
+          this.transceivers.forEach(function (transceiver) {
+            if (transceiver.iceTransport && !transceiver.rejected) {
+              states[transceiver.iceTransport.state]++;
+            }
+          });
+          newState = 'new';
+
+          if (states.failed > 0) {
+            newState = 'failed';
+          } else if (states.checking > 0) {
+            newState = 'checking';
+          } else if (states.disconnected > 0) {
+            newState = 'disconnected';
+          } else if (states["new"] > 0) {
+            newState = 'new';
+          } else if (states.connected > 0) {
+            newState = 'connected';
+          } else if (states.completed > 0) {
+            newState = 'completed';
+          }
+
+          if (newState !== this.iceConnectionState) {
+            this.iceConnectionState = newState;
+            var event = new Event('iceconnectionstatechange');
+
+            this._dispatchEvent('iceconnectionstatechange', event);
+          }
+        }; // Update the connection state.
+
+
+        RTCPeerConnection.prototype._updateConnectionState = function () {
+          var newState;
+          var states = {
+            'new': 0,
+            closed: 0,
+            connecting: 0,
+            connected: 0,
+            completed: 0,
+            disconnected: 0,
+            failed: 0
+          };
+          this.transceivers.forEach(function (transceiver) {
+            if (transceiver.iceTransport && transceiver.dtlsTransport && !transceiver.rejected) {
+              states[transceiver.iceTransport.state]++;
+              states[transceiver.dtlsTransport.state]++;
+            }
+          }); // ICETransport.completed and connected are the same for this purpose.
+
+          states.connected += states.completed;
+          newState = 'new';
+
+          if (states.failed > 0) {
+            newState = 'failed';
+          } else if (states.connecting > 0) {
+            newState = 'connecting';
+          } else if (states.disconnected > 0) {
+            newState = 'disconnected';
+          } else if (states["new"] > 0) {
+            newState = 'new';
+          } else if (states.connected > 0) {
+            newState = 'connected';
+          }
+
+          if (newState !== this.connectionState) {
+            this.connectionState = newState;
+            var event = new Event('connectionstatechange');
+
+            this._dispatchEvent('connectionstatechange', event);
+          }
+        };
+
+        RTCPeerConnection.prototype.createOffer = function () {
+          var pc = this;
+
+          if (pc._isClosed) {
+            return Promise.reject(makeError('InvalidStateError', 'Can not call createOffer after close'));
+          }
+
+          var numAudioTracks = pc.transceivers.filter(function (t) {
+            return t.kind === 'audio';
+          }).length;
+          var numVideoTracks = pc.transceivers.filter(function (t) {
+            return t.kind === 'video';
+          }).length; // Determine number of audio and video tracks we need to send/recv.
+
+          var offerOptions = arguments[0];
+
+          if (offerOptions) {
+            // Reject Chrome legacy constraints.
+            if (offerOptions.mandatory || offerOptions.optional) {
+              throw new TypeError('Legacy mandatory/optional constraints not supported.');
+            }
+
+            if (offerOptions.offerToReceiveAudio !== undefined) {
+              if (offerOptions.offerToReceiveAudio === true) {
+                numAudioTracks = 1;
+              } else if (offerOptions.offerToReceiveAudio === false) {
+                numAudioTracks = 0;
+              } else {
+                numAudioTracks = offerOptions.offerToReceiveAudio;
+              }
+            }
+
+            if (offerOptions.offerToReceiveVideo !== undefined) {
+              if (offerOptions.offerToReceiveVideo === true) {
+                numVideoTracks = 1;
+              } else if (offerOptions.offerToReceiveVideo === false) {
+                numVideoTracks = 0;
+              } else {
+                numVideoTracks = offerOptions.offerToReceiveVideo;
+              }
+            }
+          }
+
+          pc.transceivers.forEach(function (transceiver) {
+            if (transceiver.kind === 'audio') {
+              numAudioTracks--;
+
+              if (numAudioTracks < 0) {
+                transceiver.wantReceive = false;
+              }
+            } else if (transceiver.kind === 'video') {
+              numVideoTracks--;
+
+              if (numVideoTracks < 0) {
+                transceiver.wantReceive = false;
+              }
+            }
+          }); // Create M-lines for recvonly streams.
+
+          while (numAudioTracks > 0 || numVideoTracks > 0) {
+            if (numAudioTracks > 0) {
+              pc._createTransceiver('audio');
+
+              numAudioTracks--;
+            }
+
+            if (numVideoTracks > 0) {
+              pc._createTransceiver('video');
+
+              numVideoTracks--;
+            }
+          }
+
+          var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, pc._sdpSessionVersion++);
+          pc.transceivers.forEach(function (transceiver, sdpMLineIndex) {
+            // For each track, create an ice gatherer, ice transport,
+            // dtls transport, potentially rtpsender and rtpreceiver.
+            var track = transceiver.track;
+            var kind = transceiver.kind;
+            var mid = transceiver.mid || SDPUtils.generateIdentifier();
+            transceiver.mid = mid;
+
+            if (!transceiver.iceGatherer) {
+              transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, pc.usingBundle);
+            }
+
+            var localCapabilities = window.RTCRtpSender.getCapabilities(kind); // filter RTX until additional stuff needed for RTX is implemented
+            // in adapter.js
+
+            if (edgeVersion < 15019) {
+              localCapabilities.codecs = localCapabilities.codecs.filter(function (codec) {
+                return codec.name !== 'rtx';
+              });
+            }
+
+            localCapabilities.codecs.forEach(function (codec) {
+              // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552
+              // by adding level-asymmetry-allowed=1
+              if (codec.name === 'H264' && codec.parameters['level-asymmetry-allowed'] === undefined) {
+                codec.parameters['level-asymmetry-allowed'] = '1';
+              } // for subsequent offers, we might have to re-use the payload
+              // type of the last offer.
+
+
+              if (transceiver.remoteCapabilities && transceiver.remoteCapabilities.codecs) {
+                transceiver.remoteCapabilities.codecs.forEach(function (remoteCodec) {
+                  if (codec.name.toLowerCase() === remoteCodec.name.toLowerCase() && codec.clockRate === remoteCodec.clockRate) {
+                    codec.preferredPayloadType = remoteCodec.payloadType;
+                  }
+                });
+              }
+            });
+            localCapabilities.headerExtensions.forEach(function (hdrExt) {
+              var remoteExtensions = transceiver.remoteCapabilities && transceiver.remoteCapabilities.headerExtensions || [];
+              remoteExtensions.forEach(function (rHdrExt) {
+                if (hdrExt.uri === rHdrExt.uri) {
+                  hdrExt.id = rHdrExt.id;
+                }
+              });
+            }); // generate an ssrc now, to be used later in rtpSender.send
+
+            var sendEncodingParameters = transceiver.sendEncodingParameters || [{
+              ssrc: (2 * sdpMLineIndex + 1) * 1001
+            }];
+
+            if (track) {
+              // add RTX
+              if (edgeVersion >= 15019 && kind === 'video' && !sendEncodingParameters[0].rtx) {
+                sendEncodingParameters[0].rtx = {
+                  ssrc: sendEncodingParameters[0].ssrc + 1
+                };
+              }
+            }
+
+            if (transceiver.wantReceive) {
+              transceiver.rtpReceiver = new window.RTCRtpReceiver(transceiver.dtlsTransport, kind);
+            }
+
+            transceiver.localCapabilities = localCapabilities;
+            transceiver.sendEncodingParameters = sendEncodingParameters;
+          }); // always offer BUNDLE and dispose on return if not supported.
+
+          if (pc._config.bundlePolicy !== 'max-compat') {
+            sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function (t) {
+              return t.mid;
+            }).join(' ') + '\r\n';
+          }
+
+          sdp += 'a=ice-options:trickle\r\n';
+          pc.transceivers.forEach(function (transceiver, sdpMLineIndex) {
+            sdp += writeMediaSection(transceiver, transceiver.localCapabilities, 'offer', transceiver.stream, pc._dtlsRole);
+            sdp += 'a=rtcp-rsize\r\n';
+
+            if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && (sdpMLineIndex === 0 || !pc.usingBundle)) {
+              transceiver.iceGatherer.getLocalCandidates().forEach(function (cand) {
+                cand.component = 1;
+                sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n';
+              });
+
+              if (transceiver.iceGatherer.state === 'completed') {
+                sdp += 'a=end-of-candidates\r\n';
+              }
+            }
+          });
+          var desc = new window.RTCSessionDescription({
+            type: 'offer',
+            sdp: sdp
+          });
+          return Promise.resolve(desc);
+        };
+
+        RTCPeerConnection.prototype.createAnswer = function () {
+          var pc = this;
+
+          if (pc._isClosed) {
+            return Promise.reject(makeError('InvalidStateError', 'Can not call createAnswer after close'));
+          }
+
+          if (!(pc.signalingState === 'have-remote-offer' || pc.signalingState === 'have-local-pranswer')) {
+            return Promise.reject(makeError('InvalidStateError', 'Can not call createAnswer in signalingState ' + pc.signalingState));
+          }
+
+          var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, pc._sdpSessionVersion++);
+
+          if (pc.usingBundle) {
+            sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function (t) {
+              return t.mid;
+            }).join(' ') + '\r\n';
+          }
+
+          sdp += 'a=ice-options:trickle\r\n';
+          var mediaSectionsInOffer = SDPUtils.getMediaSections(pc._remoteDescription.sdp).length;
+          pc.transceivers.forEach(function (transceiver, sdpMLineIndex) {
+            if (sdpMLineIndex + 1 > mediaSectionsInOffer) {
+              return;
+            }
+
+            if (transceiver.rejected) {
+              if (transceiver.kind === 'application') {
+                if (transceiver.protocol === 'DTLS/SCTP') {
+                  // legacy fmt
+                  sdp += 'm=application 0 DTLS/SCTP 5000\r\n';
+                } else {
+                  sdp += 'm=application 0 ' + transceiver.protocol + ' webrtc-datachannel\r\n';
+                }
+              } else if (transceiver.kind === 'audio') {
+                sdp += 'm=audio 0 UDP/TLS/RTP/SAVPF 0\r\n' + 'a=rtpmap:0 PCMU/8000\r\n';
+              } else if (transceiver.kind === 'video') {
+                sdp += 'm=video 0 UDP/TLS/RTP/SAVPF 120\r\n' + 'a=rtpmap:120 VP8/90000\r\n';
+              }
+
+              sdp += 'c=IN IP4 0.0.0.0\r\n' + 'a=inactive\r\n' + 'a=mid:' + transceiver.mid + '\r\n';
+              return;
+            } // FIXME: look at direction.
+
+
+            if (transceiver.stream) {
+              var localTrack;
+
+              if (transceiver.kind === 'audio') {
+                localTrack = transceiver.stream.getAudioTracks()[0];
+              } else if (transceiver.kind === 'video') {
+                localTrack = transceiver.stream.getVideoTracks()[0];
+              }
+
+              if (localTrack) {
+                // add RTX
+                if (edgeVersion >= 15019 && transceiver.kind === 'video' && !transceiver.sendEncodingParameters[0].rtx) {
+                  transceiver.sendEncodingParameters[0].rtx = {
+                    ssrc: transceiver.sendEncodingParameters[0].ssrc + 1
+                  };
+                }
+              }
+            } // Calculate intersection of capabilities.
+
+
+            var commonCapabilities = getCommonCapabilities(transceiver.localCapabilities, transceiver.remoteCapabilities);
+            var hasRtx = commonCapabilities.codecs.filter(function (c) {
+              return c.name.toLowerCase() === 'rtx';
+            }).length;
+
+            if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) {
+              delete transceiver.sendEncodingParameters[0].rtx;
+            }
+
+            sdp += writeMediaSection(transceiver, commonCapabilities, 'answer', transceiver.stream, pc._dtlsRole);
+
+            if (transceiver.rtcpParameters && transceiver.rtcpParameters.reducedSize) {
+              sdp += 'a=rtcp-rsize\r\n';
+            }
+          });
+          var desc = new window.RTCSessionDescription({
+            type: 'answer',
+            sdp: sdp
+          });
+          return Promise.resolve(desc);
+        };
+
+        RTCPeerConnection.prototype.addIceCandidate = function (candidate) {
+          var pc = this;
+          var sections;
+
+          if (candidate && !(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) {
+            return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required'));
+          } // TODO: needs to go into ops queue.
+
+
+          return new Promise(function (resolve, reject) {
+            if (!pc._remoteDescription) {
+              return reject(makeError('InvalidStateError', 'Can not add ICE candidate without a remote description'));
+            } else if (!candidate || candidate.candidate === '') {
+              for (var j = 0; j < pc.transceivers.length; j++) {
+                if (pc.transceivers[j].rejected) {
+                  continue;
+                }
+
+                pc.transceivers[j].iceTransport.addRemoteCandidate({});
+                sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp);
+                sections[j] += 'a=end-of-candidates\r\n';
+                pc._remoteDescription.sdp = SDPUtils.getDescription(pc._remoteDescription.sdp) + sections.join('');
+
+                if (pc.usingBundle) {
+                  break;
+                }
+              }
+            } else {
+              var sdpMLineIndex = candidate.sdpMLineIndex;
+
+              if (candidate.sdpMid) {
+                for (var i = 0; i < pc.transceivers.length; i++) {
+                  if (pc.transceivers[i].mid === candidate.sdpMid) {
+                    sdpMLineIndex = i;
+                    break;
+                  }
+                }
+              }
+
+              var transceiver = pc.transceivers[sdpMLineIndex];
+
+              if (transceiver) {
+                if (transceiver.rejected) {
+                  return resolve();
+                }
+
+                var cand = Object.keys(candidate.candidate).length > 0 ? SDPUtils.parseCandidate(candidate.candidate) : {}; // Ignore Chrome's invalid candidates since Edge does not like them.
+
+                if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) {
+                  return resolve();
+                } // Ignore RTCP candidates, we assume RTCP-MUX.
+
+
+                if (cand.component && cand.component !== 1) {
+                  return resolve();
+                } // when using bundle, avoid adding candidates to the wrong
+                // ice transport. And avoid adding candidates added in the SDP.
+
+
+                if (sdpMLineIndex === 0 || sdpMLineIndex > 0 && transceiver.iceTransport !== pc.transceivers[0].iceTransport) {
+                  if (!maybeAddCandidate(transceiver.iceTransport, cand)) {
+                    return reject(makeError('OperationError', 'Can not add ICE candidate'));
+                  }
+                } // update the remoteDescription.
+
+
+                var candidateString = candidate.candidate.trim();
+
+                if (candidateString.indexOf('a=') === 0) {
+                  candidateString = candidateString.substr(2);
+                }
+
+                sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp);
+                sections[sdpMLineIndex] += 'a=' + (cand.type ? candidateString : 'end-of-candidates') + '\r\n';
+                pc._remoteDescription.sdp = SDPUtils.getDescription(pc._remoteDescription.sdp) + sections.join('');
+              } else {
+                return reject(makeError('OperationError', 'Can not add ICE candidate'));
+              }
+            }
+
+            resolve();
+          });
+        };
+
+        RTCPeerConnection.prototype.getStats = function (selector) {
+          if (selector && selector instanceof window.MediaStreamTrack) {
+            var senderOrReceiver = null;
+            this.transceivers.forEach(function (transceiver) {
+              if (transceiver.rtpSender && transceiver.rtpSender.track === selector) {
+                senderOrReceiver = transceiver.rtpSender;
+              } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track === selector) {
+                senderOrReceiver = transceiver.rtpReceiver;
+              }
+            });
+
+            if (!senderOrReceiver) {
+              throw makeError('InvalidAccessError', 'Invalid selector.');
+            }
+
+            return senderOrReceiver.getStats();
+          }
+
+          var promises = [];
+          this.transceivers.forEach(function (transceiver) {
+            ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', 'dtlsTransport'].forEach(function (method) {
+              if (transceiver[method]) {
+                promises.push(transceiver[method].getStats());
+              }
+            });
+          });
+          return Promise.all(promises).then(function (allStats) {
+            var results = new Map();
+            allStats.forEach(function (stats) {
+              stats.forEach(function (stat) {
+                results.set(stat.id, stat);
+              });
+            });
+            return results;
+          });
+        }; // fix low-level stat names and return Map instead of object.
+
+
+        var ortcObjects = ['RTCRtpSender', 'RTCRtpReceiver', 'RTCIceGatherer', 'RTCIceTransport', 'RTCDtlsTransport'];
+        ortcObjects.forEach(function (ortcObjectName) {
+          var obj = window[ortcObjectName];
+
+          if (obj && obj.prototype && obj.prototype.getStats) {
+            var nativeGetstats = obj.prototype.getStats;
+
+            obj.prototype.getStats = function () {
+              return nativeGetstats.apply(this).then(function (nativeStats) {
+                var mapStats = new Map();
+                Object.keys(nativeStats).forEach(function (id) {
+                  nativeStats[id].type = fixStatsType(nativeStats[id]);
+                  mapStats.set(id, nativeStats[id]);
+                });
+                return mapStats;
+              });
+            };
+          }
+        }); // legacy callback shims. Should be moved to adapter.js some days.
+
+        var methods = ['createOffer', 'createAnswer'];
+        methods.forEach(function (method) {
+          var nativeMethod = RTCPeerConnection.prototype[method];
+
+          RTCPeerConnection.prototype[method] = function () {
+            var args = arguments;
+
+            if (typeof args[0] === 'function' || typeof args[1] === 'function') {
+              // legacy
+              return nativeMethod.apply(this, [arguments[2]]).then(function (description) {
+                if (typeof args[0] === 'function') {
+                  args[0].apply(null, [description]);
+                }
+              }, function (error) {
+                if (typeof args[1] === 'function') {
+                  args[1].apply(null, [error]);
+                }
+              });
+            }
+
+            return nativeMethod.apply(this, arguments);
+          };
+        });
+        methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'];
+        methods.forEach(function (method) {
+          var nativeMethod = RTCPeerConnection.prototype[method];
+
+          RTCPeerConnection.prototype[method] = function () {
+            var args = arguments;
+
+            if (typeof args[1] === 'function' || typeof args[2] === 'function') {
+              // legacy
+              return nativeMethod.apply(this, arguments).then(function () {
+                if (typeof args[1] === 'function') {
+                  args[1].apply(null);
+                }
+              }, function (error) {
+                if (typeof args[2] === 'function') {
+                  args[2].apply(null, [error]);
+                }
+              });
+            }
+
+            return nativeMethod.apply(this, arguments);
+          };
+        }); // getStats is special. It doesn't have a spec legacy method yet we support
+        // getStats(something, cb) without error callbacks.
+
+        ['getStats'].forEach(function (method) {
+          var nativeMethod = RTCPeerConnection.prototype[method];
+
+          RTCPeerConnection.prototype[method] = function () {
+            var args = arguments;
+
+            if (typeof args[1] === 'function') {
+              return nativeMethod.apply(this, arguments).then(function () {
+                if (typeof args[1] === 'function') {
+                  args[1].apply(null);
+                }
+              });
+            }
+
+            return nativeMethod.apply(this, arguments);
+          };
+        });
+        return RTCPeerConnection;
+      };
+    }, {
+      "sdp": 17
+    }],
+    17: [function (require, module, exports) {
+
+      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"
+
+
+      SDPUtils.parseCandidate = function (line) {
+        var parts; // 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: parseInt(parts[1], 10),
+          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 compability.
+
+              candidate.usernameFragment = parts[i + 1];
+              break;
+
+            default:
+              // extension handling, in particular ufrag
+              candidate[parts[i]] = parts[i + 1];
+              break;
+          }
+        }
+
+        return candidate;
+      }; // Translates a candidate object into SDP candidate attribute.
+
+
+      SDPUtils.writeCandidate = function (candidate) {
+        var sdp = [];
+        sdp.push(candidate.foundation);
+        sdp.push(candidate.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.
+      // a=ice-options:foo bar
+
+
+      SDPUtils.parseIceOptions = function (line) {
+        return line.substr(14).split(' ');
+      }; // Parses an 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;
+      }; // Generate an 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 an 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 a=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 an ftmp 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;
+        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 an a=ftmp 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]) {
+              params.push(param + '=' + codec.parameters[param]);
+            } else {
+              params.push(param);
+            }
+          });
+          line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
+        }
+
+        return line;
+      }; // Parses an 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 an 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;
+      };
+
+      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);
+        }
+      };
+
+      SDPUtils.parseFingerprint = function (line) {
+        var parts = line.substr(14).split(' ');
+        return {
+          algorithm: parts[0].toLowerCase(),
+          // algorithm is case-sensitive in Edge.
+          value: parts[1]
+        };
+      }; // 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.
+        // Note2: 'algorithm' is not case sensitive except 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 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 lines = SDPUtils.splitLines(mediaSection); // Search in session part, too.
+
+        lines = lines.concat(SDPUtils.splitLines(sessionpart));
+        var iceParameters = {
+          usernameFragment: lines.filter(function (line) {
+            return line.indexOf('a=ice-ufrag:') === 0;
+          })[0].substr(12),
+          password: lines.filter(function (line) {
+            return line.indexOf('a=ice-pwd:') === 0;
+          })[0].substr(10)
+        };
+        return iceParameters;
+      }; // Serializes ICE parameters to SDP.
+
+
+      SDPUtils.writeIceParameters = function (params) {
+        return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + 'a=ice-pwd:' + params.password + '\r\n';
+      }; // 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;
+            }
+          }
+        }
+
+        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';
+        }
+
+        sdp += 'a=rtcp-mux\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;
+        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 tha 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;
+      }; // parses either a=msid: or a=ssrc:... msid lines and returns
+      // the id of the MediaStream and MediaStreamTrack.
+
+
+      SDPUtils.parseMsid = function (mediaSection) {
+        var parts;
+        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;
+
+        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 = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:')[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 boilder 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;
+        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';
+      };
+
+      SDPUtils.writeMediaSection = function (transceiver, caps, type, stream) {
+        var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); // Map ICE parameters (ufrag, pwd) to SDP.
+
+        sdp += SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters()); // Map DTLS parameters to SDP.
+
+        sdp += SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(), type === 'offer' ? 'actpass' : 'active');
+        sdp += 'a=mid:' + transceiver.mid + '\r\n';
+
+        if (transceiver.direction) {
+          sdp += 'a=' + transceiver.direction + '\r\n';
+        } else if (transceiver.rtpSender && transceiver.rtpReceiver) {
+          sdp += 'a=sendrecv\r\n';
+        } else if (transceiver.rtpSender) {
+          sdp += 'a=sendonly\r\n';
+        } else if (transceiver.rtpReceiver) {
+          sdp += 'a=recvonly\r\n';
+        } else {
+          sdp += 'a=inactive\r\n';
+        }
+
+        if (transceiver.rtpSender) {
+          // spec.
+          var msid = 'msid:' + stream.id + ' ' + transceiver.rtpSender.track.id + '\r\n';
+          sdp += 'a=' + msid; // for Chrome.
+
+          sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + ' ' + msid;
+
+          if (transceiver.sendEncodingParameters[0].rtx) {
+            sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + ' ' + msid;
+            sdp += 'a=ssrc-group:FID ' + transceiver.sendEncodingParameters[0].ssrc + ' ' + transceiver.sendEncodingParameters[0].rtx.ssrc + '\r\n';
+          }
+        } // FIXME: this should be written by writeRtpDescription.
+
+
+        sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + ' cname:' + SDPUtils.localCName + '\r\n';
+
+        if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {
+          sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + ' cname:' + SDPUtils.localCName + '\r\n';
+        }
+
+        return sdp;
+      }; // 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);
+
+          }
+        }
+
+        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) === 'object') {
+        module.exports = SDPUtils;
+      }
+    }, {}]
+  }, {}, [1])(1);
+});
+
+/*
+	The MIT License (MIT)
+
+	Copyright (c) 2016 Meetecho
+
+	Permission is hereby granted, free of charge, to any person obtaining
+	a copy of this software and associated documentation files (the "Software"),
+	to deal in the Software without restriction, including without limitation
+	the rights to use, copy, modify, merge, publish, distribute, sublicense,
+	and/or sell copies of the Software, and to permit persons to whom the
+	Software is furnished to do so, subject to the following conditions:
+
+	The above copyright notice and this permission notice shall be included
+	in all copies or substantial portions of the Software.
+
+	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+	THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+	OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+	OTHER DEALINGS IN THE SOFTWARE.
+ */
+// List of sessions
+Janus$1.sessions = {};
+
+Janus$1.isExtensionEnabled = function () {
+  if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
+    // No need for the extension, getDisplayMedia is supported
+    return true;
+  }
+
+  if (window.navigator.userAgent.match('Chrome')) {
+    var chromever = parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10);
+    var maxver = 33;
+    if (window.navigator.userAgent.match('Linux')) maxver = 35; // "known" crash in chrome 34 and 35 on linux
+
+    if (chromever >= 26 && chromever <= maxver) {
+      // Older versions of Chrome don't support this extension-based approach, so lie
+      return true;
+    }
+
+    return Janus$1.extension.isInstalled();
+  } else {
+    // Firefox of others, no need for the extension (but this doesn't mean it will work)
+    return true;
+  }
+};
+
+var defaultExtension = {
+  // Screensharing Chrome Extension ID
+  extensionId: 'hapfgfdkleiggjjpfpenajgdnfckjpaj',
+  isInstalled: function isInstalled() {
+    return document.querySelector('#janus-extension-installed') !== null;
+  },
+  getScreen: function getScreen(callback) {
+    var pending = window.setTimeout(function () {
+      var error = new Error('NavigatorUserMediaError');
+      error.name = 'The required Chrome extension is not installed: click <a href="#">here</a> to install it. (NOTE: this will need you to refresh the page)';
+      return callback(error);
+    }, 1000);
+    this.cache[pending] = callback;
+    window.postMessage({
+      type: 'janusGetScreen',
+      id: pending
+    }, '*');
+  },
+  init: function init() {
+    var cache = {};
+    this.cache = cache; // Wait for events from the Chrome Extension
+
+    window.addEventListener('message', function (event) {
+      if (event.origin != window.location.origin) return;
+
+      if (event.data.type == 'janusGotScreen' && cache[event.data.id]) {
+        var callback = cache[event.data.id];
+        delete cache[event.data.id];
+
+        if (event.data.sourceId === '') {
+          // user canceled
+          var error = new Error('NavigatorUserMediaError');
+          error.name = 'You cancelled the request for permission, giving up...';
+          callback(error);
+        } else {
+          callback(null, event.data.sourceId);
+        }
+      } else if (event.data.type == 'janusGetScreenPending') {
+        console.log('clearing ', event.data.id);
+        window.clearTimeout(event.data.id);
+      }
+    });
+  }
+};
+
+Janus$1.useDefaultDependencies = function (deps) {
+  var f = deps && deps.fetch || fetch;
+  var p = deps && deps.Promise || Promise;
+  var socketCls = deps && deps.WebSocket || WebSocket;
+  return {
+    newWebSocket: function newWebSocket(server, proto) {
+      return new socketCls(server, proto);
+    },
+    extension: deps && deps.extension || defaultExtension,
+    isArray: function isArray(arr) {
+      return Array.isArray(arr);
+    },
+    webRTCAdapter: deps && deps.adapter || window.adapter,
+    httpAPICall: function httpAPICall(url, options) {
+      var fetchOptions = {
+        method: options.verb,
+        headers: {
+          'Accept': 'application/json, text/plain, */*'
+        },
+        cache: 'no-cache'
+      };
+
+      if (options.verb === "POST") {
+        fetchOptions.headers['Content-Type'] = 'application/json';
+      }
+
+      if (options.withCredentials !== undefined) {
+        fetchOptions.credentials = options.withCredentials === true ? 'include' : options.withCredentials ? options.withCredentials : 'omit';
+      }
+
+      if (options.body !== undefined) {
+        fetchOptions.body = JSON.stringify(options.body);
+      }
+
+      var fetching = f(url, fetchOptions)["catch"](function (error) {
+        return p.reject({
+          message: 'Probably a network error, is the server down?',
+          error: error
+        });
+      });
+      /*
+       * fetch() does not natively support timeouts.
+       * Work around this by starting a timeout manually, and racing it agains the fetch() to see which thing resolves first.
+       */
+
+      if (options.timeout !== undefined) {
+        var timeout = new p(function (resolve, reject) {
+          var timerId = setTimeout(function () {
+            clearTimeout(timerId);
+            return reject({
+              message: 'Request timed out',
+              timeout: options.timeout
+            });
+          }, options.timeout);
+        });
+        fetching = p.race([fetching, timeout]);
+      }
+
+      fetching.then(function (response) {
+        if (response.ok) {
+          if (_typeof(options.success) === _typeof(Janus$1.noop)) {
+            return response.json().then(function (parsed) {
+              options.success(parsed);
+            })["catch"](function (error) {
+              return p.reject({
+                message: 'Failed to parse response body',
+                error: error,
+                response: response
+              });
+            });
+          }
+        } else {
+          return p.reject({
+            message: 'API call failed',
+            response: response
+          });
+        }
+      })["catch"](function (error) {
+        if (_typeof(options.error) === _typeof(Janus$1.noop)) {
+          options.error(error.message || '<< internal error >>', error);
+        }
+      });
+      return fetching;
+    }
+  };
+};
+
+Janus$1.useOldDependencies = function (deps) {
+  var jq = deps && deps.jQuery || jQuery;
+  var socketCls = deps && deps.WebSocket || WebSocket;
+  return {
+    newWebSocket: function newWebSocket(server, proto) {
+      return new socketCls(server, proto);
+    },
+    isArray: function isArray(arr) {
+      return jq.isArray(arr);
+    },
+    extension: deps && deps.extension || defaultExtension,
+    webRTCAdapter: deps && deps.adapter || adapter,
+    httpAPICall: function httpAPICall(url, options) {
+      var payload = options.body !== undefined ? {
+        contentType: 'application/json',
+        data: JSON.stringify(options.body)
+      } : {};
+      var credentials = options.withCredentials !== undefined ? {
+        xhrFields: {
+          withCredentials: options.withCredentials
+        }
+      } : {};
+      return jq.ajax(jq.extend(payload, credentials, {
+        url: url,
+        type: options.verb,
+        cache: false,
+        dataType: 'json',
+        async: options.async,
+        timeout: options.timeout,
+        success: function success(result) {
+          if (_typeof(options.success) === _typeof(Janus$1.noop)) {
+            options.success(result);
+          }
+        },
+        error: function error(xhr, status, err) {
+          if (_typeof(options.error) === _typeof(Janus$1.noop)) {
+            options.error(status, err);
+          }
+        }
+      }));
+    }
+  };
+};
+
+Janus$1.noop = function () {};
+
+Janus$1.dataChanDefaultLabel = "JanusDataChannel"; // Note: in the future we may want to change this, e.g., as was
+// attempted in https://github.com/meetecho/janus-gateway/issues/1670
+
+Janus$1.endOfCandidates = null; // Initialization
+
+Janus$1.init = function (options) {
+  options = options || {};
+  options.callback = typeof options.callback == "function" ? options.callback : Janus$1.noop;
+
+  if (Janus$1.initDone === true) {
+    // Already initialized
+    options.callback();
+  } else {
+    if (typeof console == "undefined" || typeof console.log == "undefined") console = {
+      log: function log() {}
+    }; // Console logging (all debugging disabled by default)
+
+    Janus$1.trace = Janus$1.noop;
+    Janus$1.debug = Janus$1.noop;
+    Janus$1.vdebug = Janus$1.noop;
+    Janus$1.log = Janus$1.noop;
+    Janus$1.warn = Janus$1.noop;
+    Janus$1.error = Janus$1.noop;
+
+    if (options.debug === true || options.debug === "all") {
+      // Enable all debugging levels
+      Janus$1.trace = console.trace.bind(console);
+      Janus$1.debug = console.debug.bind(console);
+      Janus$1.vdebug = console.debug.bind(console);
+      Janus$1.log = console.log.bind(console);
+      Janus$1.warn = console.warn.bind(console);
+      Janus$1.error = console.error.bind(console);
+    } else if (Array.isArray(options.debug)) {
+      for (var i in options.debug) {
+        var d = options.debug[i];
+
+        switch (d) {
+          case "trace":
+            Janus$1.trace = console.trace.bind(console);
+            break;
+
+          case "debug":
+            Janus$1.debug = console.debug.bind(console);
+            break;
+
+          case "vdebug":
+            Janus$1.vdebug = console.debug.bind(console);
+            break;
+
+          case "log":
+            Janus$1.log = console.log.bind(console);
+            break;
+
+          case "warn":
+            Janus$1.warn = console.warn.bind(console);
+            break;
+
+          case "error":
+            Janus$1.error = console.error.bind(console);
+            break;
+
+          default:
+            console.error("Unknown debugging option '" + d + "' (supported: 'trace', 'debug', 'vdebug', 'log', warn', 'error')");
+            break;
+        }
+      }
+    }
+
+    Janus$1.log("Initializing library");
+    var usedDependencies = options.dependencies || Janus$1.useDefaultDependencies();
+    Janus$1.isArray = usedDependencies.isArray;
+    Janus$1.webRTCAdapter = usedDependencies.webRTCAdapter;
+    Janus$1.httpAPICall = usedDependencies.httpAPICall;
+    Janus$1.newWebSocket = usedDependencies.newWebSocket;
+    Janus$1.extension = usedDependencies.extension;
+    Janus$1.extension.init(); // Helper method to enumerate devices
+
+    Janus$1.listDevices = function (callback, config) {
+      callback = typeof callback == "function" ? callback : Janus$1.noop;
+      if (config == null) config = {
+        audio: true,
+        video: true
+      };
+
+      if (Janus$1.isGetUserMediaAvailable()) {
+        navigator.mediaDevices.getUserMedia(config).then(function (stream) {
+          navigator.mediaDevices.enumerateDevices().then(function (devices) {
+            Janus$1.debug(devices);
+            callback(devices); // Get rid of the now useless stream
+
+            try {
+              var tracks = stream.getTracks();
+
+              for (var i in tracks) {
+                var mst = tracks[i];
+                if (mst !== null && mst !== undefined) mst.stop();
+              }
+            } catch (e) {}
+          });
+        })["catch"](function (err) {
+          Janus$1.error(err);
+          callback([]);
+        });
+      } else {
+        Janus$1.warn("navigator.mediaDevices unavailable");
+        callback([]);
+      }
+    }; // Helper methods to attach/reattach a stream to a video element (previously part of adapter.js)
+
+
+    Janus$1.attachMediaStream = function (element, stream) {
+      if (Janus$1.webRTCAdapter.browserDetails.browser === 'chrome') {
+        var chromever = Janus$1.webRTCAdapter.browserDetails.version;
+
+        if (chromever >= 52) {
+          element.srcObject = stream;
+        } else if (typeof element.src !== 'undefined') {
+          element.src = URL.createObjectURL(stream);
+        } else {
+          Janus$1.error("Error attaching stream to element");
+        }
+      } else {
+        element.srcObject = stream;
+      }
+    };
+
+    Janus$1.reattachMediaStream = function (to, from) {
+      if (Janus$1.webRTCAdapter.browserDetails.browser === 'chrome') {
+        var chromever = Janus$1.webRTCAdapter.browserDetails.version;
+
+        if (chromever >= 52) {
+          to.srcObject = from.srcObject;
+        } else if (typeof to.src !== 'undefined') {
+          to.src = from.src;
+        } else {
+          Janus$1.error("Error reattaching stream to element");
+        }
+      } else {
+        to.srcObject = from.srcObject;
+      }
+    }; // Detect tab close: make sure we don't loose existing onbeforeunload handlers
+    // (note: for iOS we need to subscribe to a different event, 'pagehide', see
+    // https://gist.github.com/thehunmonkgroup/6bee8941a49b86be31a787fe8f4b8cfe)
+
+
+    var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
+    var eventName = iOS ? 'pagehide' : 'beforeunload';
+    var oldOBF = window["on" + eventName];
+    window.addEventListener(eventName, function (event) {
+      Janus$1.log("Closing window");
+
+      for (var s in Janus$1.sessions) {
+        if (Janus$1.sessions[s] !== null && Janus$1.sessions[s] !== undefined && Janus$1.sessions[s].destroyOnUnload) {
+          Janus$1.log("Destroying session " + s);
+          Janus$1.sessions[s].destroy({
+            asyncRequest: false,
+            notifyDestroyed: false
+          });
+        }
+      }
+
+      if (oldOBF && typeof oldOBF == "function") oldOBF();
+    }); // If this is a Safari Technology Preview, check if VP8 is supported
+
+    Janus$1.safariVp8 = false;
+
+    if (Janus$1.webRTCAdapter.browserDetails.browser === 'safari' && Janus$1.webRTCAdapter.browserDetails.version >= 605) {
+      // Let's see if RTCRtpSender.getCapabilities() is there
+      if (RTCRtpSender && RTCRtpSender.getCapabilities && RTCRtpSender.getCapabilities("video") && RTCRtpSender.getCapabilities("video").codecs && RTCRtpSender.getCapabilities("video").codecs.length) {
+        for (var i in RTCRtpSender.getCapabilities("video").codecs) {
+          var codec = RTCRtpSender.getCapabilities("video").codecs[i];
+
+          if (codec && codec.mimeType && codec.mimeType.toLowerCase() === "video/vp8") {
+            Janus$1.safariVp8 = true;
+            break;
+          }
+        }
+
+        if (Janus$1.safariVp8) {
+          Janus$1.log("This version of Safari supports VP8");
+        } else {
+          Janus$1.warn("This version of Safari does NOT support VP8: if you're using a Technology Preview, " + "try enabling the 'WebRTC VP8 codec' setting in the 'Experimental Features' Develop menu");
+        }
+      } else {
+        // We do it in a very ugly way, as there's no alternative...
+        // We create a PeerConnection to see if VP8 is in an offer
+        var testpc = new RTCPeerConnection({}, {});
+        testpc.createOffer({
+          offerToReceiveVideo: true
+        }).then(function (offer) {
+          Janus$1.safariVp8 = offer.sdp.indexOf("VP8") !== -1;
+
+          if (Janus$1.safariVp8) {
+            Janus$1.log("This version of Safari supports VP8");
+          } else {
+            Janus$1.warn("This version of Safari does NOT support VP8: if you're using a Technology Preview, " + "try enabling the 'WebRTC VP8 codec' setting in the 'Experimental Features' Develop menu");
+          }
+
+          testpc.close();
+          testpc = null;
+        });
+      }
+    } // Check if this browser supports Unified Plan and transceivers
+    // Based on https://codepen.io/anon/pen/ZqLwWV?editors=0010
+
+
+    Janus$1.unifiedPlan = false;
+
+    if (Janus$1.webRTCAdapter.browserDetails.browser === 'firefox' && Janus$1.webRTCAdapter.browserDetails.version >= 59) {
+      // Firefox definitely does, starting from version 59
+      Janus$1.unifiedPlan = true;
+    } else if (Janus$1.webRTCAdapter.browserDetails.browser === 'chrome' && Janus$1.webRTCAdapter.browserDetails.version < 72) {
+      // Chrome does, but it's only usable from version 72 on
+      Janus$1.unifiedPlan = false;
+    } else if (typeof RTCRtpTransceiver !== 'undefined' && !('currentDirection' in RTCRtpTransceiver.prototype)) {
+      // Safari supports addTransceiver() but not Unified Plan when
+      // currentDirection is not defined (see codepen above)
+      Janus$1.unifiedPlan = false;
+    } else {
+      // Check if addTransceiver() throws an exception
+      var tempPc = new RTCPeerConnection();
+
+      try {
+        tempPc.addTransceiver('audio');
+        Janus$1.unifiedPlan = true;
+      } catch (e) {}
+
+      tempPc.close();
+    }
+
+    Janus$1.initDone = true;
+    options.callback();
+  }
+}; // Helper method to check whether WebRTC is supported by this browser
+
+
+Janus$1.isWebrtcSupported = function () {
+  return window.RTCPeerConnection !== undefined && window.RTCPeerConnection !== null;
+}; // Helper method to check whether devices can be accessed by this browser (e.g., not possible via plain HTTP)
+
+
+Janus$1.isGetUserMediaAvailable = function () {
+  return navigator.mediaDevices !== undefined && navigator.mediaDevices !== null && navigator.mediaDevices.getUserMedia !== undefined && navigator.mediaDevices.getUserMedia !== null;
+}; // Helper method to create random identifiers (e.g., transaction)
+
+
+Janus$1.randomString = function (len) {
+  var charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+  var randomString = '';
+
+  for (var i = 0; i < len; i++) {
+    var randomPoz = Math.floor(Math.random() * charSet.length);
+    randomString += charSet.substring(randomPoz, randomPoz + 1);
+  }
+
+  return randomString;
+};
+
+function Janus$1(gatewayCallbacks) {
+  if (Janus$1.initDone === undefined) {
+    gatewayCallbacks.error("Library not initialized");
+    return {};
+  }
+
+  if (!Janus$1.isWebrtcSupported()) {
+    gatewayCallbacks.error("WebRTC not supported by this browser");
+    return {};
+  }
+
+  Janus$1.log("Library initialized: " + Janus$1.initDone);
+  gatewayCallbacks = gatewayCallbacks || {};
+  gatewayCallbacks.success = typeof gatewayCallbacks.success == "function" ? gatewayCallbacks.success : Janus$1.noop;
+  gatewayCallbacks.error = typeof gatewayCallbacks.error == "function" ? gatewayCallbacks.error : Janus$1.noop;
+  gatewayCallbacks.destroyed = typeof gatewayCallbacks.destroyed == "function" ? gatewayCallbacks.destroyed : Janus$1.noop;
+
+  if (gatewayCallbacks.server === null || gatewayCallbacks.server === undefined) {
+    gatewayCallbacks.error("Invalid server url");
+    return {};
+  }
+
+  var websockets = false;
+  var ws = null;
+  var wsHandlers = {};
+  var wsKeepaliveTimeoutId = null;
+  var servers = null,
+      serversIndex = 0;
+  var server = gatewayCallbacks.server;
+
+  if (Janus$1.isArray(server)) {
+    Janus$1.log("Multiple servers provided (" + server.length + "), will use the first that works");
+    server = null;
+    servers = gatewayCallbacks.server;
+    Janus$1.debug(servers);
+  } else {
+    if (server.indexOf("ws") === 0) {
+      websockets = true;
+      Janus$1.log("Using WebSockets to contact Janus: " + server);
+    } else {
+      websockets = false;
+      Janus$1.log("Using REST API to contact Janus: " + server);
+    }
+  }
+
+  var iceServers = gatewayCallbacks.iceServers;
+  if (iceServers === undefined || iceServers === null) iceServers = [{
+    urls: "stun:stun.l.google.com:19302"
+  }];
+  var iceTransportPolicy = gatewayCallbacks.iceTransportPolicy;
+  var bundlePolicy = gatewayCallbacks.bundlePolicy; // Whether IPv6 candidates should be gathered
+
+  var ipv6Support = gatewayCallbacks.ipv6;
+  if (ipv6Support === undefined || ipv6Support === null) ipv6Support = false; // Whether we should enable the withCredentials flag for XHR requests
+
+  var withCredentials = false;
+  if (gatewayCallbacks.withCredentials !== undefined && gatewayCallbacks.withCredentials !== null) withCredentials = gatewayCallbacks.withCredentials === true; // Optional max events
+
+  var maxev = 10;
+  if (gatewayCallbacks.max_poll_events !== undefined && gatewayCallbacks.max_poll_events !== null) maxev = gatewayCallbacks.max_poll_events;
+  if (maxev < 1) maxev = 1; // Token to use (only if the token based authentication mechanism is enabled)
+
+  var token = null;
+  if (gatewayCallbacks.token !== undefined && gatewayCallbacks.token !== null) token = gatewayCallbacks.token; // API secret to use (only if the shared API secret is enabled)
+
+  var apisecret = null;
+  if (gatewayCallbacks.apisecret !== undefined && gatewayCallbacks.apisecret !== null) apisecret = gatewayCallbacks.apisecret; // Whether we should destroy this session when onbeforeunload is called
+
+  this.destroyOnUnload = true;
+  if (gatewayCallbacks.destroyOnUnload !== undefined && gatewayCallbacks.destroyOnUnload !== null) this.destroyOnUnload = gatewayCallbacks.destroyOnUnload === true; // Some timeout-related values
+
+  var keepAlivePeriod = 25000;
+  if (gatewayCallbacks.keepAlivePeriod !== undefined && gatewayCallbacks.keepAlivePeriod !== null) keepAlivePeriod = gatewayCallbacks.keepAlivePeriod;
+  if (isNaN(keepAlivePeriod)) keepAlivePeriod = 25000;
+  var longPollTimeout = 60000;
+  if (gatewayCallbacks.longPollTimeout !== undefined && gatewayCallbacks.longPollTimeout !== null) longPollTimeout = gatewayCallbacks.longPollTimeout;
+  if (isNaN(longPollTimeout)) longPollTimeout = 60000; // overrides for default maxBitrate values for simulcasting
+
+  function getMaxBitrates(simulcastMaxBitrates) {
+    var maxBitrates = {
+      high: 900000,
+      medium: 300000,
+      low: 100000
+    };
+
+    if (simulcastMaxBitrates !== undefined && simulcastMaxBitrates !== null) {
+      if (simulcastMaxBitrates.high) maxBitrates.high = simulcastMaxBitrates.high;
+      if (simulcastMaxBitrates.medium) maxBitrates.medium = simulcastMaxBitrates.medium;
+      if (simulcastMaxBitrates.low) maxBitrates.low = simulcastMaxBitrates.low;
+    }
+
+    return maxBitrates;
+  }
+
+  var connected = false;
+  var sessionId = null;
+  var pluginHandles = {};
+  var that = this;
+  var retries = 0;
+  var transactions = {};
+  createSession(gatewayCallbacks); // Public methods
+
+  this.getServer = function () {
+    return server;
+  };
+
+  this.isConnected = function () {
+    return connected;
+  };
+
+  this.reconnect = function (callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    callbacks["reconnect"] = true;
+    createSession(callbacks);
+  };
+
+  this.getSessionId = function () {
+    return sessionId;
+  };
+
+  this.destroy = function (callbacks) {
+    destroySession(callbacks);
+  };
+
+  this.attach = function (callbacks) {
+    createHandle(callbacks);
+  };
+
+  function eventHandler() {
+    if (sessionId == null) return;
+    Janus$1.debug('Long poll...');
+
+    if (!connected) {
+      Janus$1.warn("Is the server down? (connected=false)");
+      return;
+    }
+
+    var longpoll = server + "/" + sessionId + "?rid=" + new Date().getTime();
+    if (maxev !== undefined && maxev !== null) longpoll = longpoll + "&maxev=" + maxev;
+    if (token !== null && token !== undefined) longpoll = longpoll + "&token=" + encodeURIComponent(token);
+    if (apisecret !== null && apisecret !== undefined) longpoll = longpoll + "&apisecret=" + encodeURIComponent(apisecret);
+    Janus$1.httpAPICall(longpoll, {
+      verb: 'GET',
+      withCredentials: withCredentials,
+      success: handleEvent,
+      timeout: longPollTimeout,
+      error: function error(textStatus, errorThrown) {
+        Janus$1.error(textStatus + ":", errorThrown);
+        retries++;
+
+        if (retries > 3) {
+          // Did we just lose the server? :-(
+          connected = false;
+          gatewayCallbacks.error("Lost connection to the server (is it down?)");
+          return;
+        }
+
+        eventHandler();
+      }
+    });
+  } // Private event handler: this will trigger plugin callbacks, if set
+
+
+  function handleEvent(json, skipTimeout) {
+    retries = 0;
+    if (!websockets && sessionId !== undefined && sessionId !== null && skipTimeout !== true) eventHandler();
+
+    if (!websockets && Janus$1.isArray(json)) {
+      // We got an array: it means we passed a maxev > 1, iterate on all objects
+      for (var i = 0; i < json.length; i++) {
+        handleEvent(json[i], true);
+      }
+
+      return;
+    }
+
+    if (json["rtcgw"] === "keepalive") {
+      // Nothing happened
+      Janus$1.vdebug("Got a keepalive on session " + sessionId);
+      return;
+    } else if (json["rtcgw"] === "ack") {
+      // Just an ack, we can probably ignore
+      Janus$1.debug("Got an ack on session " + sessionId);
+      Janus$1.debug(json);
+      var transaction = json["transaction"];
+
+      if (transaction !== null && transaction !== undefined) {
+        var reportSuccess = transactions[transaction];
+
+        if (reportSuccess !== null && reportSuccess !== undefined) {
+          reportSuccess(json);
+        }
+
+        delete transactions[transaction];
+      }
+
+      return;
+    } else if (json["rtcgw"] === "success") {
+      // Success!
+      Janus$1.debug("Got a success on session " + sessionId);
+      Janus$1.debug(json);
+      var transaction = json["transaction"];
+
+      if (transaction !== null && transaction !== undefined) {
+        var reportSuccess = transactions[transaction];
+
+        if (reportSuccess !== null && reportSuccess !== undefined) {
+          reportSuccess(json);
+        }
+
+        delete transactions[transaction];
+      }
+
+      return;
+    } else if (json["rtcgw"] === "trickle") {
+      // We got a trickle candidate from Janus
+      var sender = json["sender"];
+
+      if (sender === undefined || sender === null) {
+        Janus$1.warn("Missing sender...");
+        return;
+      }
+
+      var pluginHandle = pluginHandles[sender];
+
+      if (pluginHandle === undefined || pluginHandle === null) {
+        Janus$1.debug("This handle is not attached to this session");
+        return;
+      }
+
+      var candidate = json["candidate"];
+      Janus$1.debug("Got a trickled candidate on session " + sessionId);
+      Janus$1.debug(candidate);
+      var config = pluginHandle.webrtcStuff;
+
+      if (config.pc && config.remoteSdp) {
+        // Add candidate right now
+        Janus$1.debug("Adding remote candidate:", candidate);
+
+        if (!candidate || candidate.completed === true) {
+          // end-of-candidates
+          config.pc.addIceCandidate(Janus$1.endOfCandidates);
+        } else {
+          // New candidate
+          config.pc.addIceCandidate(candidate);
+        }
+      } else {
+        // We didn't do setRemoteDescription (trickle got here before the offer?)
+        Janus$1.debug("We didn't do setRemoteDescription (trickle got here before the offer?), caching candidate");
+        if (!config.candidates) config.candidates = [];
+        config.candidates.push(candidate);
+        Janus$1.debug(config.candidates);
+      }
+    } else if (json["rtcgw"] === "webrtcup") {
+      // The PeerConnection with the server is up! Notify this
+      Janus$1.debug("Got a webrtcup event on session " + sessionId);
+      Janus$1.debug(json);
+      var sender = json["sender"];
+
+      if (sender === undefined || sender === null) {
+        Janus$1.warn("Missing sender...");
+        return;
+      }
+
+      var pluginHandle = pluginHandles[sender];
+
+      if (pluginHandle === undefined || pluginHandle === null) {
+        Janus$1.debug("This handle is not attached to this session");
+        return;
+      }
+
+      pluginHandle.webrtcState(true);
+      return;
+    } else if (json["rtcgw"] === "hangup") {
+      // A plugin asked the core to hangup a PeerConnection on one of our handles
+      Janus$1.debug("Got a hangup event on session " + sessionId);
+      Janus$1.debug(json);
+      var sender = json["sender"];
+
+      if (sender === undefined || sender === null) {
+        Janus$1.warn("Missing sender...");
+        return;
+      }
+
+      var pluginHandle = pluginHandles[sender];
+
+      if (pluginHandle === undefined || pluginHandle === null) {
+        Janus$1.debug("This handle is not attached to this session");
+        return;
+      }
+
+      pluginHandle.webrtcState(false, json["reason"]);
+      pluginHandle.hangup();
+    } else if (json["rtcgw"] === "detached") {
+      // A plugin asked the core to detach one of our handles
+      Janus$1.debug("Got a detached event on session " + sessionId);
+      Janus$1.debug(json);
+      var sender = json["sender"];
+
+      if (sender === undefined || sender === null) {
+        Janus$1.warn("Missing sender...");
+        return;
+      }
+
+      var pluginHandle = pluginHandles[sender];
+
+      if (pluginHandle === undefined || pluginHandle === null) {
+        // Don't warn here because destroyHandle causes this situation.
+        return;
+      }
+
+      pluginHandle.detached = true;
+      pluginHandle.ondetached();
+      pluginHandle.detach();
+    } else if (json["rtcgw"] === "media") {
+      // Media started/stopped flowing
+      Janus$1.debug("Got a media event on session " + sessionId);
+      Janus$1.debug(json);
+      var sender = json["sender"];
+
+      if (sender === undefined || sender === null) {
+        Janus$1.warn("Missing sender...");
+        return;
+      }
+
+      var pluginHandle = pluginHandles[sender];
+
+      if (pluginHandle === undefined || pluginHandle === null) {
+        Janus$1.debug("This handle is not attached to this session");
+        return;
+      }
+
+      pluginHandle.mediaState(json["type"], json["receiving"]);
+    } else if (json["rtcgw"] === "slowlink") {
+      Janus$1.debug("Got a slowlink event on session " + sessionId);
+      Janus$1.debug(json); // Trouble uplink or downlink
+
+      var sender = json["sender"];
+
+      if (sender === undefined || sender === null) {
+        Janus$1.warn("Missing sender...");
+        return;
+      }
+
+      var pluginHandle = pluginHandles[sender];
+
+      if (pluginHandle === undefined || pluginHandle === null) {
+        Janus$1.debug("This handle is not attached to this session");
+        return;
+      }
+
+      pluginHandle.slowLink(json["uplink"], json["lost"]);
+    } else if (json["rtcgw"] === "error") {
+      // Oops, something wrong happened
+      Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+      Janus$1.debug(json);
+      var transaction = json["transaction"];
+
+      if (transaction !== null && transaction !== undefined) {
+        var reportSuccess = transactions[transaction];
+
+        if (reportSuccess !== null && reportSuccess !== undefined) {
+          reportSuccess(json);
+        }
+
+        delete transactions[transaction];
+      }
+
+      return;
+    } else if (json["rtcgw"] === "event") {
+      Janus$1.debug("Got a plugin event on session " + sessionId);
+      Janus$1.debug(json);
+      var sender = json["sender"];
+
+      if (sender === undefined || sender === null) {
+        Janus$1.warn("Missing sender...");
+        return;
+      }
+
+      var plugindata = json["plugindata"];
+
+      if (plugindata === undefined || plugindata === null) {
+        Janus$1.warn("Missing plugindata...");
+        return;
+      }
+
+      Janus$1.debug("  -- Event is coming from " + sender + " (" + plugindata["plugin"] + ")");
+      var data = plugindata["data"];
+      Janus$1.debug(data);
+      var pluginHandle = pluginHandles[sender];
+
+      if (pluginHandle === undefined || pluginHandle === null) {
+        Janus$1.warn("This handle is not attached to this session");
+        return;
+      }
+
+      var jsep = json["jsep"];
+
+      if (jsep !== undefined && jsep !== null) {
+        Janus$1.debug("Handling SDP as well...");
+        Janus$1.debug(jsep);
+      }
+
+      var callback = pluginHandle.onmessage;
+
+      if (callback !== null && callback !== undefined) {
+        Janus$1.debug("Notifying application..."); // Send to callback specified when attaching plugin handle
+
+        callback(data, jsep);
+      } else {
+        // Send to generic callback (?)
+        Janus$1.debug("No provided notification callback");
+      }
+    } else if (json["rtcgw"] === "timeout") {
+      Janus$1.error("Timeout on session " + sessionId);
+      Janus$1.debug(json);
+
+      if (websockets) {
+        ws.close(3504, "Gateway timeout");
+      }
+
+      return;
+    } else {
+      Janus$1.warn("Unknown message/event  '" + json["rtcgw"] + "' on session " + sessionId);
+      Janus$1.debug(json);
+    }
+  } // Private helper to send keep-alive messages on WebSockets
+
+
+  function keepAlive() {
+    if (server === null || !websockets || !connected) return;
+    wsKeepaliveTimeoutId = setTimeout(keepAlive, keepAlivePeriod);
+    var request = {
+      "rtcgw": "keepalive",
+      "session_id": sessionId,
+      "transaction": Janus$1.randomString(12)
+    };
+    if (token !== null && token !== undefined) request["token"] = token;
+    if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+    ws.send(JSON.stringify(request));
+  } // Private method to create a session
+
+
+  function createSession(callbacks) {
+    var transaction = Janus$1.randomString(12); // console.log("jannus create_token",stream);
+
+    var request = {
+      "rtcgw": "create",
+      "transaction": transaction,
+      "token": window.EZUIKit.opt.stream,
+      "device": window.EZUIKit.opt.deviceSerial,
+      "channel": window.EZUIKit.opt.channelNo
+    };
+
+    if (callbacks["reconnect"]) {
+      // We're reconnecting, claim the session
+      connected = false;
+      request["rtcgw"] = "claim";
+      request["session_id"] = sessionId; // If we were using websockets, ignore the old connection
+
+      if (ws) {
+        ws.onopen = null;
+        ws.onerror = null;
+        ws.onclose = null;
+
+        if (wsKeepaliveTimeoutId) {
+          clearTimeout(wsKeepaliveTimeoutId);
+          wsKeepaliveTimeoutId = null;
+        }
+      }
+    }
+
+    if (token !== null && token !== undefined) request["token"] = token;
+    if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+
+    if (server === null && Janus$1.isArray(servers)) {
+      // We still need to find a working server from the list we were given
+      server = servers[serversIndex];
+
+      if (server.indexOf("ws") === 0) {
+        websockets = true;
+        Janus$1.log("Server #" + (serversIndex + 1) + ": trying WebSockets to contact Janus (" + server + ")");
+      } else {
+        websockets = false;
+        Janus$1.log("Server #" + (serversIndex + 1) + ": trying REST API to contact Janus (" + server + ")");
+      }
+    }
+
+    if (websockets) {
+      ws = Janus$1.newWebSocket(server, 'rtcgw-protocol');
+      wsHandlers = {
+        'error': function error() {
+          Janus$1.error("Error connecting to the Janus WebSockets server... " + server);
+
+          if (Janus$1.isArray(servers) && !callbacks["reconnect"]) {
+            serversIndex++;
+
+            if (serversIndex == servers.length) {
+              // We tried all the servers the user gave us and they all failed
+              callbacks.error("Error connecting to any of the provided Janus servers: Is the server down?");
+              return;
+            } // Let's try the next server
+
+
+            server = null;
+            setTimeout(function () {
+              createSession(callbacks);
+            }, 200);
+            return;
+          }
+
+          callbacks.error("Error connecting to the Janus WebSockets server: Is the server down?");
+        },
+        'open': function open() {
+          // We need to be notified about the success
+          transactions[transaction] = function (json) {
+            Janus$1.debug(json);
+
+            if (json["rtcgw"] !== "success") {
+              Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+              callbacks.error(json["error"].reason);
+              return;
+            }
+
+            wsKeepaliveTimeoutId = setTimeout(keepAlive, keepAlivePeriod);
+            connected = true;
+            sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
+
+            if (callbacks["reconnect"]) {
+              Janus$1.log("Claimed session: " + sessionId);
+            } else {
+              Janus$1.log("Created session: " + sessionId);
+            }
+
+            Janus$1.sessions[sessionId] = that;
+            callbacks.success();
+          };
+
+          ws.send(JSON.stringify(request));
+        },
+        'message': function message(event) {
+          handleEvent(JSON.parse(event.data));
+        },
+        'close': function close() {
+          if (server === null || !connected) {
+            return;
+          }
+
+          connected = false; // FIXME What if this is called when the page is closed?
+
+          gatewayCallbacks.error("Lost connection to the server (is it down?)");
+        }
+      };
+
+      for (var eventName in wsHandlers) {
+        ws.addEventListener(eventName, wsHandlers[eventName]);
+      }
+
+      return;
+    }
+
+    Janus$1.httpAPICall(server, {
+      verb: 'POST',
+      withCredentials: withCredentials,
+      body: request,
+      success: function success(json) {
+        Janus$1.debug(json);
+
+        if (json["rtcgw"] !== "success") {
+          Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+          callbacks.error(json["error"].reason);
+          return;
+        }
+
+        connected = true;
+        sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
+
+        if (callbacks["reconnect"]) {
+          Janus$1.log("Claimed session: " + sessionId);
+        } else {
+          Janus$1.log("Created session: " + sessionId);
+        }
+
+        Janus$1.sessions[sessionId] = that;
+        eventHandler();
+        callbacks.success();
+      },
+      error: function error(textStatus, errorThrown) {
+        Janus$1.error(textStatus + ":", errorThrown); // FIXME
+
+        if (Janus$1.isArray(servers) && !callbacks["reconnect"]) {
+          serversIndex++;
+
+          if (serversIndex == servers.length) {
+            // We tried all the servers the user gave us and they all failed
+            callbacks.error("Error connecting to any of the provided Janus servers: Is the server down?");
+            return;
+          } // Let's try the next server
+
+
+          server = null;
+          setTimeout(function () {
+            createSession(callbacks);
+          }, 200);
+          return;
+        }
+
+        if (errorThrown === "") callbacks.error(textStatus + ": Is the server down?");else callbacks.error(textStatus + ": " + errorThrown);
+      }
+    });
+  } // Private method to destroy a session
+
+
+  function destroySession(callbacks) {
+    callbacks = callbacks || {}; // FIXME This method triggers a success even when we fail
+
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    var asyncRequest = true;
+    if (callbacks.asyncRequest !== undefined && callbacks.asyncRequest !== null) asyncRequest = callbacks.asyncRequest === true;
+    var notifyDestroyed = true;
+    if (callbacks.notifyDestroyed !== undefined && callbacks.notifyDestroyed !== null) notifyDestroyed = callbacks.notifyDestroyed === true;
+    var cleanupHandles = false;
+    if (callbacks.cleanupHandles !== undefined && callbacks.cleanupHandles !== null) cleanupHandles = callbacks.cleanupHandles === true;
+    Janus$1.log("Destroying session " + sessionId + " (async=" + asyncRequest + ")");
+
+    if (!connected) {
+      Janus$1.warn("Is the server down? (connected=false)");
+      callbacks.success();
+      return;
+    }
+
+    if (sessionId === undefined || sessionId === null) {
+      Janus$1.warn("No session to destroy");
+      callbacks.success();
+      if (notifyDestroyed) gatewayCallbacks.destroyed();
+      return;
+    }
+
+    if (cleanupHandles) {
+      for (var handleId in pluginHandles) {
+        destroyHandle(handleId, {
+          noRequest: true
+        });
+      }
+    } // No need to destroy all handles first, Janus will do that itself
+
+
+    var request = {
+      "rtcgw": "destroy",
+      "transaction": Janus$1.randomString(12)
+    };
+    if (token !== null && token !== undefined) request["token"] = token;
+    if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+
+    if (websockets) {
+      request["session_id"] = sessionId;
+
+      var unbindWebSocket = function unbindWebSocket() {
+        for (var eventName in wsHandlers) {
+          ws.removeEventListener(eventName, wsHandlers[eventName]);
+        }
+
+        ws.removeEventListener('message', onUnbindMessage);
+        ws.removeEventListener('error', onUnbindError);
+
+        if (wsKeepaliveTimeoutId) {
+          clearTimeout(wsKeepaliveTimeoutId);
+        }
+
+        ws.close();
+      };
+
+      var onUnbindMessage = function onUnbindMessage(event) {
+        var data = JSON.parse(event.data);
+
+        if (data.session_id == request.session_id && data.transaction == request.transaction) {
+          unbindWebSocket();
+          callbacks.success();
+          if (notifyDestroyed) gatewayCallbacks.destroyed();
+        }
+      };
+
+      var onUnbindError = function onUnbindError(event) {
+        unbindWebSocket();
+        callbacks.error("Failed to destroy the server: Is the server down?");
+        if (notifyDestroyed) gatewayCallbacks.destroyed();
+      };
+
+      ws.addEventListener('message', onUnbindMessage);
+      ws.addEventListener('error', onUnbindError);
+      ws.send(JSON.stringify(request));
+      return;
+    }
+
+    Janus$1.httpAPICall(server + "/" + sessionId, {
+      verb: 'POST',
+      async: asyncRequest,
+      // Sometimes we need false here, or destroying in onbeforeunload won't work
+      withCredentials: withCredentials,
+      body: request,
+      success: function success(json) {
+        Janus$1.log("Destroyed session:");
+        Janus$1.debug(json);
+        sessionId = null;
+        connected = false;
+
+        if (json["rtcgw"] !== "success") {
+          Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+        }
+
+        callbacks.success();
+        if (notifyDestroyed) gatewayCallbacks.destroyed();
+      },
+      error: function error(textStatus, errorThrown) {
+        Janus$1.error(textStatus + ":", errorThrown); // FIXME
+        // Reset everything anyway
+
+        sessionId = null;
+        connected = false;
+        callbacks.success();
+        if (notifyDestroyed) gatewayCallbacks.destroyed();
+      }
+    });
+  } // Private method to create a plugin handle
+
+
+  function createHandle(callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    callbacks.consentDialog = typeof callbacks.consentDialog == "function" ? callbacks.consentDialog : Janus$1.noop;
+    callbacks.iceState = typeof callbacks.iceState == "function" ? callbacks.iceState : Janus$1.noop;
+    callbacks.mediaState = typeof callbacks.mediaState == "function" ? callbacks.mediaState : Janus$1.noop;
+    callbacks.webrtcState = typeof callbacks.webrtcState == "function" ? callbacks.webrtcState : Janus$1.noop;
+    callbacks.slowLink = typeof callbacks.slowLink == "function" ? callbacks.slowLink : Janus$1.noop;
+    callbacks.onmessage = typeof callbacks.onmessage == "function" ? callbacks.onmessage : Janus$1.noop;
+    callbacks.onlocalstream = typeof callbacks.onlocalstream == "function" ? callbacks.onlocalstream : Janus$1.noop;
+    callbacks.onremotestream = typeof callbacks.onremotestream == "function" ? callbacks.onremotestream : Janus$1.noop;
+    callbacks.ondata = typeof callbacks.ondata == "function" ? callbacks.ondata : Janus$1.noop;
+    callbacks.ondataopen = typeof callbacks.ondataopen == "function" ? callbacks.ondataopen : Janus$1.noop;
+    callbacks.oncleanup = typeof callbacks.oncleanup == "function" ? callbacks.oncleanup : Janus$1.noop;
+    callbacks.ondetached = typeof callbacks.ondetached == "function" ? callbacks.ondetached : Janus$1.noop;
+
+    if (!connected) {
+      Janus$1.warn("Is the server down? (connected=false)");
+      callbacks.error("Is the server down? (connected=false)");
+      return;
+    }
+
+    var plugin = callbacks.plugin;
+
+    if (plugin === undefined || plugin === null) {
+      Janus$1.error("Invalid plugin");
+      callbacks.error("Invalid plugin");
+      return;
+    }
+
+    var opaqueId = callbacks.opaqueId;
+    var handleToken = callbacks.token ? callbacks.token : token;
+    var transaction = Janus$1.randomString(12);
+    var request = {
+      "rtcgw": "attach",
+      "plugin": plugin,
+      "opaque_id": opaqueId,
+      "transaction": transaction
+    };
+    if (handleToken !== null && handleToken !== undefined) request["token"] = handleToken;
+    if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+
+    if (websockets) {
+      transactions[transaction] = function (json) {
+        Janus$1.debug(json);
+
+        if (json["rtcgw"] !== "success") {
+          Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+          callbacks.error("Ooops: " + json["error"].code + " " + json["error"].reason);
+          return;
+        }
+
+        var handleId = json.data["id"];
+        Janus$1.log("Created handle: " + handleId);
+        var pluginHandle = {
+          session: that,
+          plugin: plugin,
+          id: handleId,
+          token: handleToken,
+          detached: false,
+          webrtcStuff: {
+            started: false,
+            myStream: null,
+            streamExternal: false,
+            remoteStream: null,
+            mySdp: null,
+            mediaConstraints: null,
+            pc: null,
+            dataChannel: {},
+            dtmfSender: null,
+            trickle: true,
+            iceDone: false,
+            volume: {
+              value: null,
+              timer: null
+            },
+            bitrate: {
+              value: null,
+              bsnow: null,
+              bsbefore: null,
+              tsnow: null,
+              tsbefore: null,
+              timer: null
+            }
+          },
+          getId: function getId() {
+            return handleId;
+          },
+          getPlugin: function getPlugin() {
+            return plugin;
+          },
+          getVolume: function getVolume() {
+            return _getVolume(handleId, true);
+          },
+          getRemoteVolume: function getRemoteVolume() {
+            return _getVolume(handleId, true);
+          },
+          getLocalVolume: function getLocalVolume() {
+            return _getVolume(handleId, false);
+          },
+          isAudioMuted: function isAudioMuted() {
+            return isMuted(handleId, false);
+          },
+          muteAudio: function muteAudio() {
+            return mute(handleId, false, true);
+          },
+          unmuteAudio: function unmuteAudio() {
+            return mute(handleId, false, false);
+          },
+          isVideoMuted: function isVideoMuted() {
+            return isMuted(handleId, true);
+          },
+          muteVideo: function muteVideo() {
+            return mute(handleId, true, true);
+          },
+          unmuteVideo: function unmuteVideo() {
+            return mute(handleId, true, false);
+          },
+          getBitrate: function getBitrate() {
+            return _getBitrate(handleId);
+          },
+          send: function send(callbacks) {
+            sendMessage(handleId, callbacks);
+          },
+          data: function data(callbacks) {
+            sendData(handleId, callbacks);
+          },
+          dtmf: function dtmf(callbacks) {
+            sendDtmf(handleId, callbacks);
+          },
+          consentDialog: callbacks.consentDialog,
+          iceState: callbacks.iceState,
+          mediaState: callbacks.mediaState,
+          webrtcState: callbacks.webrtcState,
+          slowLink: callbacks.slowLink,
+          onmessage: callbacks.onmessage,
+          createOffer: function createOffer(callbacks) {
+            prepareWebrtc(handleId, true, callbacks);
+          },
+          createAnswer: function createAnswer(callbacks) {
+            prepareWebrtc(handleId, false, callbacks);
+          },
+          handleRemoteJsep: function handleRemoteJsep(callbacks) {
+            prepareWebrtcPeer(handleId, callbacks);
+          },
+          onlocalstream: callbacks.onlocalstream,
+          onremotestream: callbacks.onremotestream,
+          ondata: callbacks.ondata,
+          ondataopen: callbacks.ondataopen,
+          oncleanup: callbacks.oncleanup,
+          ondetached: callbacks.ondetached,
+          hangup: function hangup(sendRequest) {
+            cleanupWebrtc(handleId, sendRequest === true);
+          },
+          detach: function detach(callbacks) {
+            destroyHandle(handleId, callbacks);
+          }
+        };
+        pluginHandles[handleId] = pluginHandle;
+        callbacks.success(pluginHandle);
+      };
+
+      request["session_id"] = sessionId;
+      ws.send(JSON.stringify(request));
+      return;
+    }
+
+    Janus$1.httpAPICall(server + "/" + sessionId, {
+      verb: 'POST',
+      withCredentials: withCredentials,
+      body: request,
+      success: function success(json) {
+        Janus$1.debug(json);
+
+        if (json["rtcgw"] !== "success") {
+          Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+          callbacks.error("Ooops: " + json["error"].code + " " + json["error"].reason);
+          return;
+        }
+
+        var handleId = json.data["id"];
+        Janus$1.log("Created handle: " + handleId);
+        var pluginHandle = {
+          session: that,
+          plugin: plugin,
+          id: handleId,
+          token: handleToken,
+          detached: false,
+          webrtcStuff: {
+            started: false,
+            myStream: null,
+            streamExternal: false,
+            remoteStream: null,
+            mySdp: null,
+            mediaConstraints: null,
+            pc: null,
+            dataChannel: {},
+            dtmfSender: null,
+            trickle: true,
+            iceDone: false,
+            volume: {
+              value: null,
+              timer: null
+            },
+            bitrate: {
+              value: null,
+              bsnow: null,
+              bsbefore: null,
+              tsnow: null,
+              tsbefore: null,
+              timer: null
+            }
+          },
+          getId: function getId() {
+            return handleId;
+          },
+          getPlugin: function getPlugin() {
+            return plugin;
+          },
+          getVolume: function getVolume() {
+            return _getVolume(handleId, true);
+          },
+          getRemoteVolume: function getRemoteVolume() {
+            return _getVolume(handleId, true);
+          },
+          getLocalVolume: function getLocalVolume() {
+            return _getVolume(handleId, false);
+          },
+          isAudioMuted: function isAudioMuted() {
+            return isMuted(handleId, false);
+          },
+          muteAudio: function muteAudio() {
+            return mute(handleId, false, true);
+          },
+          unmuteAudio: function unmuteAudio() {
+            return mute(handleId, false, false);
+          },
+          isVideoMuted: function isVideoMuted() {
+            return isMuted(handleId, true);
+          },
+          muteVideo: function muteVideo() {
+            return mute(handleId, true, true);
+          },
+          unmuteVideo: function unmuteVideo() {
+            return mute(handleId, true, false);
+          },
+          getBitrate: function getBitrate() {
+            return _getBitrate(handleId);
+          },
+          send: function send(callbacks) {
+            sendMessage(handleId, callbacks);
+          },
+          data: function data(callbacks) {
+            sendData(handleId, callbacks);
+          },
+          dtmf: function dtmf(callbacks) {
+            sendDtmf(handleId, callbacks);
+          },
+          consentDialog: callbacks.consentDialog,
+          iceState: callbacks.iceState,
+          mediaState: callbacks.mediaState,
+          webrtcState: callbacks.webrtcState,
+          slowLink: callbacks.slowLink,
+          onmessage: callbacks.onmessage,
+          createOffer: function createOffer(callbacks) {
+            prepareWebrtc(handleId, true, callbacks);
+          },
+          createAnswer: function createAnswer(callbacks) {
+            prepareWebrtc(handleId, false, callbacks);
+          },
+          handleRemoteJsep: function handleRemoteJsep(callbacks) {
+            prepareWebrtcPeer(handleId, callbacks);
+          },
+          onlocalstream: callbacks.onlocalstream,
+          onremotestream: callbacks.onremotestream,
+          ondata: callbacks.ondata,
+          ondataopen: callbacks.ondataopen,
+          oncleanup: callbacks.oncleanup,
+          ondetached: callbacks.ondetached,
+          hangup: function hangup(sendRequest) {
+            cleanupWebrtc(handleId, sendRequest === true);
+          },
+          detach: function detach(callbacks) {
+            destroyHandle(handleId, callbacks);
+          }
+        };
+        pluginHandles[handleId] = pluginHandle;
+        callbacks.success(pluginHandle);
+      },
+      error: function error(textStatus, errorThrown) {
+        Janus$1.error(textStatus + ":", errorThrown); // FIXME
+      }
+    });
+  } // Private method to send a message
+
+
+  function sendMessage(handleId, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+
+    if (!connected) {
+      Janus$1.warn("Is the server down? (connected=false)");
+      callbacks.error("Is the server down? (connected=false)");
+      return;
+    }
+
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var message = callbacks.message;
+    var jsep = callbacks.jsep;
+    var transaction = Janus$1.randomString(12);
+    var request = {
+      "rtcgw": "message",
+      "body": message,
+      "transaction": transaction
+    };
+    if (pluginHandle.token !== null && pluginHandle.token !== undefined) request["token"] = pluginHandle.token;
+    if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+    if (jsep !== null && jsep !== undefined) request.jsep = jsep;
+    Janus$1.debug("Sending message to plugin (handle=" + handleId + "):");
+    Janus$1.debug(request);
+
+    if (websockets) {
+      request["session_id"] = sessionId;
+      request["handle_id"] = handleId;
+
+      transactions[transaction] = function (json) {
+        Janus$1.debug("Message sent!");
+        Janus$1.debug(json);
+
+        if (json["rtcgw"] === "success") {
+          // We got a success, must have been a synchronous transaction
+          var plugindata = json["plugindata"];
+
+          if (plugindata === undefined || plugindata === null) {
+            Janus$1.warn("Request succeeded, but missing plugindata...");
+            callbacks.success();
+            return;
+          }
+
+          Janus$1.log("Synchronous transaction successful (" + plugindata["plugin"] + ")");
+          var data = plugindata["data"];
+          Janus$1.debug(data);
+          callbacks.success(data);
+          return;
+        } else if (json["rtcgw"] !== "ack") {
+          // Not a success and not an ack, must be an error
+          if (json["error"] !== undefined && json["error"] !== null) {
+            Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+            callbacks.error(json["error"].code + " " + json["error"].reason);
+          } else {
+            Janus$1.error("Unknown error"); // FIXME
+
+            callbacks.error("Unknown error");
+          }
+
+          return;
+        } // If we got here, the plugin decided to handle the request asynchronously
+
+
+        callbacks.success();
+      };
+
+      ws.send(JSON.stringify(request));
+      return;
+    }
+
+    Janus$1.httpAPICall(server + "/" + sessionId + "/" + handleId, {
+      verb: 'POST',
+      withCredentials: withCredentials,
+      body: request,
+      success: function success(json) {
+        Janus$1.debug("Message sent!");
+        Janus$1.debug(json);
+
+        if (json["rtcgw"] === "success") {
+          // We got a success, must have been a synchronous transaction
+          var plugindata = json["plugindata"];
+
+          if (plugindata === undefined || plugindata === null) {
+            Janus$1.warn("Request succeeded, but missing plugindata...");
+            callbacks.success();
+            return;
+          }
+
+          Janus$1.log("Synchronous transaction successful (" + plugindata["plugin"] + ")");
+          var data = plugindata["data"];
+          Janus$1.debug(data);
+          callbacks.success(data);
+          return;
+        } else if (json["rtcgw"] !== "ack") {
+          // Not a success and not an ack, must be an error
+          if (json["error"] !== undefined && json["error"] !== null) {
+            Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+            callbacks.error(json["error"].code + " " + json["error"].reason);
+          } else {
+            Janus$1.error("Unknown error"); // FIXME
+
+            callbacks.error("Unknown error");
+          }
+
+          return;
+        } // If we got here, the plugin decided to handle the request asynchronously
+
+
+        callbacks.success();
+      },
+      error: function error(textStatus, errorThrown) {
+        Janus$1.error(textStatus + ":", errorThrown); // FIXME
+
+        callbacks.error(textStatus + ": " + errorThrown);
+      }
+    });
+  } // Private method to send a trickle candidate
+
+
+  function sendTrickleCandidate(handleId, candidate) {
+    if (!connected) {
+      Janus$1.warn("Is the server down? (connected=false)");
+      return;
+    }
+
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      return;
+    }
+
+    var request = {
+      "rtcgw": "trickle",
+      "candidate": candidate,
+      "transaction": Janus$1.randomString(12)
+    };
+    if (pluginHandle.token !== null && pluginHandle.token !== undefined) request["token"] = pluginHandle.token;
+    if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+    Janus$1.vdebug("Sending trickle candidate (handle=" + handleId + "):");
+    Janus$1.vdebug(request);
+
+    if (websockets) {
+      request["session_id"] = sessionId;
+      request["handle_id"] = handleId;
+      ws.send(JSON.stringify(request));
+      return;
+    }
+
+    Janus$1.httpAPICall(server + "/" + sessionId + "/" + handleId, {
+      verb: 'POST',
+      withCredentials: withCredentials,
+      body: request,
+      success: function success(json) {
+        Janus$1.vdebug("Candidate sent!");
+        Janus$1.vdebug(json);
+
+        if (json["rtcgw"] !== "ack") {
+          Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+
+          return;
+        }
+      },
+      error: function error(textStatus, errorThrown) {
+        Janus$1.error(textStatus + ":", errorThrown); // FIXME
+      }
+    });
+  } // Private method to create a data channel
+
+
+  function createDataChannel(handleId, dclabel, incoming, pendingText) {
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+
+    var onDataChannelMessage = function onDataChannelMessage(event) {
+      Janus$1.log('Received message on data channel:', event);
+      var label = event.target.label;
+      pluginHandle.ondata(event.data, label);
+    };
+
+    var onDataChannelStateChange = function onDataChannelStateChange(event) {
+      Janus$1.log('Received state change on data channel:', event);
+      var label = event.target.label;
+      var dcState = config.dataChannel[label] ? config.dataChannel[label].readyState : "null";
+      Janus$1.log('State change on <' + label + '> data channel: ' + dcState);
+
+      if (dcState === 'open') {
+        // Any pending messages to send?
+        if (config.dataChannel[label].pending && config.dataChannel[label].pending.length > 0) {
+          Janus$1.log("Sending pending messages on <" + label + ">:", config.dataChannel[label].pending.length);
+
+          for (var i in config.dataChannel[label].pending) {
+            var text = config.dataChannel[label].pending[i];
+            Janus$1.log("Sending string on data channel <" + label + ">: " + text);
+            config.dataChannel[label].send(text);
+          }
+
+          config.dataChannel[label].pending = [];
+        } // Notify the open data channel
+
+
+        pluginHandle.ondataopen(label);
+      }
+    };
+
+    var onDataChannelError = function onDataChannelError(error) {
+      Janus$1.error('Got error on data channel:', error); // TODO
+    };
+
+    if (!incoming) {
+      // FIXME Add options (ordered, maxRetransmits, etc.)
+      config.dataChannel[dclabel] = config.pc.createDataChannel(dclabel, {
+        ordered: false
+      });
+    } else {
+      // The channel was created by Janus
+      config.dataChannel[dclabel] = incoming;
+    }
+
+    config.dataChannel[dclabel].onmessage = onDataChannelMessage;
+    config.dataChannel[dclabel].onopen = onDataChannelStateChange;
+    config.dataChannel[dclabel].onclose = onDataChannelStateChange;
+    config.dataChannel[dclabel].onerror = onDataChannelError;
+    config.dataChannel[dclabel].pending = [];
+    if (pendingText) config.dataChannel[dclabel].pending.push(pendingText);
+  } // Private method to send a data channel message
+
+
+  function sendData(handleId, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+    var text = callbacks.text;
+
+    if (text === null || text === undefined) {
+      Janus$1.warn("Invalid text");
+      callbacks.error("Invalid text");
+      return;
+    }
+
+    var label = callbacks.label ? callbacks.label : Janus$1.dataChanDefaultLabel;
+
+    if (!config.dataChannel[label]) {
+      // Create new data channel and wait for it to open
+      createDataChannel(handleId, label, false, text);
+      callbacks.success();
+      return;
+    }
+
+    if (config.dataChannel[label].readyState !== "open") {
+      config.dataChannel[label].pending.push(text);
+      callbacks.success();
+      return;
+    }
+
+    Janus$1.log("Sending string on data channel <" + label + ">: " + text);
+    config.dataChannel[label].send(text);
+    callbacks.success();
+  } // Private method to send a DTMF tone
+
+
+  function sendDtmf(handleId, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+
+    if (config.dtmfSender === null || config.dtmfSender === undefined) {
+      // Create the DTMF sender the proper way, if possible
+      if (config.pc !== undefined && config.pc !== null) {
+        var senders = config.pc.getSenders();
+        var audioSender = senders.find(function (sender) {
+          return sender.track && sender.track.kind === 'audio';
+        });
+
+        if (!audioSender) {
+          Janus$1.warn("Invalid DTMF configuration (no audio track)");
+          callbacks.error("Invalid DTMF configuration (no audio track)");
+          return;
+        }
+
+        config.dtmfSender = audioSender.dtmf;
+
+        if (config.dtmfSender) {
+          Janus$1.log("Created DTMF Sender");
+
+          config.dtmfSender.ontonechange = function (tone) {
+            Janus$1.debug("Sent DTMF tone: " + tone.tone);
+          };
+        }
+      }
+
+      if (config.dtmfSender === null || config.dtmfSender === undefined) {
+        Janus$1.warn("Invalid DTMF configuration");
+        callbacks.error("Invalid DTMF configuration");
+        return;
+      }
+    }
+
+    var dtmf = callbacks.dtmf;
+
+    if (dtmf === null || dtmf === undefined) {
+      Janus$1.warn("Invalid DTMF parameters");
+      callbacks.error("Invalid DTMF parameters");
+      return;
+    }
+
+    var tones = dtmf.tones;
+
+    if (tones === null || tones === undefined) {
+      Janus$1.warn("Invalid DTMF string");
+      callbacks.error("Invalid DTMF string");
+      return;
+    }
+
+    var duration = dtmf.duration;
+    if (duration === null || duration === undefined) duration = 500; // We choose 500ms as the default duration for a tone
+
+    var gap = dtmf.gap;
+    if (gap === null || gap === undefined) gap = 50; // We choose 50ms as the default gap between tones
+
+    Janus$1.debug("Sending DTMF string " + tones + " (duration " + duration + "ms, gap " + gap + "ms)");
+    config.dtmfSender.insertDTMF(tones, duration, gap);
+    callbacks.success();
+  } // Private method to destroy a plugin handle
+
+
+  function destroyHandle(handleId, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    var asyncRequest = true;
+    if (callbacks.asyncRequest !== undefined && callbacks.asyncRequest !== null) asyncRequest = callbacks.asyncRequest === true;
+    var noRequest = true;
+    if (callbacks.noRequest !== undefined && callbacks.noRequest !== null) noRequest = callbacks.noRequest === true;
+    Janus$1.log("Destroying handle " + handleId + " (async=" + asyncRequest + ")");
+    cleanupWebrtc(handleId);
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.detached) {
+      // Plugin was already detached by Janus, calling detach again will return a handle not found error, so just exit here
+      delete pluginHandles[handleId];
+      callbacks.success();
+      return;
+    }
+
+    if (noRequest) {
+      // We're only removing the handle locally
+      delete pluginHandles[handleId];
+      callbacks.success();
+      return;
+    }
+
+    if (!connected) {
+      Janus$1.warn("Is the server down? (connected=false)");
+      callbacks.error("Is the server down? (connected=false)");
+      return;
+    }
+
+    var request = {
+      "rtcgw": "detach",
+      "transaction": Janus$1.randomString(12)
+    };
+    if (pluginHandle.token !== null && pluginHandle.token !== undefined) request["token"] = pluginHandle.token;
+    if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+
+    if (websockets) {
+      request["session_id"] = sessionId;
+      request["handle_id"] = handleId;
+      ws.send(JSON.stringify(request));
+      delete pluginHandles[handleId];
+      callbacks.success();
+      return;
+    }
+
+    Janus$1.httpAPICall(server + "/" + sessionId + "/" + handleId, {
+      verb: 'POST',
+      async: asyncRequest,
+      // Sometimes we need false here, or destroying in onbeforeunload won't work
+      withCredentials: withCredentials,
+      body: request,
+      success: function success(json) {
+        Janus$1.log("Destroyed handle:");
+        Janus$1.debug(json);
+
+        if (json["rtcgw"] !== "success") {
+          Janus$1.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
+        }
+
+        delete pluginHandles[handleId];
+        callbacks.success();
+      },
+      error: function error(textStatus, errorThrown) {
+        Janus$1.error(textStatus + ":", errorThrown); // FIXME
+        // We cleanup anyway
+
+        delete pluginHandles[handleId];
+        callbacks.success();
+      }
+    });
+  } // WebRTC stuff
+
+
+  function streamsDone(handleId, jsep, media, callbacks, stream) {
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+    Janus$1.debug("streamsDone:", stream);
+
+    if (stream) {
+      Janus$1.debug("  -- Audio tracks:", stream.getAudioTracks());
+      Janus$1.debug("  -- Video tracks:", stream.getVideoTracks());
+    } // We're now capturing the new stream: check if we're updating or if it's a new thing
+
+
+    var addTracks = false;
+
+    if (!config.myStream || !media.update || config.streamExternal) {
+      config.myStream = stream;
+      addTracks = true;
+    } else {
+      // We only need to update the existing stream
+      if ((!media.update && isAudioSendEnabled(media) || media.update && (media.addAudio || media.replaceAudio)) && stream.getAudioTracks() && stream.getAudioTracks().length) {
+        config.myStream.addTrack(stream.getAudioTracks()[0]);
+
+        if (Janus$1.unifiedPlan) {
+          // Use Transceivers
+          Janus$1.log((media.replaceAudio ? "Replacing" : "Adding") + " audio track:", stream.getAudioTracks()[0]);
+          var audioTransceiver = null;
+          var transceivers = config.pc.getTransceivers();
+
+          if (transceivers && transceivers.length > 0) {
+            for (var i in transceivers) {
+              var t = transceivers[i];
+
+              if (t.sender && t.sender.track && t.sender.track.kind === "audio" || t.receiver && t.receiver.track && t.receiver.track.kind === "audio") {
+                audioTransceiver = t;
+                break;
+              }
+            }
+          }
+
+          if (audioTransceiver && audioTransceiver.sender) {
+            audioTransceiver.sender.replaceTrack(stream.getAudioTracks()[0]);
+          } else {
+            config.pc.addTrack(stream.getAudioTracks()[0], stream);
+          }
+        } else {
+          Janus$1.log((media.replaceAudio ? "Replacing" : "Adding") + " audio track:", stream.getAudioTracks()[0]);
+          config.pc.addTrack(stream.getAudioTracks()[0], stream);
+        }
+      }
+
+      if ((!media.update && isVideoSendEnabled(media) || media.update && (media.addVideo || media.replaceVideo)) && stream.getVideoTracks() && stream.getVideoTracks().length) {
+        config.myStream.addTrack(stream.getVideoTracks()[0]);
+
+        if (Janus$1.unifiedPlan) {
+          // Use Transceivers
+          Janus$1.log((media.replaceVideo ? "Replacing" : "Adding") + " video track:", stream.getVideoTracks()[0]);
+          var videoTransceiver = null;
+          var transceivers = config.pc.getTransceivers();
+
+          if (transceivers && transceivers.length > 0) {
+            for (var i in transceivers) {
+              var t = transceivers[i];
+
+              if (t.sender && t.sender.track && t.sender.track.kind === "video" || t.receiver && t.receiver.track && t.receiver.track.kind === "video") {
+                videoTransceiver = t;
+                break;
+              }
+            }
+          }
+
+          if (videoTransceiver && videoTransceiver.sender) {
+            videoTransceiver.sender.replaceTrack(stream.getVideoTracks()[0]);
+          } else {
+            config.pc.addTrack(stream.getVideoTracks()[0], stream);
+          }
+        } else {
+          Janus$1.log((media.replaceVideo ? "Replacing" : "Adding") + " video track:", stream.getVideoTracks()[0]);
+          config.pc.addTrack(stream.getVideoTracks()[0], stream);
+        }
+      }
+    } // If we still need to create a PeerConnection, let's do that
+
+
+    if (!config.pc) {
+      var pc_config = {
+        "iceServers": iceServers,
+        "iceTransportPolicy": iceTransportPolicy,
+        "bundlePolicy": bundlePolicy
+      };
+
+      if (Janus$1.webRTCAdapter.browserDetails.browser === "chrome") {
+        // For Chrome versions before 72, we force a plan-b semantic, and unified-plan otherwise
+        pc_config["sdpSemantics"] = Janus$1.webRTCAdapter.browserDetails.version < 72 ? "plan-b" : "unified-plan";
+      }
+
+      var pc_constraints = {
+        "optional": [{
+          "DtlsSrtpKeyAgreement": true
+        }]
+      };
+
+      if (ipv6Support === true) {
+        pc_constraints.optional.push({
+          "googIPv6": true
+        });
+      } // Any custom constraint to add?
+
+
+      if (callbacks.rtcConstraints && _typeof(callbacks.rtcConstraints) === 'object') {
+        Janus$1.debug("Adding custom PeerConnection constraints:", callbacks.rtcConstraints);
+
+        for (var i in callbacks.rtcConstraints) {
+          pc_constraints.optional.push(callbacks.rtcConstraints[i]);
+        }
+      }
+
+      if (Janus$1.webRTCAdapter.browserDetails.browser === "edge") {
+        // This is Edge, enable BUNDLE explicitly
+        pc_config.bundlePolicy = "max-bundle";
+      }
+
+      Janus$1.log("Creating PeerConnection");
+      Janus$1.debug(pc_constraints);
+      config.pc = new RTCPeerConnection(pc_config, pc_constraints);
+      Janus$1.debug(config.pc);
+
+      if (config.pc.getStats) {
+        // FIXME
+        config.volume = {};
+        config.bitrate.value = "0 kbits/sec";
+      }
+
+      Janus$1.log("Preparing local SDP and gathering candidates (trickle=" + config.trickle + ")");
+
+      config.pc.oniceconnectionstatechange = function (e) {
+        if (config.pc) pluginHandle.iceState(config.pc.iceConnectionState);
+      };
+
+      config.pc.onicecandidate = function (event) {
+        if (event.candidate == null || Janus$1.webRTCAdapter.browserDetails.browser === 'edge' && event.candidate.candidate.indexOf('endOfCandidates') > 0) {
+          Janus$1.log("End of candidates.");
+          config.iceDone = true;
+
+          if (config.trickle === true) {
+            // Notify end of candidates
+            sendTrickleCandidate(handleId, {
+              "completed": true
+            });
+          } else {
+            // No trickle, time to send the complete SDP (including all candidates)
+            sendSDP(handleId, callbacks);
+          }
+        } else {
+          // JSON.stringify doesn't work on some WebRTC objects anymore
+          // See https://code.google.com/p/chromium/issues/detail?id=467366
+          var candidate = {
+            "candidate": event.candidate.candidate,
+            "sdpMid": event.candidate.sdpMid,
+            "sdpMLineIndex": event.candidate.sdpMLineIndex
+          };
+
+          if (config.trickle === true) {
+            // Send candidate
+            sendTrickleCandidate(handleId, candidate);
+          }
+        }
+      };
+
+      config.pc.ontrack = function (event) {
+        Janus$1.log("Handling Remote Track");
+        Janus$1.debug(event);
+        if (!event.streams) return;
+        config.remoteStream = event.streams[0];
+        pluginHandle.onremotestream(config.remoteStream);
+        if (event.track.onended) return;
+        Janus$1.log("Adding onended callback to track:", event.track);
+
+        event.track.onended = function (ev) {
+          Janus$1.log("Remote track muted/removed:", ev);
+
+          if (config.remoteStream) {
+            config.remoteStream.removeTrack(ev.target);
+            pluginHandle.onremotestream(config.remoteStream);
+          }
+        };
+
+        event.track.onmute = event.track.onended;
+
+        event.track.onunmute = function (ev) {
+          Janus$1.log("Remote track flowing again:", ev);
+
+          try {
+            config.remoteStream.addTrack(ev.target);
+            pluginHandle.onremotestream(config.remoteStream);
+          } catch (e) {
+            Janus$1.error(e);
+          }
+        };
+      };
+    }
+
+    if (addTracks && stream !== null && stream !== undefined) {
+      Janus$1.log('Adding local stream');
+      var simulcast2 = callbacks.simulcast2 === true ? true : false;
+      stream.getTracks().forEach(function (track) {
+        Janus$1.log('Adding local track:', track);
+
+        if (!simulcast2) {
+          config.pc.addTrack(track, stream);
+        } else {
+          if (track.kind === "audio") {
+            config.pc.addTrack(track, stream);
+          } else {
+            Janus$1.log('Enabling rid-based simulcasting:', track);
+            var maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);
+            config.pc.addTransceiver(track, {
+              direction: "sendrecv",
+              streams: [stream],
+              sendEncodings: [{
+                rid: "h",
+                active: true,
+                maxBitrate: maxBitrates.high
+              }, {
+                rid: "m",
+                active: true,
+                maxBitrate: maxBitrates.medium,
+                scaleResolutionDownBy: 2
+              }, {
+                rid: "l",
+                active: true,
+                maxBitrate: maxBitrates.low,
+                scaleResolutionDownBy: 4
+              }]
+            });
+          }
+        }
+      });
+    } // Any data channel to create?
+
+
+    if (isDataEnabled(media) && !config.dataChannel[Janus$1.dataChanDefaultLabel]) {
+      Janus$1.log("Creating data channel");
+      createDataChannel(handleId, Janus$1.dataChanDefaultLabel, false);
+
+      config.pc.ondatachannel = function (event) {
+        Janus$1.log("Data channel created by Janus:", event);
+        createDataChannel(handleId, event.channel.label, event.channel);
+      };
+    } // If there's a new local stream, let's notify the application
+
+
+    if (config.myStream) pluginHandle.onlocalstream(config.myStream); // Create offer/answer now
+
+    if (jsep === null || jsep === undefined) {
+      createOffer(handleId, media, callbacks);
+    } else {
+      config.pc.setRemoteDescription(jsep).then(function () {
+        Janus$1.log("Remote description accepted!");
+        config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?
+
+        if (config.candidates && config.candidates.length > 0) {
+          for (var i = 0; i < config.candidates.length; i++) {
+            var candidate = config.candidates[i];
+            Janus$1.debug("Adding remote candidate:", candidate);
+
+            if (!candidate || candidate.completed === true) {
+              // end-of-candidates
+              config.pc.addIceCandidate(Janus$1.endOfCandidates);
+            } else {
+              // New candidate
+              config.pc.addIceCandidate(candidate);
+            }
+          }
+
+          config.candidates = [];
+        } // Create the answer now
+
+
+        createAnswer(handleId, media, callbacks);
+      }, callbacks.error);
+    }
+  }
+
+  function prepareWebrtc(handleId, offer, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : webrtcError;
+    var jsep = callbacks.jsep;
+
+    if (offer && jsep) {
+      Janus$1.error("Provided a JSEP to a createOffer");
+      callbacks.error("Provided a JSEP to a createOffer");
+      return;
+    } else if (!offer && (!jsep || !jsep.type || !jsep.sdp)) {
+      Janus$1.error("A valid JSEP is required for createAnswer");
+      callbacks.error("A valid JSEP is required for createAnswer");
+      return;
+    }
+
+    callbacks.media = callbacks.media || {
+      audio: true,
+      video: true
+    };
+    var media = callbacks.media;
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+    config.trickle = isTrickleEnabled(callbacks.trickle); // Are we updating a session?
+
+    if (config.pc === undefined || config.pc === null) {
+      // Nope, new PeerConnection
+      media.update = false;
+      media.keepAudio = false;
+      media.keepVideo = false;
+    } else if (config.pc !== undefined && config.pc !== null) {
+      Janus$1.log("Updating existing media session");
+      media.update = true; // Check if there's anything to add/remove/replace, or if we
+      // can go directly to preparing the new SDP offer or answer
+
+      if (callbacks.stream !== null && callbacks.stream !== undefined) {
+        // External stream: is this the same as the one we were using before?
+        if (callbacks.stream !== config.myStream) {
+          Janus$1.log("Renegotiation involves a new external stream");
+        }
+      } else {
+        // Check if there are changes on audio
+        if (media.addAudio) {
+          media.keepAudio = false;
+          media.replaceAudio = false;
+          media.removeAudio = false;
+          media.audioSend = true;
+
+          if (config.myStream && config.myStream.getAudioTracks() && config.myStream.getAudioTracks().length) {
+            Janus$1.error("Can't add audio stream, there already is one");
+            callbacks.error("Can't add audio stream, there already is one");
+            return;
+          }
+        } else if (media.removeAudio) {
+          media.keepAudio = false;
+          media.replaceAudio = false;
+          media.addAudio = false;
+          media.audioSend = false;
+        } else if (media.replaceAudio) {
+          media.keepAudio = false;
+          media.addAudio = false;
+          media.removeAudio = false;
+          media.audioSend = true;
+        }
+
+        if (config.myStream === null || config.myStream === undefined) {
+          // No media stream: if we were asked to replace, it's actually an "add"
+          if (media.replaceAudio) {
+            media.keepAudio = false;
+            media.replaceAudio = false;
+            media.addAudio = true;
+            media.audioSend = true;
+          }
+
+          if (isAudioSendEnabled(media)) {
+            media.keepAudio = false;
+            media.addAudio = true;
+          }
+        } else {
+          if (config.myStream.getAudioTracks() === null || config.myStream.getAudioTracks() === undefined || config.myStream.getAudioTracks().length === 0) {
+            // No audio track: if we were asked to replace, it's actually an "add"
+            if (media.replaceAudio) {
+              media.keepAudio = false;
+              media.replaceAudio = false;
+              media.addAudio = true;
+              media.audioSend = true;
+            }
+
+            if (isAudioSendEnabled(media)) {
+              media.keepVideo = false;
+              media.addAudio = true;
+            }
+          } else {
+            // We have an audio track: should we keep it as it is?
+            if (isAudioSendEnabled(media) && !media.removeAudio && !media.replaceAudio) {
+              media.keepAudio = true;
+            }
+          }
+        } // Check if there are changes on video
+
+
+        if (media.addVideo) {
+          media.keepVideo = false;
+          media.replaceVideo = false;
+          media.removeVideo = false;
+          media.videoSend = true;
+
+          if (config.myStream && config.myStream.getVideoTracks() && config.myStream.getVideoTracks().length) {
+            Janus$1.error("Can't add video stream, there already is one");
+            callbacks.error("Can't add video stream, there already is one");
+            return;
+          }
+        } else if (media.removeVideo) {
+          media.keepVideo = false;
+          media.replaceVideo = false;
+          media.addVideo = false;
+          media.videoSend = false;
+        } else if (media.replaceVideo) {
+          media.keepVideo = false;
+          media.addVideo = false;
+          media.removeVideo = false;
+          media.videoSend = true;
+        }
+
+        if (config.myStream === null || config.myStream === undefined) {
+          // No media stream: if we were asked to replace, it's actually an "add"
+          if (media.replaceVideo) {
+            media.keepVideo = false;
+            media.replaceVideo = false;
+            media.addVideo = true;
+            media.videoSend = true;
+          }
+
+          if (isVideoSendEnabled(media)) {
+            media.keepVideo = false;
+            media.addVideo = true;
+          }
+        } else {
+          if (config.myStream.getVideoTracks() === null || config.myStream.getVideoTracks() === undefined || config.myStream.getVideoTracks().length === 0) {
+            // No video track: if we were asked to replace, it's actually an "add"
+            if (media.replaceVideo) {
+              media.keepVideo = false;
+              media.replaceVideo = false;
+              media.addVideo = true;
+              media.videoSend = true;
+            }
+
+            if (isVideoSendEnabled(media)) {
+              media.keepVideo = false;
+              media.addVideo = true;
+            }
+          } else {
+            // We have a video track: should we keep it as it is?
+            if (isVideoSendEnabled(media) && !media.removeVideo && !media.replaceVideo) {
+              media.keepVideo = true;
+            }
+          }
+        } // Data channels can only be added
+
+
+        if (media.addData) media.data = true;
+      } // If we're updating and keeping all tracks, let's skip the getUserMedia part
+
+
+      if (isAudioSendEnabled(media) && media.keepAudio && isVideoSendEnabled(media) && media.keepVideo) {
+        pluginHandle.consentDialog(false);
+        streamsDone(handleId, jsep, media, callbacks, config.myStream);
+        return;
+      }
+    } // If we're updating, check if we need to remove/replace one of the tracks
+
+
+    if (media.update && !config.streamExternal) {
+      if (media.removeAudio || media.replaceAudio) {
+        if (config.myStream && config.myStream.getAudioTracks() && config.myStream.getAudioTracks().length) {
+          var s = config.myStream.getAudioTracks()[0];
+          Janus$1.log("Removing audio track:", s);
+          config.myStream.removeTrack(s);
+
+          try {
+            s.stop();
+          } catch (e) {}
+        }
+
+        if (config.pc.getSenders() && config.pc.getSenders().length) {
+          var ra = true;
+
+          if (media.replaceAudio && Janus$1.unifiedPlan) {
+            // We can use replaceTrack
+            ra = false;
+          }
+
+          if (ra) {
+            for (var index in config.pc.getSenders()) {
+              var s = config.pc.getSenders()[index];
+
+              if (s && s.track && s.track.kind === "audio") {
+                Janus$1.log("Removing audio sender:", s);
+                config.pc.removeTrack(s);
+              }
+            }
+          }
+        }
+      }
+
+      if (media.removeVideo || media.replaceVideo) {
+        if (config.myStream && config.myStream.getVideoTracks() && config.myStream.getVideoTracks().length) {
+          var s = config.myStream.getVideoTracks()[0];
+          Janus$1.log("Removing video track:", s);
+          config.myStream.removeTrack(s);
+
+          try {
+            s.stop();
+          } catch (e) {}
+        }
+
+        if (config.pc.getSenders() && config.pc.getSenders().length) {
+          var rv = true;
+
+          if (media.replaceVideo && Janus$1.unifiedPlan) {
+            // We can use replaceTrack
+            rv = false;
+          }
+
+          if (rv) {
+            for (var index in config.pc.getSenders()) {
+              var s = config.pc.getSenders()[index];
+
+              if (s && s.track && s.track.kind === "video") {
+                Janus$1.log("Removing video sender:", s);
+                config.pc.removeTrack(s);
+              }
+            }
+          }
+        }
+      }
+    } // Was a MediaStream object passed, or do we need to take care of that?
+
+
+    if (callbacks.stream !== null && callbacks.stream !== undefined) {
+      var stream = callbacks.stream;
+      Janus$1.log("MediaStream provided by the application");
+      Janus$1.debug(stream); // If this is an update, let's check if we need to release the previous stream
+
+      if (media.update) {
+        if (config.myStream && config.myStream !== callbacks.stream && !config.streamExternal) {
+          // We're replacing a stream we captured ourselves with an external one
+          try {
+            // Try a MediaStreamTrack.stop() for each track
+            var tracks = config.myStream.getTracks();
+
+            for (var i in tracks) {
+              var mst = tracks[i];
+              Janus$1.log(mst);
+              if (mst !== null && mst !== undefined) mst.stop();
+            }
+          } catch (e) {// Do nothing if this fails
+          }
+
+          config.myStream = null;
+        }
+      } // Skip the getUserMedia part
+
+
+      config.streamExternal = true;
+      pluginHandle.consentDialog(false);
+      streamsDone(handleId, jsep, media, callbacks, stream);
+      return;
+    }
+
+    if (isAudioSendEnabled(media) || isVideoSendEnabled(media)) {
+      if (!Janus$1.isGetUserMediaAvailable()) {
+        callbacks.error("getUserMedia not available");
+        return;
+      }
+
+      var constraints = {
+        mandatory: {},
+        optional: []
+      };
+      pluginHandle.consentDialog(true);
+      var audioSupport = isAudioSendEnabled(media);
+
+      if (audioSupport === true && media != undefined && media != null) {
+        if (_typeof(media.audio) === 'object') {
+          audioSupport = media.audio;
+        }
+      }
+
+      var videoSupport = isVideoSendEnabled(media);
+
+      if (videoSupport === true && media != undefined && media != null) {
+        var simulcast = callbacks.simulcast === true ? true : false;
+        var simulcast2 = callbacks.simulcast2 === true ? true : false;
+        if ((simulcast || simulcast2) && !jsep && (media.video === undefined || media.video === false)) media.video = "hires";
+
+        if (media.video && media.video != 'screen' && media.video != 'window') {
+          if (_typeof(media.video) === 'object') {
+            videoSupport = media.video;
+          } else {
+            var width = 0;
+            var height = 0;
+
+            if (media.video === 'lowres') {
+              // Small resolution, 4:3
+              height = 240;
+              width = 320;
+            } else if (media.video === 'lowres-16:9') {
+              // Small resolution, 16:9
+              height = 180;
+              width = 320;
+            } else if (media.video === 'hires' || media.video === 'hires-16:9' || media.video === 'hdres') {
+              // High(HD) resolution is only 16:9
+              height = 720;
+              width = 1280;
+            } else if (media.video === 'fhdres') {
+              // Full HD resolution is only 16:9
+              height = 1080;
+              width = 1920;
+            } else if (media.video === '4kres') {
+              // 4K resolution is only 16:9
+              height = 2160;
+              width = 3840;
+            } else if (media.video === 'stdres') {
+              // Normal resolution, 4:3
+              height = 480;
+              width = 640;
+            } else if (media.video === 'stdres-16:9') {
+              // Normal resolution, 16:9
+              height = 360;
+              width = 640;
+            } else {
+              Janus$1.log("Default video setting is stdres 4:3");
+              height = 480;
+              width = 640;
+            }
+
+            Janus$1.log("Adding media constraint:", media.video);
+            videoSupport = {
+              'height': {
+                'ideal': height
+              },
+              'width': {
+                'ideal': width
+              }
+            };
+            Janus$1.log("Adding video constraint:", videoSupport);
+          }
+        } else if (media.video === 'screen' || media.video === 'window') {
+          // We're going to try and use the extension for Chrome 34+, the old approach
+          // for older versions of Chrome, or the experimental support in Firefox 33+
+          var callbackUserMedia = function callbackUserMedia(error, stream) {
+            pluginHandle.consentDialog(false);
+
+            if (error) {
+              callbacks.error(error);
+            } else {
+              streamsDone(handleId, jsep, media, callbacks, stream);
+            }
+          };
+
+          var getScreenMedia = function getScreenMedia(constraints, gsmCallback, useAudio) {
+            Janus$1.log("Adding media constraint (screen capture)");
+            Janus$1.debug(constraints);
+            navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
+              if (useAudio) {
+                navigator.mediaDevices.getUserMedia({
+                  audio: true,
+                  video: false
+                }).then(function (audioStream) {
+                  stream.addTrack(audioStream.getAudioTracks()[0]);
+                  gsmCallback(null, stream);
+                });
+              } else {
+                gsmCallback(null, stream);
+              }
+            })["catch"](function (error) {
+              pluginHandle.consentDialog(false);
+              gsmCallback(error);
+            });
+          };
+
+          if (!media.screenshareFrameRate) {
+            media.screenshareFrameRate = 3;
+          }
+
+          if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
+            // The new experimental getDisplayMedia API is available, let's use that
+            // https://groups.google.com/forum/#!topic/discuss-webrtc/Uf0SrR4uxzk
+            // https://webrtchacks.com/chrome-screensharing-getdisplaymedia/
+            navigator.mediaDevices.getDisplayMedia({
+              video: true
+            }).then(function (stream) {
+              pluginHandle.consentDialog(false);
+
+              if (isAudioSendEnabled(media) && !media.keepAudio) {
+                navigator.mediaDevices.getUserMedia({
+                  audio: true,
+                  video: false
+                }).then(function (audioStream) {
+                  stream.addTrack(audioStream.getAudioTracks()[0]);
+                  streamsDone(handleId, jsep, media, callbacks, stream);
+                });
+              } else {
+                streamsDone(handleId, jsep, media, callbacks, stream);
+              }
+            }, function (error) {
+              pluginHandle.consentDialog(false);
+              callbacks.error(error);
+            });
+            return;
+          }
+
+          if (Janus$1.webRTCAdapter.browserDetails.browser === 'chrome') {
+            var chromever = Janus$1.webRTCAdapter.browserDetails.version;
+            var maxver = 33;
+            if (window.navigator.userAgent.match('Linux')) maxver = 35; // "known" crash in chrome 34 and 35 on linux
+
+            if (chromever >= 26 && chromever <= maxver) {
+              // Chrome 26->33 requires some awkward chrome://flags manipulation
+              constraints = {
+                video: {
+                  mandatory: {
+                    googLeakyBucket: true,
+                    maxWidth: window.screen.width,
+                    maxHeight: window.screen.height,
+                    minFrameRate: media.screenshareFrameRate,
+                    maxFrameRate: media.screenshareFrameRate,
+                    chromeMediaSource: 'screen'
+                  }
+                },
+                audio: isAudioSendEnabled(media) && !media.keepAudio
+              };
+              getScreenMedia(constraints, callbackUserMedia);
+            } else {
+              // Chrome 34+ requires an extension
+              Janus$1.extension.getScreen(function (error, sourceId) {
+                if (error) {
+                  pluginHandle.consentDialog(false);
+                  return callbacks.error(error);
+                }
+
+                constraints = {
+                  audio: false,
+                  video: {
+                    mandatory: {
+                      chromeMediaSource: 'desktop',
+                      maxWidth: window.screen.width,
+                      maxHeight: window.screen.height,
+                      minFrameRate: media.screenshareFrameRate,
+                      maxFrameRate: media.screenshareFrameRate
+                    },
+                    optional: [{
+                      googLeakyBucket: true
+                    }, {
+                      googTemporalLayeredScreencast: true
+                    }]
+                  }
+                };
+                constraints.video.mandatory.chromeMediaSourceId = sourceId;
+                getScreenMedia(constraints, callbackUserMedia, isAudioSendEnabled(media) && !media.keepAudio);
+              });
+            }
+          } else if (Janus$1.webRTCAdapter.browserDetails.browser === 'firefox') {
+            if (Janus$1.webRTCAdapter.browserDetails.version >= 33) {
+              // Firefox 33+ has experimental support for screen sharing
+              constraints = {
+                video: {
+                  mozMediaSource: media.video,
+                  mediaSource: media.video
+                },
+                audio: isAudioSendEnabled(media) && !media.keepAudio
+              };
+              getScreenMedia(constraints, function (err, stream) {
+                callbackUserMedia(err, stream); // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1045810
+
+                if (!err) {
+                  var lastTime = stream.currentTime;
+                  var polly = window.setInterval(function () {
+                    if (!stream) window.clearInterval(polly);
+
+                    if (stream.currentTime == lastTime) {
+                      window.clearInterval(polly);
+
+                      if (stream.onended) {
+                        stream.onended();
+                      }
+                    }
+
+                    lastTime = stream.currentTime;
+                  }, 500);
+                }
+              });
+            } else {
+              var error = new Error('NavigatorUserMediaError');
+              error.name = 'Your version of Firefox does not support screen sharing, please install Firefox 33 (or more recent versions)';
+              pluginHandle.consentDialog(false);
+              callbacks.error(error);
+              return;
+            }
+          }
+
+          return;
+        }
+      } // If we got here, we're not screensharing
+
+
+      if (media === null || media === undefined || media.video !== 'screen') {
+        // Check whether all media sources are actually available or not
+        navigator.mediaDevices.enumerateDevices().then(function (devices) {
+          var audioExist = devices.some(function (device) {
+            return device.kind === 'audioinput';
+          }),
+              videoExist = isScreenSendEnabled(media) || devices.some(function (device) {
+            return device.kind === 'videoinput';
+          }); // Check whether a missing device is really a problem
+
+          var audioSend = isAudioSendEnabled(media);
+          var videoSend = isVideoSendEnabled(media);
+          var needAudioDevice = isAudioSendRequired(media);
+          var needVideoDevice = isVideoSendRequired(media);
+
+          if (audioSend || videoSend || needAudioDevice || needVideoDevice) {
+            // We need to send either audio or video
+            var haveAudioDevice = audioSend ? audioExist : false;
+            var haveVideoDevice = videoSend ? videoExist : false;
+
+            if (!haveAudioDevice && !haveVideoDevice) {
+              // FIXME Should we really give up, or just assume recvonly for both?
+              pluginHandle.consentDialog(false);
+              callbacks.error('No capture device found');
+              return false;
+            } else if (!haveAudioDevice && needAudioDevice) {
+              pluginHandle.consentDialog(false);
+              callbacks.error('Audio capture is required, but no capture device found');
+              return false;
+            } else if (!haveVideoDevice && needVideoDevice) {
+              pluginHandle.consentDialog(false);
+              callbacks.error('Video capture is required, but no capture device found');
+              return false;
+            }
+          }
+
+          var gumConstraints = {
+            audio: audioExist && !media.keepAudio ? audioSupport : false,
+            video: videoExist && !media.keepVideo ? videoSupport : false
+          };
+          Janus$1.debug("getUserMedia constraints", gumConstraints);
+
+          if (!gumConstraints.audio && !gumConstraints.video) {
+            pluginHandle.consentDialog(false);
+            streamsDone(handleId, jsep, media, callbacks, stream);
+          } else {
+            navigator.mediaDevices.getUserMedia(gumConstraints).then(function (stream) {
+              pluginHandle.consentDialog(false);
+              streamsDone(handleId, jsep, media, callbacks, stream);
+            })["catch"](function (error) {
+              pluginHandle.consentDialog(false);
+              callbacks.error({
+                code: error.code,
+                name: error.name,
+                message: error.message
+              });
+            });
+          }
+        })["catch"](function (error) {
+          pluginHandle.consentDialog(false);
+          callbacks.error('enumerateDevices error', error);
+        });
+      }
+    } else {
+      // No need to do a getUserMedia, create offer/answer right away
+      streamsDone(handleId, jsep, media, callbacks);
+    }
+  }
+
+  function prepareWebrtcPeer(handleId, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : webrtcError;
+    var jsep = callbacks.jsep;
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+
+    if (jsep !== undefined && jsep !== null) {
+      if (config.pc === null) {
+        Janus$1.warn("Wait, no PeerConnection?? if this is an answer, use createAnswer and not handleRemoteJsep");
+        callbacks.error("No PeerConnection: if this is an answer, use createAnswer and not handleRemoteJsep");
+        return;
+      }
+
+      config.pc.setRemoteDescription(jsep).then(function () {
+        Janus$1.log("Remote description accepted!");
+        config.remoteSdp = jsep.sdp; // Any trickle candidate we cached?
+
+        if (config.candidates && config.candidates.length > 0) {
+          for (var i = 0; i < config.candidates.length; i++) {
+            var candidate = config.candidates[i];
+            Janus$1.debug("Adding remote candidate:", candidate);
+
+            if (!candidate || candidate.completed === true) {
+              // end-of-candidates
+              config.pc.addIceCandidate(Janus$1.endOfCandidates);
+            } else {
+              // New candidate
+              config.pc.addIceCandidate(candidate);
+            }
+          }
+
+          config.candidates = [];
+        } // Done
+
+
+        callbacks.success();
+      }, callbacks.error);
+    } else {
+      callbacks.error("Invalid JSEP");
+    }
+  }
+
+  function createOffer(handleId, media, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    callbacks.customizeSdp = typeof callbacks.customizeSdp == "function" ? callbacks.customizeSdp : Janus$1.noop;
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+    var simulcast = callbacks.simulcast === true ? true : false;
+
+    if (!simulcast) {
+      Janus$1.log("Creating offer (iceDone=" + config.iceDone + ")");
+    } else {
+      Janus$1.log("Creating offer (iceDone=" + config.iceDone + ", simulcast=" + simulcast + ")");
+    } // https://code.google.com/p/webrtc/issues/detail?id=3508
+
+
+    var mediaConstraints = {};
+
+    if (Janus$1.unifiedPlan) {
+      // We can use Transceivers
+      var audioTransceiver = null,
+          videoTransceiver = null;
+      var transceivers = config.pc.getTransceivers();
+
+      if (transceivers && transceivers.length > 0) {
+        for (var i in transceivers) {
+          var t = transceivers[i];
+
+          if (t.sender && t.sender.track && t.sender.track.kind === "audio" || t.receiver && t.receiver.track && t.receiver.track.kind === "audio") {
+            if (!audioTransceiver) audioTransceiver = t;
+            continue;
+          }
+
+          if (t.sender && t.sender.track && t.sender.track.kind === "video" || t.receiver && t.receiver.track && t.receiver.track.kind === "video") {
+            if (!videoTransceiver) videoTransceiver = t;
+            continue;
+          }
+        }
+      } // Handle audio (and related changes, if any)
+
+
+      var audioSend = isAudioSendEnabled(media);
+      var audioRecv = isAudioRecvEnabled(media);
+
+      if (!audioSend && !audioRecv) {
+        // Audio disabled: have we removed it?
+        if (media.removeAudio && audioTransceiver) {
+          if (audioTransceiver.setDirection) {
+            audioTransceiver.setDirection("inactive");
+          } else {
+            audioTransceiver.direction = "inactive";
+          }
+
+          Janus$1.log("Setting audio transceiver to inactive:", audioTransceiver);
+        }
+      } else {
+        // Take care of audio m-line
+        if (audioSend && audioRecv) {
+          if (audioTransceiver) {
+            if (audioTransceiver.setDirection) {
+              audioTransceiver.setDirection("sendrecv");
+            } else {
+              audioTransceiver.direction = "sendrecv";
+            }
+
+            Janus$1.log("Setting audio transceiver to sendrecv:", audioTransceiver);
+          }
+        } else if (audioSend && !audioRecv) {
+          if (audioTransceiver) {
+            if (audioTransceiver.setDirection) {
+              audioTransceiver.setDirection("sendonly");
+            } else {
+              audioTransceiver.direction = "sendonly";
+            }
+
+            Janus$1.log("Setting audio transceiver to sendonly:", audioTransceiver);
+          }
+        } else if (!audioSend && audioRecv) {
+          if (audioTransceiver) {
+            if (audioTransceiver.setDirection) {
+              audioTransceiver.setDirection("recvonly");
+            } else {
+              audioTransceiver.direction = "recvonly";
+            }
+
+            Janus$1.log("Setting audio transceiver to recvonly:", audioTransceiver);
+          } else {
+            // In theory, this is the only case where we might not have a transceiver yet
+            audioTransceiver = config.pc.addTransceiver("audio", {
+              direction: "recvonly"
+            });
+            Janus$1.log("Adding recvonly audio transceiver:", audioTransceiver);
+          }
+        }
+      } // Handle video (and related changes, if any)
+
+
+      var videoSend = isVideoSendEnabled(media);
+      var videoRecv = isVideoRecvEnabled(media);
+
+      if (!videoSend && !videoRecv) {
+        // Video disabled: have we removed it?
+        if (media.removeVideo && videoTransceiver) {
+          if (videoTransceiver.setDirection) {
+            videoTransceiver.setDirection("inactive");
+          } else {
+            videoTransceiver.direction = "inactive";
+          }
+
+          Janus$1.log("Setting video transceiver to inactive:", videoTransceiver);
+        }
+      } else {
+        // Take care of video m-line
+        if (videoSend && videoRecv) {
+          if (videoTransceiver) {
+            if (videoTransceiver.setDirection) {
+              videoTransceiver.setDirection("sendrecv");
+            } else {
+              videoTransceiver.direction = "sendrecv";
+            }
+
+            Janus$1.log("Setting video transceiver to sendrecv:", videoTransceiver);
+          }
+        } else if (videoSend && !videoRecv) {
+          if (videoTransceiver) {
+            if (videoTransceiver.setDirection) {
+              videoTransceiver.setDirection("sendonly");
+            } else {
+              videoTransceiver.direction = "sendonly";
+            }
+
+            Janus$1.log("Setting video transceiver to sendonly:", videoTransceiver);
+          }
+        } else if (!videoSend && videoRecv) {
+          if (videoTransceiver) {
+            if (videoTransceiver.setDirection) {
+              videoTransceiver.setDirection("recvonly");
+            } else {
+              videoTransceiver.direction = "recvonly";
+            }
+
+            Janus$1.log("Setting video transceiver to recvonly:", videoTransceiver);
+          } else {
+            // In theory, this is the only case where we might not have a transceiver yet
+            videoTransceiver = config.pc.addTransceiver("video", {
+              direction: "recvonly"
+            });
+            Janus$1.log("Adding recvonly video transceiver:", videoTransceiver);
+          }
+        }
+      }
+    } else {
+      mediaConstraints["offerToReceiveAudio"] = isAudioRecvEnabled(media);
+      mediaConstraints["offerToReceiveVideo"] = isVideoRecvEnabled(media);
+    }
+
+    var iceRestart = callbacks.iceRestart === true ? true : false;
+
+    if (iceRestart) {
+      mediaConstraints["iceRestart"] = true;
+    }
+
+    Janus$1.debug(mediaConstraints); // Check if this is Firefox and we've been asked to do simulcasting
+
+    var sendVideo = isVideoSendEnabled(media);
+
+    if (sendVideo && simulcast && Janus$1.webRTCAdapter.browserDetails.browser === "firefox") {
+      // FIXME Based on https://gist.github.com/voluntas/088bc3cc62094730647b
+      Janus$1.log("Enabling Simulcasting for Firefox (RID)");
+      var sender = config.pc.getSenders().find(function (s) {
+        return s.track.kind == "video";
+      });
+
+      if (sender) {
+        var parameters = sender.getParameters();
+        if (!parameters) parameters = {};
+        var maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);
+        parameters.encodings = [{
+          rid: "h",
+          active: true,
+          maxBitrate: maxBitrates.high
+        }, {
+          rid: "m",
+          active: true,
+          maxBitrate: maxBitrates.medium,
+          scaleResolutionDownBy: 2
+        }, {
+          rid: "l",
+          active: true,
+          maxBitrate: maxBitrates.low,
+          scaleResolutionDownBy: 4
+        }];
+        sender.setParameters(parameters);
+      }
+    }
+
+    config.pc.createOffer(mediaConstraints).then(function (offer) {
+      Janus$1.debug(offer); // JSON.stringify doesn't work on some WebRTC objects anymore
+      // See https://code.google.com/p/chromium/issues/detail?id=467366
+
+      var jsep = {
+        "type": offer.type,
+        "sdp": offer.sdp
+      };
+      callbacks.customizeSdp(jsep);
+      offer.sdp = jsep.sdp;
+      Janus$1.log("Setting local description");
+
+      if (sendVideo && simulcast) {
+        // This SDP munging only works with Chrome (Safari STP may support it too)
+        if (Janus$1.webRTCAdapter.browserDetails.browser === "chrome" || Janus$1.webRTCAdapter.browserDetails.browser === "safari") {
+          Janus$1.log("Enabling Simulcasting for Chrome (SDP munging)");
+          offer.sdp = mungeSdpForSimulcasting(offer.sdp);
+        } else if (Janus$1.webRTCAdapter.browserDetails.browser !== "firefox") {
+          Janus$1.warn("simulcast=true, but this is not Chrome nor Firefox, ignoring");
+        }
+      }
+
+      config.mySdp = offer.sdp;
+      config.pc.setLocalDescription(offer)["catch"](callbacks.error);
+      config.mediaConstraints = mediaConstraints;
+
+      if (!config.iceDone && !config.trickle) {
+        // Don't do anything until we have all candidates
+        Janus$1.log("Waiting for all candidates...");
+        return;
+      }
+
+      Janus$1.log("Offer ready");
+      Janus$1.debug(callbacks);
+      callbacks.success(offer);
+    }, callbacks.error);
+  }
+
+  function createAnswer(handleId, media, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    callbacks.customizeSdp = typeof callbacks.customizeSdp == "function" ? callbacks.customizeSdp : Janus$1.noop;
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      callbacks.error("Invalid handle");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+    var simulcast = callbacks.simulcast === true ? true : false;
+
+    if (!simulcast) {
+      Janus$1.log("Creating answer (iceDone=" + config.iceDone + ")");
+    } else {
+      Janus$1.log("Creating answer (iceDone=" + config.iceDone + ", simulcast=" + simulcast + ")");
+    }
+
+    var mediaConstraints = null;
+
+    if (Janus$1.unifiedPlan) {
+      // We can use Transceivers
+      mediaConstraints = {};
+      var audioTransceiver = null,
+          videoTransceiver = null;
+      var transceivers = config.pc.getTransceivers();
+
+      if (transceivers && transceivers.length > 0) {
+        for (var i in transceivers) {
+          var t = transceivers[i];
+
+          if (t.sender && t.sender.track && t.sender.track.kind === "audio" || t.receiver && t.receiver.track && t.receiver.track.kind === "audio") {
+            if (!audioTransceiver) audioTransceiver = t;
+            continue;
+          }
+
+          if (t.sender && t.sender.track && t.sender.track.kind === "video" || t.receiver && t.receiver.track && t.receiver.track.kind === "video") {
+            if (!videoTransceiver) videoTransceiver = t;
+            continue;
+          }
+        }
+      } // Handle audio (and related changes, if any)
+
+
+      var audioSend = isAudioSendEnabled(media);
+      var audioRecv = isAudioRecvEnabled(media);
+
+      if (!audioSend && !audioRecv) {
+        // Audio disabled: have we removed it?
+        if (media.removeAudio && audioTransceiver) {
+          try {
+            if (audioTransceiver.setDirection) {
+              audioTransceiver.setDirection("inactive");
+            } else {
+              audioTransceiver.direction = "inactive";
+            }
+
+            Janus$1.log("Setting audio transceiver to inactive:", audioTransceiver);
+          } catch (e) {
+            Janus$1.error(e);
+          }
+        }
+      } else {
+        // Take care of audio m-line
+        if (audioSend && audioRecv) {
+          if (audioTransceiver) {
+            try {
+              if (audioTransceiver.setDirection) {
+                audioTransceiver.setDirection("sendrecv");
+              } else {
+                audioTransceiver.direction = "sendrecv";
+              }
+
+              Janus$1.log("Setting audio transceiver to sendrecv:", audioTransceiver);
+            } catch (e) {
+              Janus$1.error(e);
+            }
+          }
+        } else if (audioSend && !audioRecv) {
+          try {
+            if (audioTransceiver) {
+              if (audioTransceiver.setDirection) {
+                audioTransceiver.setDirection("sendonly");
+              } else {
+                audioTransceiver.direction = "sendonly";
+              }
+
+              Janus$1.log("Setting audio transceiver to sendonly:", audioTransceiver);
+            }
+          } catch (e) {
+            Janus$1.error(e);
+          }
+        } else if (!audioSend && audioRecv) {
+          if (audioTransceiver) {
+            try {
+              if (audioTransceiver.setDirection) {
+                audioTransceiver.setDirection("recvonly");
+              } else {
+                audioTransceiver.direction = "recvonly";
+              }
+
+              Janus$1.log("Setting audio transceiver to recvonly:", audioTransceiver);
+            } catch (e) {
+              Janus$1.error(e);
+            }
+          } else {
+            // In theory, this is the only case where we might not have a transceiver yet
+            audioTransceiver = config.pc.addTransceiver("audio", {
+              direction: "recvonly"
+            });
+            Janus$1.log("Adding recvonly audio transceiver:", audioTransceiver);
+          }
+        }
+      } // Handle video (and related changes, if any)
+
+
+      var videoSend = isVideoSendEnabled(media);
+      var videoRecv = isVideoRecvEnabled(media);
+
+      if (!videoSend && !videoRecv) {
+        // Video disabled: have we removed it?
+        if (media.removeVideo && videoTransceiver) {
+          try {
+            if (videoTransceiver.setDirection) {
+              videoTransceiver.setDirection("inactive");
+            } else {
+              videoTransceiver.direction = "inactive";
+            }
+
+            Janus$1.log("Setting video transceiver to inactive:", videoTransceiver);
+          } catch (e) {
+            Janus$1.error(e);
+          }
+        }
+      } else {
+        // Take care of video m-line
+        if (videoSend && videoRecv) {
+          if (videoTransceiver) {
+            try {
+              if (videoTransceiver.setDirection) {
+                videoTransceiver.setDirection("sendrecv");
+              } else {
+                videoTransceiver.direction = "sendrecv";
+              }
+
+              Janus$1.log("Setting video transceiver to sendrecv:", videoTransceiver);
+            } catch (e) {
+              Janus$1.error(e);
+            }
+          }
+        } else if (videoSend && !videoRecv) {
+          if (videoTransceiver) {
+            try {
+              if (videoTransceiver.setDirection) {
+                videoTransceiver.setDirection("sendonly");
+              } else {
+                videoTransceiver.direction = "sendonly";
+              }
+
+              Janus$1.log("Setting video transceiver to sendonly:", videoTransceiver);
+            } catch (e) {
+              Janus$1.error(e);
+            }
+          }
+        } else if (!videoSend && videoRecv) {
+          if (videoTransceiver) {
+            try {
+              if (videoTransceiver.setDirection) {
+                videoTransceiver.setDirection("recvonly");
+              } else {
+                videoTransceiver.direction = "recvonly";
+              }
+
+              Janus$1.log("Setting video transceiver to recvonly:", videoTransceiver);
+            } catch (e) {
+              Janus$1.error(e);
+            }
+          } else {
+            // In theory, this is the only case where we might not have a transceiver yet
+            videoTransceiver = config.pc.addTransceiver("video", {
+              direction: "recvonly"
+            });
+            Janus$1.log("Adding recvonly video transceiver:", videoTransceiver);
+          }
+        }
+      }
+    } else {
+      if (Janus$1.webRTCAdapter.browserDetails.browser == "firefox" || Janus$1.webRTCAdapter.browserDetails.browser == "edge") {
+        mediaConstraints = {
+          offerToReceiveAudio: isAudioRecvEnabled(media),
+          offerToReceiveVideo: isVideoRecvEnabled(media)
+        };
+      } else {
+        mediaConstraints = {
+          mandatory: {
+            OfferToReceiveAudio: isAudioRecvEnabled(media),
+            OfferToReceiveVideo: isVideoRecvEnabled(media)
+          }
+        };
+      }
+    }
+
+    Janus$1.debug(mediaConstraints); // Check if this is Firefox and we've been asked to do simulcasting
+
+    var sendVideo = isVideoSendEnabled(media);
+
+    if (sendVideo && simulcast && Janus$1.webRTCAdapter.browserDetails.browser === "firefox") {
+      // FIXME Based on https://gist.github.com/voluntas/088bc3cc62094730647b
+      Janus$1.log("Enabling Simulcasting for Firefox (RID)");
+      var sender = config.pc.getSenders()[1];
+      Janus$1.log(sender);
+      var parameters = sender.getParameters();
+      Janus$1.log(parameters);
+      var maxBitrates = getMaxBitrates(callbacks.simulcastMaxBitrates);
+      sender.setParameters({
+        encodings: [{
+          rid: "high",
+          active: true,
+          priority: "high",
+          maxBitrate: maxBitrates.high
+        }, {
+          rid: "medium",
+          active: true,
+          priority: "medium",
+          maxBitrate: maxBitrates.medium
+        }, {
+          rid: "low",
+          active: true,
+          priority: "low",
+          maxBitrate: maxBitrates.low
+        }]
+      });
+    }
+
+    config.pc.createAnswer(mediaConstraints).then(function (answer) {
+      Janus$1.debug(answer); // JSON.stringify doesn't work on some WebRTC objects anymore
+      // See https://code.google.com/p/chromium/issues/detail?id=467366
+
+      var jsep = {
+        "type": answer.type,
+        "sdp": answer.sdp
+      };
+      callbacks.customizeSdp(jsep);
+      answer.sdp = jsep.sdp;
+      Janus$1.log("Setting local description");
+
+      if (sendVideo && simulcast) {
+        // This SDP munging only works with Chrome
+        if (Janus$1.webRTCAdapter.browserDetails.browser === "chrome") {
+          // FIXME Apparently trying to simulcast when answering breaks video in Chrome...
+          //~ Janus.log("Enabling Simulcasting for Chrome (SDP munging)");
+          //~ answer.sdp = mungeSdpForSimulcasting(answer.sdp);
+          Janus$1.warn("simulcast=true, but this is an answer, and video breaks in Chrome if we enable it");
+        } else if (Janus$1.webRTCAdapter.browserDetails.browser !== "firefox") {
+          Janus$1.warn("simulcast=true, but this is not Chrome nor Firefox, ignoring");
+        }
+      }
+
+      config.mySdp = answer.sdp;
+      config.pc.setLocalDescription(answer)["catch"](callbacks.error);
+      config.mediaConstraints = mediaConstraints;
+
+      if (!config.iceDone && !config.trickle) {
+        // Don't do anything until we have all candidates
+        Janus$1.log("Waiting for all candidates...");
+        return;
+      }
+
+      callbacks.success(answer);
+    }, callbacks.error);
+  }
+
+  function sendSDP(handleId, callbacks) {
+    callbacks = callbacks || {};
+    callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus$1.noop;
+    callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus$1.noop;
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle, not sending anything");
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+    Janus$1.log("Sending offer/answer SDP...");
+
+    if (config.mySdp === null || config.mySdp === undefined) {
+      Janus$1.warn("Local SDP instance is invalid, not sending anything...");
+      return;
+    }
+
+    config.mySdp = {
+      "type": config.pc.localDescription.type,
+      "sdp": config.pc.localDescription.sdp
+    };
+    if (config.trickle === false) config.mySdp["trickle"] = false;
+    Janus$1.debug(callbacks);
+    config.sdpSent = true;
+    callbacks.success(config.mySdp);
+  }
+
+  function _getVolume(handleId, remote) {
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      return 0;
+    }
+
+    var stream = remote ? "remote" : "local";
+    var config = pluginHandle.webrtcStuff;
+    if (!config.volume[stream]) config.volume[stream] = {
+      value: 0
+    }; // Start getting the volume, if getStats is supported
+
+    if (config.pc.getStats && Janus$1.webRTCAdapter.browserDetails.browser === "chrome") {
+      if (remote && (config.remoteStream === null || config.remoteStream === undefined)) {
+        Janus$1.warn("Remote stream unavailable");
+        return 0;
+      } else if (!remote && (config.myStream === null || config.myStream === undefined)) {
+        Janus$1.warn("Local stream unavailable");
+        return 0;
+      }
+
+      if (config.volume[stream].timer === null || config.volume[stream].timer === undefined) {
+        Janus$1.log("Starting " + stream + " volume monitor");
+        config.volume[stream].timer = setInterval(function () {
+          config.pc.getStats(function (stats) {
+            var results = stats.result();
+
+            for (var i = 0; i < results.length; i++) {
+              var res = results[i];
+
+              if (res.type == 'ssrc') {
+                if (remote && res.stat('audioOutputLevel')) config.volume[stream].value = parseInt(res.stat('audioOutputLevel'));else if (!remote && res.stat('audioInputLevel')) config.volume[stream].value = parseInt(res.stat('audioInputLevel'));
+              }
+            }
+          });
+        }, 200);
+        return 0; // We don't have a volume to return yet
+      }
+
+      return config.volume[stream].value;
+    } else {
+      // audioInputLevel and audioOutputLevel seem only available in Chrome? audioLevel
+      // seems to be available on Chrome and Firefox, but they don't seem to work
+      Janus$1.warn("Getting the " + stream + " volume unsupported by browser");
+      return 0;
+    }
+  }
+
+  function isMuted(handleId, video) {
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      return true;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+
+    if (config.pc === null || config.pc === undefined) {
+      Janus$1.warn("Invalid PeerConnection");
+      return true;
+    }
+
+    if (config.myStream === undefined || config.myStream === null) {
+      Janus$1.warn("Invalid local MediaStream");
+      return true;
+    }
+
+    if (video) {
+      // Check video track
+      if (config.myStream.getVideoTracks() === null || config.myStream.getVideoTracks() === undefined || config.myStream.getVideoTracks().length === 0) {
+        Janus$1.warn("No video track");
+        return true;
+      }
+
+      return !config.myStream.getVideoTracks()[0].enabled;
+    } else {
+      // Check audio track
+      if (config.myStream.getAudioTracks() === null || config.myStream.getAudioTracks() === undefined || config.myStream.getAudioTracks().length === 0) {
+        Janus$1.warn("No audio track");
+        return true;
+      }
+
+      return !config.myStream.getAudioTracks()[0].enabled;
+    }
+  }
+
+  function mute(handleId, video, mute) {
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      return false;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+
+    if (config.pc === null || config.pc === undefined) {
+      Janus$1.warn("Invalid PeerConnection");
+      return false;
+    }
+
+    if (config.myStream === undefined || config.myStream === null) {
+      Janus$1.warn("Invalid local MediaStream");
+      return false;
+    }
+
+    if (video) {
+      // Mute/unmute video track
+      if (config.myStream.getVideoTracks() === null || config.myStream.getVideoTracks() === undefined || config.myStream.getVideoTracks().length === 0) {
+        Janus$1.warn("No video track");
+        return false;
+      }
+
+      config.myStream.getVideoTracks()[0].enabled = mute ? false : true;
+      return true;
+    } else {
+      // Mute/unmute audio track
+      if (config.myStream.getAudioTracks() === null || config.myStream.getAudioTracks() === undefined || config.myStream.getAudioTracks().length === 0) {
+        Janus$1.warn("No audio track");
+        return false;
+      }
+
+      config.myStream.getAudioTracks()[0].enabled = mute ? false : true;
+      return true;
+    }
+  }
+
+  function _getBitrate(handleId) {
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined || pluginHandle.webrtcStuff === null || pluginHandle.webrtcStuff === undefined) {
+      Janus$1.warn("Invalid handle");
+      return "Invalid handle";
+    }
+
+    var config = pluginHandle.webrtcStuff;
+    if (config.pc === null || config.pc === undefined) return "Invalid PeerConnection"; // Start getting the bitrate, if getStats is supported
+
+    if (config.pc.getStats) {
+      if (config.bitrate.timer === null || config.bitrate.timer === undefined) {
+        Janus$1.log("Starting bitrate timer (via getStats)");
+        config.bitrate.timer = setInterval(function () {
+          config.pc.getStats().then(function (stats) {
+            stats.forEach(function (res) {
+              if (!res) return;
+              var inStats = false; // Check if these are statistics on incoming media
+
+              if ((res.mediaType === "video" || res.id.toLowerCase().indexOf("video") > -1) && res.type === "inbound-rtp" && res.id.indexOf("rtcp") < 0) {
+                // New stats
+                inStats = true;
+              } else if (res.type == 'ssrc' && res.bytesReceived && (res.googCodecName === "VP8" || res.googCodecName === "")) {
+                // Older Chromer versions
+                inStats = true;
+              } // Parse stats now
+
+
+              if (inStats) {
+                config.bitrate.bsnow = res.bytesReceived;
+                config.bitrate.tsnow = res.timestamp;
+
+                if (config.bitrate.bsbefore === null || config.bitrate.tsbefore === null) {
+                  // Skip this round
+                  config.bitrate.bsbefore = config.bitrate.bsnow;
+                  config.bitrate.tsbefore = config.bitrate.tsnow;
+                } else {
+                  // Calculate bitrate
+                  var timePassed = config.bitrate.tsnow - config.bitrate.tsbefore;
+                  if (Janus$1.webRTCAdapter.browserDetails.browser == "safari") timePassed = timePassed / 1000; // Apparently the timestamp is in microseconds, in Safari
+
+                  var bitRate = Math.round((config.bitrate.bsnow - config.bitrate.bsbefore) * 8 / timePassed);
+                  if (Janus$1.webRTCAdapter.browserDetails.browser === 'safari') bitRate = parseInt(bitRate / 1000);
+                  config.bitrate.value = bitRate + ' kbits/sec'; //~ Janus.log("Estimated bitrate is " + config.bitrate.value);
+
+                  config.bitrate.bsbefore = config.bitrate.bsnow;
+                  config.bitrate.tsbefore = config.bitrate.tsnow;
+                }
+              }
+            });
+          });
+        }, 1000);
+        return "0 kbits/sec"; // We don't have a bitrate value yet
+      }
+
+      return config.bitrate.value;
+    } else {
+      Janus$1.warn("Getting the video bitrate unsupported by browser");
+      return "Feature unsupported by browser";
+    }
+  }
+
+  function webrtcError(error) {
+    Janus$1.error("WebRTC error:", error);
+  }
+
+  function cleanupWebrtc(handleId, hangupRequest) {
+    Janus$1.log("Cleaning WebRTC stuff");
+    var pluginHandle = pluginHandles[handleId];
+
+    if (pluginHandle === null || pluginHandle === undefined) {
+      // Nothing to clean
+      return;
+    }
+
+    var config = pluginHandle.webrtcStuff;
+
+    if (config !== null && config !== undefined) {
+      if (hangupRequest === true) {
+        // Send a hangup request (we don't really care about the response)
+        var request = {
+          "rtcgw": "hangup",
+          "transaction": Janus$1.randomString(12)
+        };
+        if (pluginHandle.token !== null && pluginHandle.token !== undefined) request["token"] = pluginHandle.token;
+        if (apisecret !== null && apisecret !== undefined) request["apisecret"] = apisecret;
+        Janus$1.debug("Sending hangup request (handle=" + handleId + "):");
+        Janus$1.debug(request);
+
+        if (websockets) {
+          request["session_id"] = sessionId;
+          request["handle_id"] = handleId;
+          ws.send(JSON.stringify(request));
+        } else {
+          Janus$1.httpAPICall(server + "/" + sessionId + "/" + handleId, {
+            verb: 'POST',
+            withCredentials: withCredentials,
+            body: request
+          });
+        }
+      } // Cleanup stack
+
+
+      config.remoteStream = null;
+
+      if (config.volume) {
+        if (config.volume["local"] && config.volume["local"].timer) clearInterval(config.volume["local"].timer);
+        if (config.volume["remote"] && config.volume["remote"].timer) clearInterval(config.volume["remote"].timer);
+      }
+
+      config.volume = {};
+      if (config.bitrate.timer) clearInterval(config.bitrate.timer);
+      config.bitrate.timer = null;
+      config.bitrate.bsnow = null;
+      config.bitrate.bsbefore = null;
+      config.bitrate.tsnow = null;
+      config.bitrate.tsbefore = null;
+      config.bitrate.value = null;
+
+      try {
+        // Try a MediaStreamTrack.stop() for each track
+        if (!config.streamExternal && config.myStream !== null && config.myStream !== undefined) {
+          Janus$1.log("Stopping local stream tracks");
+          var tracks = config.myStream.getTracks();
+
+          for (var i in tracks) {
+            var mst = tracks[i];
+            Janus$1.log(mst);
+            if (mst !== null && mst !== undefined) mst.stop();
+          }
+        }
+      } catch (e) {// Do nothing if this fails
+      }
+
+      config.streamExternal = false;
+      config.myStream = null; // Close PeerConnection
+
+      try {
+        config.pc.close();
+      } catch (e) {// Do nothing
+      }
+
+      config.pc = null;
+      config.candidates = null;
+      config.mySdp = null;
+      config.remoteSdp = null;
+      config.iceDone = false;
+      config.dataChannel = {};
+      config.dtmfSender = null;
+    }
+
+    pluginHandle.oncleanup();
+  } // Helper method to munge an SDP to enable simulcasting (Chrome only)
+
+
+  function mungeSdpForSimulcasting(sdp) {
+    // Let's munge the SDP to add the attributes for enabling simulcasting
+    // (based on https://gist.github.com/ggarber/a19b4c33510028b9c657)
+    var lines = sdp.split("\r\n");
+    var video = false;
+    var ssrc = [-1],
+        ssrc_fid = [-1];
+    var cname = null,
+        msid = null,
+        mslabel = null,
+        label = null;
+    var insertAt = -1;
+
+    for (var i = 0; i < lines.length; i++) {
+      var mline = lines[i].match(/m=(\w+) */);
+
+      if (mline) {
+        var medium = mline[1];
+
+        if (medium === "video") {
+          // New video m-line: make sure it's the first one
+          if (ssrc[0] < 0) {
+            video = true;
+          } else {
+            // We're done, let's add the new attributes here
+            insertAt = i;
+            break;
+          }
+        } else {
+          // New non-video m-line: do we have what we were looking for?
+          if (ssrc[0] > -1) {
+            // We're done, let's add the new attributes here
+            insertAt = i;
+            break;
+          }
+        }
+
+        continue;
+      }
+
+      if (!video) continue;
+      var fid = lines[i].match(/a=ssrc-group:FID (\d+) (\d+)/);
+
+      if (fid) {
+        ssrc[0] = fid[1];
+        ssrc_fid[0] = fid[2];
+        lines.splice(i, 1);
+        i--;
+        continue;
+      }
+
+      if (ssrc[0]) {
+        var match = lines[i].match('a=ssrc:' + ssrc[0] + ' cname:(.+)');
+
+        if (match) {
+          cname = match[1];
+        }
+
+        match = lines[i].match('a=ssrc:' + ssrc[0] + ' msid:(.+)');
+
+        if (match) {
+          msid = match[1];
+        }
+
+        match = lines[i].match('a=ssrc:' + ssrc[0] + ' mslabel:(.+)');
+
+        if (match) {
+          mslabel = match[1];
+        }
+
+        match = lines[i].match('a=ssrc:' + ssrc[0] + ' label:(.+)');
+
+        if (match) {
+          label = match[1];
+        }
+
+        if (lines[i].indexOf('a=ssrc:' + ssrc_fid[0]) === 0) {
+          lines.splice(i, 1);
+          i--;
+          continue;
+        }
+
+        if (lines[i].indexOf('a=ssrc:' + ssrc[0]) === 0) {
+          lines.splice(i, 1);
+          i--;
+          continue;
+        }
+      }
+
+      if (lines[i].length == 0) {
+        lines.splice(i, 1);
+        i--;
+        continue;
+      }
+    }
+
+    if (ssrc[0] < 0) {
+      // Couldn't find a FID attribute, let's just take the first video SSRC we find
+      insertAt = -1;
+      video = false;
+
+      for (var i = 0; i < lines.length; i++) {
+        var mline = lines[i].match(/m=(\w+) */);
+
+        if (mline) {
+          var medium = mline[1];
+
+          if (medium === "video") {
+            // New video m-line: make sure it's the first one
+            if (ssrc[0] < 0) {
+              video = true;
+            } else {
+              // We're done, let's add the new attributes here
+              insertAt = i;
+              break;
+            }
+          } else {
+            // New non-video m-line: do we have what we were looking for?
+            if (ssrc[0] > -1) {
+              // We're done, let's add the new attributes here
+              insertAt = i;
+              break;
+            }
+          }
+
+          continue;
+        }
+
+        if (!video) continue;
+
+        if (ssrc[0] < 0) {
+          var value = lines[i].match(/a=ssrc:(\d+)/);
+
+          if (value) {
+            ssrc[0] = value[1];
+            lines.splice(i, 1);
+            i--;
+            continue;
+          }
+        } else {
+          var match = lines[i].match('a=ssrc:' + ssrc[0] + ' cname:(.+)');
+
+          if (match) {
+            cname = match[1];
+          }
+
+          match = lines[i].match('a=ssrc:' + ssrc[0] + ' msid:(.+)');
+
+          if (match) {
+            msid = match[1];
+          }
+
+          match = lines[i].match('a=ssrc:' + ssrc[0] + ' mslabel:(.+)');
+
+          if (match) {
+            mslabel = match[1];
+          }
+
+          match = lines[i].match('a=ssrc:' + ssrc[0] + ' label:(.+)');
+
+          if (match) {
+            label = match[1];
+          }
+
+          if (lines[i].indexOf('a=ssrc:' + ssrc_fid[0]) === 0) {
+            lines.splice(i, 1);
+            i--;
+            continue;
+          }
+
+          if (lines[i].indexOf('a=ssrc:' + ssrc[0]) === 0) {
+            lines.splice(i, 1);
+            i--;
+            continue;
+          }
+        }
+
+        if (lines[i].length == 0) {
+          lines.splice(i, 1);
+          i--;
+          continue;
+        }
+      }
+    }
+
+    if (ssrc[0] < 0) {
+      // Still nothing, let's just return the SDP we were asked to munge
+      Janus$1.warn("Couldn't find the video SSRC, simulcasting NOT enabled");
+      return sdp;
+    }
+
+    if (insertAt < 0) {
+      // Append at the end
+      insertAt = lines.length;
+    } // Generate a couple of SSRCs (for retransmissions too)
+    // Note: should we check if there are conflicts, here?
+
+
+    ssrc[1] = Math.floor(Math.random() * 0xFFFFFFFF);
+    ssrc[2] = Math.floor(Math.random() * 0xFFFFFFFF);
+    ssrc_fid[1] = Math.floor(Math.random() * 0xFFFFFFFF);
+    ssrc_fid[2] = Math.floor(Math.random() * 0xFFFFFFFF); // Add attributes to the SDP
+
+    for (var i = 0; i < ssrc.length; i++) {
+      if (cname) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' cname:' + cname);
+        insertAt++;
+      }
+
+      if (msid) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' msid:' + msid);
+        insertAt++;
+      }
+
+      if (mslabel) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' mslabel:' + mslabel);
+        insertAt++;
+      }
+
+      if (label) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc[i] + ' label:' + label);
+        insertAt++;
+      } // Add the same info for the retransmission SSRC
+
+
+      if (cname) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' cname:' + cname);
+        insertAt++;
+      }
+
+      if (msid) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' msid:' + msid);
+        insertAt++;
+      }
+
+      if (mslabel) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' mslabel:' + mslabel);
+        insertAt++;
+      }
+
+      if (label) {
+        lines.splice(insertAt, 0, 'a=ssrc:' + ssrc_fid[i] + ' label:' + label);
+        insertAt++;
+      }
+    }
+
+    lines.splice(insertAt, 0, 'a=ssrc-group:FID ' + ssrc[2] + ' ' + ssrc_fid[2]);
+    lines.splice(insertAt, 0, 'a=ssrc-group:FID ' + ssrc[1] + ' ' + ssrc_fid[1]);
+    lines.splice(insertAt, 0, 'a=ssrc-group:FID ' + ssrc[0] + ' ' + ssrc_fid[0]);
+    lines.splice(insertAt, 0, 'a=ssrc-group:SIM ' + ssrc[0] + ' ' + ssrc[1] + ' ' + ssrc[2]);
+    sdp = lines.join("\r\n");
+    if (!sdp.endsWith("\r\n")) sdp += "\r\n";
+    return sdp;
+  } // Helper methods to parse a media object
+
+
+  function isAudioSendEnabled(media) {
+    Janus$1.debug("isAudioSendEnabled:", media);
+    if (media === undefined || media === null) return true; // Default
+
+    if (media.audio === false) return false; // Generic audio has precedence
+
+    if (media.audioSend === undefined || media.audioSend === null) return true; // Default
+
+    return media.audioSend === true;
+  }
+
+  function isAudioSendRequired(media) {
+    Janus$1.debug("isAudioSendRequired:", media);
+    if (media === undefined || media === null) return false; // Default
+
+    if (media.audio === false || media.audioSend === false) return false; // If we're not asking to capture audio, it's not required
+
+    if (media.failIfNoAudio === undefined || media.failIfNoAudio === null) return false; // Default
+
+    return media.failIfNoAudio === true;
+  }
+
+  function isAudioRecvEnabled(media) {
+    Janus$1.debug("isAudioRecvEnabled:", media);
+    if (media === undefined || media === null) return true; // Default
+
+    if (media.audio === false) return false; // Generic audio has precedence
+
+    if (media.audioRecv === undefined || media.audioRecv === null) return true; // Default
+
+    return media.audioRecv === true;
+  }
+
+  function isVideoSendEnabled(media) {
+    Janus$1.debug("isVideoSendEnabled:", media);
+    if (media === undefined || media === null) return true; // Default
+
+    if (media.video === false) return false; // Generic video has precedence
+
+    if (media.videoSend === undefined || media.videoSend === null) return true; // Default
+
+    return media.videoSend === true;
+  }
+
+  function isVideoSendRequired(media) {
+    Janus$1.debug("isVideoSendRequired:", media);
+    if (media === undefined || media === null) return false; // Default
+
+    if (media.video === false || media.videoSend === false) return false; // If we're not asking to capture video, it's not required
+
+    if (media.failIfNoVideo === undefined || media.failIfNoVideo === null) return false; // Default
+
+    return media.failIfNoVideo === true;
+  }
+
+  function isVideoRecvEnabled(media) {
+    Janus$1.debug("isVideoRecvEnabled:", media);
+    if (media === undefined || media === null) return true; // Default
+
+    if (media.video === false) return false; // Generic video has precedence
+
+    if (media.videoRecv === undefined || media.videoRecv === null) return true; // Default
+
+    return media.videoRecv === true;
+  }
+
+  function isScreenSendEnabled(media) {
+    Janus$1.debug("isScreenSendEnabled:", media);
+    if (media === undefined || media === null) return false;
+    if (_typeof(media.video) !== 'object' || _typeof(media.video.mandatory) !== 'object') return false;
+    var constraints = media.video.mandatory;
+    if (constraints.chromeMediaSource) return constraints.chromeMediaSource === 'desktop' || constraints.chromeMediaSource === 'screen';else if (constraints.mozMediaSource) return constraints.mozMediaSource === 'window' || constraints.mozMediaSource === 'screen';else if (constraints.mediaSource) return constraints.mediaSource === 'window' || constraints.mediaSource === 'screen';
+    return false;
+  }
+
+  function isDataEnabled(media) {
+    Janus$1.debug("isDataEnabled:", media);
+
+    if (Janus$1.webRTCAdapter.browserDetails.browser == "edge") {
+      Janus$1.warn("Edge doesn't support data channels yet");
+      return false;
+    }
+
+    if (media === undefined || media === null) return false; // Default
+
+    return media.data === true;
+  }
+
+  function isTrickleEnabled(trickle) {
+    Janus$1.debug("isTrickleEnabled:", trickle);
+    if (trickle === undefined || trickle === null) return true; // Default is true
+
+    return trickle === true;
+  }
+}
+window.Janus = Janus$1;
+
+// We make use of this 'server' variable to provide the address of the
+var janus = null;
+var tts = null;
+var opaqueId = "tts-" + Janus.randomString(12);
+var spinner = null;
+Janus = window.Janus; // Initialize the library (all console debuggers enabled)
+
+Janus.init({
+  debug: "all",
+  callback: function callback() {
+    window.stopTalk = function () {
+      janus.destroy();
+    }; // debugger;
+
+
+    window.startTalk = function () {
+      // Make sure the browser supports WebRTC
+      if (!Janus.isWebrtcSupported()) {
+        bootbox.alert("No WebRTC support... ");
+        return;
+      } // if($('#tts_url').val().length == 0){
+      // 	bootbox.alert("Please input tts url... ");
+      // 	return;
+      // }
+      // $(this).attr('disabled', true).unbind('click');
+      // Create session
+
+
+      janus = new Janus({
+        server: window.EZUIKit.opt.rtcUrl,
+        // No "iceServers" is provided, meaning janus.js will use a default STUN server
+        // Here are some examples of how an iceServers field may look like to support TURN
+        // 		iceServers: [{urls: "turn:yourturnserver.com:3478", username: "janususer", credential: "januspwd"}],
+        // 		iceServers: [{urls: "turn:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}],
+        // 		iceServers: [{urls: "turns:yourturnserver.com:443?transport=tcp", username: "janususer", credential: "januspwd"}],
+        // Should the Janus API require authentication, you can specify either the API secret or user token here too
+        //		token: "mytoken",
+        //	or
+        //		apisecret: "serversecret",
+        success: function success() {
+          // Attach to tts plugin
+          janus.attach({
+            plugin: "rtcgw.plugin.tts",
+            opaqueId: opaqueId,
+            success: function success(pluginHandle) {
+              // $('#details').remove();
+              tts = pluginHandle;
+              Janus.log("Plugin attached! (" + tts.getPlugin() + ", id=" + tts.getId() + ")"); // Negotiate WebRTC
+              //var url = "tts://61.130.6.23:8664/talk://D13781761:0:1:cas.ys7.com:6500?97fbd2a75fa94b7682c994d3d1fac8ca:ut.5porslgu79e9r7ca48z32k8abgl3rp58-77bhb6i7xr-1kmumtg-jkhy7pvfr:0:3"
+              //var url = "tts://10.86.15.209:8664/talk://D13781761:0:1:cas.ys7.com:6500?32db2578ba7c4a84be22ecc0bcd0f8db:ut.5lqpkhim5m7cdk2y5w60g7hm9vd7i3v0-3d2pwhxe2t-11wx2ge-sh4yazbll:0:3"
+              //var url = "tts://10.86.15.209:8664/talk://D13781761:0:1:cas.ys7.com:6500"
+              //test12.ys.com
+              //var url = "tts://10.86.15.209:8664/talk://D08197169:0:1:cas.ys7.com:6500"
+              //test10.ys.com
+              //var url = "tts://10.86.29.210:8664/talk://D08197169:0:1:cas.ys7.com:6500"
+
+              var url = window.EZUIKit.opt.talkLink;
+              console.log("ttsUlr", url);
+              var body = {
+                "request": "start",
+                "url": url,
+                "codec": "opus",
+                "dir": "sendrecv",
+                "audio_debug": 1
+              };
+
+              if (window.EZUIKit.opt.talkType === 'gb28181') {
+                body['devProto'] = 'gb28181';
+              } //tts.send({"message": body});
+
+
+              Janus.debug("Trying a createOffer too (audio/video sendrecv)");
+              tts.createOffer({
+                // No media provided: by default, it's sendrecv for audio and video
+                media: {
+                  audio: true,
+                  video: false,
+                  data: false
+                },
+                // Audio only
+                // If you want to test simulcasting (Chrome and Firefox only), then
+                // pass a ?simulcast=true when opening this demo page: it will turn
+                // the following 'simulcast' property to pass to janus.js to true
+                simulcast: false,
+                simulcast2: false,
+                success: function success(jsep) {
+                  Janus.debug("Got SDP!");
+                  Janus.debug(jsep);
+                  tts.send({
+                    "message": body,
+                    "jsep": jsep
+                  });
+
+                  if (typeof window.EZUIKit.handleTalkSuccess !== 'undefined') {
+                    window.EZUIKit.handleTalkSuccess();
+                  }
+                },
+                error: function error(_error) {
+                  Janus.error("WebRTC error:", _error); //	bootbox.alert("WebRTC error... " + JSON.stringify(error));
+
+                  if (typeof window.EZUIKit.handleTalkError !== 'undefined') {
+                    window.EZUIKit.handleTalkError(_error);
+                  }
+                }
+              }); // $('#start').removeAttr('disabled').html("Stop")
+              // 	.click(function() {
+              // 		$(this).attr('disabled', true);
+              // 		janus.destroy();
+              // 	});
+            },
+            error: function error(_error2) {
+              console.error("  -- Error attaching plugin...", _error2);
+              bootbox.alert("Error attaching plugin... " + _error2);
+
+              if (window.EZUIKit.handleTalkError !== 'undefined') {
+                window.EZUIKit.handleTalkError(_error2);
+              }
+            },
+            consentDialog: function consentDialog(on) {
+              Janus.debug("Consent dialog should be " + (on ? "on" : "off") + " now");
+            },
+            iceState: function iceState(state) {
+              Janus.log("ICE state changed to " + state);
+            },
+            mediaState: function mediaState(medium, on) {
+              Janus.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium);
+            },
+            webrtcState: function webrtcState(on) {
+              Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now"); // $("#audioleft").parent().unblock();
+            },
+            slowLink: function slowLink(uplink, lost) {
+              Janus.warn("Janus reports problems " + (uplink ? "sending" : "receiving") + " packets on this PeerConnection (" + lost + " lost packets)");
+            },
+            onmessage: function onmessage(msg, jsep) {
+              Janus.debug(" ::: Got a message :::");
+              Janus.debug(msg);
+
+              if (jsep !== undefined && jsep !== null) {
+                Janus.debug("Handling SDP as well...");
+                Janus.debug(jsep);
+                tts.handleRemoteJsep({
+                  jsep: jsep
+                });
+              }
+
+              var result = msg["result"];
+
+              if (result !== null && result !== undefined) {
+                if (result === "done") {
+                  // The plugin closed
+                  bootbox.alert("The TTS Test is over");
+                  if (spinner !== null && spinner !== undefined) spinner.stop();
+                  spinner = null; // $('#myaudio').remove();
+                  //$('#waitingvideo').remove();
+                  // $('#peeraudio').remove();
+
+                  return;
+                }
+
+                if (result === "msg") {
+                  if (typeof window.EZUIKit.handleTalkMessage !== 'undefined') {
+                    window.EZUIKit.handleTalkMessage(msg);
+                  }
+                } // Any loss?
+
+
+                var status = result["status"];
+
+                if (status === "slow_link") {
+                  //~ var bitrate = result["bitrate"];
+                  //~ toastr.warning("The bitrate has been cut to " + (bitrate/1000) + "kbps", "Packet loss?", {timeOut: 2000});
+                  toastr.warning("Janus apparently missed many packets we sent, maybe we should reduce the bitrate", "Packet loss?", {
+                    timeOut: 2000
+                  });
+                }
+              }
+            },
+            onlocalstream: function onlocalstream(stream) {
+              Janus.debug(" ::: Got a local stream :::");
+              Janus.debug(stream); // if($('#myaudio').length === 0) {
+              // 	$('#audios').removeClass('hide').show();
+              // 	$('#audioleft').append('<audio id="myaudio" autoplay controls muted>Your browser does not support audio tag</audio>');
+              // }
+
+              Janus.attachMediaStream(document.getElementById("myaudio"), stream); //$("#myaudio").get(0).muted = "muted";
+
+              if (tts.webrtcStuff.pc.iceConnectionState !== "completed" && tts.webrtcStuff.pc.iceConnectionState !== "connected") {
+                // $("#audioleft").parent().block({
+                // 	message: '<b>Publishing...</b>',
+                // 	css: {
+                // 		border: 'none',
+                // 		backgroundColor: 'transparent',
+                // 		color: 'white'
+                // 	}
+                // });
+                // No remote video yet
+                //$('#audioright').append('<video class="rounded centered" id="waitingvideo" width=320 height=240 />');
+                if (spinner == null) {
+                  document.getElementById('audioright'); //spinner = new Spinner({top:100}).spin(target);
+                } else {
+                  spinner.spin();
+                }
+              }
+
+              var audioTracks = stream.getAudioTracks();
+
+              if (audioTracks === null || audioTracks === undefined || audioTracks.length === 0) ;
+            },
+            onremotestream: function onremotestream(stream) {
+              Janus.debug(" ::: Got a remote stream :::");
+              Janus.debug(stream); // if($('#peeraudio').length === 0) {
+              // 	$('#audios').removeClass('hide').show();
+              // 	// $('#audioright').append('<audio id="peeraudio" autoplay controls>Your browser does not support audio tag</audio>');
+              // 	// Show the video, hide the spinner and show the resolution when we get a playing event
+              // 	var audio = $('<audio id="peeraudio" autoplay controls playsinline preload="preload" loop="true"></audio>');
+              // 	audio = audio.get(0);
+              // 	audio.setAttribute("id", 'peeraudio');
+              // 	audio.setAttribute("preload","preload");
+              // 	// 鑷姩鎾斁瑙e喅鑻规灉涓嶅吋瀹筧utoplay灞炴��
+              // 	audio.setAttribute("loop",true);
+              // 	$('#audioright').append(audio);
+              // 	$("#peeraudio").bind("playing", function () {
+              // 		//$('#waitingvideo').remove();
+              // 		$('#peeraudio').removeClass('hide').show();
+              // 		if(spinner !== null && spinner !== undefined)
+              // 			spinner.stop();
+              // 		spinner = null;
+              // 	});
+              // }
+
+              Janus.attachMediaStream(document.getElementById("peeraudio"), stream);
+              var audioTracks = stream.getAudioTracks();
+
+              if (audioTracks === null || audioTracks === undefined || audioTracks.length === 0) ; else {
+                //	$('#peeraudio').removeClass('hide').show();
+                document.getElementById('peeraudio').play();
+              }
+            },
+            ondataopen: function ondataopen(data) {
+              Janus.log("The DataChannel is available!");
+            },
+            ondata: function ondata(data) {
+              Janus.debug("We got data from the DataChannel! " + data);
+            },
+            oncleanup: function oncleanup() {
+              Janus.log(" ::: Got a cleanup notification :::");
+              if (spinner !== null && spinner !== undefined) spinner.stop();
+              spinner = null; // $('#myaudio').remove();
+              // //$('#waitingvideo').remove();
+              // $("#audioleft").parent().unblock();
+              // $('#peeraudio').remove();
+            }
+          });
+        },
+        error: function error(_error3) {
+          Janus.error(_error3);
+
+          if (window.EZUIKit.handleTalkError !== 'undefined') {
+            window.EZUIKit.handleTalkError(_error3);
+          }
+        },
+        destroyed: function destroyed() {// window.location.reload();
+        }
+      });
+    };
+  }
+});
+
+window.janus = janus;
+window.tts = tts;
+
+var Talk = /*#__PURE__*/function () {
+  function Talk(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, Talk);
+
+    this.jSPlugin = jSPlugin;
+    var audioLeft = document.createElement('div');
+    audioLeft.id = "audioleft";
+    var audioRight = document.createElement('div');
+    audioRight.id = "audioright";
+    audioRight.style = "display:none;";
+    var audioLeftDOM = document.createElement('audio');
+    audioLeftDOM.id = "myaudio";
+    audioLeftDOM.muted = true;
+    audioLeftDOM.setAttribute("autoplay", true);
+    audioLeftDOM.setAttribute("controls", true);
+    audioLeft.appendChild(audioLeftDOM);
+    audioLeft.style = "display:none;";
+    var audioRightDOM = document.createElement('audio');
+    audioRightDOM.id = "peeraudio";
+    audioRightDOM.setAttribute("autoplay", true);
+    audioRightDOM.setAttribute("controls", true);
+    audioRight.appendChild(audioRightDOM); // addJs(`${this.jSPlugin.staticPath}/talk/adapeter.js`, () => {
+    //   addJs(`${this.jSPlugin.staticPath}/talk/janus.js`, () => {
+    //     addJs(`${this.jSPlugin.staticPath}/talk/tts-v4.js`, () => {
+    // 涓存椂澶勭悊
+
+    window.EZUIKit["handleTalkError"] = function (err) {
+      console.log("talk err", err);
+
+      if (typeof _this.jSPlugin.handleTalkError !== 'undefined') {
+        _this.jSPlugin.handleTalkError(err);
+      }
+    };
+
+    window.EZUIKit["handleTalkSuccess"] = function (data) {
+      console.log("talk success", data);
+
+      if (typeof _this.jSPlugin.handleTalkSuccess !== 'undefined') {
+        _this.jSPlugin.handleTalkSuccess(data);
+      }
+    };
+
+    window.EZUIKit.opt = {
+      rtcUrl: "",
+      talkLink: "",
+      ttsUrl: "",
+      stream: "",
+      deviceSerial: matchEzopenUrl(this.jSPlugin.url).deviceSerial,
+      channelNo: matchEzopenUrl(this.jSPlugin.url).channelNo
+    };
+    document.body.appendChild(audioLeft);
+    document.body.appendChild(audioRight); //     });
+    //   });
+    // });
+  }
+
+  _createClass$1(Talk, [{
+    key: "toString",
+    value: function toString() {
+      return "".concat(this.coreX, "-").concat(this.coreY);
+    }
+  }, {
+    key: "startTalk",
+    value: function startTalk() {
+      var _this2 = this;
+
+      if (this.jSPlugin.capacity && this.jSPlugin.capacity.support_talk && !(this.jSPlugin.capacity && (this.jSPlugin.capacity.support_talk === '3' || this.jSPlugin.capacity.support_talk === '1'))) {
+        if (typeof this.jSPlugin.params.handleError === 'function') {
+          this.jSPlugin.params.handleError({
+            msg: "璁惧涓嶆敮鎸佸璁�",
+            retcode: -1000,
+            id: this.jSPlugin.params.id,
+            type: "handleError"
+          });
+        }
+        console.log("璁惧涓嶆敮鎸佸璁�");
+        return false;
+      }
+
+      var formData = new FormData();
+      formData.append("accessToken", this.jSPlugin.accessToken);
+      formData.append("deviceSerial", matchEzopenUrl(this.jSPlugin.url).deviceSerial);
+      formData.append("channelNo", matchEzopenUrl(this.jSPlugin.url).channelNo);
+      fetch(this.jSPlugin.env.domain + "/api/lapp/live/talk/url", {
+        method: "POST",
+        // headers: {
+        //   'Content-Type': 'application/json'
+        // },
+        body: formData
+      }).then(function (response) {
+        return response.json();
+      }).then(function (data) {
+        if (data.code == 200) {
+          var apiResult = data.data;
+
+          if (apiResult) {
+            // 涓存椂灏唄ttps杞崲涓簑ebsocket
+            var rtcTrunk = apiResult.rtcUrl;
+
+            if (rtcTrunk.indexOf("ws") === -1) {
+              rtcTrunk = rtcTrunk.replace("https", "wss").replace("rtcgw", "rtcgw-ws");
+            }
+
+            window.EZUIKit.opt.rtcUrl = rtcTrunk;
+            window.EZUIKit.opt.ttsUrl = "tts://" + apiResult.ttsUrl;
+            window.EZUIKit.opt.deviceSerial = matchEzopenUrl(_this2.jSPlugin.url).deviceSerial;
+            window.EZUIKit.opt.channelNo = matchEzopenUrl(_this2.jSPlugin.url).channelNo;
+            var urlList = window.EZUIKit.opt.ttsUrl.split("?");
+
+            if (urlList.length === 2) {
+              // 鍥芥爣璁惧
+              var talk = "talk?dev=" + window.EZUIKit.opt.deviceSerial + "&chann=" + window.EZUIKit.opt.channelNo + "&encodetype=2";
+              window.EZUIKit.opt.talkLink = window.EZUIKit.opt.ttsUrl.split("?")[0] + "/" + talk;
+              window.EZUIKit.opt.talkType = "gb28181";
+            } else {
+              // 鏅�氳澶�
+              var talk = "talk://" + window.EZUIKit.opt.deviceSerial + ":0:" + window.EZUIKit.opt.channelNo + ":cas.ys7.com:6500";
+              window.EZUIKit.opt.talkLink = window.EZUIKit.opt.ttsUrl.split("?")[0] + "/" + talk;
+            }
+
+            window.EZUIKit.opt.stream = apiResult.stream;
+            window.startTalk();
+          }
+        } else {
+          if (typeof _this2.jSPlugin.params.handleError === 'function') {
+            _this2.jSPlugin.params.handleError({
+              msg: data.msg,
+              retcode: data.code,
+              id: _this2.jSPlugin.params.id,
+              type: "handleError"
+            });
+          }
+        }
+      })["catch"](function (err) {
+        console.log("err", err);
+      });
+    }
+  }, {
+    key: "stopTalk",
+    value: function stopTalk() {
+      window.stopTalk();
+
+      if (document.getElementById("myaudio") && document.getElementById("myaudio").srcObject) {
+        document.getElementById("myaudio").srcObject.getTracks()[0].stop();
+      }
+    }
+  }]);
+
+  return Talk;
+}();
+
+var MobilePtz = /*#__PURE__*/function () {
+  function MobilePtz(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, MobilePtz);
+
+    this.jSPlugin = jSPlugin;
+    var oS = document.createElement('style');
+    oS.innerHTML = "\n    body{\n      padding: 0;\n      margin: 0;\n    }\n    #mobile-ez-ptz-container {\n      display: inline-block;\n      width: 375px;\n      text-align: center;\n    }\n    .live-ptz-title{\n      height: 25px;\n      font-size: 18px;\n      color: #2c2c2c;\n      text-align: center;\n      font-weight: 700;\n      margin: 24px 0 12px;\n    }\n    .live-ptz-intro {\n      margin-bottom: 24px;\n      color: #aaaaaa;\n    }\n    .mobile-ez-ptz-wrap {\n      background-image: linear-gradient(180deg, #f6f8ff 0%, #ededed6b 50%)\n    }\n    #mobile-ez-ptz-container .mobile-ez-ptz-container {\n      position: relative;\n      width: 260px;\n      height: 260px;\n      background: rgba(255, 255, 255, 0.80);\n      border: 1px solid rgba(255, 255, 255, 0.80);\n      border-radius: 100%;\n      cursor: pointer;\n      overflow: hidden;\n      margin: auto;\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.top {\n      width: 0;\n      height: 0;\n      border-left: 6px solid transparent;\n      border-right: 6px solid transparent;\n      border-bottom: 6px solid #aaaaaa;\n      position: absolute;\n      display: inline-block;\n      left: calc(50% - 6px);\n      top: 10px;\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.top.active {\n      border-bottom-color: #1890FF;\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.bottom {\n      width: 0;\n      height: 0;\n      border-left: 6px solid transparent;\n      border-right: 6px solid transparent;\n      border-top: 6px solid #aaaaaa;\n      position: absolute;\n      display: inline-block;\n      left: calc(50% - 6px);\n      bottom: 10px;\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.bottom.active {\n      border-top-color: #1890FF;\n\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.right {\n      width: 0;\n      height: 0;\n      border-top: 6px solid transparent;\n      border-bottom: 6px solid transparent;\n      border-left: 6px solid #aaaaaa;\n      position: absolute;\n      display: inline-block;\n      top: calc(50% - 6px);\n      right: 10px;\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.right.active {\n      border-left-color: #1890FF;\n\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.left {\n      width: 0;\n      height: 0;\n      border-top: 6px solid transparent;\n      border-bottom: 6px solid transparent;\n      border-right: 6px solid #aaaaaa;\n      position: absolute;\n      display: inline-block;\n      top: calc(50% - 6px);\n      left: 10px;\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .mobile-ez-ptz-icon.left.active {\n      border-right-color: #1890FF;\n\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-container .ez-ptz-main.center {\n      width: 52px;\n      height: 52px;\n      background: #FFFFFF;\n      border: 2px solid #eee;\n      border-radius: 100%;\n      top: calc(50% - 26px);\n      left: calc(50% - 26px);\n      position: absolute;\n      /* box-shadow: 0px -39px 40px 6px #1890ff; */\n    }\n\n    #mobile-ez-ptz-container .mobile-ez-ptz-wrap {\n      display: inline-block;\n      padding: 24px 24px;\n      border-radius: 100%;\n      overflow: hidden;\n    }\n\n    #mobile-ez-ptz-container .ez-ptz-close {\n      position: absolute;\n      color: #FFFFFF;\n      top: 0;\n      right: 0px;\n    }";
+    document.getElementsByTagName("head")[0].appendChild(oS);
+    var mobileContainer = document.createElement('div');
+    mobileContainer.className = "mobile-ez-ptz-container";
+    mobileContainer.id = "mobile-ez-ptz-container";
+    mobileContainer.style = "display:inline-block;width: ".concat(this.jSPlugin.width, "px;text-align:center;");
+    var mobileContainerTitle = document.createElement('div');
+    mobileContainerTitle.className = "live-ptz-title";
+    mobileContainerTitle.id = "live-ptz-title";
+    mobileContainerTitle.innerHTML = "浜戝彴鎺у埗";
+
+    if (!document.getElementById("live-ptz-title")) {
+      mobileContainer.appendChild(mobileContainerTitle);
+    }
+
+    var mobileContainerIntro = document.createElement('div');
+    mobileContainerIntro.className = "live-ptz-intro";
+    mobileContainerIntro.id = "live-ptz-intro";
+    mobileContainerIntro.innerHTML = "璇烽�氳繃鎿嶆帶浜戝彴鏉ヨ皟鏁存憚鍍忔満瑙嗚";
+
+    if (!document.getElementById("live-ptz-intro")) {
+      mobileContainer.appendChild(mobileContainerIntro);
+    }
+
+    var ptzWrap = document.createElement('div');
+    ptzWrap.id = "mobile-ez-ptz-item";
+    ptzWrap.className = "mobile-ez-ptz-wrap";
+    ptzWrap.innerHTML = "\n    <div class=\"mobile-ez-ptz-container\" id=\"mobile-ez-ptz-container\">\n      <div class=\"ez-ptz-main center\"></div>\n      <div class=\"mobile-ez-ptz-icon top default\"></div>\n      <div class=\"mobile-ez-ptz-icon left default\"></div>\n      <div class=\"mobile-ez-ptz-icon bottom default\"></div>\n      <div class=\"mobile-ez-ptz-icon right default\"></div>\n    </div>\n      ";
+
+    if (!document.getElementById("mobile-ez-ptz-item")) {
+      mobileContainer.appendChild(ptzWrap);
+    } //document.getElementById(jSPlugin.id).appendChild(mobileContainer);
+
+
+    insertAfter$1(mobileContainer, document.getElementById("".concat(this.jSPlugin.id, "-wrap"))); // 浜戝彴鎺у埗浜嬩欢缁戝畾
+    // 浜戝彴鎺у埗
+
+    document.getElementById("mobile-ez-ptz-item").ontouchstart = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜寮�濮�");
+
+      _this._handlePtzTouch(e, 'start');
+    };
+
+    document.getElementById("mobile-ez-ptz-item").ontouchend = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜缁撴潫", e);
+
+      _this._handlePtzTouch(e, 'stop');
+    }; // 浜戝彴鎺у埗
+
+
+    document.getElementById("mobile-ez-ptz-item").onmousedown = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜寮�濮�");
+
+      _this._handlePtzTouch(e, 'start');
+    };
+
+    document.getElementById("mobile-ez-ptz-item").onmouseup = function (e) {
+      e.preventDefault();
+      console.log("瑙︽懜缁撴潫", e);
+
+      _this._handlePtzTouch(e, 'stop');
+    };
+  }
+
+  _createClass$1(MobilePtz, [{
+    key: "show",
+    value: function show() {
+      document.getElementById("mobile-ez-ptz-item").style = "display: inline-block";
+    }
+  }, {
+    key: "hide",
+    value: function hide() {
+      document.getElementById("mobile-ez-ptz-item").style = "display: none";
+    }
+  }, {
+    key: "_handlePtzTouch",
+    value: function _handlePtzTouch(e, type) {
+      var container = document.getElementById('mobile-ez-ptz-item').getBoundingClientRect();
+      var containerCenterX = container.left + 130;
+      var containerCenterY = container.top + 130;
+      var eventX = e.x || e.changedTouches[0].clientX;
+      var eventY = e.y || e.changedTouches[0].clientY;
+      var left = eventX - containerCenterX;
+      var top = eventY - containerCenterY;
+      var direction = 0; //鎿嶄綔鍛戒护锛�0-涓婏紝1-涓嬶紝2-宸︼紝3鍙筹紝4-宸︿笂锛�5-宸︿笅锛�6-鍙充笂锛�7-鍙充笅锛�8-鏀惧ぇ锛�9-缂╁皬锛�10-杩戠劍璺濓紝11-杩滅劍璺�
+
+      var url = this.jSPlugin.env.domain + "/api/lapp/device/ptz/start"; // var nextPtzImg = ptzNormalImg;
+      // var nextPtzImgFailed = ptzNormalImg;
+      // 鍒よ鏂逛綅
+
+      if (Math.abs(left) > Math.abs(top)) {
+        if (left > 0) {
+          direction = 3;
+          document.getElementsByClassName("mobile-ez-ptz-icon")[3].className = document.getElementsByClassName("mobile-ez-ptz-icon")[3].className.replace("default", "active");
+        } else {
+          direction = 2;
+          document.getElementsByClassName("mobile-ez-ptz-icon")[1].className = document.getElementsByClassName("mobile-ez-ptz-icon")[1].className.replace("default", "active");
+        }
+      } else {
+        if (top > 0) {
+          direction = 1;
+          document.getElementsByClassName("mobile-ez-ptz-icon")[2].className = document.getElementsByClassName("mobile-ez-ptz-icon")[2].className.replace("default", "active");
+        } else {
+          direction = 0;
+          document.getElementsByClassName("mobile-ez-ptz-icon")[0].className = document.getElementsByClassName("mobile-ez-ptz-icon")[0].className.replace("default", "active");
+        }
+      }
+
+      document.getElementById("mobile-ez-ptz-item").style = "background-image:linear-gradient(".concat(direction === 0 ? 180 : direction === 1 ? 0 : direction === 2 ? 90 : 270, "deg, #c0ddf1 0%, rgba(100,143,252,0.00) 50%)");
+
+      if (type === 'stop') {
+        url = this.jSPlugin.env.domain + '/api/lapp/device/ptz/stop';
+        document.getElementById("mobile-ez-ptz-item").style = "";
+        document.getElementsByClassName("mobile-ez-ptz-icon")[3].className = document.getElementsByClassName("mobile-ez-ptz-icon")[3].className.replace("active", "default");
+        document.getElementsByClassName("mobile-ez-ptz-icon")[1].className = document.getElementsByClassName("mobile-ez-ptz-icon")[1].className.replace("active", "default");
+        document.getElementsByClassName("mobile-ez-ptz-icon")[2].className = document.getElementsByClassName("mobile-ez-ptz-icon")[2].className.replace("active", "default");
+        document.getElementsByClassName("mobile-ez-ptz-icon")[0].className = document.getElementsByClassName("mobile-ez-ptz-icon")[0].className.replace("active", "default");
+      }
+
+      var data = new FormData();
+      data.append("deviceSerial", matchEzopenUrl(this.jSPlugin.url).deviceSerial);
+      data.append("channelNo", matchEzopenUrl(this.jSPlugin.url).channelNo);
+      data.append("speed", 1);
+      data.append("direction", direction);
+      data.append("accessToken", this.jSPlugin.accessToken);
+      fetch(url, {
+        method: "POST",
+        body: data
+      }).then(function (response) {
+        return response.json();
+      }).then(function (rt) {
+        if (rt.code == 200) ; else {
+          //document.getElementById('ptz-img-container').childNodes[0].src = nextPtzImgFailed;
+          // layer.msg(data.msg);
+          if (rt.code == 60005 || rt.code == 60002 || rt.code == 60003 || rt.code == 60004) {
+            document.getElementById("mobile-ez-ptz-item").style = "background-image:linear-gradient(".concat(direction === 0 ? 180 : direction === 1 ? 0 : direction === 2 ? 90 : 270, "deg, #f45656 0%, rgba(100,143,252,0.00) 50%)");
+          }
+        }
+      })["catch"](function (err) {
+        console.log("浜戝彴璋冪敤寮傚父", err);
+      });
+    }
+  }]);
+
+  return MobilePtz;
+}();
+
+var retcode = 0;
+var msg = "鎴愬姛";
+var data$7 = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-0",
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-1",
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-2",
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-3",
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "rgb(0 0 0 / 0%)",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-0",
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-1",
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-2",
+				iconId: "sound",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-3",
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-4",
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-5",
+				iconId: "talk",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-6",
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-7",
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-footer-8",
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0,
+				themeId: "f7896c8942c9476fb439370dd974f1c0"
+			}
+		]
+	}
+};
+var emptyData = {
+	retcode: retcode,
+	msg: msg,
+	data: data$7
+};
+
+var data$6 = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "#00000080",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "sound",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "talk",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "zoom",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	}
+};
+var mobileLiveFullData = {
+	data: data$6
+};
+
+var data$5 = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "#00000080",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "sound",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "talk",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "zoom",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "speed",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	}
+};
+var mobileRecFullData = {
+	data: data$5
+};
+
+var data$4 = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-0",
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-1",
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-2",
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-3",
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "#00000080",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "sound",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "talk",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "zoom",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "speed",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	}
+};
+var pcLiveFullData = {
+	data: data$4
+};
+
+var data$3 = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-0",
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-1",
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-2",
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				btnKey: "c1cbc1d4e86d49a0981f54beea95280a-f7896c8942c9476fb439370dd974f1c0-header-3",
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "#00000080",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "talk",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "sound",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "zoom",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	}
+};
+var pcLiveSecurityData = {
+	data: data$3
+};
+
+var data$2 = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 0
+			},
+			{
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "sound",
+				part: "left",
+				defaultActive: 1,
+				isrender: 0
+			},
+			{
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "talk",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "zoom",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			}
+		]
+	}
+};
+var pcLiveSimpleData = {
+	data: data$2
+};
+
+var data$1 = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "#00000080",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "talk",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "sound",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "zoom",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	}
+};
+var pcLiveVoiceData = {
+	data: data$1
+};
+
+var data = {
+	header: {
+		color: "#FFFFFF",
+		backgroundColor: "#000000",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "deviceID",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "deviceName",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "cloudRec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "rec",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	},
+	footer: {
+		color: "#FFFFFF",
+		backgroundColor: "#00000080",
+		activeColor: "#1890FF",
+		btnList: [
+			{
+				iconId: "play",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "capturePicture",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "sound",
+				part: "left",
+				defaultActive: 1,
+				isrender: 1
+			},
+			{
+				iconId: "pantile",
+				part: "left",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "recordvideo",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "zoom",
+				part: "left",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "speed",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "hd",
+				part: "right",
+				defaultActive: 0,
+				isrender: 0
+			},
+			{
+				iconId: "webExpend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			},
+			{
+				iconId: "expend",
+				part: "right",
+				defaultActive: 0,
+				isrender: 1
+			}
+		]
+	}
+};
+var pcRecFullDataData = {
+	data: data
+};
+
+var officeTemplateList = [{
+  autoFocus: 5,
+  createTime: '2021-06-14T08:04:37.000Z',
+  themeId: 'pcLive',
+  themeIntro: 'PC鐩存挱鍏ㄩ噺鐗�',
+  themeName: 'PC鐩存挱鍏ㄩ噺鐗�',
+  themeType: 'webLive',
+  updateTime: '2021-06-14T08:04:37.000Z',
+  label: '瀹樻柟',
+  labelPic: "https://resource.eziot.com/group1/M00/00/8A/CtwQEmLr_DmANlElAAA-xyivSaw030.png",
+  poster: "https://resource.eziot.com/group1/M00/00/89/CtwQEmLl8r-AZU7wAAETKlvgerU237.png",
+  header: pcLiveFullData.data.header,
+  footer: pcLiveFullData.data.footer
+}, {
+  autoFocus: 5,
+  createTime: '2021-06-14T08:04:37.000Z',
+  themeId: 'security',
+  themeIntro: 'PC鐩存挱瀹夐槻鐗�',
+  themeName: 'PC鐩存挱瀹夐槻鐗�',
+  themeType: 'webLive',
+  updateTime: '2021-06-14T08:04:37.000Z',
+  label: '瀹樻柟',
+  labelPic: "https://resource.eziot.com/group1/M00/00/8A/CtwQEmLr_DmANlElAAA-xyivSaw030.png",
+  poster: "https://resource.eziot.com/group1/M00/00/89/CtwQEmLl8r-AZU7wAAETKlvgerU237.png",
+  header: pcLiveSecurityData.data.header,
+  footer: pcLiveSecurityData.data.footer
+}, {
+  autoFocus: 5,
+  createTime: '2021-06-14T08:04:37.000Z',
+  themeId: 'voice',
+  themeIntro: 'PC鐩存挱璇煶鐗�',
+  themeName: 'PC鐩存挱璇煶鐗�',
+  themeType: 'webLive',
+  updateTime: '2021-06-14T08:04:37.000Z',
+  label: '瀹樻柟',
+  labelPic: "https://resource.eziot.com/group1/M00/00/8A/CtwQEmLr_DmANlElAAA-xyivSaw030.png",
+  poster: "https://resource.eziot.com/group1/M00/00/89/CtwQEmLl8r-AZU7wAAETKlvgerU237.png",
+  header: pcLiveVoiceData.data.header,
+  footer: pcLiveVoiceData.data.footer
+}, {
+  autoFocus: 5,
+  createTime: '2021-06-14T08:04:37.000Z',
+  themeId: 'simple',
+  themeIntro: 'PC鐩存挱鏋佺畝鐗�',
+  themeName: 'PC鐩存挱鏋佺畝鐗�',
+  themeType: 'webLive',
+  updateTime: '2021-06-14T08:04:37.000Z',
+  label: '瀹樻柟',
+  labelPic: "https://resource.eziot.com/group1/M00/00/8A/CtwQEmLr_DmANlElAAA-xyivSaw030.png",
+  poster: "",
+  header: pcLiveSimpleData.data.header,
+  footer: pcLiveSimpleData.data.footer
+}, {
+  autoFocus: 5,
+  createTime: '2021-06-14T08:04:37.000Z',
+  themeId: 'pcRec',
+  themeIntro: 'PC鍥炴斁鍏ㄩ噺鐗�',
+  themeName: 'PC鍥炴斁鍏ㄩ噺鐗�',
+  themeType: 'webRec',
+  updateTime: '2021-06-14T08:04:37.000Z',
+  label: '瀹樻柟',
+  labelPic: "https://resource.eziot.com/group1/M00/00/8A/CtwQEmLr_DmANlElAAA-xyivSaw030.png",
+  poster: "https://resource.eziot.com/group1/M00/00/89/CtwQEmLl8r-AZU7wAAETKlvgerU237.png",
+  header: pcRecFullDataData.data.header,
+  footer: pcRecFullDataData.data.footer
+}, {
+  autoFocus: 5,
+  createTime: '2021-06-14T08:04:37.000Z',
+  themeId: 'mobileLive',
+  themeIntro: 'Mobile鐩存挱鍏ㄩ噺鐗�',
+  themeName: 'Mobile鐩存挱鍏ㄩ噺鐗�',
+  themeType: 'mobileLive',
+  updateTime: '2021-06-14T08:04:37.000Z',
+  label: '瀹樻柟',
+  labelPic: "https://resource.eziot.com/group1/M00/00/8A/CtwQEmLr_GmAL5IhAABZs1vUK0s564.png",
+  poster: "https://resource.eziot.com/group1/M00/00/89/CtwQEmLl8r-AZU7wAAETKlvgerU237.png",
+  header: mobileLiveFullData.data.header,
+  footer: mobileLiveFullData.data.footer
+}, {
+  autoFocus: 5,
+  createTime: '2021-06-14T08:04:37.000Z',
+  themeId: 'mobileRec',
+  themeIntro: 'Mobile鍥炴斁鍏ㄩ噺鐗�',
+  themeName: 'Mobile鍥炴斁鍏ㄩ噺鐗�',
+  themeType: 'mobileRec',
+  updateTime: '2021-06-14T08:04:37.000Z',
+  label: '瀹樻柟',
+  labelPic: "https://resource.eziot.com/group1/M00/00/8A/CtwQEmLr_GmAL5IhAABZs1vUK0s564.png",
+  poster: "https://resource.eziot.com/group1/M00/00/89/CtwQEmLl8r-AZU7wAAETKlvgerU237.png",
+  header: mobileRecFullData.data.header,
+  footer: mobileRecFullData.data.footer
+}];
+
+var Zoom = /*#__PURE__*/function () {
+  function Zoom(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, Zoom);
+
+    this.jSPlugin = jSPlugin;
+    this.enableZoom = false;
+    this.isMouseDown = false, this.videoWidth = 1920;
+    this.videoHeight = 1080;
+    this.currentScale = 1;
+    this.currentPosition = {
+      x: 0,
+      //鎿嶄綔鐐� -x
+      y: 0,
+      //
+      xPercent: 0.10,
+      // 鐧惧垎姣� -x
+      yPercent: 0.10,
+      // 鐧惧垎姣�
+      xCurrentVideo: 0,
+      // 褰撳墠鏀惧ぇ鍚庡彲瑙嗚棰戝乏涓婅璧风偣
+      yCurrentVideo: 0,
+      left: 0,
+      top: 0,
+      right: 1920,
+      bottom: 1080
+    };
+    this.DOM = document.getElementById(jSPlugin.id);
+    this.clientRect = document.getElementById(jSPlugin.id).getBoundingClientRect(); //audioControls-left
+
+    var scaleDOMContainer = document.createElement('div');
+    scaleDOMContainer.id = "".concat(jSPlugin.id, "-zoom-container");
+    scaleDOMContainer.style = "position: absolute;\n    display:none;\n    left: 12px;\n    bottom: 80px;";
+    var scaleDOMHTML = "\n    <div\n    style=\"display: inline-flex;flex-direction: column;width: 38px;height: 160px;background:rgba(0,0,0,0.60);border-radius: 8px;align-items: center;\">\n    <div id=\"".concat(this.jSPlugin.id, "-scale-value\" style=\"font-size: 12px;color:#FFFFFF;margin-top:10px;margin-bottom:4px;\">2.0X</div>\n    <div style=\"width: 24px;\" id=\"").concat(this.jSPlugin.id, "-addScale\">\n      <?xml version=\"1.0\" encoding=\"utf-8\"?>\n      <svg version=\"1.1\" fill=\"#FFFFFF\" id=\"\u56FE\u5C42_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n         viewBox=\"0 0 20 20\" style=\"enable-background:new 0 0 20 20;\" xml:space=\"preserve\">\n      <title>\u653E\u5927</title>\n      <g id=\"\u77E9\u5F62\">\n        <rect class=\"st0\" width=\"20\" height=\"20\" fill=\"none\"/>\n      </g>\n      <g id=\"\u5F62\u72B6\u7ED3\u5408\">\n        <path class=\"st1\" d=\"M10,3.8c3.5,0,6.2,2.8,6.2,6.2s-2.8,6.2-6.2,6.2S3.8,13.5,3.8,10S6.5,3.8,10,3.8z M10,5c-2.8,0-5,2.2-5,5\n          s2.2,5,5,5s5-2.2,5-5S12.8,5,10,5z\"/>\n      </g>\n      <g id=\"\u8DEF\u5F84-4\">\n        <path class=\"st2\" d=\"M12.5,10.7h-5c-0.3,0-0.6-0.3-0.6-0.6s0.3-0.6,0.6-0.6h5c0.3,0,0.6,0.3,0.6,0.6S12.8,10.7,12.5,10.7z\"/>\n      </g>\n      <g id=\"\u8DEF\u5F84-4\u5907\u4EFD\">\n        <path class=\"st2\" d=\"M10,13.2c-0.3,0-0.6-0.3-0.6-0.6v-5c0-0.3,0.3-0.6,0.6-0.6s0.6,0.3,0.6,0.6v5C10.6,12.9,10.3,13.2,10,13.2z\"/>\n      </g>\n      </svg>\n    </div>\n    <div style=\"\n    position: relative;\n    width: 1px;\n    height: 64px;\n    border: 1px solid rgba(255,255,255,0.75);\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: flex-end;\">\n    <div class=\"scale-body-line-dot\" id=\"").concat(this.jSPlugin.id, "-scale-body-line-dot\" style=\"width: 8px;\n      height: 8px;\n      background: #FFFFFF;\n      border-radius: 100%;\n      position: absolute;\n      border: 1.5px solid rgba(64,122,255,1);\"></div>\n      <div id=\"").concat(this.jSPlugin.id, "-line-dot\" style=\"width: 1px;\n      height: 0%;\n      background: #1890FF;\n      bottom: 0;\"></div>\n    </div>\n    <div style=\"width: 24px;margin-top: 6px;\" id=\"").concat(this.jSPlugin.id, "-subScale\">\n      <?xml version=\"1.0\" encoding=\"utf-8\"?>\n      <svg fill=\"#FFFFFF\" version=\"1.1\" id=\"\u56FE\u5C42_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n        viewBox=\"0 0 20 20\" style=\"enable-background:new 0 0 20 20;\" xml:space=\"preserve\">\n        <title>\u7F29\u5C0F</title>\n        <g id=\"\u77E9\u5F62\">\n          <rect class=\"st0\" width=\"20\" height=\"20\" fill=\"none\"/>\n        </g>\n        <g id=\"\u5F62\u72B6\u7ED3\u5408\">\n          <path class=\"st1\" d=\"M10,3.8c3.5,0,6.2,2.8,6.2,6.2s-2.8,6.2-6.2,6.2S3.8,13.5,3.8,10S6.5,3.8,10,3.8z M10,5c-2.8,0-5,2.2-5,5\n            s2.2,5,5,5s5-2.2,5-5S12.8,5,10,5z\"/>\n        </g>\n        <g id=\"\u8DEF\u5F84-4\">\n          <path class=\"st2\" d=\"M12.5,10.7h-5c-0.3,0-0.6-0.3-0.6-0.6s0.3-0.6,0.6-0.6h5c0.3,0,0.6,0.3,0.6,0.6S12.8,10.7,12.5,10.7z\"/>\n        </g>\n      </svg>\n    </div>\n  </div>\n    ");
+    scaleDOMContainer.innerHTML = scaleDOMHTML;
+    document.getElementById("".concat(jSPlugin.id, "-audioControls-left")).parentNode.appendChild(scaleDOMContainer);
+
+    document.getElementById("".concat(jSPlugin.id, "-addScale")).onclick = function () {
+      _this.addScale();
+    };
+
+    document.getElementById("".concat(jSPlugin.id, "-subScale")).onclick = function () {
+      _this.subScale();
+    }; // document.getElementById("video-container").addEventListener("mouseenter",(event)=> {
+    //   console.log("榧犳爣杩涘叆", event);
+    // });
+
+  }
+
+  _createClass$1(Zoom, [{
+    key: "onMouseDown",
+    value: function onMouseDown(event) {
+      this.currentPosition;
+          this.currentScale;
+      this.moveX = event.clientX;
+      this.moveY = event.clientY;
+      this.isMouseDown = true;
+    }
+  }, {
+    key: "onMouseUp",
+    value: function onMouseUp(event) {
+      var currentPosition = this.currentPosition;
+          this.enableZoom;
+      this.isMouseDown = false;
+      currentPosition.left = currentPosition.left - (event.clientX - this.moveX);
+      currentPosition.top = currentPosition.top - (event.clientY - this.moveY);
+      this.doScale();
+    }
+  }, {
+    key: "onMouseOut",
+    value: function onMouseOut(event) {
+      if (this.isMouseDown) {
+        console.log("榧犳爣鎸変笂", event);
+        this.isMouseDown = false;
+      }
+
+      this.isMouseDown = false;
+    }
+  }, {
+    key: "renderDot",
+    value: function renderDot() {
+      var currentScale = this.currentScale;
+      document.getElementById("".concat(this.jSPlugin.id, "-scale-value")).innerHTML = "".concat(currentScale, ".0X");
+      document.getElementById("".concat(this.jSPlugin.id, "-line-dot")).style.height = "".concat((currentScale - 1) / 7 * 100, "%");
+      document.getElementById("".concat(this.jSPlugin.id, "-scale-body-line-dot")).style.bottom = "calc(".concat((currentScale - 1) / 7 * 100, "% - 6px)");
+    }
+  }, {
+    key: "startZoom",
+    value: function startZoom() {
+      var _this2 = this;
+
+      var info = this.jSPlugin.jSPlugin._JSPlayM4_GetFrameInfo(0);
+
+      this.videoWidth = info.width;
+      this.videoHeight = info.height;
+      this.currentPosition.right = info.width;
+      this.currentPosition.bottom = info.height;
+      this.currentScale = 1;
+      document.getElementById("".concat(this.jSPlugin.id, "-zoom-container")).style.display = "block";
+
+      this.jSPlugin.jSPlugin._JSPlayM4_SetDisplayRegion(0, this.videoWidth, 0, this.videoHeight);
+
+      this.renderDot();
+      this.enableZoom = true;
+
+      if (document.getElementById("".concat(this.jSPlugin.id, "canvas_draw0"))) {
+        document.getElementById("".concat(this.jSPlugin.id, "canvas_draw0")).addEventListener("mousedown", function (event) {
+          return _this2.onMouseDown(event);
+        });
+        document.getElementById("".concat(this.jSPlugin.id, "canvas_draw0")).addEventListener("mouseup", function (event) {
+          return _this2.onMouseUp(event);
+        });
+        document.getElementById("".concat(this.jSPlugin.id, "canvas_draw0")).addEventListener("mouseout", function (event) {
+          return _this2.onMouseOut(event);
+        });
+      } else if (document.getElementById("".concat(this.jSPlugin.id, "-player"))) {
+        document.getElementById("".concat(this.jSPlugin.id, "-player")).addEventListener("mousedown", function (event) {
+          return _this2.onMouseDown(event);
+        });
+        document.getElementById("".concat(this.jSPlugin.id, "-player")).addEventListener("mouseup", function (event) {
+          return _this2.onMouseUp(event);
+        });
+        document.getElementById("".concat(this.jSPlugin.id, "-player")).addEventListener("mouseout", function (event) {
+          return _this2.onMouseOut(event);
+        });
+      }
+    }
+  }, {
+    key: "stopZoom",
+    value: function stopZoom() {
+      var _this3 = this;
+
+      this.currentScale = 1;
+
+      this.jSPlugin.jSPlugin._JSPlayM4_SetDisplayRegion(0, this.videoWidth, 0, this.videoHeight);
+
+      document.getElementById("".concat(this.jSPlugin.id, "-zoom-container")).style.display = "none";
+      this.renderDot();
+      this.enableZoom = false;
+      document.getElementById(this.jSPlugin.id).removeEventListener("mousedown", function (event) {
+        return _this3.onMouseDown(event);
+      });
+      document.getElementById(this.jSPlugin.id).removeEventListener("mouseup", function (event) {
+        return _this3.onMouseUp(event);
+      });
+      document.getElementById(this.jSPlugin.id).removeEventListener("mouseout", function (event) {
+        return _this3.onMouseOut(event);
+      });
+    } // scrollFunc(e) {
+    //   e = e || window.event;
+    //   if (e.wheelDelta) {  //鍒ゆ柇娴忚鍣↖E锛岃胺姝屾粦杞簨浠�               
+    //     if (e.wheelDelta > 0) { //褰撴粦杞悜涓婃粴鍔ㄦ椂  
+    //       this.isScrollOverVideo(e, 'up');
+    //     }
+    //     if (e.wheelDelta < 0) { //褰撴粦杞悜涓嬫粴鍔ㄦ椂  
+    //       this.isScrollOverVideo(e, 'down');
+    //     }
+    //   } else if (e.detail) {  //Firefox婊戣疆浜嬩欢  
+    //     if (e.detail > 0) { //褰撴粦杞悜涓嬫粴鍔ㄦ椂  
+    //       this.isScrollOverVideo(e, 'down');
+    //     }
+    //     if (e.detail < 0) { //褰撴粦杞悜涓婃粴鍔ㄦ椂  
+    //       this.isScrollOverVideo(e, 'up');
+    //     }
+    //   }
+    // }
+    // isScrollOverVideo(e, type) {
+    //   const { clientRect } = this;
+    //   if (e.clientX > clientRect.x && e.clientX < (clientRect.x + clientRect.width)) {
+    //     if (e.clientY > clientRect.y && e.clientY < (clientRect.y + clientRect.height)) {
+    //       if (type == 'up' && currentScale < 8) {
+    //         this.currentScale++;
+    //         console.log("褰撳墠鏀惧ぇ灏哄害", currentScale)
+    //         this.calCurrentPosition(e);
+    //       }
+    //       if (type == 'down' && currentScale > 1) {
+    //         this.currentScale--;
+    //         console.log("褰撳墠鏀惧ぇ灏哄害", currentScale)
+    //         this.calCurrentPosition(e);
+    //       }
+    //       return;
+    //     }
+    //   }
+    //   return false
+    // }
+
+  }, {
+    key: "doScale",
+    value: function doScale() {
+      console.log("鎵ц鏀惧ぇ");
+      var currentPosition = this.currentPosition,
+          currentScale = this.currentScale;
+      currentPosition.left = currentPosition.left + currentPosition.xPercent * (currentPosition.right - currentPosition.left) - 1 / 2 * (this.videoWidth / currentScale);
+
+      if (currentPosition.left < 0) {
+        currentPosition.left = 0;
+      } else if (currentPosition.left > this.videoWidth - this.videoWidth / currentScale) {
+        currentPosition.left = this.videoWidth - this.videoWidth / currentScale;
+      }
+
+      currentPosition.right = currentPosition.left + this.videoWidth / currentScale;
+      currentPosition.top = currentPosition.top + currentPosition.yPercent * (currentPosition.bottom - currentPosition.top) - 1 / 2 * (this.videoHeight / currentScale);
+
+      if (currentPosition.top < 0) {
+        currentPosition.top = 0;
+      } else if (currentPosition.top > this.videoHeight - this.videoHeight / currentScale) {
+        currentPosition.top = this.videoHeight - this.videoHeight / currentScale;
+      }
+
+      currentPosition.bottom = currentPosition.top + this.videoHeight / currentScale; //鏁存暟鍖�
+
+      currentPosition.left = parseInt(currentPosition.left, 10);
+      currentPosition.right = parseInt(currentPosition.right, 10);
+      currentPosition.top = parseInt(currentPosition.top, 10);
+      currentPosition.bottom = parseInt(currentPosition.bottom, 10);
+      console.log("璁$畻鍚庯紝", this.jSPlugin.jSPlugin, currentPosition.left, currentPosition.right, currentPosition.top, currentPosition.bottom, currentPosition.xPercent, currentPosition.yPercent);
+
+      this.jSPlugin.jSPlugin._JSPlayM4_SetDisplayRegion(currentPosition.left, currentPosition.right, currentPosition.top, currentPosition.bottom);
+
+      this.renderDot();
+    }
+  }, {
+    key: "calCurrentPosition",
+    value: function calCurrentPosition(e) {
+      var currentPosition = this.currentPosition,
+          clientRect = this.clientRect;
+      currentPosition.x = e.clientX;
+      currentPosition.y = e.clientY;
+      currentPosition.xPercent = (e.clientX - clientRect.x) / clientRect.width;
+      currentPosition.yPercent = (e.clientY - clientRect.y) / clientRect.height;
+      this.doScale();
+      return;
+    }
+  }, {
+    key: "addScale",
+    value: function addScale() {
+      var currentScale = this.currentScale,
+          currentPosition = this.currentPosition;
+
+      if (currentScale >= 8) {
+        console.log("杈惧埌鏈�澶у�嶇巼浜�");
+
+        if (this.jSPlugin.Message) {
+          this.jSPlugin.Message["default"]("宸茬粡鏀惧ぇ鍒版渶澶у�嶆暟8.0X");
+        }
+
+        return false;
+      }
+
+      this.currentScale++;
+      currentPosition.xPercent = 0.5;
+      currentPosition.yPercent = 0.5;
+      this.doScale();
+    }
+  }, {
+    key: "subScale",
+    value: function subScale() {
+      var currentScale = this.currentScale,
+          currentPosition = this.currentPosition;
+
+      if (currentScale <= 1) {
+        console.log("杈惧埌鏈�灏忓�嶇巼浜�");
+        return false;
+      }
+
+      this.currentScale--;
+      currentPosition.xPercent = 0.5;
+      currentPosition.yPercent = 0.5;
+      this.doScale();
+    }
+  }]);
+
+  return Zoom;
+}();
+
+function lineLength(point1, point2) {
+  return Math.abs(point2.clientX - point1.clientX) * Math.abs(point2.clientX - point1.clientX) + Math.abs(point2.clientY - point1.clientY) * Math.abs(point2.clientY - point1.clientY);
+}
+
+var MobileZoom = /*#__PURE__*/function () {
+  function MobileZoom(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, MobileZoom);
+
+    this.jSPlugin = jSPlugin;
+    this.enableZoom = false;
+    this.isDubboTouch = false, this.videoWidth = 0;
+    this.videoHeight = 0;
+    this.currentScale = 1;
+    this.currentPosition = {
+      x: 0,
+      //鎿嶄綔鐐� -x
+      y: 0,
+      //
+      xPercent: 0.10,
+      // 鐧惧垎姣� -x
+      yPercent: 0.10,
+      // 鐧惧垎姣�
+      xCurrentVideo: 0,
+      // 褰撳墠鏀惧ぇ鍚庡彲瑙嗚棰戝乏涓婅璧风偣
+      yCurrentVideo: 0,
+      left: 0,
+      top: 0,
+      right: 1920,
+      bottom: 1080
+    };
+    this.DOM = document.getElementById(jSPlugin.id);
+    this.clientRect = document.getElementById(jSPlugin.id).getBoundingClientRect();
+    this.point1 = {
+      clientX: 0,
+      clientY: 0
+    };
+    this.point2 = {
+      clientX: 0,
+      clientY: 0
+    };
+    this.touchLineLength = 0;
+    this.inited = false;
+    var scaleDOMContainer = document.createElement('div');
+    scaleDOMContainer.id = "".concat(jSPlugin.id, "-zoom-container");
+    scaleDOMContainer.style = "display:none;\n    position: absolute;\n    left: 10px;\n    top: -30px;\n    border: 1px solid rgba(0,0,0,0.6);\n    color: #FFFFFF;\n    background: rgba(0,0,0,0.6);\n    border-radius: 10px;\n    width: 36px;\n    font-size: 12px;\n    text-align: center;\n    height: 22px;\n    line-height: 22px;";
+    var scaleDOMHTML = "1X";
+    scaleDOMContainer.innerHTML = scaleDOMHTML;
+    document.getElementById("".concat(jSPlugin.id, "-audioControls-left")).parentNode.appendChild(scaleDOMContainer); // document.getElementById(this.jSPlugin.id).addEventListener("mousedown",(event)=>this.onMouseDown(event));
+    // document.getElementById(this.jSPlugin.id).addEventListener("mouseup",(event)=>this.onMouseUp(event));
+    // document.getElementById(this.jSPlugin.id).addEventListener("mouseout",(event)=>this.onMouseOut(event));
+
+    document.getElementById(this.jSPlugin.id).addEventListener("touchstart", function (event) {
+      return _this.onTouchstart(event);
+    });
+    document.getElementById(this.jSPlugin.id).addEventListener("touchmove", function (event) {
+      return _this.onTouchmove(event);
+    }); // var info = jSPlugin.jSPlugin._JSPlayM4_GetFrameInfo(0);
+    // this.videoWidth = info.width;
+    // this.videoHeight = info.height;
+    // this.currentPosition.right = info.width;
+    // this.currentPosition.bottom = info.height;
+  }
+
+  _createClass$1(MobileZoom, [{
+    key: "onTouchstart",
+    value: function onTouchstart(event) {
+      if (!this.inited) {
+        var info = this.jSPlugin.jSPlugin._JSPlayM4_GetFrameInfo(0);
+
+        this.videoWidth = info.width;
+        this.videoHeight = info.height;
+        this.currentPosition.right = info.width;
+        this.currentPosition.bottom = info.height;
+        this.inited = true;
+      }
+
+      var currentPosition = this.currentPosition;
+          this.currentScale;
+      console.log("鍙屾寚鎸変笅", currentPosition);
+      var touches = event.touches;
+      var events = touches[0];
+      var events2 = touches[1];
+
+      if (events) {
+        this.point1.clientX = events.clientX;
+        this.point1.clientY = events.clientY;
+      }
+
+      if (events2) {
+        this.point2.clientX = events2.clientX;
+        this.point2.clientY = events2.clientY;
+        this.touchLineLength = lineLength(this.point1, this.point2);
+        this.isDubboTouch = true;
+        this.moveX = events.clientX;
+        this.moveY = events.clientY;
+      }
+
+      console.log("鍙屾寚鎸変笅2", currentPosition);
+    }
+  }, {
+    key: "onTouchmove",
+    value: function onTouchmove(event) {
+      var isDubboTouch = this.isDubboTouch,
+          currentPosition = this.currentPosition,
+          clientRect = this.clientRect; // console.log("event.touches.lenght",event.touches.length);
+
+      if (event.touches.length === 1) {
+        var events = event.touches[0]; //console.log("currentPosition.xPercent",event.touches)
+
+        currentPosition.xPercent = currentPosition.xPercent + (this.point1.clientX - events.clientX) / clientRect.width / this.currentScale;
+        currentPosition.yPercent = currentPosition.yPercent + (this.point1.clientY - events.clientY) / clientRect.height / this.currentScale;
+        this.doScale();
+        this.point1.clientX = events.clientX;
+        this.point1.clientY = events.clientY;
+        return false;
+      }
+
+      if (!isDubboTouch) {
+        return false;
+      }
+
+      var touches = event.touches;
+      var events = touches[0];
+      var events2 = touches[1];
+
+      if (events) {
+        this.point1.clientX = events.clientX;
+        this.point1.clientY = events.clientY;
+      }
+
+      if (events2) {
+        this.point2.clientX = events2.clientX;
+        this.point2.clientY = events2.clientY;
+        var newtTouchLineLength = lineLength(this.point1, this.point2);
+
+        if (newtTouchLineLength !== this.touchLineLength) {
+          if (newtTouchLineLength > this.touchLineLength) {
+            if (this.currentScale < 8) {
+              ++this.currentScale;
+              currentPosition.xPercent = (this.point1.clientX + this.point2.clientX) / 2 / clientRect.width;
+              currentPosition.yPercent = (this.point1.clientY + this.point2.clientY) / 2 / clientRect.height;
+              this.doScale();
+            } else {
+              console.log("宸茬粡鏄渶澶�8鍊嶇巼浜�");
+            }
+          } else {
+            if (this.currentScale > 1) {
+              --this.currentScale;
+              currentPosition.xPercent = (this.point1.clientX + this.point2.clientX) / 2 / clientRect.width;
+              currentPosition.yPercent = (this.point1.clientY + this.point2.clientY) / 2 / clientRect.height;
+              this.doScale();
+            } else {
+              console.log("宸茬粡鏄渶灏�1鍊嶇巼浜�");
+            }
+          }
+
+          this.isDubboTouch = false;
+        }
+      }
+    }
+  }, {
+    key: "startZoom",
+    value: function startZoom() {
+      var info = this.jSPlugin.jSPlugin._JSPlayM4_GetFrameInfo(0);
+
+      this.videoWidth = info.width;
+      this.videoHeight = info.height;
+      this.currentPosition.right = info.width;
+      this.currentPosition.bottom = info.height;
+      this.currentScale = 1;
+      document.getElementById("".concat(this.jSPlugin.id, "-zoom-container")).style.display = "block";
+
+      this.jSPlugin.jSPlugin._JSPlayM4_SetDisplayRegion(0, this.videoWidth, 0, this.videoHeight);
+
+      this.renderDot();
+    }
+  }, {
+    key: "stopZoom",
+    value: function stopZoom() {
+      this.currentScale = 1;
+
+      this.jSPlugin.jSPlugin._JSPlayM4_SetDisplayRegion(0, this.videoWidth, 0, this.videoHeight);
+
+      document.getElementById("".concat(this.jSPlugin.id, "-zoom-container")).style.display = "none";
+      this.renderDot();
+    }
+  }, {
+    key: "doScale",
+    value: function doScale() {
+      var currentPosition = this.currentPosition,
+          currentScale = this.currentScale;
+      currentPosition.left = currentPosition.left + currentPosition.xPercent * (currentPosition.right - currentPosition.left) - 1 / 2 * (this.videoWidth / currentScale);
+
+      if (currentPosition.left < 0) {
+        currentPosition.left = 0;
+      } else if (currentPosition.left > this.videoWidth - this.videoWidth / currentScale) {
+        currentPosition.left = this.videoWidth - this.videoWidth / currentScale;
+      }
+
+      currentPosition.right = currentPosition.left + this.videoWidth / currentScale;
+      currentPosition.top = currentPosition.top + currentPosition.yPercent * (currentPosition.bottom - currentPosition.top) - 1 / 2 * (this.videoHeight / currentScale);
+
+      if (currentPosition.top < 0) {
+        currentPosition.top = 0;
+      } else if (currentPosition.top > this.videoHeight - this.videoHeight / currentScale) {
+        currentPosition.top = this.videoHeight - this.videoHeight / currentScale;
+      }
+
+      currentPosition.bottom = currentPosition.top + this.videoHeight / currentScale; //鏁存暟鍖�
+
+      currentPosition.left = parseInt(currentPosition.left, 10);
+      currentPosition.right = parseInt(currentPosition.right, 10);
+      currentPosition.top = parseInt(currentPosition.top, 10);
+      currentPosition.bottom = parseInt(currentPosition.bottom, 10);
+      console.log("瑙嗛瀹介珮", this.videoWidth, this.videoHeight);
+      console.log("璁$畻鍚庯紝", currentPosition.left, currentPosition.right, currentPosition.top, currentPosition.bottom, currentPosition.xPercent, currentPosition.yPercent); // 娉ㄦ剰锛屽拰PC
+
+      if (currentPosition.left < currentPosition.right && currentPosition.top < currentPosition.bottom && currentPosition.bottom <= this.videoHeight && currentPosition.right <= this.videoWidth) {
+        this.jSPlugin.jSPlugin._JSPlayM4_SetDisplayRegion(currentPosition.left, currentPosition.right, currentPosition.top, currentPosition.bottom);
+      }
+
+      document.getElementById("".concat(this.jSPlugin.id, "-zoom-container")).innerHTML = "".concat(currentScale, ".0X");
+      document.getElementById("".concat(this.jSPlugin.id, "-zoom-container")).style.display = currentScale === 1 ? "none" : "inline-block";
+    }
+  }, {
+    key: "calCurrentPosition",
+    value: function calCurrentPosition(e) {
+      var currentPosition = this.currentPosition,
+          clientRect = this.clientRect;
+      currentPosition.x = e.clientX;
+      currentPosition.y = e.clientY;
+      currentPosition.xPercent = (e.clientX - clientRect.x) / clientRect.width;
+      currentPosition.yPercent = (e.clientY - clientRect.y) / clientRect.height;
+      this.doScale();
+      return;
+    }
+  }]);
+
+  return MobileZoom;
+}();
+
+var styleToString = function styleToString(obj) {
+  var styleString = "";
+  Object.keys(obj).map(function (item, index) {
+    styleString += "".concat(item, ":").concat(obj[item]).concat(index < Object.keys(obj).length - 1 ? ';' : "");
+  });
+  return styleString;
+};
+
+var MEDIAWIDTH = 500;
+var Theme = /*#__PURE__*/function () {
+  function Theme(jSPlugin) {
+    var _this = this;
+
+    _classCallCheck$1(this, Theme);
+
+    this.jSPlugin = jSPlugin;
+    this.isNeedRenderHeader = false;
+    this.isNeedRenderFooter = false;
+    this.autoFocus = 0, this.autoFocusTimer = null, this.recordTimer = null;
+    this.nextRate = 1;
+    this.showHD = false;
+    this.decoderState = {
+      state: {
+        isEditing: false,
+        play: false,
+        sound: false,
+        recordvideo: false,
+        recordCount: "00:00",
+        talk: false,
+        zoom: false,
+        pantile: false,
+        hd: false,
+        speed: false,
+        expend: false,
+        webExpend: false,
+        cloudRec: matchEzopenUrl(jSPlugin.url).type === 'cloud.rec',
+        rec: matchEzopenUrl(jSPlugin.url).type === 'rec',
+        type: matchEzopenUrl(jSPlugin.url).type
+      }
+    };
+    console.log(" matchEzopenUrl(jSPlugin.url)", matchEzopenUrl(jSPlugin.url), this.decoderState.state);
+    this.inited = false;
+    this.isMobile = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+
+    if (typeof jSPlugin.isMobile !== 'undefined') {
+      this.isMobile = jSPlugin.isMobile;
+    } // 榛樿涓婚 - 鎸夐挳鍏ㄩ儴灞曠ず
+
+
+    this.themeData = emptyData.data; // 鑷�傚簲涓婚鏁版嵁
+
+    /*
+     绉诲姩绔� & 鐩存挱 =銆� mobileLive
+     绉诲姩绔� & 鍥炴斁鍦板潃 => mobileRec
+     PC绔� & 鐩存挱 =銆� pcLive
+     PC绔� & 鍥炴斁鍦板潃 => pcRec
+    */
+
+    if (this.jSPlugin.themeId) {
+      switch (this.jSPlugin.themeId) {
+        case 'pcLive':
+        case 'pcRec':
+        case 'mobileLive':
+        case 'mobileRec':
+        case 'security':
+        case 'voice':
+        case 'simple':
+          var ezuikitTemplateDetail = lodash.find(officeTemplateList, function (item) {
+            return item.themeId === _this.jSPlugin.themeId;
+          });
+
+          if (ezuikitTemplateDetail) {
+            this.themeData = ezuikitTemplateDetail;
+          }
+
+          this.initThemeData();
+          this.renderThemeData();
+          break;
+
+        case 'themeData':
+          this.themeData = this.jSPlugin.params.themeData;
+          this.initThemeData();
+          this.renderThemeData();
+          break;
+
+        default:
+          this.fetchThemeData(this.jSPlugin.themeId);
+          break;
+      }
+    }
+
+    if (!this.jSPlugin.Talk) {
+      this.jSPlugin.Talk = new Talk(this.jSPlugin);
+    }
+
+    addCss("".concat(this.jSPlugin.staticPath, "/speed/speed.css"));
+    addCss("".concat(this.jSPlugin.staticPath, "/css/theme.css"));
+  }
+
+  _createClass$1(Theme, [{
+    key: "fetchThemeData",
+    value: function fetchThemeData(themeId) {
+      var _this2 = this;
+
+      var url = "".concat(this.jSPlugin.env.domain, "/console/jssdk/ezopen/template/getDetail?accessToken=").concat(this.jSPlugin.accessToken, "&id=").concat(themeId);
+
+      if (window.location.hostname === "test11open.ys7.com" || window.location.hostname === "127.0.0.1" || window.location.hostname === "jianboyu.top") {
+        url = url.replace("test12open.ys7.com/console/jssdk", "test11open.ys7.com/console/jssdk");
+      }
+
+      fetch(url, {
+        method: 'GET'
+      }).then(function (response) {
+        return response.json();
+      }).then(function (data) {
+        console.log("get theme data", data);
+
+        if (data.meta.code === 0 && data.data) {
+          _this2.themeData = data.data;
+
+          if (data.data.header) {
+            _this2.themeData.header = data.data.header;
+            _this2.themeData.header.btnList = _this2.themeData.header.btnList.sort(function (a, b) {
+              return a.btnKey.split("-")[3] - b.btnKey.split("-")[3];
+            });
+          }
+
+          if (data.data.footer) {
+            _this2.themeData.footer = data.data.footer;
+            _this2.themeData.footer.btnList = _this2.themeData.footer.btnList.sort(function (a, b) {
+              return a.btnKey.split("-")[3] - b.btnKey.split("-")[3];
+            });
+          }
+
+          _this2.initThemeData();
+
+          _this2.renderThemeData();
+        }
+      })["catch"](function (error) {
+        _this2.renderThemeData();
+      });
+    }
+  }, {
+    key: "changeTheme",
+    value: function changeTheme(options) {
+      var _this3 = this;
+
+      if (typeof options === 'string') {
+        this.jSPlugin.themeId = options;
+
+        switch (this.jSPlugin.themeId) {
+          case 'pcLive':
+          case 'pcRec':
+          case 'mobileLive':
+          case 'mobileRec':
+          case 'security':
+          case 'voice':
+          case 'simple':
+            var ezuikitTemplateDetail = lodash.find(officeTemplateList, function (item) {
+              return item.themeId === _this3.jSPlugin.themeId;
+            });
+
+            if (ezuikitTemplateDetail) {
+              this.themeData = ezuikitTemplateDetail;
+            }
+
+            this.initThemeData();
+            this.renderThemeData();
+            break;
+
+          default:
+            this.fetchThemeData(options);
+            break;
+        }
+      } else if (_typeof(options) === 'object') {
+        this.themeData = options;
+        this.initThemeData();
+        this.renderThemeData();
+
+        if (this.decoderState.state.isEditing) {
+          this.editStart();
+        }
+      }
+
+      if (this.jSPlugin && this.jSPlugin.handleThemeChange) {
+        this.jSPlugin.handleThemeChange(options);
+      }
+    }
+  }, {
+    key: "renderThemeData",
+    value: function renderThemeData() {
+      var _this4 = this;
+
+      var _this$themeData = this.themeData,
+          header = _this$themeData.header,
+          footer = _this$themeData.footer;
+
+      if (this.isNeedRenderHeader && header) {
+        document.getElementById("".concat(this.jSPlugin.id, "-headControl")).style.background = header.backgroundColor.replace("-diy", "");
+        document.getElementById("".concat(this.jSPlugin.id, "-headControl")).style.color = header.color.replace("-diy", "");
+        header.btnList.map(function (item, index) {
+          if (item.isrender) {
+            _this4.setDecoderState(_defineProperty({}, item.iconId, _this4.decoderState.state[item.iconId]));
+          }
+        });
+      }
+
+      if (this.isNeedRenderFooter && footer) {
+        document.getElementById("".concat(this.jSPlugin.id, "-audioControls")).style.background = footer.backgroundColor.replace("-diy", "");
+        document.getElementById("".concat(this.jSPlugin.id, "-audioControls")).style.color = footer.color.replace("-diy", "");
+        footer.btnList.map(function (item, index) {
+          if (item.isrender) {
+            _this4.setDecoderState(_defineProperty({}, item.iconId, _this4.decoderState.state[item.iconId]));
+          }
+
+          if (item.iconId === "play" && item.defaultActive) {
+            var checkTimer = setInterval(function () {
+              if (window.EZUIKit[_this4.jSPlugin.id].state.EZUIKitPlayer.init) {
+                clearInterval(checkTimer);
+
+                _this4.jSPlugin.play();
+              }
+            }, 50);
+          }
+        }); // 鍒ゆ柇鏍囨竻楂樻竻
+
+        if (this.jSPlugin.url.indexOf("hd.live") !== -1) {
+          this.setDecoderState({
+            hd: true
+          });
+        } // 鍒ゆ柇鏄惁鑷姩闅愯棌鎺т欢
+
+
+        if (this.themeData.autoFocus > 0) {
+          this.autoFocus = parseInt(this.themeData.autoFocus);
+          this.startAutoFocus();
+          document.getElementById("".concat(this.jSPlugin.id, "-wrap")).addEventListener("click", function () {
+            _this4.stopAutoFocus();
+          }); // document.getElementById(`${this.jSPlugin.id}-wrap`).addEventListener("mouseout", ()=>{
+          //   console.log("寮�鍚嚜鍔ㄩ殣钘�")
+          //   this.startAutoFocus();
+          // })
+        }
+      } else {
+        var _checkTimer = setInterval(function () {
+          if (window.EZUIKit[_this4.jSPlugin.id].state.EZUIKitPlayer.init) {
+            clearInterval(_checkTimer);
+
+            _this4.jSPlugin.play();
+          }
+        }, 50);
+      }
+
+      var isNeedRoom = lodash.findIndex(this.themeData.footer.btnList, function (v) {
+        return v.iconId === 'zoom' && v.isrender > 0;
+      }) >= 0;
+
+      if (isNeedRoom) {
+        if (this.isMobile) {
+          this.jSPlugin.Zoom = new MobileZoom(this.jSPlugin);
+        } else {
+          this.jSPlugin.Zoom = new Zoom(this.jSPlugin);
+        }
+      }
+
+      var checkTimer = setInterval(function () {
+        if (window.EZUIKit[_this4.jSPlugin.id].state.EZUIKitPlayer.init) {
+          clearInterval(checkTimer); // 鎵ц涓�娆eSize
+
+          _this4.jSPlugin.reSize(_this4.jSPlugin.params.width, _this4.jSPlugin.params.height);
+        }
+      }, 50);
+    }
+  }, {
+    key: "setDecoderState",
+    value: function setDecoderState(options) {
+      var _this5 = this;
+
+      var _this$themeData2 = this.themeData,
+          header = _this$themeData2.header,
+          footer = _this$themeData2.footer;
+      Object.keys(options).map(function (item, index) {
+        var color = "#FFFFFF";
+        var activeColor = "#FFFFFF";
+
+        var _index = header.btnList.findIndex(function (i) {
+          return i.iconId === item;
+        });
+
+        if (_index === -1) {
+          color = footer.color.replace("-diy", "");
+          activeColor = footer.activeColor.replace("-diy", "");
+        } else {
+          color = header.color.replace("-diy", ""); // 鎸夐挳鐩稿叧鐨勬縺娲婚鑹茬粺涓�浣跨敤搴曢儴鐨�
+
+          activeColor = footer.activeColor.replace("-diy", "");
+        }
+
+        switch (item) {
+          case 'play':
+            if (options[item]) {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-play"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play-content")).children[0].children[0].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play-content")).children[0].children[1].style = "display:none";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play")).className = options[item] ? 'active' : '';
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play-content")).childNodes[0].children[0].style.fill = options[item] ? activeColor : color;
+              }
+            } else {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-play"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play-content")).children[0].children[1].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play-content")).children[0].children[0].style = "display:none";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play")).className = options[item] ? 'active' : '';
+                document.getElementById("".concat(_this5.jSPlugin.id, "-play-content")).childNodes[0].children[1].style.fill = options[item] ? activeColor : color;
+              }
+            }
+
+            break;
+
+          case 'sound':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-sound"))) {
+              if (options[item]) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound-content")).children[0].children[1].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound-content")).children[0].children[0].style = "display:none";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound")).className = options[item] ? 'active' : '';
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound-content")).childNodes[0].children[1].style.fill = options[item] ? activeColor : color;
+              } else {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound-content")).children[0].children[0].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound-content")).children[0].children[1].style = "display:none";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound")).className = options[item] ? 'active' : '';
+                document.getElementById("".concat(_this5.jSPlugin.id, "-sound-content")).childNodes[0].children[0].style.fill = options[item] ? activeColor : color;
+              }
+            }
+
+            break;
+
+          case 'recordvideo':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-recordvideo"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-recordvideo")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-recordvideo-content")).childNodes[0].style.fill = options[item] ? activeColor : color; // 瀹氭椂鍣ㄥ鐞�
+
+              if (options[item]) {
+                _this5.countTime('add', 0); // this.recordTimer = setInterval(() => {
+                // }, 1000);
+
+              } else {
+                _this5.countTime('destroy', 0); // clearInterval(this.recordTimer);
+
+              }
+            }
+
+            break;
+
+          case 'talk':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-talk"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-talk")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-talk-content")).childNodes[1].style.fill = options[item] ? activeColor : color;
+            }
+
+            break;
+
+          case 'zoom':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-zoom"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-zoom")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-zoom-content")).childNodes[1].style.fill = options[item] ? activeColor : color;
+            }
+
+            break;
+
+          case 'pantile':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-pantile"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-pantile")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-pantile-content")).childNodes[0].style.fill = options[item] ? activeColor : color;
+            }
+
+            break;
+
+          case 'webExpend':
+            if (options[item]) {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend-content")).children[0].children[1].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend-content")).children[0].children[0].style = "display:none";
+              } // 鍏ㄥ睆缃伆
+
+
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-expend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-expend")).className = "disabled";
+              }
+            } else {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend-content")).children[0].children[0].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend-content")).children[0].children[1].style = "display:none";
+              } // 鍏ㄥ睆缃伆
+
+
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-expend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-expend")).className = "";
+              }
+            }
+
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend-content")).childNodes[0].childNodes[0].style.fill = options[item] ? activeColor : color;
+              document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend-content")).childNodes[0].childNodes[1].style.fill = options[item] ? activeColor : color;
+            }
+
+            break;
+
+          case 'capturePicture':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-capturePicture"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-capturePicture")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-capturePicture-content")).childNodes[0].style.fill = options[item] ? activeColor : color;
+            }
+
+            break;
+
+          case 'expend':
+            if (options[item]) {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-expend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-expend-content")).children[0].children[1].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-expend-content")).children[0].children[0].style = "display:none";
+              } // 缃戠珯鍏ㄥ睆缃伆
+
+
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend")).className = "disabled";
+              }
+            } else {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-expend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-expend-content")).children[0].children[0].style = "display:inline-block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-expend-content")).children[0].children[1].style = "display:none";
+              } // 缃戠珯鍏ㄥ睆缃伆
+
+
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-webExpend")).className = "";
+              }
+            }
+
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-expend"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-expend")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-expend-content")).childNodes[0].childNodes[0].style.fill = options[item] ? activeColor : color;
+              document.getElementById("".concat(_this5.jSPlugin.id, "-expend-content")).childNodes[0].childNodes[1].style.fill = options[item] ? activeColor : color;
+            }
+
+            break;
+
+          case 'hd':
+            if (options[item]) {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-hd"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-hd-content")).children[1].children[0].style = "display:block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-hd-content")).children[1].children[1].style = "display:none";
+              }
+            } else {
+              if (document.getElementById("".concat(_this5.jSPlugin.id, "-hd"))) {
+                document.getElementById("".concat(_this5.jSPlugin.id, "-hd-content")).children[1].children[1].style = "display:block";
+                document.getElementById("".concat(_this5.jSPlugin.id, "-hd-content")).children[1].children[0].style = "display:none";
+              }
+            }
+
+            break;
+
+          case 'speed':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-speed"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-speed-content")).children[1].children[0].style.color = options[item] ? activeColor : color;
+              document.getElementById("".concat(_this5.jSPlugin.id, "-speed-content")).children[1].children[0].style.borderColor = options[item] ? activeColor : color;
+            }
+
+            if (_this5.isMobile && options[item]) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-select-mask")).style.display = "block";
+            } else {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-select-mask")).style.display = "none";
+            }
+
+            break;
+
+          case 'cloudRec':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-cloudRec"))) {
+              console.log("document.getElementById(`${this.jSPlugin.id}-cloudRec-content`)", document.getElementById("".concat(_this5.jSPlugin.id, "-cloudRec")));
+              document.getElementById("".concat(_this5.jSPlugin.id, "-cloudRec")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-cloudRec-content")).children[0].children[0].style.fill = options[item] ? activeColor : color;
+            }
+
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-rec"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-rec")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-rec-content")).children[0].children[0].style.fill = options[item] ? color : activeColor;
+            }
+
+            break;
+
+          case 'rec':
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-cloudRec"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-cloudRec")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-cloudRec-content")).children[0].children[0].style.fill = options[item] ? color : activeColor;
+            }
+
+            if (document.getElementById("".concat(_this5.jSPlugin.id, "-rec"))) {
+              document.getElementById("".concat(_this5.jSPlugin.id, "-rec")).className = options[item] ? 'active' : '';
+              document.getElementById("".concat(_this5.jSPlugin.id, "-rec-content")).children[0].children[0].style.fill = options[item] ? activeColor : color;
+            }
+
+            break;
+        }
+
+        _this5.decoderState.state = Object.assign(_this5.decoderState.state, options);
+      });
+    }
+  }, {
+    key: "startAutoFocus",
+    value: function startAutoFocus() {
+      var _this6 = this;
+
+      console.log("寮�濮嬭嚜鍔ㄩ殣钘�", this.autoFocus);
+      var autoFocus = this.autoFocus; // if(document.getElementById(`${this.jSPlugin.id}-audioControls`)) {
+
+      if (this.autoFocusTimer) {
+        clearTimeout(this.autoFocusTimer);
+      }
+
+      this.autoFocusTimer = setTimeout(function () {
+        if (document.getElementById("".concat(_this6.jSPlugin.id, "-audioControls"))) {
+          document.getElementById("".concat(_this6.jSPlugin.id, "-audioControls")).style.opacity = 0;
+        }
+      }, autoFocus * 1000);
+    }
+  }, {
+    key: "stopAutoFocus",
+    value: function stopAutoFocus() {
+      console.log("缁撴潫鑷姩闅愯棌");
+
+      if (document.getElementById("".concat(this.jSPlugin.id, "-audioControls"))) {
+        document.getElementById("".concat(this.jSPlugin.id, "-audioControls")).style.opacity = 1;
+      }
+
+      if (this.autoFocusTimer) {
+        clearTimeout(this.autoFocusTimer);
+      }
+
+      this.startAutoFocus();
+    }
+  }, {
+    key: "toString",
+    value: function toString() {
+      return "".concat(this.coreX, "-").concat(this.coreY);
+    }
+  }, {
+    key: "renderFooter",
+    value: function renderFooter(id, part) {
+      var _this7 = this;
+
+      // 鎾斁鍋滄
+      var objItem = this.matchBtn(id); // 绉诲姩绔笉灞曠ず鐢靛瓙鏀惧ぇ
+
+      if (this.isMobile && objItem.id === "zoom") {
+        return false;
+      }
+
+      var objDOM = document.createElement('div');
+      objDOM.className = "theme-icon-item";
+      objDOM.innerHTML = "".concat("<span id=\"".concat(this.jSPlugin.id, "-").concat(objItem.id, "\" style=\"position:relative;\">") // +`<span id="${this.jSPlugin.id}-${objItem.id}-left" class="ezuikit-theme-icon" title="宸︾Щ" style="position: absolute;top: calc(50% - 26px);left: -6px;display: none;"><svg fill="#ffffff" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 10 15" style="background:#00000080;"><path d="M7.4,10V5.3c0-0.3-0.3-0.6-0.6-0.6c-0.1,0-0.3,0.1-0.4,0.2L3.7,7.4c-0.2,0.2-0.3,0.6,0,0.8 c0,0,0,0,0.1,0.1l2.7,2.2c0.2,0.2,0.6,0.2,0.8-0.1C7.3,10.3,7.4,10.2,7.4,10z"></path></svg></span>`  
+      + "<div id=\"".concat(this.jSPlugin.id, "-").concat(objItem.id, "-content\" title=\"").concat(objItem.title, "\" style=\"height:").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "px;display: flex;align-items: center;position:relative;\">")).concat(objItem.domString, "</div>") // +`<span id="${this.jSPlugin.id}-${objItem.id}-right" class="ezuikit-theme-icon" title="鍙崇Щ" style="position: absolute;top: calc(50% - 26px);left: calc(100% - 0px);display: none;"><svg fill="#ffffff" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 10 15" style="background:#00000080"><path d="M3.4,5.2v4.7c0,0.3,0.3,0.6,0.6,0.6c0.1,0,0.3-0.1,0.4-0.2l2.7-2.5c0.2-0.2,0.3-0.6,0-0.8 c0,0,0,0-0.1-0.1L4.4,4.8C4.1,4.6,3.8,4.6,3.6,4.9C3.5,5,3.4,5.1,3.4,5.2z"></path></svg></span>`
+      + '</span>';
+
+      objDOM.onclick = function (e) {
+        if (_this7.decoderState.state.isEditing) {
+          return false;
+        }
+
+        objItem.onclick(e);
+      };
+
+      if (objItem.onmouseenter) {
+        objDOM.onmouseenter = function (e) {
+          if (_this7.decoderState.state.isEditing) {
+            return false;
+          }
+
+          objItem.onmouseenter(e);
+        };
+      }
+
+      if (objItem.onmouseleave) {
+        objDOM.onmouseleave = function (e) {
+          if (_this7.decoderState.state.isEditing) {
+            return false;
+          }
+
+          objItem.onmouseleave(e);
+        };
+      }
+
+      var toLeft = document.createElement('span');
+      toLeft.className = "icon-move left";
+      toLeft.innerHTML = "<span id=\"".concat(this.jSPlugin.id, "-").concat(objItem.id, "-left\" title=\"\u5DE6\u79FB\" style=\"position: absolute;top: calc(50% - 10px);left: -4px;\"><svg fill=\"#ffffff\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"24\" viewBox=\"0 0 10 15\" style=\"background:#00000080;\"><path d=\"M7.4,10V5.3c0-0.3-0.3-0.6-0.6-0.6c-0.1,0-0.3,0.1-0.4,0.2L3.7,7.4c-0.2,0.2-0.3,0.6,0,0.8 c0,0,0,0,0.1,0.1l2.7,2.2c0.2,0.2,0.6,0.2,0.8-0.1C7.3,10.3,7.4,10.2,7.4,10z\"></path></svg></span>");
+
+      toLeft.onclick = function () {
+        _this7.editIcon(objItem.id, 'left', 'footer');
+      };
+
+      objDOM.appendChild(toLeft);
+      var toRight = document.createElement('span');
+      toRight.className = "icon-move right";
+      toRight.innerHTML = "<span id=\"".concat(this.jSPlugin.id, "-").concat(objItem.id, "-right\" class=\"ezuikit-theme-icon\" title=\"\u53F3\u79FB\" style=\"position: absolute;top: calc(50% - 10px);left: calc(100% - 8px);\"><svg fill=\"#ffffff\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"12\" height=\"24\" viewBox=\"0 0 10 15\" style=\"background:#00000080\"><path d=\"M3.4,5.2v4.7c0,0.3,0.3,0.6,0.6,0.6c0.1,0,0.3-0.1,0.4-0.2l2.7-2.5c0.2-0.2,0.3-0.6,0-0.8 c0,0,0,0-0.1-0.1L4.4,4.8C4.1,4.6,3.8,4.6,3.6,4.9C3.5,5,3.4,5.1,3.4,5.2z\"></path></svg></span>");
+
+      toRight.onclick = function () {
+        _this7.editIcon(objItem.id, 'right', 'footer');
+      };
+
+      objDOM.appendChild(toRight);
+      var toClose = document.createElement('span');
+      toClose.className = "icon-move close";
+      toClose.innerHTML = "<span id=\"".concat(objItem.id, "-remove\" class=\"ezuikit-theme-icon\" title=\"\u79FB\u9664\" style=\"position: absolute;top: -10px;right: -10px;\">") + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 15 15">' + '<circle style="fill-rule:evenodd;clip-rule:evenodd;fill-opacity:0.8011;" cx="7.5" cy="7.6" r="7" />' + '<rect x="3.9" y="3.5" class="st1" style="fill:none;" width="8.1" height="8.1" />' + '<line style="fill:none;stroke:#ffffff;stroke-width:0.5833;stroke-linecap:round;" x1="4.9" y1="5" x2="10" y2="10.1" />' + '<line style="fill:none;stroke:#ffffff;stroke-width:0.5833;stroke-linecap:round;" x1="4.9" y1="10.1" x2="10" y2="5" />' + '</svg>' + '</span>';
+
+      toClose.onclick = function () {
+        _this7.editIcon(objItem.id, 'delete', 'footer');
+      };
+
+      objDOM.appendChild(toClose);
+
+      if (part === 'left') {
+        document.getElementById("".concat(this.jSPlugin.id, "-audioControls")).childNodes[0].appendChild(objDOM);
+      } else {
+        document.getElementById("".concat(this.jSPlugin.id, "-audioControls")).childNodes[1].appendChild(objDOM);
+      } // 鎴浘
+
+    }
+  }, {
+    key: "editIcon",
+    value: function editIcon(id, type, area) {
+      console.log("缂栬緫缁勪欢", id, type, area);
+      var newThemeData = this.themeData;
+      console.log("themeData", this.themeData);
+      var btnList = this.themeData[area].btnList;
+
+      var _index = lodash.findIndex(btnList, function (item) {
+        return item.iconId === id;
+      });
+
+      var tmp = btnList[_index];
+
+      switch (type) {
+        case 'delete':
+          // btnList.splice(_index, 1);
+          // 闄愬埗鍥炴斁蹇呴』閫変腑涓�绉嶄粙璐�
+          if (id === "rec") {
+            if (lodash.findIndex(btnList, function (item) {
+              return item.iconId === "cloudRec" && item.isrender == 1;
+            }) === -1) {
+              if (this.jSPlugin.Message) {
+                this.jSPlugin.Message["default"]("蹇呴』閫変腑涓�绉嶅瓨鍌ㄤ粙璐�");
+              }
+
+              return false;
+            }
+          } else if (id === "cloudRec") {
+            if (lodash.findIndex(btnList, function (item) {
+              return item.iconId === "rec" && item.isrender == 1;
+            }) === -1) {
+              if (this.jSPlugin.Message) {
+                this.jSPlugin.Message["default"]("蹇呴』閫変腑涓�绉嶅瓨鍌ㄤ粙璐�");
+              }
+
+              return false;
+            }
+          }
+
+          btnList[_index].isrender = 0;
+          break;
+
+        case 'right':
+          var nextRightBtnIndex = -1;
+
+          for (var i = _index + 1; i < btnList.length; i++) {
+            if (btnList[i].part === btnList[_index].part && btnList[i].isrender == 1) {
+              nextRightBtnIndex = i;
+              break;
+            }
+          }
+
+          if (nextRightBtnIndex !== -1) {
+            btnList[_index] = btnList[nextRightBtnIndex];
+            btnList[nextRightBtnIndex] = tmp;
+          }
+
+          break;
+
+        case 'left':
+          var nextLeftBtnIndex = -1;
+
+          for (var _i = _index - 1; _i >= 0; _i--) {
+            if (btnList[_i].part === btnList[_index].part && btnList[_i].isrender == 1) {
+              nextLeftBtnIndex = _i;
+              break;
+            }
+          }
+
+          if (nextLeftBtnIndex !== -1) {
+            btnList[_index] = btnList[nextLeftBtnIndex];
+            btnList[nextLeftBtnIndex] = tmp;
+          }
+
+          break;
+      }
+
+      console.log("new btnList", btnList);
+      newThemeData[area].btnList = btnList; //this.renderThemeData();
+
+      this.changeTheme(newThemeData);
+    }
+  }, {
+    key: "renderHeader",
+    value: function renderHeader(id, part) {
+      var _this8 = this;
+
+      // 鎾斁鍋滄
+      var objItem = this.matchBtn(id);
+      var objDOM = document.createElement('div');
+      objDOM.className = "theme-icon-item";
+      objDOM.innerHTML = "".concat("<span id=\"".concat(this.jSPlugin.id, "-").concat(objItem.id, "\" style=\"position:relative\";>") // +`<span id="${this.jSPlugin.id}-${objItem.id}-left" title="宸︾Щ" style="position: absolute;top: calc(50% - 10px);left: -6px;display: none;"><svg fill="#ffffff" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 10 15" style="background:#00000080;"><path d="M7.4,10V5.3c0-0.3-0.3-0.6-0.6-0.6c-0.1,0-0.3,0.1-0.4,0.2L3.7,7.4c-0.2,0.2-0.3,0.6,0,0.8 c0,0,0,0,0.1,0.1l2.7,2.2c0.2,0.2,0.6,0.2,0.8-0.1C7.3,10.3,7.4,10.2,7.4,10z"></path></svg></span>`  
+      + "<span id=\"".concat(this.jSPlugin.id, "-").concat(objItem.id, "-content\" title=\"").concat(objItem.title, "\" style=\"display:inline-block;height:").concat(this.width > MEDIAWIDTH ? 48 : 32, "px;\">")).concat(objItem.domString, "</span>") //+`<span id="${this.jSPlugin.id}-${objItem.id}-right" title="鍙崇Щ" style="position: absolute;top: calc(50% - 10px);left: calc(100% - 6px);display: none;"><svg fill="#ffffff" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 10 15" style="background:#00000080"><path d="M3.4,5.2v4.7c0,0.3,0.3,0.6,0.6,0.6c0.1,0,0.3-0.1,0.4-0.2l2.7-2.5c0.2-0.2,0.3-0.6,0-0.8 c0,0,0,0-0.1-0.1L4.4,4.8C4.1,4.6,3.8,4.6,3.6,4.9C3.5,5,3.4,5.1,3.4,5.2z"></path></svg></span>`
+      + "<span id=\"".concat(this.jSPlugin.id, "-").concat(objItem.id, "-remove\" title=\"\u79FB\u9664\" style=\"position: absolute;top: -6px;left: 38px;display: none;\">") + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 15 15">' + '<circle style="fill-rule:evenodd;clip-rule:evenodd;fill-opacity:0.8011;" cx="7.5" cy="7.6" r="7" />' + '<rect x="3.9" y="3.5" class="st1" style="fill:none;" width="8.1" height="8.1" />' + '<line style="fill:none;stroke:#ffffff;stroke-width:0.5833;stroke-linecap:round;" x1="4.9" y1="5" x2="10" y2="10.1" />' + '<line style="fill:none;stroke:#ffffff;stroke-width:0.5833;stroke-linecap:round;" x1="4.9" y1="10.1" x2="10" y2="5" />' + '</svg>' + '</span>' + '</span>'; // var toLeft = document.createElement('span');
+      // toLeft.innerHTML =  +`<span id="${this.jSPlugin.id}-${objItem.id}-left" title="宸︾Щ" style="position: absolute;top: calc(50% - 10px);left: -6px;display: none;"><svg fill="#ffffff" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 10 15" style="background:#00000080;"><path d="M7.4,10V5.3c0-0.3-0.3-0.6-0.6-0.6c-0.1,0-0.3,0.1-0.4,0.2L3.7,7.4c-0.2,0.2-0.3,0.6,0,0.8 c0,0,0,0,0.1,0.1l2.7,2.2c0.2,0.2,0.6,0.2,0.8-0.1C7.3,10.3,7.4,10.2,7.4,10z"></path></svg></span>`;
+      // toLeft.onclick = () => {console.log("宸︾Щ鍔�")};
+
+      objDOM.onclick = function (e) {
+        if (_this8.decoderState.state.isEditing) {
+          return false;
+        }
+
+        objItem.onclick(e);
+      }; // var toLeft = document.createElement('span');
+      // toLeft.className = "icon-move left";
+      // toLeft.innerHTML =  `<span id="${this.jSPlugin.id}-${objItem.id}-left" title="宸︾Щ" style="position: absolute;top: calc(50% - 10px);left: -4px;"><svg fill="#ffffff" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 10 15" style="background:#00000080;"><path d="M7.4,10V5.3c0-0.3-0.3-0.6-0.6-0.6c-0.1,0-0.3,0.1-0.4,0.2L3.7,7.4c-0.2,0.2-0.3,0.6,0,0.8 c0,0,0,0,0.1,0.1l2.7,2.2c0.2,0.2,0.6,0.2,0.8-0.1C7.3,10.3,7.4,10.2,7.4,10z"></path></svg></span>`;
+      // toLeft.onclick = () => {this.editIcon(objItem.id,'left','header')};
+      // objDOM.appendChild(toLeft);
+      // var toRight = document.createElement('span');
+      // toRight.className = "icon-move right";
+      // toRight.innerHTML = `<span id="${this.jSPlugin.id}-${objItem.id}-right" class="ezuikit-theme-icon" title="鍙崇Щ" style="position: absolute;top: calc(50% - 10px);left: calc(100% - 8px);"><svg fill="#ffffff" version="1.1" xmlns="http://www.w3.org/2000/svg" width="12" height="24" viewBox="0 0 10 15" style="background:#00000080"><path d="M3.4,5.2v4.7c0,0.3,0.3,0.6,0.6,0.6c0.1,0,0.3-0.1,0.4-0.2l2.7-2.5c0.2-0.2,0.3-0.6,0-0.8 c0,0,0,0-0.1-0.1L4.4,4.8C4.1,4.6,3.8,4.6,3.6,4.9C3.5,5,3.4,5.1,3.4,5.2z"></path></svg></span>`;
+      // toRight.onclick = () => {this.editIcon(objItem.id,'right','header')};
+      // objDOM.appendChild(toRight);
+
+
+      var toClose = document.createElement('span');
+      toClose.className = "icon-move close";
+      toClose.innerHTML = "<span id=\"".concat(objItem.id, "-remove\" class=\"ezuikit-theme-icon\" title=\"\u79FB\u9664\" style=\"position: absolute;top: -6px;right: -6px;\">") + '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 15 15">' + '<circle style="fill-rule:evenodd;clip-rule:evenodd;fill-opacity:0.8011;" cx="7.5" cy="7.6" r="7" />' + '<rect x="3.9" y="3.5" class="st1" style="fill:none;" width="8.1" height="8.1" />' + '<line style="fill:none;stroke:#ffffff;stroke-width:0.5833;stroke-linecap:round;" x1="4.9" y1="5" x2="10" y2="10.1" />' + '<line style="fill:none;stroke:#ffffff;stroke-width:0.5833;stroke-linecap:round;" x1="4.9" y1="10.1" x2="10" y2="5" />' + '</svg>' + '</span>';
+
+      toClose.onclick = function () {
+        _this8.editIcon(objItem.id, 'delete', 'header');
+      };
+
+      objDOM.appendChild(toClose); // objDOM.appendChild(toLeft);
+
+      if (part === 'left') {
+        document.getElementById("".concat(this.jSPlugin.id, "-headControl")).childNodes[0].appendChild(objDOM);
+      } else {
+        document.getElementById("".concat(this.jSPlugin.id, "-headControl")).childNodes[1].appendChild(objDOM);
+      }
+    }
+  }, {
+    key: "countTime",
+    value: function countTime(type) {
+      var start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+      var that = this;
+
+      if (!document.getElementById(this.jSPlugin.id + "time-area")) {
+        var recordDOM = document.createElement("div");
+        recordDOM.id = this.jSPlugin.id + "time-area";
+        recordDOM.className = "time-area";
+        recordDOM.innerHTML = "<span class=\"dot\"></span><span class=\"value\">00:00</span>";
+
+        if (document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container"))) {
+          document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container")).appendChild(recordDOM);
+        }
+      }
+
+      if (this.countTimer) {
+        clearInterval(this.countTimer);
+      }
+
+      if (type === 'add') {
+        var i = start;
+        document.getElementById(that.jSPlugin.id + "time-area").style.display = 'flex';
+        this.countTimer = setInterval(function () {
+          ++i;
+          document.getElementById(that.jSPlugin.id + "time-area").children[1].innerHTML = formatSeconds(i);
+        }, 1000);
+      } else if (type === 'destroy') {
+        if (this.countTimer) {
+          clearInterval(this.countTimer);
+        }
+        this.countTimer = undefined;
+
+        if (document.getElementById(that.jSPlugin.id + "time-area")) {
+          document.getElementById(that.jSPlugin.id + "time-area").children[1].innerHTML = '00:00';
+          document.getElementById(that.jSPlugin.id + "time-area").style.display = 'none';
+        }
+      } //灏嗙鏁拌浆鎹负鏃跺垎绉掓牸寮�
+
+
+      function formatSeconds(value) {
+        var theTime = parseInt(value); // 绉�
+
+        var middle = 0; // 鍒�
+
+        var hour = 0; // 灏忔椂
+
+        var secondV = '00';
+        var minV = '00';
+        var hourV = '00';
+
+        if (theTime > 59) {
+          middle = parseInt(theTime / 60);
+          theTime = parseInt(theTime % 60);
+
+          if (middle > 59) {
+            hour = parseInt(middle / 60);
+            middle = parseInt(middle % 60);
+          }
+        }
+
+        secondV = parseInt(theTime) > 9 ? parseInt(theTime) : '0' + parseInt(theTime);
+        minV = parseInt(middle) > 9 ? parseInt(middle) : '0' + parseInt(middle);
+        hourV = parseInt(hour) > 9 ? parseInt(hour) : '0' + parseInt(hour);
+
+        if (hour > 0) {
+          return hourV + ':' + minV + ':' + secondV;
+        } else if (middle > 0) {
+          return minV + ':' + secondV;
+        } else {
+          return '00:' + secondV;
+        }
+      }
+    }
+  }, {
+    key: "matchBtn",
+    value: function matchBtn(btnId) {
+      var _this9 = this;
+
+      var _this$themeData3 = this.themeData,
+          header = _this$themeData3.header,
+          footer = _this$themeData3.footer;
+      var btnItem = {
+        title: "",
+        id: "",
+        domString: "",
+        color: "#FFFFFF",
+        activeColor: "#FFFFFF",
+        onclick: function onclick() {},
+        onmoveleft: function onmoveleft() {},
+        onmoveright: function onmoveright() {},
+        onremove: function onremove() {}
+      };
+
+      var _index = header.btnList.findIndex(function (item) {
+        return item.iconId === btnId;
+      });
+
+      if (_index === -1) {
+        btnItem.color = footer.color;
+        btnItem.backgroundColor = footer.backgroundColor;
+        btnItem.activeColor = footer.activeColor;
+      } else {
+        btnItem.color = header.color;
+        btnItem.backgroundColor = header.backgroundColor;
+        btnItem.activeColor = header.activeColor;
+      }
+
+      switch (btnId) {
+        case 'play':
+          btnItem.title = "鎾斁/缁撴潫鎾斁";
+          btnItem.id = btnId;
+          btnItem.domString = '<div style="height: 100%">' + "<svg style=\"display:none\" width=\"".concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\"  fill=\"").concat(btnItem.color, "\" viewBox=\"-6 -6 32 32\">\n            <path id=\"Stroke-1\" class=\"st1\" d=\"M10.5,1.7c-4.9,0-8.8,4-8.8,8.8s4,8.8,8.8,8.8s8.8-4,8.8-8.8S15.4,1.7,10.5,1.7z M10.5,2.7\n              c4.3,0,7.8,3.5,7.8,7.8s-3.5,7.8-7.8,7.8s-7.8-3.5-7.8-7.8S6.2,2.7,10.5,2.7z\"/>\n            <path class=\"st2\" d=\"M8.7,8C9,8,9.3,8.3,9.3,8.6v3.8C9.3,12.7,9,13,8.7,13C8.3,13,8,12.7,8,12.4V8.6C8,8.3,8.3,8,8.7,8z\"/>\n            <path id=\"Rectangle-Copy-10\" class=\"st2\" d=\"M12.8,8c0.3,0,0.6,0.3,0.6,0.6v3.8c0,0.3-0.3,0.6-0.6,0.6c-0.3,0-0.6-0.3-0.6-0.6V8.6\n              C12.2,8.3,12.5,8,12.8,8z\"/>\n          </svg>") + "<svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M13,9.8L10.1,8C9.9,7.9,9.7,7.9,9.5,7.9c-0.6,0-1,0.4-1,1v3.7c0,0.2,0.1,0.4,0.2,0.5c0.3,0.5,0.9,0.6,1.4,0.3 l2.9-1.8c0.1-0.1,0.2-0.2,0.3-0.3C13.6,10.7,13.4,10.1,13,9.8z" />' + '<path d="M10.5,1.9c-4.9,0-8.8,4-8.8,8.8c0,4.9,4,8.8,8.8,8.8s8.8-4,8.8-8.8C19.4,5.8,15.4,1.9,10.5,1.9z M10.5,18.5 c-4.3,0-7.8-3.5-7.8-7.8s3.5-7.8,7.8-7.8c4.3,0,7.8,3.5,7.8,7.8S14.9,18.5,10.5,18.5z" />' + '</svg>' + '</div>';
+
+          btnItem.onclick = function () {
+            var _this9$decoderState$s = _this9.decoderState.state,
+                play = _this9$decoderState$s.play,
+                isEditing = _this9$decoderState$s.isEditing;
+
+            if (isEditing) {
+              return false;
+            }
+
+            if (play) {
+              _this9.jSPlugin.stop();
+            } else {
+              _this9.jSPlugin.play();
+            }
+
+            _this9.setDecoderState({
+              play: !play
+            });
+          };
+
+          return btnItem;
+
+        case 'sound':
+          btnItem.title = "澹伴煶";
+          btnItem.id = btnId;
+          btnItem.domString = '<span style="height: 100%">' + "<svg style=\"display:none\" fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">\n            <path d=\"M8.5,4.2c0.8-0.7,2.1-0.2,2.2,0.9l0,0.1v10c0,1.1-1.2,1.7-2.1,1.1l-0.1-0.1l-3.3-2.8C5,13.2,5,12.9,5.1,12.7 c0.2-0.2,0.4-0.2,0.6-0.1l0.1,0.1l3.3,2.8c0.2,0.2,0.5,0.1,0.5-0.2l0-0.1v-10c0-0.3-0.3-0.4-0.5-0.3L9.2,5L5.9,7.8 C5.6,7.9,5.3,7.9,5.1,7.7C5,7.5,5,7.3,5.1,7.1L5.2,7L8.5,4.2z\"/>\n            <path d=\"M5.5,6.9C5.8,6.9,6,7.1,6,7.4c0,0.2-0.2,0.4-0.4,0.5l-0.1,0h-2C3.4,7.9,3.3,8,3.2,8.2l0,0.1v4 c0,0.2,0.1,0.3,0.3,0.3l0.1,0h2C5.8,12.5,6,12.7,6,13c0,0.2-0.2,0.4-0.4,0.5l-0.1,0h-2c-0.7,0-1.3-0.5-1.3-1.2l0-0.1v-4 c0-0.7,0.5-1.3,1.2-1.3l0.1,0H5.5z\"/>\n            <path d=\"M17.4,7.9c0.2-0.2,0.5-0.2,0.7,0c0.2,0.2,0.2,0.4,0.1,0.6l-0.1,0.1l-3.8,3.8c-0.2,0.2-0.5,0.2-0.7,0 c-0.2-0.2-0.2-0.4-0.1-0.6l0.1-0.1L17.4,7.9z\"/>\n            <path d=\"M13.7,7.9c0.2-0.2,0.4-0.2,0.6-0.1l0.1,0.1l3.8,3.8c0.2,0.2,0.2,0.5,0,0.7c-0.2,0.2-0.4,0.2-0.6,0.1l-0.1-0.1 l-3.7-3.8C13.5,8.4,13.5,8.1,13.7,7.9z\"/>\n            </svg>") + "<svg style=\"display:inline-block\" width=\"".concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" fill=\"").concat(btnItem.color, "\" viewBox=\"-6 -6 32 32\">\n              <path d=\"M13.2,7.1c0.1-0.2,0.5-0.3,0.7-0.2c1.1,0.7,1.9,2.2,1.9,3.7c0,1.6-0.7,3-1.9,3.7\n                c-0.2,0.1-0.5,0.1-0.7-0.2c-0.1-0.2-0.1-0.5,0.2-0.7c0.8-0.5,1.4-1.6,1.4-2.9c0-1.3-0.6-2.4-1.4-2.9C13.1,7.6,13,7.3,13.2,7.1z\"/>\n              <path d=\"M15.7,4.5c0.2-0.2,0.5-0.2,0.7-0.1C18,5.8,19,8.2,19,10.7c0,2.5-1,4.8-2.7,6.3\n                c-0.2,0.2-0.5,0.2-0.7-0.1c-0.2-0.2-0.2-0.5,0.1-0.7c1.4-1.2,2.3-3.3,2.3-5.5c0-2.2-0.9-4.3-2.3-5.5C15.5,5,15.5,4.7,15.7,4.5z\"/>\n              <path id=\"Stroke-5\" class=\"st1\" d=\"M8.5,4.7c0.8-0.7,2.1-0.2,2.2,0.9l0,0.1v10c0,1.1-1.2,1.7-2.1,1.1l-0.1-0.1l-3.3-2.8\n                C5,13.7,5,13.4,5.1,13.2c0.2-0.2,0.4-0.2,0.6-0.1l0.1,0.1l3.3,2.8c0.2,0.2,0.5,0.1,0.5-0.2l0-0.1v-10c0-0.3-0.3-0.4-0.5-0.3l-0.1,0\n                L5.9,8.3C5.6,8.4,5.3,8.4,5.1,8.2C5,8,5,7.7,5.1,7.6l0.1-0.1L8.5,4.7z\"/>\n              <path  d=\"M5.5,7.4C5.8,7.4,6,7.6,6,7.9c0,0.2-0.2,0.4-0.4,0.5l-0.1,0h-2c-0.2,0-0.3,0.1-0.3,0.3l0,0.1v4\n                c0,0.2,0.1,0.3,0.3,0.3l0.1,0h2C5.8,13,6,13.2,6,13.5c0,0.2-0.2,0.4-0.4,0.5l-0.1,0h-2c-0.7,0-1.3-0.5-1.3-1.2l0-0.1v-4\n                c0-0.7,0.5-1.3,1.2-1.3l0.1,0H5.5z\"/>\n            </svg>") + '</span>';
+
+          btnItem.onclick = function () {
+            var _this9$decoderState$s2 = _this9.decoderState.state,
+                play = _this9$decoderState$s2.play,
+                sound = _this9$decoderState$s2.sound;
+
+            if (play) {
+              if (sound) {
+                _this9.jSPlugin.closeSound();
+
+                _this9.setDecoderState({
+                  sound: false
+                });
+              } else {
+                _this9.jSPlugin.openSound();
+
+                _this9.setDecoderState({
+                  sound: true
+                });
+              }
+            }
+          };
+
+          return btnItem;
+
+        case 'recordvideo':
+          btnItem.title = "褰曞睆";
+          btnItem.id = btnId;
+          btnItem.domString = "<svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M11.6,5.3H4.7c-1.4,0-2.5,1.1-2.5,2.5v5.9c0,1.4,1.1,2.5,2.5,2.5h6.9c1.4,0,2.5-1.1,2.5-2.5V7.7 C14.1,6.4,13,5.3,11.6,5.3z M4.7,6.3h6.9c0.8,0,1.5,0.7,1.5,1.5v5.9c0,0.8-0.7,1.5-1.5,1.5H4.7c-0.8,0-1.5-0.7-1.5-1.5V7.7 C3.3,6.9,3.9,6.3,4.7,6.3z" />' + '<path d="M16.6,6.7c0.9-0.8,2.3-0.1,2.4,1l0,0.1v5.7c0,1.2-1.3,1.9-2.3,1.2l-0.1-0.1L13.3,12 c-0.2-0.2-0.2-0.5-0.1-0.7c0.2-0.2,0.4-0.2,0.6-0.1l0.1,0.1l3.3,2.7c0.3,0.2,0.7,0.1,0.8-0.3l0-0.1V7.8c0-0.4-0.4-0.6-0.7-0.4 l-0.1,0l-3.3,2.7c-0.2,0.2-0.5,0.1-0.7-0.1c-0.2-0.2-0.1-0.5,0-0.6l0.1-0.1L16.6,6.7z" />' + '</svg>';
+
+          btnItem.onclick = function () {
+            var _this9$decoderState$s3 = _this9.decoderState.state,
+                play = _this9$decoderState$s3.play,
+                recordvideo = _this9$decoderState$s3.recordvideo;
+
+            if (play) {
+              if (recordvideo) {
+                _this9.jSPlugin.stopSave();
+
+                _this9.setDecoderState({
+                  recordvideo: false
+                });
+              } else {
+                _this9.jSPlugin.startSave("".concat(new Date().getTime()));
+
+                _this9.setDecoderState({
+                  recordvideo: true
+                });
+              }
+            }
+          };
+
+          return btnItem;
+
+        case 'capturePicture':
+          btnItem.title = "鎴浘";
+          btnItem.id = btnId;
+          btnItem.domString = "<svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M10.8,7.7c-2,0-3.7,1.6-3.7,3.7S8.7,15,10.8,15c2,0,3.7-1.6,3.7-3.7S12.8,7.7,10.8,7.7z M10.8,8.7c1.5,0,2.7,1.2,2.7,2.7S12.2,14,10.8,14c-1.5,0-2.7-1.2-2.7-2.7S9.3,8.7,10.8,8.7z" />' + '<path d="M8.6,3.7l-0.1,0C8,3.7,7.7,4,7.5,4.3l-1,1.7l-1.3,0C4,6.1,3.1,7,3.1,8.2v7.1 c0,1.2,0.9,2.1,2.1,2.1h11.1c1.2,0,2.1-0.9,2.1-2.1V8.2l0-0.1c-0.1-1.1-1-1.9-2.1-1.9l-1.3,0l-1.1-1.8c-0.2-0.4-0.7-0.6-1.1-0.6H8.6 z M8.6,4.7h4.2c0.1,0,0.2,0.1,0.3,0.1l1.2,2c0.1,0.2,0.3,0.2,0.4,0.2h1.6c0.6,0,1.1,0.5,1.1,1.1v7.1c0,0.6-0.5,1.1-1.1,1.1H5.1 c-0.6,0-1.1-0.5-1.1-1.1V8.2c0-0.6,0.5-1.1,1.1-1.1h1.6c0.2,0,0.3-0.1,0.4-0.2l1.2-2C8.4,4.7,8.5,4.7,8.6,4.7z" />' + '</svg>';
+
+          btnItem.onclick = function () {
+            var play = _this9.decoderState.state.play;
+
+            if (play) {
+              _this9.jSPlugin.capturePicture("".concat(new Date().getTime()));
+            } else {
+              console.log("瑙嗛鏈挱鏀撅紝鏃犳硶鎴浘");
+            }
+          };
+
+          return btnItem;
+
+        case 'talk':
+          btnItem.title = "瀵硅";
+          btnItem.id = btnId;
+          btnItem.domString = '<div></div>' + "<svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M10.1,2.7C8.5,2.7,7.2,4,7.2,5.6v5.2c0,1.6,1.3,2.9,2.9,2.9l0.2,0c1.5-0.1,2.7-1.4,2.7-2.9V5.6	C13,4,11.7,2.7,10.1,2.7z M10.1,3.7c1.1,0,1.9,0.9,1.9,1.9v5.2c0,1-0.8,1.8-1.8,1.9l-0.1,0c-1,0-1.9-0.9-1.9-1.9V5.6 C8.2,4.5,9,3.7,10.1,3.7z" />' + '<path d="M15.1,8.5c0.2,0,0.4,0.2,0.5,0.4l0,0.1v1.7c0,3-2.5,5.5-5.5,5.5c-3,0-5.4-2.3-5.5-5.3l0-0.2V9 c0-0.3,0.2-0.5,0.5-0.5c0.2,0,0.4,0.2,0.5,0.4l0,0.1v1.7c0,2.5,2,4.5,4.5,4.5c2.4,0,4.4-1.9,4.5-4.3l0-0.2V9 C14.6,8.7,14.8,8.5,15.1,8.5z" />' + '<path d="M13.5,17.7c0.3,0,0.5,0.2,0.5,0.5c0,0.2-0.2,0.4-0.4,0.5l-0.1,0h-7c-0.3,0-0.5-0.2-0.5-0.5 c0-0.2,0.2-0.4,0.4-0.5l0.1,0H13.5z" />' + '<path d="M10.1,15.2c0.2,0,0.4,0.2,0.5,0.4l0,0.1v2.5c0,0.3-0.2,0.5-0.5,0.5c-0.2,0-0.4-0.2-0.5-0.4l0-0.1 v-2.5C9.6,15.4,9.8,15.2,10.1,15.2z" />' + '</svg>';
+
+          btnItem.onclick = function () {
+            var _this9$decoderState$s4 = _this9.decoderState.state,
+                talk = _this9$decoderState$s4.talk,
+                sound = _this9$decoderState$s4.sound;
+
+            if (talk) {
+              console.log('缁撴潫瀵硅');
+
+              _this9.setDecoderState({
+                talk: false
+              });
+
+              _this9.jSPlugin.Talk.stopTalk();
+
+              var isReOpenSound = lodash.findIndex(_this9.themeData.footer.btnList, function (v) {
+                return v.iconId === 'sound' && v.isrender === 1 && v.defaultActive === 1;
+              }) > -1;
+
+              if (_this9.themeData && isReOpenSound) {
+                _this9.jSPlugin.openSound();
+
+                _this9.setDecoderState({
+                  sound: true
+                });
+              }
+            } else {
+              console.log('寮�濮嬪璁�');
+
+              _this9.setDecoderState({
+                talk: true
+              });
+
+              if (sound) {
+                _this9.jSPlugin.closeSound();
+
+                _this9.setDecoderState({
+                  sound: false
+                });
+              }
+
+              _this9.jSPlugin.Talk.startTalk();
+            }
+          };
+
+          return btnItem;
+
+        case 'zoom':
+          btnItem.title = "鐢靛瓙鏀惧ぇ";
+          btnItem.id = btnId;
+          btnItem.domString = '<div></div>' + "<svg  fill=\"".concat(btnItem.color, "\" version=\"1.1\" id=\"\u56FE\u5C42_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n          width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"5 -6 5 32\" style=\"enable-background:new 0 0 20 20.1;\" xml:space=\"preserve\">\n              <path class=\"st1\" d=\"M8.8,2.6c3.5,0,6.2,2.8,6.2,6.2s-2.8,6.2-6.2,6.2s-6.2-2.8-6.2-6.2S5.3,2.6,8.8,2.6z M8.8,3.9\n                c-2.8,0-5,2.2-5,5s2.2,5,5,5s5-2.2,5-5S11.5,3.9,8.8,3.9z M12.7,12.7l3.9,3.9\"/>\n              <path class=\"st2\" d=\"M11.2,9.5h-5c-0.3,0-0.6-0.3-0.6-0.6s0.3-0.6,0.6-0.6h5c0.3,0,0.6,0.3,0.6,0.6S11.6,9.5,11.2,9.5z\"/>\n              <path class=\"st2\" d=\"M8.7,12c-0.3,0-0.6-0.3-0.6-0.6v-5c0-0.3,0.3-0.6,0.6-0.6s0.6,0.3,0.6,0.6v5C9.3,11.8,9.1,12,8.7,12z\"/>\n              <path class=\"st2\" d=\"M16.9,17.6c-0.1,0-0.3-0.1-0.4-0.2l-3.9-3.9c-0.2-0.2-0.2-0.6,0-0.8s0.6-0.2,0.8,0l3.9,3.9\n                c0.2,0.2,0.2,0.6,0,0.8C17.2,17.5,17,17.6,16.9,17.6z\"/>\n          </svg>");
+
+          btnItem.onclick = function () {
+            var zoom = _this9.decoderState.state.zoom;
+
+            if (zoom) {
+              console.log('缁撴潫鐢靛瓙鏀惧ぇ');
+
+              _this9.setDecoderState({
+                zoom: false
+              });
+
+              _this9.jSPlugin.Zoom.stopZoom();
+            } else {
+              console.log('寮�濮嬬數瀛愭斁澶�');
+
+              _this9.jSPlugin.Zoom.startZoom();
+
+              _this9.setDecoderState({
+                zoom: true
+              });
+            }
+          };
+
+          return btnItem;
+
+        case 'pantile':
+          btnItem.title = "浜戝彴鎺у埗";
+          btnItem.id = btnId;
+          btnItem.domString = "<svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M10.2,7.8c1.6,0,2.9,1.3,2.9,2.9s-1.3,2.9-2.9,2.9s-2.9-1.3-2.9-2.9S8.5,7.8,10.2,7.8z M10.2,8.8c-1.1,0-1.9,0.9-1.9,1.9s0.9,1.9,1.9,1.9s1.9-0.9,1.9-1.9S11.2,8.8,10.2,8.8z" />' + '<path d="M8.8,3.5c0.7-0.6,1.8-0.6,2.5-0.1l0.1,0.1l1.4,1.1c0.2,0.2,0.3,0.5,0.1,0.7 c-0.2,0.2-0.4,0.2-0.6,0.1l-0.1,0l-1.4-1.1C10.5,3.9,10,3.9,9.6,4.2L9.4,4.3L8,5.4C7.8,5.5,7.5,5.5,7.3,5.3c-0.2-0.2-0.1-0.5,0-0.6 l0.1-0.1L8.8,3.5z" />' + '<path d="M2.5,12.3c-0.6-0.7-0.6-1.8-0.1-2.5l0.1-0.1l1.1-1.4c0.2-0.2,0.5-0.3,0.7-0.1 c0.2,0.2,0.2,0.4,0.1,0.6l0,0.1l-1.1,1.4C3,10.6,3,11.1,3.2,11.5l0.1,0.1L4.4,13c0.2,0.2,0.1,0.5-0.1,0.7c-0.2,0.2-0.5,0.1-0.6,0 l-0.1-0.1L2.5,12.3z" />' + '<path d="M17.7,12.3c0.6-0.7,0.6-1.8,0.1-2.5l-0.1-0.1l-1.1-1.4c-0.2-0.2-0.5-0.3-0.7-0.1 c-0.2,0.2-0.2,0.4-0.1,0.6l0,0.1l1.1,1.4c0.3,0.4,0.3,0.9,0.1,1.3l-0.1,0.1L15.8,13c-0.2,0.2-0.1,0.5,0.1,0.7c0.2,0.2,0.5,0.1,0.6,0 l0.1-0.1L17.7,12.3z" />' + '<path d="M8.8,18.2c0.7,0.6,1.8,0.6,2.5,0.1l0.1-0.1l1.4-1.1c0.2-0.2,0.3-0.5,0.1-0.7 c-0.2-0.2-0.4-0.2-0.6-0.1l-0.1,0l-1.4,1.1c-0.4,0.3-0.9,0.3-1.3,0.1l-0.1-0.1L8,16.3c-0.2-0.2-0.5-0.1-0.7,0.1 c-0.2,0.2-0.1,0.5,0,0.6l0.1,0.1L8.8,18.2z" />' + '</svg>';
+
+          btnItem.onclick = function () {
+            var _this9$decoderState$s5 = _this9.decoderState.state,
+                pantile = _this9$decoderState$s5.pantile,
+                expend = _this9$decoderState$s5.expend;
+
+            if (!pantile) {
+              console.log('鏄剧ず浜戝彴');
+
+              if (_this9.isMobile && !expend) {
+                console.log("绉诲姩绔紝闈炲叏灞忕姸鎬佷笉灞曠ず浜戝彴"); // 绉诲姩绔紝闈炲叏灞忕姸鎬佷笉灞曠ず浜戝彴
+
+                return false;
+              }
+
+              _this9.Ptz.show();
+
+              _this9.setDecoderState({
+                pantile: true
+              });
+            } else {
+              console.log('闅愯棌浜戝彴');
+
+              _this9.Ptz.hide();
+
+              _this9.setDecoderState({
+                pantile: false
+              });
+            }
+          };
+
+          return btnItem;
+
+        case 'expend':
+          btnItem.title = "鍏ㄥ眬鍏ㄥ睆";
+          btnItem.id = btnId;
+          btnItem.domString = "<span><svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M3.4,7.6c-0.3,0-0.5-0.2-0.5-0.5V5.3c0-1.2,1-2.3,2.2-2.3h1.8c0.3,0,0.5,0.2,0.5,0.5S7.2,4.1,6.9,4.1H5.2 c-0.7,0-1.2,0.6-1.2,1.3v1.8C3.9,7.4,3.7,7.6,3.4,7.6z" />' + '<path d="M6.9,18.1H5.2c-1.2,0-2.2-1-2.2-2.2v-1.8c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5v1.8c0,0.7,0.6,1.2,1.2,1.2 h1.8c0.3,0,0.5,0.2,0.5,0.5S7.2,18.1,6.9,18.1z" />' + '<path d="M15.7,18.1h-1.8c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h1.8c0.7,0,1.2-0.6,1.2-1.2v-1.8 c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5v1.8C17.9,17.1,16.9,18.1,15.7,18.1z" />' + '<path d="M17.4,7.6c-0.3,0-0.5-0.2-0.5-0.5V5.3c0-0.7-0.6-1.3-1.2-1.3h-1.8c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h1.8 c1.2,0,2.2,1,2.2,2.3v1.8C17.9,7.4,17.7,7.6,17.4,7.6z" />' + '</svg>' + "<svg style=\"display:none\" width=\"".concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" fill=\"").concat(btnItem.color, "\" viewBox=\"-6 -6 32 32\">\n            <path class=\"st1\" d=\"M5.7,8.1H3.9c-0.3,0-0.6-0.2-0.6-0.6S3.6,7,3.9,7h1.9c0.7,0,1.3-0.6,1.3-1.3V3.8c0-0.3,0.2-0.6,0.6-0.6\n              s0.6,0.2,0.6,0.6v1.9C8.2,7,7.1,8.1,5.7,8.1z\"/>\n            <path class=\"st1\" d=\"M7.6,17.7c-0.3,0-0.6-0.2-0.6-0.6v-1.9c0-0.7-0.6-1.3-1.3-1.3H3.9c-0.3,0-0.6-0.2-0.6-0.6s0.2-0.6,0.6-0.6h1.9\n              c1.3,0,2.4,1.1,2.4,2.4v1.9C8.2,17.5,7.9,17.7,7.6,17.7z\"/>\n            <path class=\"st1\" d=\"M13.4,17.7c-0.3,0-0.6-0.2-0.6-0.6v-1.9c0-1.3,1.1-2.4,2.4-2.4h1.9c0.3,0,0.6,0.2,0.6,0.6S17.5,14,17.2,14\n              h-1.9c-0.7,0-1.3,0.6-1.3,1.3v1.9C14,17.5,13.8,17.7,13.4,17.7z\"/>\n            <path class=\"st1\" d=\"M17.2,8.1h-1.9c-1.3,0-2.4-1.1-2.4-2.4V3.8c0-0.3,0.2-0.6,0.6-0.6S14,3.5,14,3.8v1.9C14,6.4,14.6,7,15.3,7h1.9\n              c0.3,0,0.6,0.2,0.6,0.6S17.5,8.1,17.2,8.1z\"/>\n          </svg>\n          </span>");
+
+          btnItem.onclick = function () {
+            var _this9$decoderState$s6 = _this9.decoderState.state,
+                webExpend = _this9$decoderState$s6.webExpend,
+                expend = _this9$decoderState$s6.expend,
+                play = _this9$decoderState$s6.play,
+                pantile = _this9$decoderState$s6.pantile;
+
+            if (!play) {
+              return false;
+            }
+
+            if (webExpend) {
+              console.log("姝e湪缃戠珯鍏ㄥ睆");
+              return false;
+            }
+
+            if (!expend) {
+              console.log("鎵ц鍏ㄥ眬鍏ㄥ睆");
+
+              if (_this9.isMobile) {
+                var heightIntercept = parseInt(getComputedStyle(document.getElementById("".concat(_this9.jSPlugin.id, "-wrap"))).height, 10) - parseInt(getComputedStyle(document.getElementById(_this9.jSPlugin.id)).height, 10);
+                requestMobileFullScreen(document.getElementById("".concat(_this9.jSPlugin.id, "-wrap")));
+                setTimeout(function () {
+                  var width = document.documentElement.clientWidth;
+                  var height = document.documentElement.clientHeight; // 鍏煎寰俊娴忚鍣╢ooter琚殣钘�
+                  // document.getElementById(`${this.jSPlugin.id}-ez-iframe-footer-container`).style.marginTop = "0px";
+                  // document.getElementById(`${this.jSPlugin.id}-headControl`).style.position = "absolute";
+
+                  document.getElementById("".concat(_this9.jSPlugin.id)).style["backface-visibility"] = "hidden";
+
+                  _this9.jSPlugin.jSPlugin.JS_Resize(height, width - heightIntercept);
+                }, 100);
+              } else {
+                var promise = requestFullScreenPromise(document.getElementById("".concat(_this9.jSPlugin.id)));
+                promise.then(function (data) {
+                  _this9.jSPlugin.jSPlugin.JS_Resize(window.screen.availWidth, window.screen.availHeight);
+                })["catch"](function (err) {
+                  console.log(err);
+                });
+              }
+            } else {
+              if (_this9.isMobile) {
+                var heightIntercept = parseInt(getComputedStyle(document.getElementById("".concat(_this9.jSPlugin.id, "-wrap"))).height, 10) - parseInt(getComputedStyle(document.getElementById(_this9.jSPlugin.id)).height, 10);
+
+                if (document.getElementById("".concat(_this9.jSPlugin.id, "-ez-iframe-footer-container"))) {
+                  document.getElementById("".concat(_this9.jSPlugin.id, "-ez-iframe-footer-container")).style.marginTop = "-32px";
+                }
+
+                if (document.getElementById("".concat(_this9.jSPlugin.id, "-headControl"))) {
+                  document.getElementById("".concat(_this9.jSPlugin.id, "-headControl")).style.position = "relative";
+                }
+
+                cancelMobileFullScreen(document.getElementById("".concat(_this9.jSPlugin.id, "-wrap")), _this9.jSPlugin.width, _this9.jSPlugin.height + heightIntercept);
+
+                _this9.jSPlugin.jSPlugin.JS_Resize(_this9.jSPlugin.width, _this9.jSPlugin.height); // 绉诲姩绔彇娑堝叏灞忥紝濡傛灉寮�鍚簡浜戝彴锛屽彇娑堜簯鍙�
+
+
+                if (pantile) {
+                  _this9.Ptz.hide();
+
+                  _this9.setDecoderState({
+                    pantile: false
+                  });
+                }
+              } else {
+                console.log("鍙栨秷鍏ㄥ眬鍏ㄥ睆");
+                var cancelPromise = cancelFullScreenPromise();
+                cancelPromise.then(function (data) {
+                  console.log("鍙栨秷鍏ㄥ睆", data, _this9.jSPlugin);
+
+                  _this9.jSPlugin.jSPlugin.JS_Resize(_this9.jSPlugin.width, _this9.jSPlugin.height);
+                });
+              }
+            }
+
+            _this9.setDecoderState({
+              expend: !expend
+            });
+          };
+
+          return btnItem;
+
+        case 'webExpend':
+          btnItem.title = "缃戦〉鍏ㄥ睆";
+          btnItem.id = btnId;
+          btnItem.domString = "<span><svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M3.1,7.6c-0.3,0-0.5-0.2-0.5-0.5V5.3c0-1.2,1-2.3,2.2-2.3h1.8c0.3,0,0.5,0.2,0.5,0.5S6.8,4.1,6.6,4.1H4.8 c-0.7,0-1.2,0.6-1.2,1.3v1.8C3.6,7.4,3.3,7.6,3.1,7.6z" />' + '<path d="M15.3,18.1h-1.8c-0.3,0-0.5-0.2-0.5-0.5s0.2-0.5,0.5-0.5h1.8c0.7,0,1.2-0.6,1.2-1.2v-1.8 c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5v1.8C17.6,17.1,16.6,18.1,15.3,18.1z" />' + '<circle class="st2" cx="10.2" cy="10.4" r="1.1"/>' + '</svg>' + "<svg fill=\"".concat(btnItem.color, "\" style=\"display:none;\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">\n          <path class=\"st1\" d=\"M5.4,8.1H3.5C3.2,8.1,3,7.9,3,7.6s0.2-0.5,0.5-0.5h1.9c0.8,0,1.4-0.6,1.4-1.4V3.8c0-0.3,0.2-0.5,0.5-0.5\n            s0.5,0.2,0.5,0.5v1.9C7.7,7,6.7,8.1,5.4,8.1z\"/>\n          <path class=\"st1\" d=\"M13.1,17.7c-0.3,0-0.5-0.2-0.5-0.5v-1.9c0-1.3,1.1-2.4,2.4-2.4h1.9c0.3,0,0.5,0.2,0.5,0.5s-0.2,0.5-0.5,0.5H15\n            c-0.8,0-1.4,0.6-1.4,1.4v1.9C13.6,17.4,13.4,17.7,13.1,17.7z\"/>\n            <circle class=\"st2\" cx=\"10.2\" cy=\"10.4\" r=\"1.1\"/>\n          ") + '</svg></span>';
+
+          btnItem.onclick = function () {
+            var _this9$decoderState$s7 = _this9.decoderState.state,
+                webExpend = _this9$decoderState$s7.webExpend,
+                expend = _this9$decoderState$s7.expend,
+                play = _this9$decoderState$s7.play;
+
+            if (!play) {
+              return false;
+            }
+
+            if (expend) {
+              console.log("姝e湪鍏ㄥ眬鍏ㄥ睆");
+              return false;
+            }
+
+            if (!webExpend) {
+              console.log("鎵ц缃戦〉鍏ㄥ睆");
+              var footerDOMHeight = 0;
+              var headerDOMHeight = 0; // ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange'].forEach((item) => {
+              //   window.addEventListener(item, (data) => fullscreenchange("fullscreenchange", data));
+              // });
+              // //  鐩戝惉鍏ㄥ睆浜嬩欢瑙﹀彂
+              // function fullscreenchange() {
+              //   let isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+              //   return isFullScreen;
+              // }
+
+              var promise = requestFullScreenPromise(document.getElementById("".concat(_this9.jSPlugin.id, "-wrap")));
+              promise.then(function (data) {
+                console.log("鍏ㄥ睆promise", window.screen.availWidth);
+
+                if (document.getElementById("".concat(_this9.jSPlugin.id, "-canvas-container"))) {
+                  footerDOMHeight = parseInt(window.getComputedStyle(document.getElementById("".concat(_this9.jSPlugin.id, "-canvas-container"))).height, 10);
+                }
+
+                if (document.getElementById("".concat(_this9.jSPlugin.id, "-headControl"))) {
+                  headerDOMHeight = parseInt(window.getComputedStyle(document.getElementById("".concat(_this9.jSPlugin.id, "-headControl"))).height, 10);
+                }
+
+                console.log("this.jSPlugin.JS_Resiz", footerDOMHeight, headerDOMHeight, document.body.clientWidth);
+
+                _this9.jSPlugin.jSPlugin.JS_Resize(window.screen.availWidth, window.screen.availHeight - footerDOMHeight - headerDOMHeight);
+              })["catch"](function (err) {
+                console.log(err);
+              });
+            } else {
+              console.log("鍙栨秷缃戦〉鍏ㄥ睆");
+              var cancelPromise = cancelFullScreenPromise();
+              cancelPromise.then(function (data) {
+                _this9.jSPlugin.jSPlugin.JS_Resize(_this9.jSPlugin.width, _this9.jSPlugin.height);
+              });
+            }
+
+            _this9.setDecoderState({
+              webExpend: !webExpend
+            });
+          };
+
+          return btnItem;
+
+        case 'hd':
+          btnItem.title = "鐢婚潰娓呮櫚搴�";
+          btnItem.id = btnId;
+          btnItem.domString = "<ul id=\"".concat(this.jSPlugin.id, "-hdSelect\" class=\"hd speed-select ").concat(this.isMobile ? "mobile" : "", "\" style=\"display:none;\">") // + `<li class="selectOption" style="width: 60px;height: 32px;text-align: center;line-height: 32px;list-style: none;cursor: pointer;font-size: 13px;color: rgba(0, 0, 0, .85);" name="option" id="${this.jSPlugin.id}-select-hd">楂樻竻</li>`
+          // + `<li class="selectOption" style="width: 60px;height: 32px;text-align: center;line-height: 32px;list-style: none;cursor: pointer;font-size: 13px;color: rgba(0, 0, 0, .85);" name="option" id="${this.jSPlugin.id}-select-sd">鏍囨竻</li>`
+          + "<li class=\"selectOption default\" style=\"height: 45px;text-align: center;line-height: 45px;list-style: none;cursor: pointer;\" name=\"option\" id=\"".concat(this.jSPlugin.id, "-select-hd\">\u9AD8\u6E05</li>") + "<li class=\"selectOption default\" style=\"height: 45px;text-align: center;line-height: 45px;list-style: none;cursor: pointer;\"  name=\"option\" id=\"".concat(this.jSPlugin.id, "-select-sd\">\u6807\u6E05</li>") + "<li class=\"selectOption cancel\" style=\"".concat(this.isMobile ? "" : "display:none;", "\" name=\"option\" id=\"").concat(this.jSPlugin.id, "-select-speed\">\u53D6\u6D88</li>") + '</ul>' + "<span><svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -6 32 32\">") + '<path d="M17.4,16.5H3.1c-0.8,0-1.4-0.6-1.4-1.4V5.4c0-0.9,0.7-1.6,1.6-1.6h14.1c0.8,0,1.4,0.6,1.4,1.4v9.8 C18.8,15.9,18.2,16.5,17.4,16.5z M3.3,5C3.1,5,2.9,5.2,2.9,5.4v9.7c0,0.2,0.1,0.3,0.3,0.3h14.3c0.2,0,0.3-0.1,0.3-0.3V5.3 c0-0.2-0.1-0.3-0.3-0.3H3.3z" />' + '<path d="M13.3,13.6h-1.6c-0.4,0-0.7-0.3-0.7-0.7V7.4c0-0.4,0.3-0.7,0.7-0.7h1.6c1.2,0,2.2,1,2.2,2.2v2.4 C15.6,12.6,14.6,13.6,13.3,13.6z M12.2,12.5h1.1c0.6,0,1.1-0.5,1.1-1.1V9c0-0.6-0.5-1.1-1.1-1.1h-1.1V12.5z" />' + '<path d="M5.5,13.6c-0.3,0-0.6-0.2-0.6-0.6V7.3C5,7,5.2,6.8,5.5,6.8S6.1,7,6.1,7.3v5.7C6.1,13.4,5.8,13.6,5.5,13.6z" />' + '<path d="M9.2,13.6c-0.3,0-0.6-0.2-0.6-0.6V7.3c0-0.3,0.2-0.6,0.6-0.6S9.8,7,9.8,7.3v5.7C9.8,13.4,9.5,13.6,9.2,13.6z" />' + '<rect x="5.6" y="9.6" width="3.6" height="1.1" />' + '</svg>' + "<svg style=\"display:none\" fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-6 -8 40 44\">\n                <path d=\"M24.1,23.8h-20c-1.1,0-1.9-0.9-1.9-1.9V8.4c0-1.2,1-2.2,2.1-2.2h19.7c1.1,0,1.9,0.9,1.9,1.9v13.8\n                    C26,23,25.1,23.8,24.1,23.8z M4.3,7.7C4,7.7,3.7,8,3.7,8.4v13.5c0,0.2,0.2,0.4,0.4,0.4h20c0.2,0,0.4-0.2,0.4-0.4V8.2\n                    c0-0.2-0.2-0.4-0.4-0.4H4.3z\"/>\n                <path d=\"M18.4,19.8h-2.2c-0.5,0-0.9-0.4-0.9-0.9v-7.8c0-0.5,0.4-0.9,0.9-0.9h2.2c1.7,0,3.1,1.4,3.1,3.1v3.3\n                C21.5,18.4,20.1,19.8,18.4,19.8z M16.7,18.3h1.6c0.9,0,1.6-0.7,1.6-1.6v-3.3c0-0.9-0.7-1.6-1.6-1.6h-1.6V18.3z\"/>\n                <path d=\"M10.5,19.8c1.2,0,2.1-0.3,2.7-0.9c0.6-0.6,0.9-1.3,0.9-2.1c0-0.8-0.3-1.4-0.9-1.8c-0.4-0.2-1.1-0.5-2.2-0.8\n                    l0,0l-1-0.2c-0.4-0.1-0.8-0.2-1-0.4c-0.4-0.2-0.6-0.5-0.6-0.9c0-0.4,0.1-0.6,0.4-0.9s0.7-0.3,1.3-0.3c0.8,0,1.4,0.2,1.8,0.6\n                    c0.2,0.3,0.3,0.6,0.4,0.9l0,0h1.4c0-0.6-0.2-1.1-0.5-1.6c-0.6-0.8-1.6-1.2-2.9-1.2c-1,0-1.8,0.3-2.4,0.8c-0.6,0.5-0.9,1.2-0.9,2\n                    c0,0.7,0.3,1.3,1,1.7c0.4,0.2,0.9,0.4,1.7,0.6l0,0l1.2,0.3c0.6,0.2,1.1,0.3,1.3,0.4c0.3,0.2,0.5,0.5,0.5,0.9c0,0.5-0.2,0.9-0.6,1.1\n                    s-0.9,0.4-1.5,0.4c-0.9,0-1.6-0.2-2-0.7c-0.2-0.3-0.3-0.6-0.4-1.1l0,0H6.8c0,0.9,0.3,1.6,0.9,2.2C8.2,19.5,9.2,19.8,10.5,19.8z\"/>\n                <defs>\n                  <filter id=\"Adobe_OpacityMaskFilter\" filterUnits=\"userSpaceOnUse\" x=\"15.2\" y=\"10.3\" width=\"6.2\" height=\"9.5\">\n                    <feColorMatrix  type=\"matrix\" values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"/>\n                  </filter>\n                </defs>\n                <mask maskUnits=\"userSpaceOnUse\" x=\"15.2\" y=\"10.3\" width=\"6.2\" height=\"9.5\" id=\"mask-2_2_\">\n                  <g class=\"st2\">\n                    <path id=\"path-1_2_\" class=\"st3\" d=\"M24.1,23.1h-20c-0.6,0-1.2-0.5-1.2-1.2V8.2C2.9,7.5,3.5,7,4.1,7h19.7c0.8,0,1.4,0.6,1.4,1.4\n                      v13.5C25.2,22.6,24.7,23.1,24.1,23.1z\"/>\n                  </g>\n                </mask>\n                <defs>\n                  <filter id=\"Adobe_OpacityMaskFilter_1_\" filterUnits=\"userSpaceOnUse\" x=\"6.8\" y=\"10.3\" width=\"7.3\" height=\"9.5\">\n                    <feColorMatrix  type=\"matrix\" values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 1 0\"/>\n                  </filter>\n                </defs>\n                <mask maskUnits=\"userSpaceOnUse\" x=\"6.8\" y=\"10.3\" width=\"7.3\" height=\"9.5\" id=\"mask-2_3_\">\n                  <g class=\"st5\">\n                    <path id=\"path-1_3_\" class=\"st3\" d=\"M24.1,23.1h-20c-0.6,0-1.2-0.5-1.2-1.2V8.2C2.9,7.5,3.5,7,4.1,7h19.7c0.8,0,1.4,0.6,1.4,1.4\n                      v13.5C25.2,22.6,24.7,23.1,24.1,23.1z\"/>\n                  </g>\n                </mask>\n                </svg>\n                ") + "<span class='speed-select-mask' style=\"display:none\" id=\"".concat(this.jSPlugin.id, "-select-hd-mask\"></span>") + '</span>';
+
+          btnItem.onclick = function (e) {
+            var _this9$decoderState$s8 = _this9.decoderState.state,
+                hd = _this9$decoderState$s8.hd,
+                expend = _this9$decoderState$s8.expend; // 閫夋嫨娓呮櫚搴﹂�夐」鏃舵墠瑙﹀彂浜嬩欢
+
+            if (hd && e.target.id === "".concat(_this9.jSPlugin.id, "-select-sd")) {
+              //decoder.changePlayUrl({ hd: false });
+              console.log("鍒囨崲鍒版爣娓�");
+
+              _this9.jSPlugin.changeVideoLevel(0);
+
+              _this9.setDecoderState({
+                hd: false
+              });
+            } else if (!hd && e.target.id === "".concat(_this9.jSPlugin.id, "-select-hd")) {
+              _this9.jSPlugin.changeVideoLevel(1);
+
+              _this9.setDecoderState({
+                hd: true
+              });
+            }
+
+            _this9.showHD = !_this9.showHD;
+
+            if (document.getElementById("".concat(_this9.jSPlugin.id, "-hdSelect"))) {
+              document.getElementById("".concat(_this9.jSPlugin.id, "-hdSelect")).style.display = document.getElementById("".concat(_this9.jSPlugin.id, "-hdSelect")).style.display === 'none' ? 'block' : 'none';
+
+              if (_this9.isMobile) {
+                document.getElementById("".concat(_this9.jSPlugin.id, "-select-hd-mask")).style.display = document.getElementById("".concat(_this9.jSPlugin.id, "-select-hd-mask")).style.display === 'none' ? 'block' : 'none';
+              }
+            }
+
+            if (_this9.isMobile && expend && _this9.showHD) {
+              document.getElementById("".concat(_this9.jSPlugin.id, "-hdSelect")).className = "hd speed-select mobile expend";
+            } else {
+              document.getElementById("".concat(_this9.jSPlugin.id, "-hdSelect")).className = _this9.isMobile ? "hd speed-select mobile" : "speed-select";
+            }
+          };
+
+          return btnItem;
+
+        case 'speed':
+          btnItem.title = "鍥炴斁鍊嶉��";
+          btnItem.id = btnId;
+          btnItem.domString = "<ul id=\"".concat(this.jSPlugin.id, "-speedSelect\" class=\"speed speed-select ").concat(this.isMobile ? "mobile" : "", "\" style=\"display:none;\">") + "<li class=\"selectOption default\" style=\"height: 45px;text-align: center;line-height: 45px;list-style: none;cursor: pointer;font-size: 13px;\" name=\"option\" id=\"".concat(this.jSPlugin.id, "-select-speed4\">4\u500D</li>") + "<li class=\"selectOption default\" style=\"height: 45px;text-align: center;line-height: 45px;list-style: none;cursor: pointer;font-size: 13px;\" name=\"option\" id=\"".concat(this.jSPlugin.id, "-select-speed2\">2\u500D</li>") + "<li class=\"selectOption active\" style=\"height: 45px;text-align: center;line-height: 45px;list-style: none;cursor: pointer;font-size: 13px;\" name=\"option\" id=\"".concat(this.jSPlugin.id, "-select-speed1\">1\u500D\uFF08\u6B63\u5E38\u64AD\u653E\uFF09</li>") + "<li class=\"selectOption default\" style=\"height: 45px;text-align: center;line-height: 45px;list-style: none;cursor: pointer;font-size: 13px;\" name=\"option\" id=\"".concat(this.jSPlugin.id, "-select-speed05\">0.5\u500D</li>") + "<li class=\"selectOption cancel\" style=\"".concat(this.isMobile ? "" : "display:none;", "\" name=\"option\" id=\"").concat(this.jSPlugin.id, "-select-speed\">\u53D6\u6D88</li>") + '</ul>' + "<span>\n          <div style=\"font-size: 12px;\n          vertical-align: bottom;\n          display: inline-flex;\n          padding: 0px 7px;\n          width: 48px;\n          line-height: 24px;\n          justify-content: center;\n          border: 1px solid ".concat(btnItem.color, ";\n          text-align: center;border-radius: 12.5px;\"\n          id=\"").concat(this.jSPlugin.id, "-speed-text\"\n          >").concat(this.nextRate === 1 ? "鍊嶉��" : "".concat(this.nextRate, "\u500D").replace("3", "0.5"), "</div>\n                ") + "<span class='speed-select-mask' style=\"display:none\" id=\"".concat(this.jSPlugin.id, "-select-mask\"></span>") + '</span>';
+
+          var setLiActive = function setLiActive(index) {
+            console.log("setLiActive", index);
+            document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[0].className = document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[0].className.replace("active", "default");
+            document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[1].className = document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[1].className.replace("active", "default");
+            document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[2].className = document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[2].className.replace("active", "default");
+            document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[3].className = document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[3].className.replace("active", "default");
+            document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[index].className = document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).childNodes[index].className.replace("default", "active");
+          };
+
+          if (!this.isMobile) {
+            btnItem.onmouseenter = function (e) {
+              console.log("榧犳爣绉诲叆", e);
+
+              _this9.setDecoderState({
+                speed: true
+              });
+
+              if (document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect"))) {
+                document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).style.display = 'block';
+              }
+            };
+
+            btnItem.onmouseleave = function (e) {
+              console.log("榧犳爣绉诲嚭", e);
+
+              _this9.setDecoderState({
+                speed: false
+              });
+
+              if (document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect"))) {
+                document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).style.display = 'none';
+              }
+            };
+          }
+
+          btnItem.onclick = function (e) {
+            var _this9$decoderState$s9 = _this9.decoderState.state,
+                speed = _this9$decoderState$s9.speed,
+                expend = _this9$decoderState$s9.expend;
+
+            if (!speed && _this9.isMobile) {
+              document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).className = expend ? "speed speed-select mobile expend" : "speed speed-select mobile";
+            }
+
+            _this9.nextRate = 1; // 閫夋嫨娓呮櫚搴﹂�夐」鏃舵墠瑙﹀彂浜嬩欢
+            // if(this.isMobile) {
+            //   console.log("璇锋墽琛岀Щ鍔ㄧ鍊嶉��");
+            //   return false;
+            // }
+
+            if (e.target.id) {
+              switch (e.target.id) {
+                case "".concat(_this9.jSPlugin.id, "-select-speed1"):
+                  // case `${this.jSPlugin.id}-select-speed`:
+                  console.log("鍊嶉��1");
+                  _this9.nextRate = 1;
+
+                  _this9.jSPlugin.jSPlugin.JS_Speed(_this9.nextRate);
+
+                  if (document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text"))) {
+                    document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text")).innerHTML = "鍊嶉��";
+                    setLiActive(2);
+                  }
+
+                  _this9.setDecoderState({
+                    speed: !speed
+                  });
+
+                  break;
+
+                case "".concat(_this9.jSPlugin.id, "-select-speed2"):
+                  console.log("鍊嶉��2");
+                  _this9.nextRate = 2;
+
+                  _this9.jSPlugin.jSPlugin.JS_Speed(_this9.nextRate);
+
+                  if (document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text"))) {
+                    document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text")).innerHTML = "2鍊�"; // 璁剧疆2鍊嶉�熼�変腑鏁堟灉
+
+                    setLiActive(1);
+                  }
+
+                  _this9.setDecoderState({
+                    speed: !speed
+                  });
+
+                  break;
+
+                case "".concat(_this9.jSPlugin.id, "-select-speed4"):
+                  console.log("鍊嶉��4");
+                  _this9.nextRate = 4;
+
+                  _this9.jSPlugin.jSPlugin.JS_Speed(_this9.nextRate);
+
+                  if (document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text"))) {
+                    document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text")).innerHTML = "4鍊�";
+                    setLiActive(0);
+                  }
+
+                  _this9.setDecoderState({
+                    speed: !speed
+                  });
+
+                  break;
+
+                case "".concat(_this9.jSPlugin.id, "-select-speed05"):
+                  console.log("鍊嶉��05");
+                  _this9.nextRate = 3;
+
+                  _this9.jSPlugin.jSPlugin.JS_Speed(_this9.nextRate);
+
+                  if (document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text"))) {
+                    document.getElementById("".concat(_this9.jSPlugin.id, "-speed-text")).innerHTML = "0.5鍊�";
+                    setLiActive(3);
+                  }
+
+                  _this9.setDecoderState({
+                    speed: !speed
+                  });
+
+                  break;
+
+                default:
+                  // if(document.getElementById(`${this.jSPlugin.id}-speed-text`)){
+                  //   document.getElementById(`${this.jSPlugin.id}-speed-text`).innerHTML = this.nextRate +"鍊�";
+                  // }
+                  // pc 绔偣鍑讳笉鍐嶉殣钘忥紝鍙�氳繃绉诲嚭闅愯棌
+                  if (!_this9.isMobile) {
+                    _this9.setDecoderState({
+                      speed: true
+                    });
+                  } else {
+                    _this9.setDecoderState({
+                      speed: !speed
+                    });
+                  }
+
+                  break;
+              }
+            } // pc 绔偣鍑讳笉鍐嶉殣钘忥紝鍙�氳繃绉诲嚭闅愯棌
+
+
+            if (!_this9.isMobile && e.target.id === "".concat(_this9.jSPlugin.id, "-speed-text")) {
+              document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).style.display = 'block';
+            } else {
+              if (document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect"))) {
+                document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).style.display = document.getElementById("".concat(_this9.jSPlugin.id, "-speedSelect")).style.display === 'none' ? 'block' : 'none';
+              }
+            }
+          };
+
+          return btnItem;
+
+        case 'deviceName':
+          btnItem.title = "璁惧鍚嶇О";
+          btnItem.id = btnId;
+          btnItem.domString = '<span>璁惧鍚嶇О</span>';
+
+          btnItem.onclick = function () {};
+
+          return btnItem;
+
+        case 'deviceID':
+          btnItem.title = "璁惧搴忓垪鍙�";
+          btnItem.id = btnId;
+          btnItem.domString = '<span>璁惧搴忓垪鍙�</span>';
+
+          btnItem.onclick = function () {};
+
+          return btnItem;
+
+        case 'cloudRec':
+          btnItem.title = "浜戝瓨鍌ㄥ洖鏀�";
+          btnItem.id = btnId;
+          btnItem.domString = "\n        <span>\n          <svg fill=\"".concat(btnItem.color, "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"  width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"-10 0 40 15\">\n\t<path d=\"M9.5,13.1c-0.3,0-0.5-0.2-0.5-0.5V8.8c0-0.3,0.2-0.5,0.5-0.5S10,8.5,10,8.8v3.8C10,12.8,9.8,13.1,9.5,13.1z\"/>\n\t<path d=\"M7.6,10.6c-0.1,0-0.3-0.1-0.4-0.2C7,10.2,7,9.9,7.3,9.7l1.9-1.7c0.2-0.2,0.5-0.2,0.7,0l1.8,1.7\n\t\tc0.2,0.2,0.2,0.5,0,0.7c-0.2,0.2-0.5,0.2-0.7,0L9.5,9.1l-1.6,1.4C7.8,10.6,7.7,10.6,7.6,10.6z\"/>\n\t<path d=\"M13.2,15.7H5.6c-2.1-0.1-3.8-1.8-3.8-3.9c0-1.8,1.3-3.4,3-3.8c0.4-2.2,2.3-3.9,4.6-3.9c2.3,0,4.2,1.7,4.6,3.8\n\t\tc1.8,0.4,3.1,1.9,3.1,3.8C17.1,13.9,15.4,15.7,13.2,15.7z M5.6,14.7h7.6c1.6,0,2.9-1.3,2.9-2.9c0-1.5-1.1-2.7-2.6-2.9l-0.4,0l0-0.4\n\t\tc-0.2-1.9-1.7-3.3-3.6-3.3C7.5,5.1,6,6.6,5.8,8.5l0,0.4l-0.4,0c-1.4,0.2-2.5,1.4-2.5,2.9C2.8,13.3,4.1,14.6,5.6,14.7z\"/>\n          </svg>\n        </span>\n        ");
+
+          btnItem.onclick = function () {
+            console.log("鐐瑰嚮浜戝洖鏀�");
+
+            _this9.setDecoderState({
+              type: 'cloud.rec',
+              cloudRec: true,
+              rec: false
+            });
+
+            _this9.jSPlugin.changePlayUrl({
+              type: 'cloud.rec'
+            });
+
+            console.log(_this9.jSPlugin);
+            var initDate = getQueryString("begin", _this9.jSPlugin.url) || new Date().Format('yyyyMMdd');
+
+            _this9.Rec.renderRec("".concat(initDate.slice(0, 4), "-").concat(initDate.slice(4, 6), "-").concat(initDate.slice(6, 8)));
+          };
+
+          return btnItem;
+
+        case 'rec':
+          btnItem.title = "鏈湴瀛樺偍";
+          btnItem.id = btnId;
+          btnItem.domString = "\n        <span>\n        <svg fill=".concat(btnItem.color, " version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"  width=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" height=\"").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "\" viewBox=\"0 0 40 15\">\n          <path d=\"M13,16.3H5.5c-1.1,0-2-0.9-2-2V3.8c0-1.1,0.9-2,2-2h5.4c0.5,0,1,0.2,1.4,0.6l2.1,2.1C14.8,4.8,15,5.3,15,5.9\n  v8.4C15,15.4,14.1,16.3,13,16.3z M5.5,2.8c-0.6,0-1,0.4-1,1v10.5c0,0.6,0.4,1,1,1H13c0.6,0,1-0.4,1-1V5.9c0-0.3-0.1-0.5-0.3-0.7\n  L11.6,3c-0.2-0.2-0.4-0.3-0.7-0.3H5.5z\"/>\n<path d=\"M6.3,7.3C6,7.3,5.8,7,5.8,6.8V4.5C5.8,4.2,6,4,6.3,4s0.5,0.2,0.5,0.5v2.2C6.8,7,6.6,7.3,6.3,7.3z\"/>\n<path d=\"M8.5,7.3C8.3,7.3,8,7,8,6.8V4.5C8,4.2,8.3,4,8.5,4S9,4.2,9,4.5v2.2C9,7,8.8,7.3,8.5,7.3z\"/>\n<path d=\"M10.8,7.3c-0.3,0-0.5-0.2-0.5-0.5V4.5c0-0.3,0.2-0.5,0.5-0.5s0.5,0.2,0.5,0.5v2.2C11.3,7,11.1,7.3,10.8,7.3z\"\n  />\n        </svg>\n      </span>\n        ");
+
+          btnItem.onclick = function () {
+            console.log("鐐瑰嚮鏈湴鍥炴斁");
+
+            _this9.setDecoderState({
+              type: 'rec',
+              cloudRec: false,
+              rec: true
+            });
+
+            _this9.jSPlugin.changePlayUrl({
+              type: 'rec'
+            });
+
+            console.log(_this9.jSPlugin);
+            var initDate = getQueryString("begin", _this9.jSPlugin.url) || new Date().Format('yyyyMMdd');
+
+            _this9.Rec.renderRec("".concat(initDate.slice(0, 4), "-").concat(initDate.slice(4, 6), "-").concat(initDate.slice(6, 8)));
+          };
+
+          return btnItem;
+
+        default:
+          return btnItem;
+      }
+    }
+  }, {
+    key: "initThemeData",
+    value: function initThemeData() {
+      var _this10 = this;
+
+      var _this$themeData4 = this.themeData,
+          header = _this$themeData4.header,
+          footer = _this$themeData4.footer;
+      var videoId = this.jSPlugin.id;
+      this.header = defaultTheme.header;
+      this.footer = defaultTheme.footer;
+      this.isNeedRenderHeader = lodash.findIndex(header.btnList, function (v) {
+        return v.isrender > 0;
+      }) >= 0;
+
+      if (this.isMobile) {
+        // 绉诲姩绔洖鏀撅紝闇�瑕佸垽鏂澶囧簭鍒楀彿锛岃澶囧悕绉�
+        this.isNeedRenderHeader = lodash.findIndex(header.btnList, function (v) {
+          return v.isrender > 0 && v.iconId === "deviceID" || v.isrender > 0 && v.iconId === "deviceName";
+        }) >= 0;
+      }
+
+      this.isNeedRenderFooter = lodash.findIndex(footer.btnList, function (v) {
+        return v.isrender > 0;
+      }) >= 0;
+      this.isNeedRenderTimeLine = lodash.findIndex(header.btnList, function (v) {
+        return v.iconId === 'cloudRec' && v.isrender === 1 || v.iconId === 'rec' && v.isrender === 1;
+      }) >= 0 && !this.jSPlugin.disabledTimeLine;
+      ["date-switch-container-wrap", "rec-type-container-wrap", "mobile-rec-wrap", "mobile-ez-ptz-container"].forEach(function (item, index) {
+        if (document.getElementById(item)) {
+          document.getElementById(item).parentElement.removeChild(document.getElementById(item));
+        }
+      });
+
+      if (this.isNeedRenderHeader) {
+        if (!document.getElementById("".concat(this.jSPlugin.id, "-headControl"))) {
+          var headerContainer = document.createElement('div');
+          headerContainer.setAttribute('id', "".concat(this.jSPlugin.id, "-headControl"));
+          headerContainer.setAttribute('class', 'header-controls');
+          headerContainer.innerHTML = "<div id='".concat(this.jSPlugin.id, "-headControl-left' class=\"header-controls-left\" style='display:flex'></div><div id='").concat(this.jSPlugin.id, "-headControl-right' class=\"header-controls-right\" style='display:flex'></div>");
+          var headerStyle = {
+            height: this.jSPlugin.width > MEDIAWIDTH ? "48px" : "32px",
+            "line-height": this.jSPlugin.width > MEDIAWIDTH ? "48px" : "32px",
+            display: "flex",
+            "justify-content": "space-between",
+            top: 0,
+            "z-index": 1,
+            background: "#000000",
+            color: "#FFFFFF",
+            width: "100%"
+          };
+          headerContainer.style = styleToString(headerStyle);
+          document.getElementById("".concat(videoId, "-wrap")).insertBefore(headerContainer, document.getElementById(videoId)); // 澶撮儴棰勭暀x鍍忕礌绌洪棿
+
+          var _checkTimer2 = setInterval(function () {
+            if (window.EZUIKit[_this10.jSPlugin.id].state.EZUIKitPlayer.init) {
+              clearInterval(_checkTimer2); // 妫�娴嬪埌娓叉煋澶撮儴锛屾墽琛屼竴娆eSize
+              // this.jSPlugin.reSize(this.jSPlugin.params.width,this.jSPlugin.params.height);
+            }
+          }, 50);
+        } else {
+          document.getElementById("".concat(this.jSPlugin.id, "-headControl")).innerHTML = "<div id='".concat(this.jSPlugin.id, "-headControl-left' style='display:flex'></div><div id='").concat(this.jSPlugin.id, "-headControl-right' style='display:flex'></div>");
+        }
+      } else {
+        if (document.getElementById("".concat(this.jSPlugin.id, "-headControl"))) {
+          document.getElementById("".concat(this.jSPlugin.id, "-headControl")).parentElement.removeChild(document.getElementById("".concat(this.jSPlugin.id, "-headControl")));
+        } // this.jSPlugin.reSize(this.jSPlugin.params.width,this.jSPlugin.params.height);
+
+      }
+
+      if (this.isNeedRenderFooter) {
+        if (!document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container"))) {
+          var footerContainer = document.createElement('div');
+          footerContainer.setAttribute('id', "".concat(this.jSPlugin.id, "-ez-iframe-footer-container"));
+          footerContainer.setAttribute('class', 'ez-iframe-footer-container');
+          var footerStyle = {
+            "min-height": this.jSPlugin.width > MEDIAWIDTH ? "48px" : "32px",
+            "max-height": this.jSPlugin.width > MEDIAWIDTH ? "96px" : "80px",
+            "position": "relative",
+            "margin-top": this.jSPlugin.width > MEDIAWIDTH ? "-48px" : "-32px",
+            display: "flex",
+            "flex-wrap": "wrap",
+            "justify-content": "space-between",
+            "z-index": 999,
+            top: 0,
+            color: "#FFFFFF",
+            width: "100%"
+          };
+          footerContainer.style = styleToString(footerStyle);
+          footerContainer.innerHTML = "<div id=\"".concat(this.jSPlugin.id, "-audioControls\" class=\"footer-controls\" style='display:flex;height:").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "px;justify-content: space-between;width:100%;z-index:999;position: relative;'><div id='").concat(this.jSPlugin.id, "-audioControls-left' class=\"footer-controls-left\" style='display:flex;margin-lefacti'></div><div id='").concat(this.jSPlugin.id, "-audioControls-right' class=\"footer-controls-right\" style='display:flex'></div></div>");
+          insertAfter$1(footerContainer, document.getElementById(videoId));
+        } else {
+          if (document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container"))) {
+            document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container")).innerHTML = "<div id=\"".concat(this.jSPlugin.id, "-audioControls\"  class=\"footer-controls\" style='display:flex;justify-content: space-between;height: ").concat(this.jSPlugin.width > MEDIAWIDTH ? 48 : 32, "px;width:100%;'><div id='").concat(this.jSPlugin.id, "-audioControls-left' class=\"footer-controls-left\" style='display:flex'></div><div id='").concat(this.jSPlugin.id, "-audioControls-right' class=\"footer-controls-right\" style='display:flex'></div></div>");
+          }
+        }
+      } else {
+        if (document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container"))) {
+          document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container")).parentElement.removeChild(document.getElementById("".concat(this.jSPlugin.id, "-ez-iframe-footer-container")));
+        }
+      }
+
+      if (this.isNeedRenderHeader && document.getElementById("".concat(this.jSPlugin.id, "-headControl"))) {
+        document.getElementById("".concat(this.jSPlugin.id, "-headControl")).style.background = header.backgroundColor;
+        document.getElementById("".concat(this.jSPlugin.id, "-headControl")).style.color = header.color;
+        header.btnList.map(function (item, index) {
+          if (item.isrender) {
+            _this10.renderHeader(item.iconId, item.part);
+          }
+        });
+      }
+
+      if (this.isNeedRenderFooter && document.getElementById("".concat(this.jSPlugin.id, "-audioControls"))) {
+        document.getElementById("".concat(this.jSPlugin.id, "-audioControls")).style.background = footer.backgroundColor;
+        document.getElementById("".concat(this.jSPlugin.id, "-audioControls")).style.color = footer.color;
+        footer.btnList.map(function (item, index) {
+          if (item.isrender) {
+            _this10.renderFooter(item.iconId, item.part);
+          }
+        });
+      }
+
+      if (this.isNeedRenderTimeLine) {
+        if (this.isMobile) {
+          if (document.getElementById("".concat(this.jSPlugin.id, "-headControl-right"))) {
+            document.getElementById("".concat(this.jSPlugin.id, "-headControl-right")).style.display = "none";
+          }
+
+          this.Rec = new MobileRec(this.jSPlugin);
+        } else {
+          this.Rec = new Rec(this.jSPlugin); // 鍥炴斁鏃堕棿杞撮鐣�48鍍忕礌绌洪棿
+
+          var _checkTimer3 = setInterval(function () {
+            if (window.EZUIKit[_this10.jSPlugin.id].state.EZUIKitPlayer.init) {
+              clearInterval(_checkTimer3); // 妫�娴嬪埌娓叉煋鍥炴斁鏃堕棿杞达紝鎵ц涓�娆eSize
+              // this.jSPlugin.reSize(this.jSPlugin.params.width, this.jSPlugin.params.height);
+            }
+          }, 50);
+        }
+      }
+
+      var isNeedRenderPTZ = lodash.findIndex(this.themeData.footer.btnList, function (v) {
+        return v.iconId === 'pantile' && v.isrender === 1;
+      }) >= 0 && !this.jSPlugin.disabledPTZ;
+
+      if (isNeedRenderPTZ) {
+        if (this.isMobile) {
+          this.MobilePtz = new MobilePtz(this.jSPlugin);
+        }
+
+        this.Ptz = new Ptz(this.jSPlugin);
+      } //  鐩戝惉鍏ㄥ睆浜嬩欢瑙﹀彂
+
+
+      var fullscreenchange = function fullscreenchange() {
+        var _this10$decoderState$ = _this10.decoderState.state,
+            expend = _this10$decoderState$.expend,
+            webExpend = _this10$decoderState$.webExpend;
+        var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+
+        if (!isFullScreen) {
+          _this10.jSPlugin.reSize(_this10.jSPlugin.params.width, _this10.jSPlugin.params.height);
+
+          if (expend) {
+            _this10.setDecoderState({
+              expend: false
+            });
+          }
+
+          if (webExpend) {
+            _this10.setDecoderState({
+              webExpend: false
+            });
+          }
+        }
+      };
+
+      ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange'].forEach(function (item) {
+        window.addEventListener(item, function (data) {
+          return fullscreenchange();
+        });
+      }); // // 鍒ゆ柇鏄惁閰嶇疆灏侀潰
+
+      if (this.themeData.poster) {
+        this.jSPlugin.poster = this.themeData.poster;
+        var checkTimer = setInterval(function () {
+          if (window.EZUIKit[_this10.jSPlugin.id].state.EZUIKitPlayer.init) {
+            clearInterval(checkTimer);
+
+            _this10.jSPlugin.setPoster(_this10.themeData.poster);
+          }
+        }, 50);
+      }
+
+      this.inited = true; //璁惧淇℃伅
+
+      this.getDeviceInfo();
+    }
+  }, {
+    key: "getDeviceInfo",
+    value: function getDeviceInfo() {
+      var _this11 = this;
+
+      var deviceAPISuccess = function deviceAPISuccess(data) {
+        if (data.code == 200 && data.data) {
+          // 璁惧搴忓垪鍙�
+          if (document.getElementById("".concat(_this11.jSPlugin.id, "-deviceName-content"))) {
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceName-content")).style.maxWidth = "160px";
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceName-content")).style.overflow = "hidden";
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceName-content")).style.textOverflow = "ellipsis";
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceName-content")).innerHTML = data.data.deviceName;
+          } // 璁惧搴忓垪鍙�
+
+
+          if (document.getElementById("".concat(_this11.jSPlugin.id, "-deviceID-content"))) {
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceID-content")).style.maxWidth = "160px";
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceID-content")).style.overflow = "hidden";
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceID-content")).style.textOverflow = "ellipsis";
+            document.getElementById("".concat(_this11.jSPlugin.id, "-deviceID-content")).innerHTML = matchEzopenUrl(_this11.jSPlugin.url).deviceSerial;
+          }
+        }
+      };
+
+      request(this.jSPlugin.env.domain + '/api/lapp/device/info', 'POST', {
+        accessToken: this.jSPlugin.accessToken,
+        deviceSerial: matchEzopenUrl(this.jSPlugin.url).deviceSerial
+      }, '', deviceAPISuccess);
+    }
+  }, {
+    key: "editStart",
+    value: function editStart(callback) {
+      var audioControlsDOM = document.getElementById("".concat(this.jSPlugin.id, "-audioControls"));
+      var headerMessageDOM = document.getElementById("".concat(this.jSPlugin.id, "-headControl"));
+
+      if (headerMessageDOM) {
+        headerMessageDOM.setAttribute('class', 'header-controls themeEditing');
+      }
+
+      if (audioControlsDOM) {
+        audioControlsDOM.setAttribute('class', 'footer-controls themeEditing');
+      }
+
+      this.setDecoderState({
+        isEditing: true
+      });
+    }
+  }, {
+    key: "editEnd",
+    value: function editEnd(callback) {
+      var audioControlsDOM = document.getElementById("".concat(this.jSPlugin.id, "-audioControls"));
+      var headerMessageDOM = document.getElementById("".concat(this.jSPlugin.id, "-headControl"));
+
+      if (headerMessageDOM) {
+        headerMessageDOM.setAttribute('class', 'header-controls');
+      }
+
+      if (audioControlsDOM) {
+        audioControlsDOM.setAttribute('class', 'footer-controls');
+      }
+
+      this.setDecoderState({
+        isEditing: false
+      });
+    }
+  }, {
+    key: "webExpend",
+    value: function webExpend() {
+      var _this12 = this;
+
+      var _this$decoderState$st = this.decoderState.state;
+          _this$decoderState$st.webExpend;
+          var expend = _this$decoderState$st.expend,
+          play = _this$decoderState$st.play;
+
+      if (!play) {
+        return false;
+      }
+
+      if (expend) {
+        console.log("姝e湪鍏ㄥ眬鍏ㄥ睆");
+        return false;
+      }
+
+      console.log("鎵ц缃戦〉鍏ㄥ睆");
+      var footerDOMHeight = 0;
+      var headerDOMHeight = 0; // ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange'].forEach((item) => {
+      //   window.addEventListener(item, (data) => fullscreenchange("fullscreenchange", data));
+      // });
+      // //  鐩戝惉鍏ㄥ睆浜嬩欢瑙﹀彂
+      // function fullscreenchange() {
+      //   let isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+      //   return isFullScreen;
+      // }
+
+      var promise = requestFullScreenPromise(document.getElementById("".concat(this.jSPlugin.id, "-wrap")));
+      promise.then(function (data) {
+        console.log("鍏ㄥ睆promise", window.screen.availWidth);
+
+        if (document.getElementById("".concat(_this12.jSPlugin.id, "-canvas-container"))) {
+          footerDOMHeight = parseInt(window.getComputedStyle(document.getElementById("".concat(_this12.jSPlugin.id, "-canvas-container"))).height, 10);
+        }
+
+        if (document.getElementById("".concat(_this12.jSPlugin.id, "-headControl"))) {
+          headerDOMHeight = parseInt(window.getComputedStyle(document.getElementById("".concat(_this12.jSPlugin.id, "-headControl"))).height, 10);
+        }
+
+        console.log("this.jSPlugin.JS_Resiz", footerDOMHeight, headerDOMHeight, document.body.clientWidth);
+
+        _this12.jSPlugin.jSPlugin.JS_Resize(window.screen.availWidth, window.screen.availHeight - footerDOMHeight - headerDOMHeight);
+      })["catch"](function (err) {
+        console.log(err);
+      });
+    }
+  }, {
+    key: "expend",
+    value: function expend() {
+      var _this13 = this;
+
+      var _this$decoderState$st2 = this.decoderState.state,
+          webExpend = _this$decoderState$st2.webExpend;
+          _this$decoderState$st2.expend;
+          var play = _this$decoderState$st2.play;
+          _this$decoderState$st2.pantile;
+
+      if (!play) {
+        return false;
+      }
+
+      if (webExpend) {
+        console.log("姝e湪缃戠珯鍏ㄥ睆");
+        return false;
+      }
+
+      console.log("鎵ц鍏ㄥ眬鍏ㄥ睆");
+
+      if (this.isMobile) {
+        var heightIntercept = parseInt(getComputedStyle(document.getElementById("".concat(this.jSPlugin.id, "-wrap"))).height, 10) - parseInt(getComputedStyle(document.getElementById(this.jSPlugin.id)).height, 10);
+        requestMobileFullScreen(document.getElementById("".concat(this.jSPlugin.id, "-wrap")));
+        setTimeout(function () {
+          var width = document.documentElement.clientWidth;
+          var height = document.documentElement.clientHeight; // 鍏煎寰俊娴忚鍣╢ooter琚殣钘�
+          // document.getElementById(`${this.jSPlugin.id}-ez-iframe-footer-container`).style.marginTop = "0px";
+          // document.getElementById(`${this.jSPlugin.id}-headControl`).style.position = "absolute";
+
+          document.getElementById("".concat(_this13.jSPlugin.id)).style["backface-visibility"] = "hidden";
+
+          _this13.jSPlugin.jSPlugin.JS_Resize(height, width - heightIntercept);
+        }, 100);
+      } else {
+        var promise = requestFullScreenPromise(document.getElementById("".concat(this.jSPlugin.id)));
+        promise.then(function (data) {
+          _this13.jSPlugin.jSPlugin.JS_Resize(window.screen.availWidth, window.screen.availHeight);
+        })["catch"](function (err) {
+          console.log(err);
+        });
+      }
+    }
+  }]);
+
+  return Theme;
+}();
+
+Date.prototype.Format = function (fmt) {
+  //author: meizz
+  var o = {
+    "M+": this.getMonth() + 1,
+    //鏈堜唤
+    "d+": this.getDate(),
+    //鏃�
+    "h+": this.getHours(),
+    //灏忔椂
+    "m+": this.getMinutes(),
+    //鍒�
+    "s+": this.getSeconds(),
+    //绉�
+    "q+": Math.floor((this.getMonth() + 3) / 3),
+    //瀛e害
+    "S": this.getMilliseconds() //姣
+
+  };
+  if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+
+  for (var k in o) {
+    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
+  }
+
+  return fmt;
+};
+
+var Monitor = /*#__PURE__*/function () {
+  function Monitor(params, jsPlugin) {
+    _classCallCheck$1(this, Monitor);
+
+    this.params = params;
+    this.state = {};
+    this.jsPlugin = jsPlugin;
+    this.url = "https://log.ys7.com/statistics.do?";
+
+    if (params.env) {
+      switch (params.env) {
+        case 'test12':
+          this.url = "https://test12dclog.ys7.com/statistics.do?";
+          break;
+
+        case 'online':
+          break;
+
+        default:
+          this.url = params.env;
+          break;
+      }
+    }
+  }
+  /** 鐢熸垚uuid */
+
+
+  _createClass$1(Monitor, [{
+    key: "uuid",
+    value: function uuid() {
+      var s = [];
+      var hexDigits = "0123456789abcdef";
+
+      for (var i = 0; i < 36; i++) {
+        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
+      }
+      s[14] = "4";
+      s[19] = hexDigits.substr(s[19] & 0x3 | 0x8, 1);
+      s[8] = s[13] = s[18] = s[23] = "-";
+      var uuid = s.join("");
+      return uuid;
+    }
+  }, {
+    key: "dclog",
+    value: function dclog(dclogObj) {
+      var imgUrl = this.url;
+      var obj = Object.assign({}, {
+        systemName: "open_website_monitor"
+      }, {
+        bn: "ezuikit-js"
+      }, dclogObj, {
+        un: dclogObj.url
+      }, {
+        st: new Date().getTime(),
+        h: window.location.pathname
+      }); // usr_name 鏇存敼涓簎n锛屽吋瀹规棫
+
+      Object.keys(obj).forEach(function (item, index) {
+        var value = obj[item];
+
+        if (typeof obj[item] === 'string') {
+          value = obj[item].replace('%', '%25'); // decodeURIComponent 鏃犳硶瑙f瀽%
+        }
+
+        if (typeof obj[item] === 'undefined') {
+          return;
+        }
+
+        imgUrl += "".concat(index === 0 ? '' : '&').concat(item, "=").concat(encodeURIComponent(value));
+      });
+      var img = new Image();
+      img.src = imgUrl;
+    }
+  }, {
+    key: "localInfoLog",
+    value: function localInfoLog(dclogObj) {
+      var imgUrl = this.url; // var obj = Object.assign({}, { systemName: "open_netstream_localinfo" }, dclogObj, {un:dclogObj.url}, { st: new Date().getTime(), h: window.location.pathname }); // usr_name 鏇存敼涓簎n锛屽吋瀹规棫
+
+      var domain = window.location.protocol + '//' + window.location.host;
+      var obj = {
+        systemName: "open_netstream_localinfo",
+        Ver: 'v6.0.0',
+        PlatAddr: domain,
+        ExterVer: 'v6.0.0',
+        OpId: this.uuid(),
+        CltType: 102,
+        AppId: "",
+        playurl: encodeURIComponent(this.jsPlugin.url),
+        StartTime: new Date().Format('yyyy-MM-dd hh:mm:ss.S'),
+        // 姣忎釜鏃ュ織鍖呭惈褰撳墠鐨勬椂闂�
+        OS: navigator.platform
+      };
+      obj = Object.assign(obj, dclogObj);
+      Object.keys(obj).forEach(function (item, index) {
+        var value = obj[item];
+
+        if (typeof obj[item] === 'string') {
+          value = obj[item].replace('%', '%25'); // decodeURIComponent 鏃犳硶瑙f瀽%
+        }
+
+        if (typeof obj[item] === 'undefined') {
+          return;
+        }
+
+        imgUrl += "".concat(index === 0 ? '' : '&').concat(item, "=").concat(encodeURIComponent(value));
+      });
+      var img = new Image();
+      img.src = imgUrl;
+    }
+  }, {
+    key: "playLog",
+    value: function playLog(dclogObj) {
+      var url = this.url;
+      var imgUrl = url;
+      var obj = {
+        systemName: "open_netstream_play_main",
+        playurl: encodeURIComponent(this.jsPlugin.url),
+        Time: new Date().Format('yyyy-MM-dd hh:mm:ss.S'),
+        //Enc: 0,  // 0 涓嶅姞瀵� 1 鍔犲瘑
+        //PlTp: PlTp,  // 1 鐩存挱 2 鍥炴斁
+        Via: 2,
+        // 2 鏈嶅姟绔彇娴�
+        //ErrCd: 0,
+        OpId: this.uuid() //Cost: (new Date()).getTime() - _this.initTime,  // 姣鏁�
+        //Serial: getQueryString('dev', item),
+        //Channel: getQueryString('chn', item),
+
+      };
+      obj = Object.assign(obj, dclogObj);
+      Object.keys(obj).forEach(function (item, index) {
+        var value = obj[item];
+
+        if (typeof obj[item] === 'string') {
+          value = obj[item].replace('%', '%25'); // decodeURIComponent 鏃犳硶瑙f瀽%
+        }
+
+        if (typeof obj[item] === 'undefined') {
+          return;
+        }
+
+        imgUrl += "".concat(index === 0 ? '' : '&').concat(item, "=").concat(encodeURIComponent(value));
+      });
+      var img = new Image();
+      img.src = imgUrl;
+    }
+  }]);
+
+  return Monitor;
+}();
+
+(function (global, factory) {
+
+  if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && _typeof(module.exports) === "object") {
+    module.exports = global.document ? factory(global, true) : function (w) {
+      if (!w.document) {
+        throw new Error("EZUIPlayer requires a window with a document");
+      }
+
+      return factory(w);
+    };
+  } else {
+    factory(global);
+  } // Pass this if window is not defined yet
+
+})(typeof window !== "undefined" ? window : void 0, function (window, noGlobal) {
+  var _state;
+
+  // 鍔犺浇js
+  function addJs(filepath, callback) {
+    var headerScript = document.getElementsByTagName('head')[0].getElementsByTagName("script");
+    var isReady = false;
+
+    for (var i = 0; i < headerScript.length; i++) {
+      if (headerScript[i].getAttribute("src") == filepath) {
+        isReady = true;
+        callback();
+      }
+    }
+
+    if (!isReady) {
+      var oJs = document.createElement("script");
+      oJs.setAttribute("src", filepath);
+      oJs.onload = callback;
+      document.getElementsByTagName("head")[0].appendChild(oJs);
+    }
+  } // 鍔犺浇css
+
+
+  function addCss(filepath, callback) {
+    var headerLink = document.getElementsByTagName('head')[0].getElementsByTagName("link");
+    var isReady = false;
+
+    for (var i = 0; i < headerLink.length; i++) {
+      if (headerLink[i].getAttribute("href") == filepath) {
+        isReady = true;
+        callback();
+      }
+    }
+
+    if (!isReady) {
+      var oJs = document.createElement('link');
+      oJs.rel = 'stylesheet';
+      oJs.type = 'text/css';
+      oJs.href = filepath;
+      oJs.onload = callback;
+      document.getElementsByTagName("head")[0].appendChild(oJs);
+    }
+  } // 閫氱敤璇锋眰鏂规硶
+
+
+  function request(url, method, params, header, success, error) {
+    var _url = url;
+    var http_request = new XMLHttpRequest();
+
+    http_request.onreadystatechange = function () {
+      if (http_request.readyState == 4) {
+        if (http_request.status == 200) {
+          var _data = JSON.parse(http_request.responseText);
+
+          success(_data);
+        }
+      }
+    };
+
+    http_request.open(method, _url, true); // http_request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+
+    var data = new FormData();
+
+    for (var i in params) {
+      data.append(i, params[i]);
+    }
+
+    http_request.send(data);
+  }
+
+
+  var EZUIKit = {
+    EZUIKitPlayer: undefined,
+    EZUIKitTalk: undefined,
+    opt: {
+      apiDomain: 'https://open.ys7.com/api/lapp/live/talk/url',
+      filePath: 'https://open.ys7.com/assets/ezuikit_v2.6.4',
+      accessToken: '',
+      url: '',
+      deviceSerial: '',
+      channelNo: '',
+      id: '',
+      talkLink: '',
+      rtcUrl: '',
+      ttsUrl: '',
+      stream: '',
+      // 瀵硅鎻掍欢渚濊禆
+      isReliesReady: false,
+      template: 'simple',
+      plugin: [],
+      // 鍔犺浇鎻掍欢锛宼alk-瀵硅
+      audio: 1,
+      // 澹伴煶id  0-涓嶅紑鍚� 1-寮�鍚�
+      autoplay: 1,
+      videoLoading: false
+    },
+    state: (_state = {
+      countTimer: undefined,
+      // countTime 璁℃椂鍣�
+      recodeTime: 0,
+      // 褰曢煶鏃堕棿
+      recodeTimer: undefined
+    }, _defineProperty(_state, "recodeTime", 0), _defineProperty(_state, "fetchDefaultList", false), _defineProperty(_state, "page", 0), _defineProperty(_state, "pageSize", 5), _state),
+    handleTalkSuccess: function handleTalkSuccess() {},
+    handleTalkError: function handleTalkError() {}
+  };
+  /**
+   * 瑙嗛鎾斁鍣�-寮�濮�
+   */
+
+  var domain = "https://open.ys7.com";
+  var filePathDomain = domain;
+
+  var EZUIKitPlayer = function EZUIKitPlayer(params) {
+    var _this = this;
+
+    this.opt = {
+      id: params.id,
+      apiDomain: domain + '/api/lapp/live/talk/url',
+      filePath: filePathDomain + '/assets/ezuikit_v2.6.4',
+      decoderVersion: '',
+      accessToken: '',
+      url: '',
+      deviceSerial: '',
+      channelNo: '',
+      talkLink: '',
+      rtcUrl: '',
+      ttsUrl: '',
+      stream: '',
+      // 瀵硅鎻掍欢渚濊禆
+      isReliesReady: false,
+      template: 'simple',
+      plugin: [],
+      // 鍔犺浇鎻掍欢锛宼alk-瀵硅
+      audio: 1,
+      // 澹伴煶id  0-涓嶅紑鍚� 1-寮�鍚�
+      autoplay: 1,
+      fullScreenStatus: 0,
+      bSupporDoubleClickFull: true,
+      videoLoading: false
+    };
+    this.params = params;
+
+    if (params.id) {
+      this.opt.id = params.id;
+    }
+
+    if (params.accessToken) {
+      this.opt.accessToken = params.accessToken;
+    }
+
+    if (typeof params.audio !== 'undefined') {
+      this.opt.audio = params.audio;
+    }
+
+    if (typeof params.decoderVersion !== 'undefined') {
+      this.opt.decoderVersion = params.decoderVersion;
+    }
+
+    if (typeof params.env !== 'undefined') {
+      if (typeof params.env.domain !== 'undefined') {
+        domain = params.env.domain;
+        this.opt.apiDomain = domain + '/api/lapp/live/talk/url';
+      }
+
+      if (typeof params.env.filePathDomain !== 'undefined') {
+        filePathDomain = params.env.filePathDomain;
+        this.opt.filePathDomain = params.env.filePathDomain;
+      }
+    } // if(typeof params.domain !== 'undefined'){
+    //   this.opt.apiDomain = params.domain + '/api/lapp/live/talk/url';
+    // }
+
+
+    if (params.url) {
+      this.opt.url = params.url;
+      this.opt.deviceSerial = params.url.split("/")[3];
+      this.opt.channelNo = params.url.split("/")[4].split(".")[0];
+    }
+
+    if (typeof params.template !== 'undefined') {
+      this.opt.template = params.template;
+    }
+
+    if (params.plugin) {
+      this.opt.plugin = params.plugin;
+    }
+
+    if (typeof params.autoplay !== 'undefined') {
+      this.opt.autoplay = params.autoplay ? 1 : 0;
+    }
+
+    if (typeof params.bSupporDoubleClickFull !== 'undefined') {
+      this.opt.bSupporDoubleClickFull = params.bSupporDoubleClickFull;
+    }
+
+    if (typeof params.handleTalkSuccess !== 'undefined') {
+      window.EZUIKit.handleTalkSuccess = params.handleTalkSuccess;
+    }
+
+    if (typeof params.handleTalkError !== 'undefined') {
+      window.EZUIKit.handleTalkError = params.handleTalkError;
+    }
+
+    var id = this.opt.id;
+    var domElement = document.getElementById(id); // 闂撮殭
+
+    domElement.style.fontSize = 0;
+    domElement.style.overflowY = 'auto';
+    domElement.style.position = 'relative';
+    /**
+     * 娓叉煋iframe瑙嗛妗�
+     */
+
+    var iframe = document.createElement('iframe');
+
+    function matchIframeUrl() {
+      switch (_this.opt.template) {
+        case 'simple':
+          var iframeUrl = domain + "/ezopen/h5/iframe?bSupporDoubleClickFull=0&url=" + _this.opt.url.replace("?", "&") + "&autoplay=" + _this.opt.autoplay + "&audio=" + _this.opt.audio + "&accessToken=" + params.accessToken + "&templete=0" + "&id=" + id + "&decoderVersion=" + _this.opt.decoderVersion;
+
+          var controlsValue = "";
+
+          if (typeof params.controls !== 'undefined' && params.controls) {
+            console.log("typeof", _typeof(params.controls));
+            controlsValue = "play,voice,hd,fullScreen";
+
+            if (params.controls.length > 0) {
+              controlsValue = params.controls.join(",");
+              iframeUrl += '&controls=' + controlsValue;
+            }
+          }
+
+          if (params.websocketParams) {
+            iframeUrl += '&websocketParams=' + JSON.stringify(params.websocketParams);
+          }
+
+          return iframeUrl;
+
+        case 'standard':
+          return domain + "/ezopen/h5/iframe?bSupporDoubleClickFull=0&url=" + _this.opt.url.replace("?", "&") + "&autoplay=" + _this.opt.autoplay + "&audio=" + _this.opt.audio + "&accessToken=" + params.accessToken + "&templete=1" + "&id=" + id + "&decoderVersion=" + _this.opt.decoderVersion;
+
+        case 'security':
+          return domain + "/ezopen/h5/iframe_se?bSupporDoubleClickFull=0&url=" + _this.opt.url.replace("?", "&") + "&autoplay=" + _this.opt.autoplay + "&audio=" + _this.opt.audio + "&accessToken=" + params.accessToken + "&templete=0" + "&id=" + id + "&decoderVersion=" + _this.opt.decoderVersion;
+
+        case 'theme':
+          iframeUrl = domain + "/jssdk/theme.html?url=".concat(params.url, "&accessToken=").concat(params.accessToken, "&id=").concat(id, "&isMobile=").concat(params.isMobile);
+
+          if (typeof params.isMobile !== 'undefined') {
+            iframeUrl += '&isMobile=' + params.isMobile;
+          }
+
+          if (typeof params.autoplay !== 'undefined') {
+            iframeUrl += '&autoplay=' + params.autoplay;
+          }
+
+          if (typeof params.domain !== 'undefined') {
+            if (params.domain == 'https://test12open.ys7.com') iframeUrl += '&env=' + 'test12';
+          }
+
+          if (typeof params.env !== 'undefined') {
+            if (typeof params.env.domain !== 'undefined') {
+              if (params.env.domain == 'https://test12open.ys7.com') {
+                iframeUrl += '&env=' + 'test12';
+              }
+            }
+          }
+
+          if (typeof params.header !== 'undefined') {
+            iframeUrl += '&header=' + params.header;
+          }
+
+          return iframeUrl;
+
+        default:
+          return domain + "/ezopen/h5/iframe?bSupporDoubleClickFull=0&url=" + _this.opt.url.replace("?", "&") + "&autoplay=" + _this.opt.autoplay + "&audio=" + _this.opt.audio + "&accessToken=" + params.accessToken + "&templete=0" + "&id=" + id + "&decoderVersion=" + _this.opt.decoderVersion;
+      }
+    }
+
+    iframe.src = matchIframeUrl(); // 榛樿鍙栧鍣ㄥ楂�
+
+    var iframeHeight = document.getElementById(id).offsetHeight;
+    var iframeWidth = document.getElementById(id).offsetWidth;
+
+    if (params.height) {
+      iframeHeight = parseInt(params.height);
+
+      if (/\%$/.test(params.height)) {
+        iframeWidth = document.getElementById(id).offsetWidth * (parseInt(params.height) / 100);
+      }
+    }
+
+    if (params.width) {
+      iframeWidth = parseInt(params.width);
+
+      if (/\%$/.test(params.width)) {
+        iframeWidth = document.getElementById(id).offsetWidth * (parseInt(params.width) / 100);
+      }
+    }
+
+    iframe.width = iframeWidth;
+    iframe.height = iframeHeight;
+    iframe.id = 'EZUIKitPlayer-' + id; // 閮ㄥ垎iframe灞炴��
+
+    iframe.setAttribute("allowfullscreen", true);
+    iframe.setAttribute("allow", "autoplay");
+    iframe.setAttribute("frameborder", 0);
+    domElement.appendChild(iframe);
+    var jqueryJS = _this.opt.filePath + '/js/jquery.js';
+    var layerJs = 'https://open.ys7.com/assets/layer/layer.js';
+    addJs(jqueryJS, function () {
+      addJs(layerJs, function () {
+        //   });
+        // });
+
+        /**
+        * 娓叉煋header
+        */
+        if (matchHeaderOpt().headerContainer) {
+          // if (params.header && params.header instanceof Array) {
+          var headerContainer = document.createElement('div');
+          headerContainer.setAttribute('class', 'panel-top');
+          var controsDOM = document.createElement('div');
+          controsDOM.setAttribute('class', 'contros');
+          headerContainer.appendChild(controsDOM);
+          domElement.insertBefore(headerContainer, iframe);
+
+          if (matchHeaderOpt().capturePictureModule) {
+            // 鎴浘
+            var capturePictureDOM = document.createElement('span');
+            capturePictureDOM.innerHTML = '<span title="鎴浘">' + '<svg id="capturePicture" title="鎴浘" t="1578882764585" class="icon" viewBox="0 0 1024 1024" version="1.1"' + '  xmlns="http://www.w3.org/2000/svg" p-id="5958" width="24" height="24">' + '  <path' + '    d="M887.296 315.904h-153.6c-51.2 0-68.096-102.4-119.296-102.4H392.704c-34.304 0-51.2 102.4-102.4 102.4h-153.6c-29.696 0-51.2 21.504-51.2 51.2v439.296c0 25.6 21.504 47.104 51.2 47.104h751.104c29.696 0 51.2-21.504 51.2-51.2v-435.2c-0.512-30.208-21.504-51.2-51.712-51.2zM512 768c-115.2 0-204.8-89.6-204.8-200.704s89.6-200.704 204.8-200.704 204.8 89.6 204.8 200.704-93.696 200.704-204.8 200.704z m247.296-354.304c-12.8 0-25.6-12.8-25.6-25.6s12.8-25.6 25.6-25.6 25.6 12.8 25.6 25.6c0 17.408-12.8 25.6-25.6 25.6zM256 264.704c0-8.704-8.704-16.896-16.896-16.896h-51.2c-8.704 0-16.896 8.704-16.896 16.896V281.6H256v-16.896z m256 148.992c-85.504 0-153.6 68.096-153.6 153.6s68.096 153.6 153.6 153.6 153.6-68.096 153.6-153.6-68.096-153.6-153.6-153.6z"' + '    fill="#ffffff" p-id="5959"></path>' + '</svg>' + '</span>';
+
+            capturePictureDOM.onclick = function () {
+              _this.capturePicture();
+            };
+
+            controsDOM.appendChild(capturePictureDOM);
+          }
+
+          console.log("matchHeaderOpt().saveModule", matchHeaderOpt().saveModule);
+
+          if (matchHeaderOpt().saveModule) {
+            var startSaveDOM = document.createElement('span');
+            startSaveDOM.innerHTML = '<span title="寮�濮嬪綍鍍�">' + '  <svg id="startSave" t="1578882716693" class="icon" viewBox="0 0 1024 1024" version="1.1"' + '    xmlns="http://www.w3.org/2000/svg" p-id="3782" width="24" height="24">' + '    <path' + '      d="M915.2 729.6l-128-76.8c-25.6-12.8-44.8-32-44.8-51.2V435.2c0-25.6 19.2-38.4 44.8-51.2l128-76.8c25.6-12.8 44.8 0 44.8 19.2V704c0 32-19.2 38.4-44.8 25.6z m-332.8 89.6H96c-51.2 0-89.6-38.4-89.6-89.6V332.8c0-51.2 38.4-89.6 89.6-89.6h486.4c51.2 0 89.6 38.4 89.6 89.6v396.8c0 51.2-38.4 89.6-89.6 89.6zM192 364.8c-32 6.4-57.6 32-64 64-12.8 57.6 38.4 115.2 96 102.4 32-6.4 57.6-32 64-70.4 12.8-57.6-38.4-108.8-96-96z m0 0"' + '      p-id="3783" fill="#ffffff"></path>' + '  </svg>' + '</span>';
+
+            startSaveDOM.onclick = function () {
+              _this.startSave();
+
+              document.getElementById('startSave').setAttribute('class', 'icon hide');
+              document.getElementById('stopSave').setAttribute('class', 'icon');
+            };
+
+            controsDOM.appendChild(startSaveDOM);
+            var stopSaveDOM = document.createElement('span');
+            stopSaveDOM.innerHTML = '<span title="缁撴潫褰曞儚">' + ' <svg id="stopSave" t="1578882716693" class="icon hide" viewBox="0 0 1024 1024" version="1.1"' + '   xmlns="http://www.w3.org/2000/svg" p-id="3782" width="24" height="24">' + '   <path' + '     d="M915.2 729.6l-128-76.8c-25.6-12.8-44.8-32-44.8-51.2V435.2c0-25.6 19.2-38.4 44.8-51.2l128-76.8c25.6-12.8 44.8 0 44.8 19.2V704c0 32-19.2 38.4-44.8 25.6z m-332.8 89.6H96c-51.2 0-89.6-38.4-89.6-89.6V332.8c0-51.2 38.4-89.6 89.6-89.6h486.4c51.2 0 89.6 38.4 89.6 89.6v396.8c0 51.2-38.4 89.6-89.6 89.6zM192 364.8c-32 6.4-57.6 32-64 64-12.8 57.6 38.4 115.2 96 102.4 32-6.4 57.6-32 64-70.4 12.8-57.6-38.4-108.8-96-96z m0 0"' + '     p-id="3783" fill="red"></path>' + ' </svg>' + ' </span>';
+
+            stopSaveDOM.onclick = function () {
+              _this.stopSave();
+
+              document.getElementById('stopSave').setAttribute('class', 'icon hide');
+              document.getElementById('startSave').setAttribute('class', 'icon');
+            };
+
+            controsDOM.appendChild(stopSaveDOM);
+          }
+
+          if (matchHeaderOpt().zoomModule) {
+            var enableZoomDOM = document.createElement('span');
+            enableZoomDOM.innerHTML = '<span title="寮�鍚數瀛愭斁澶�">' + '  <svg id="enableZoom" t="1578882639834" class="icon" viewBox="0 0 1000 1000" version="1.1"' + '    xmlns="http://www.w3.org/2000/svg" p-id="2227" width="24" height="24">' + '    <path' + '      d="M830.6119 441.1089c0-193.7756-157.0939-350.8641-350.8775-350.8641S128.8559 247.3333 128.8559 441.1089 285.9508 791.972 479.7344 791.972 830.6119 634.8845 830.6119 441.1089zM483.2821 710.4863c-146.7975 0-265.8187-118.9953-265.8187-265.8088S336.4847 178.8697 483.2821 178.8697s265.8197 118.9953 265.8197 265.8078S630.0796 710.4863 483.2821 710.4863zM770.6031 653.5739l-72.6417 75.9485 141.6917 160.1814 82.0737-90.0739L770.6031 653.5739zM527.5849 267.4727h-88.60655762279428v132.90489048425167H306.0690340253259v88.60292721534799h132.90933675248866v132.9038911617923h88.60655762279428V488.9794719180395h132.90933675248866v-88.60292721534799H527.5849284006089V267.4726535408993z"' + '      p-id="2228" fill="#ffffff"></path>' + '  </svg>' + '</span>';
+
+            enableZoomDOM.onclick = function () {
+              _this.enableZoom();
+
+              document.getElementById('enableZoom').setAttribute('class', 'icon hide');
+              document.getElementById('closeZoom').setAttribute('class', 'icon');
+            };
+
+            controsDOM.appendChild(enableZoomDOM);
+            var closeZoomDOM = document.createElement('span');
+            closeZoomDOM.innerHTML = '<span title="鍏抽棴鐢靛瓙鏀惧ぇ">' + '  <svg id="closeZoom" t="1578882639834" class="icon hide" viewBox="0 0 1000 1000" version="1.1"' + '    xmlns="http://www.w3.org/2000/svg" p-id="2227" width="24" height="24">' + '    <path' + '      d="M830.6119 441.1089c0-193.7756-157.0939-350.8641-350.8775-350.8641S128.8559 247.3333 128.8559 441.1089 285.9508 791.972 479.7344 791.972 830.6119 634.8845 830.6119 441.1089zM483.2821 710.4863c-146.7975 0-265.8187-118.9953-265.8187-265.8088S336.4847 178.8697 483.2821 178.8697s265.8197 118.9953 265.8197 265.8078S630.0796 710.4863 483.2821 710.4863zM770.6031 653.5739l-72.6417 75.9485 141.6917 160.1814 82.0737-90.0739L770.6031 653.5739zM527.5849 267.4727h-88.60655762279428v132.90489048425167H306.0690340253259v88.60292721534799h132.90933675248866v132.9038911617923h88.60655762279428V488.9794719180395h132.90933675248866v-88.60292721534799H527.5849284006089V267.4726535408993z"' + '      p-id="2228" fill="red"></path>' + '  </svg>' + '</span>';
+
+            closeZoomDOM.onclick = function () {
+              _this.closeZoom();
+
+              document.getElementById('closeZoom').setAttribute('class', 'icon hide');
+              document.getElementById('enableZoom').setAttribute('class', 'icon');
+            };
+
+            controsDOM.appendChild(closeZoomDOM);
+          }
+        }
+        /**
+         * 娓叉煋footer
+         */
+
+        /** 鏍规嵁閰嶇疆鍖归厤搴曢儴娓叉煋 */
+
+
+        function matchFooterOpt() {
+          var result = {
+            footerContainer: false,
+            talkModule: false,
+            broadcastModule: false,
+            hdModule: false,
+            fullScreenModule: false
+          };
+          var template = _this.opt.template;
+
+          switch (template) {
+            case 'simple':
+              if (params.footer && params.footer instanceof Array) {
+                var footer = params.footer;
+                result = {
+                  footerContainer: true,
+                  talkModule: footer.indexOf('talk') !== -1,
+                  broadcastModule: footer.indexOf('broadcast') !== -1,
+                  hdModule: footer.indexOf('hd') !== -1,
+                  fullScreenModule: footer.indexOf('fullScreen') !== -1
+                };
+              }
+
+              break;
+
+            case 'standard':
+              if (params.footer && params.footer instanceof Array) {
+                var footer = params.footer;
+                result = {
+                  footerContainer: true,
+                  talkModule: footer.indexOf('talk') !== -1,
+                  broadcastModule: footer.indexOf('broadcast') !== -1,
+                  hdModule: footer.indexOf('hd') !== -1,
+                  fullScreenModule: footer.indexOf('fullScreen') !== -1
+                };
+              }
+
+              break;
+
+            case 'security':
+              break;
+
+            case 'voice':
+              result = {
+                footerContainer: true,
+                talkModule: true,
+                broadcastModule: true,
+                hdModule: true,
+                fullScreenModule: true
+              };
+              break;
+          }
+
+          return result;
+        }
+        /** 鏍规嵁閰嶇疆鍖归厤搴曢儴娓叉煋 */
+
+
+        function matchHeaderOpt() {
+          var result = {
+            headerContainer: false,
+            capturePictureModule: false,
+            saveModule: false,
+            zoomModule: false
+          };
+          var template = _this.opt.template;
+
+          switch (template) {
+            case 'simple':
+              if (params.header && params.header instanceof Array) {
+                var header = params.header;
+                result = {
+                  headerContainer: true,
+                  capturePictureModule: header.indexOf('capturePicture') !== -1,
+                  saveModule: header.indexOf('save') !== -1,
+                  zoomModule: header.indexOf('zoom') !== -1
+                };
+              }
+
+              break;
+
+            case 'standard':
+              break;
+
+            case 'security':
+              break;
+
+            case 'voice':
+              result = {
+                headerContainer: true,
+                capturePictureModule: true,
+                saveModule: true,
+                zoomModule: true
+              };
+              break;
+          }
+
+          return result;
+        }
+
+        if (matchFooterOpt().footerContainer || _this.opt.plugin.indexOf('talk') !== -1) {
+          var recoderCSS = _this.opt.filePath + '/npm/css/recoder.css';
+          var recoderJs = _this.opt.filePath + '/npm/js/recoder.js';
+          var recorderJs = _this.opt.filePath + '/recorder.js'; // addCss()
+
+          addCss(recoderCSS, function () {});
+          addJs(recoderJs, function () {
+            addJs(recorderJs, function () {});
+          }); // 瀵硅妯″潡
+
+          if (_this.opt.plugin.indexOf('talk') !== -1 || matchFooterOpt().talkModule) {
+            var apiSuccess = function apiSuccess(data) {
+              console.log("data", data);
+
+              if (data.code == 200) {
+                var apiResult = data.data;
+
+                if (apiResult) {
+                  // 涓存椂灏唄ttps杞崲涓簑ebsocket
+                  var rtcTrunk = apiResult.rtcUrl;
+
+                  if (rtcTrunk.indexOf("ws") === -1) {
+                    rtcTrunk = rtcTrunk.replace("https", "wss").replace("rtcgw", "rtcgw-ws");
+                  }
+
+                  _this.opt.rtcUrl = rtcTrunk;
+                  _this.opt.ttsUrl = "tts://" + apiResult.ttsUrl;
+                  var talk = "talk://" + _this.opt.deviceSerial + ":0:" + _this.opt.channelNo + ":cas.ys7.com:6500";
+                  _this.opt.talkLink = _this.opt.ttsUrl + "/" + talk;
+                  _this.opt.stream = apiResult.stream;
+                  console.log("_this.opt", _this.opt); // 鍔犺浇渚濊禆
+
+                  if (!_this.opt.isReliesReady) {
+                    var adapeterJS = _this.opt.filePath + '/npm/js/adapeter.js';
+                    var janusJS = _this.opt.filePath + '/npm/js/janus.js';
+                    var ttsJS = _this.opt.filePath + '/npm/js/tts.js';
+                    console.log("鍔犺浇jquery.js");
+                    addJs(adapeterJS, function () {
+                      console.log("鍔犺浇adapeter.js");
+                      addJs(janusJS, function () {
+                        console.log("鍔犺浇janus.js");
+                        addJs(ttsJS, function () {
+                          console.log("鍔犺浇tts.js"); // 鏂囦欢鍔犺浇瀹屾瘯;
+
+                          _this.opt.isReliesReady = true;
+                        });
+                      });
+                    }, function () {
+                      return !!window.adapter;
+                    });
+                  } // 鍒涘缓DOM
+
+
+                  if (!document.getElementById("audioleft")) {
+                    var audioleft = document.createElement('div');
+                    audioleft.style.display = 'none';
+                    audioleft.id = 'audioleft';
+                    document.body.appendChild(audioleft);
+                  }
+
+                  if (!document.getElementById("audioright")) {
+                    var audioright = document.createElement('div');
+                    audioright.style.display = 'none';
+                    audioright.id = 'audioright';
+                    document.body.appendChild(audioright);
+                  }
+                }
+              }
+
+              EZUIKit.opt = _this.opt;
+
+              if (window.EZUIKit) {
+                window.EZUIKit.opt = _this.opt;
+              }
+            };
+
+            request(_this.opt.apiDomain, 'POST', {
+              accessToken: _this.opt.accessToken,
+              deviceSerial: _this.opt.deviceSerial,
+              channelNo: _this.opt.channelNo
+            }, '', apiSuccess);
+          }
+
+          if (matchFooterOpt().footerContainer) {
+            /* 鏃堕棿璁℃暟 */
+            var countTime = function countTime(type, start) {
+              clearInterval(EZUIKit.state.countTimer);
+
+              if (type === 'add') {
+                var i = start;
+                EZUIKit.state.countTimer = setInterval(function () {
+                  ++i;
+                  document.getElementById("time-area").innerHTML = formatSeconds(i);
+                }, 1000);
+              } else if (type === 'sub') {
+                var i = start;
+                EZUIKit.state.countTimer = setInterval(function () {
+                  if (i > 0) {
+                    i--;
+                    document.getElementById("time-area").innerHTML = formatSeconds(i);
+                  } else {
+                    clearInterval(EZUIKit.state.countTimer);
+                    EZUIKit.state.countTimer = undefined;
+                    console.log("鍊掕鏃剁粨鏉燂紝寮�鍚0闊�"); // decoder.openSound(0);
+                  }
+                }, 1000);
+              } else if (type === 'destory') {
+                clearInterval(EZUIKit.state.countTimer);
+                EZUIKit.state.countTimer = undefined;
+                document.getElementById("time-area").innerHTML = '00:00';
+              } //灏嗙鏁拌浆鎹负鏃跺垎绉掓牸寮�
+
+
+              function formatSeconds(value) {
+                var theTime = parseInt(value); // 绉�
+
+                var middle = 0; // 鍒�
+
+                var hour = 0; // 灏忔椂
+
+                var secondV = '00';
+                var minV = '00';
+                var hourV = '00';
+
+                if (theTime > 59) {
+                  middle = parseInt(theTime / 60);
+                  theTime = parseInt(theTime % 60);
+
+                  if (middle > 59) {
+                    hour = parseInt(middle / 60);
+                    middle = parseInt(middle % 60);
+                  }
+                }
+
+                secondV = parseInt(theTime) > 9 ? parseInt(theTime) : '0' + parseInt(theTime);
+                minV = parseInt(middle) > 9 ? parseInt(middle) : '0' + parseInt(middle);
+                hourV = parseInt(hour) > 9 ? parseInt(hour) : '0' + parseInt(hour);
+
+                if (hour > 0) {
+                  return hourV + ':' + minV + ':' + secondV;
+                } else if (middle > 0) {
+                  return minV + ':' + secondV;
+                } else {
+                  return '00:' + secondV;
+                }
+              }
+            };
+
+            // 搴曢儴瀹瑰櫒
+            var footerContainer = document.createElement('div');
+            footerContainer.setAttribute("class", 'audio-controls');
+            domElement.appendChild(footerContainer);
+
+            if (matchFooterOpt().hdModule || matchFooterOpt().fullScreenModule) {
+              // 搴曢儴鍙充晶鍏冪礌
+              var rightContros = document.createElement('div');
+              rightContros.setAttribute('class', 'contros');
+              footerContainer.appendChild(rightContros);
+
+              if (matchFooterOpt().hdModule) {
+                // 楂樻竻-鏍囨竻鍒囨崲
+                var hdDom = document.createElement('span');
+                hdDom.setAttribute('id', 'video-hd');
+                hdDom.innerHTML = _this.opt.url.indexOf('.hd') === -1 ? '鏍囨竻' : '楂樻竻';
+
+                hdDom.onclick = function () {
+                  // 鍋滄
+                  if (_this.opt.videoLoading) {
+                    layer.msg("瑙嗛鍔犺浇涓紝璇风◢鍚�");
+                    return false;
+                  } else {
+                    var stopPromise = _this.stop();
+
+                    _this.opt.videoLoading = true;
+                    stopPromise.then(function (data) {
+                      _this.opt.videoLoading = false;
+
+                      if (_this.opt.url.indexOf('.hd') === -1) {
+                        _this.opt.url = _this.opt.url.replace('.live', '.hd.live');
+                        hdDom.innerHTML = _this.opt.url.indexOf('.hd') === -1 ? '鏍囨竻' : '楂樻竻';
+                      } else {
+                        _this.opt.url = _this.opt.url.replace('.hd.live', '.live');
+                        hdDom.innerHTML = _this.opt.url.indexOf('.hd') === -1 ? '鏍囨竻' : '楂樻竻';
+                      }
+
+                      _this.play(_this.opt.url);
+                    })["catch"](function (error) {
+                      console.log("error", error);
+                    });
+                  } //iframe.src = domain +"/ezopen/h5/iframe?url=" + _this.opt.url.replace('.hd.live', '.live') + "&autoplay=1&audio=" + _this.opt.audio + "&accessToken=" + _this.opt.accessToken + "&templete=" + 0;
+
+                };
+
+                rightContros.appendChild(hdDom);
+              }
+
+              if (matchFooterOpt().fullScreenModule) {
+                // 澹伴煶鎺у埗
+                var openSoundDOM = document.createElement('span');
+                openSoundDOM.setAttribute('class', 'hide');
+                openSoundDOM.setAttribute('id', 'ezuikit-open-sound');
+                openSoundDOM.setAttribute('title', '鎵撳紑澹伴煶');
+                openSoundDOM.setAttribute('style', 'vertical-align: top;');
+                openSoundDOM.innerHTML = '<svg t="1590476263239" class="icon" viewBox="0 0 1178 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2273" width="16" height="16"><path d="M665.6 51.2 665.6 51.2c-10.24-30.72-40.96-51.2-71.68-51.2-5.12 0-15.36 0-20.48 5.12l0 0L358.4 153.6 51.2 209.92l0 0C20.48 220.16 0 250.88 0 281.6 0 286.72 0 291.84 0 307.2l0 0 0 409.6 0 0c0 15.36 0 20.48 0 25.6 0 30.72 20.48 61.44 51.2 71.68l0 0L358.4 870.4l97.28 71.68 107.52 76.8 0 0c5.12 5.12 15.36 5.12 25.6 5.12 40.96 0 76.8-35.84 76.8-76.8 0-10.24 0-10.24 0-25.6l0 0L665.6 51.2zM563.2 870.4l-153.6-102.4-307.2-51.2L102.4 307.2l307.2-51.2 153.6-102.4L563.2 870.4z" p-id="2274" fill="#FF0000"></path><path d="M1049.6 537.6l112.64-112.64c20.48-20.48 20.48-56.32 0-76.8-20.48-20.48-56.32-20.48-76.8 0L972.8 460.8l-112.64-112.64c0 0 0 0 0 0-20.48-20.48-56.32-20.48-76.8 0 0 0 0 0 0 0-20.48 20.48-20.48 56.32 0 76.8l112.64 112.64-112.64 112.64c-20.48 20.48-20.48 56.32 0 76.8 20.48 20.48 56.32 20.48 76.8 0L972.8 614.4l112.64 112.64c20.48 20.48 56.32 20.48 76.8 0s20.48-56.32 0-76.8L1049.6 537.6z" p-id="2275" fill="#FF0000"></path></svg>';
+
+                openSoundDOM.onclick = function () {
+                  _this.openSound(0);
+
+                  openSoundDOM.setAttribute('class', 'hide');
+                  closeSoundDOM.setAttribute('class', '');
+                }; // 澹伴煶鎺у埗
+
+
+                var closeSoundDOM = document.createElement('span');
+                openSoundDOM.setAttribute('id', 'ezuikit-close-sound');
+                closeSoundDOM.setAttribute('class', 'hide');
+                closeSoundDOM.setAttribute('title', '鍏抽棴澹伴煶');
+                closeSoundDOM.setAttribute('style', 'vertical-align: top;');
+                closeSoundDOM.innerHTML = '<svg t="1590414410633" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20545" width="16" height="16"><path d="M840.533333 98.133333c-17.066667-17.066667-42.666667-17.066667-59.733333 0-17.066667 17.066667-17.066667 42.666667 0 59.733334C883.2 256 938.666667 392.533333 938.666667 533.333333c0 140.8-55.466667 277.333333-157.866667 375.466667-17.066667 17.066667-17.066667 42.666667 0 59.733333 8.533333 8.533333 21.333333 12.8 29.866667 12.8 8.533333 0 21.333333-4.266667 29.866666-12.8 115.2-110.933333 183.466667-268.8 183.466667-435.2 0-166.4-68.266667-324.266667-183.466667-435.2zM571.733333 12.8c-17.066667-8.533333-34.133333-4.266667-46.933333 8.533333L281.6 256H42.666667c-25.6 0-42.666667 17.066667-42.666667 42.666667v426.666666c0 25.6 17.066667 42.666667 42.666667 42.666667h238.933333l243.2 234.666667c8.533333 8.533333 17.066667 12.8 29.866667 12.8 4.266667 0 12.8 0 17.066666-4.266667 17.066667-8.533333 25.6-21.333333 25.6-38.4V51.2c0-17.066667-8.533333-34.133333-25.6-38.4zM512 870.4l-183.466667-179.2c-8.533333-4.266667-17.066667-8.533333-29.866666-8.533333H85.333333V341.333333h213.333334c12.8 0 21.333333-4.266667 29.866666-12.8L512 153.6v716.8z" p-id="20546" fill="#ffffff"></path><path d="M759.466667 349.866667c-12.8-21.333333-38.4-25.6-59.733334-8.533334-21.333333 12.8-25.6 38.4-8.533333 59.733334 21.333333 29.866667 34.133333 76.8 34.133333 123.733333 0 46.933333-12.8 93.866667-34.133333 123.733333-12.8 21.333333-8.533333 46.933333 8.533333 59.733334 8.533333 4.266667 17.066667 8.533333 25.6 8.533333 12.8 0 25.6-4.266667 34.133334-17.066667 34.133333-46.933333 51.2-106.666667 51.2-174.933333 0-68.266667-17.066667-128-51.2-174.933333z" p-id="20547" fill="#ffffff"></path></svg>';
+
+                closeSoundDOM.onclick = function () {
+                  _this.closeSound(0);
+
+                  openSoundDOM.setAttribute('class', '');
+                  closeSoundDOM.setAttribute('class', 'hide');
+                };
+
+                rightContros.appendChild(openSoundDOM);
+                rightContros.appendChild(closeSoundDOM);
+              } // 鏍规嵁褰撳墠闊抽閰嶇疆灞曠ず
+
+
+              if (_this.opt.audio == 1) {
+                closeSoundDOM.setAttribute('class', '');
+              } else {
+                openSoundDOM.setAttribute('class', '');
+
+                _this.closeSound(0);
+              }
+
+              if (matchFooterOpt().fullScreenModule) {
+                // 鍏ㄥ睆鎺у埗
+                var fullScreenDOM = document.createElement('span');
+                fullScreenDOM.setAttribute('title', '鍏ㄥ睆');
+                fullScreenDOM.setAttribute('style', 'vertical-align: top;');
+                fullScreenDOM.innerHTML = '<svg id="fullScreen" t="1578020167938" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5035" width="16" height="16"> <path d="M348.373333 625.706667l-128 128-64 64v-128a33.28 33.28 0 0 0-35.413333-35.413334A33.493333 33.493333 0 0 0 85.333333 689.706667v213.333333A33.706667 33.706667 0 0 0 120.96 938.666667h213.333333a35.626667 35.626667 0 0 0 0-71.04h-128l64-64 128-128a35.2 35.2 0 0 0-49.92-49.92zM206.293333 156.373333h128a33.28 33.28 0 0 0 35.413334-35.413333A33.493333 33.493333 0 0 0 334.293333 85.333333H113.706667c-7.04 0-14.08 7.04-21.333334 14.293334a26.026667 26.026667 0 0 0-7.04 21.333333v213.333333a33.493333 33.493333 0 0 0 35.626667 35.413334 33.28 33.28 0 0 0 35.413333-35.413334v-128l192 192a35.2 35.2 0 0 0 49.92-49.92zM903.04 85.333333h-213.333333a33.493333 33.493333 0 0 0-35.413334 35.626667 33.28 33.28 0 0 0 35.413334 35.413333h128l-64 64-128 128a35.2 35.2 0 0 0 49.92 49.92l128-128 64-64v128a35.626667 35.626667 0 0 0 71.04 0v-213.333333A33.706667 33.706667 0 0 0 903.04 85.333333zM903.04 654.293333a33.28 33.28 0 0 0-35.413333 35.413334v128l-64-64-128-128a35.2 35.2 0 0 0-49.92 49.92l128 128 64 64h-128a35.626667 35.626667 0 0 0 0 71.04h213.333333A33.706667 33.706667 0 0 0 938.666667 903.04v-213.333333a33.493333 33.493333 0 0 0-35.626667-35.413334z" p-id="5036" fill="#ffffff"></path></svg>';
+
+                fullScreenDOM.onclick = function () {
+                  _this.fullScreen();
+                };
+
+                rightContros.appendChild(fullScreenDOM);
+              }
+            }
+
+            if (matchFooterOpt().talkModule) {
+              // 瀵硅
+              var startTalkDOM = document.createElement('div');
+              var stopTalkDOM = document.createElement('div');
+              startTalkDOM.setAttribute("class", "ptp-talk off");
+              startTalkDOM.innerHTML = '<span title="瀵硅">' + '<svg t="1581930496966" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"' + '  p-id="1641" width="16" height="16">' + '  <path' + '    d="M715.648 647.872c-30.208-22.336-61.568 39.36-100.992 77.44-39.36 38.08-34.112 31.488-123.392-17.088S311.488 540.224 280 491.648C248.448 443.072 265.472 424.704 265.472 424.704s78.72-62.976 97.152-81.344c18.368-18.368 13.12-30.208 13.12-30.208l-128.64-190.144c-23.616-5.184-64.32 5.12-128.576 57.6C54.208 233.088 30.592 353.856 151.296 575.68c120.768 221.824 347.84 330.752 485.568 374.08 137.856 43.328 228.416-61.696 249.408-103.68 21.056-41.984 13.12-85.312 13.12-85.312S745.856 670.208 715.648 647.872z"' + '    p-id="1642" fill="#ffffff"></path>' + '  <path' + '    d="M715.328 64C580.992 64 472.192 172.864 472.192 307.2s108.8 243.2 243.136 243.2 243.2-108.864 243.2-243.2S849.6 64 715.328 64zM715.328 461.056c-84.992 0-153.856-68.864-153.856-153.856s68.864-153.856 153.856-153.856 153.856 68.928 153.856 153.856S800.32 461.056 715.328 461.056z"' + '    p-id="1643" fill="#ffffff"></path>' + '  <path' + '    d="M777.472 277.376c-18.176 0-32.96-14.784-32.96-33.024 0-8.448 3.136-16.064 8.32-21.888-11.52-5.12-24.128-8-37.568-8-51.2 0-92.672 41.472-92.672 92.736s41.472 92.736 92.672 92.736S808.064 358.4 808.064 307.2c0-13.696-3.072-26.688-8.384-38.4C793.728 274.112 786.048 277.376 777.472 277.376zM715.328 340.928c-18.624 0-33.664-15.104-33.664-33.728 0-18.624 15.04-33.728 33.664-33.728 18.688 0 33.728 15.104 33.728 33.728C749.056 325.824 734.016 340.928 715.328 340.928z"' + '    p-id="1644" fill="#ffffff"></path>' + ' </svg>' + ' </span>' + ' <span>寮�鍚璁�</span>';
+
+              startTalkDOM.onclick = function () {
+                console.log("EZUIKit.state.countTimer", EZUIKit.state.countTimer);
+
+                if (EZUIKit.state.countTimer) {
+                  window.layer.msg("璇煶璁惧姝e繖锛岃绋嶅悗閲嶈瘯");
+                  return false;
+                }
+
+                countTime('add', 0);
+                console.log("寮�濮嬪璁诧紝鍏抽棴澹伴煶");
+
+                _this.closeSound(0);
+
+                console.log(_this.opt);
+
+                _this.startTalk();
+
+                this.setAttribute("class", "ptp-talk off hide");
+                stopTalkDOM.setAttribute("class", "ptp-talk on");
+              };
+
+              stopTalkDOM.setAttribute("class", "ptp-talk on hide");
+              stopTalkDOM.innerHTML = '<span title="瀵硅">' + ' <svg t="1581930496966" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"' + '    p-id="1641" width="16" height="16">' + '    <path' + '      d="M715.648 647.872c-30.208-22.336-61.568 39.36-100.992 77.44-39.36 38.08-34.112 31.488-123.392-17.088S311.488 540.224 280 491.648C248.448 443.072 265.472 424.704 265.472 424.704s78.72-62.976 97.152-81.344c18.368-18.368 13.12-30.208 13.12-30.208l-128.64-190.144c-23.616-5.184-64.32 5.12-128.576 57.6C54.208 233.088 30.592 353.856 151.296 575.68c120.768 221.824 347.84 330.752 485.568 374.08 137.856 43.328 228.416-61.696 249.408-103.68 21.056-41.984 13.12-85.312 13.12-85.312S745.856 670.208 715.648 647.872z"' + '      p-id="1642" fill="#ff0000"></path>' + '    <path' + '      d="M715.328 64C580.992 64 472.192 172.864 472.192 307.2s108.8 243.2 243.136 243.2 243.2-108.864 243.2-243.2S849.6 64 715.328 64zM715.328 461.056c-84.992 0-153.856-68.864-153.856-153.856s68.864-153.856 153.856-153.856 153.856 68.928 153.856 153.856S800.32 461.056 715.328 461.056z"' + '      p-id="1643" fill="#ff0000"></path>' + '    <path' + '      d="M777.472 277.376c-18.176 0-32.96-14.784-32.96-33.024 0-8.448 3.136-16.064 8.32-21.888-11.52-5.12-24.128-8-37.568-8-51.2 0-92.672 41.472-92.672 92.736s41.472 92.736 92.672 92.736S808.064 358.4 808.064 307.2c0-13.696-3.072-26.688-8.384-38.4C793.728 274.112 786.048 277.376 777.472 277.376zM715.328 340.928c-18.624 0-33.664-15.104-33.664-33.728 0-18.624 15.04-33.728 33.664-33.728 18.688 0 33.728 15.104 33.728 33.728C749.056 325.824 734.016 340.928 715.328 340.928z"' + '      p-id="1644" fill="#ff0000"></path>' + '  </svg>' + ' </span>' + '<span>鍏抽棴瀵硅</span>';
+
+              stopTalkDOM.onclick = function () {
+                console.log(_this.opt);
+
+                _this.stopTalk();
+
+                countTime('destory', 0);
+
+                _this.openSound(0);
+
+                this.setAttribute("class", "ptp-talk on hide");
+                startTalkDOM.setAttribute("class", "ptp-talk off");
+              };
+
+              footerContainer.appendChild(startTalkDOM);
+              footerContainer.appendChild(stopTalkDOM);
+            }
+
+            if (matchFooterOpt().broadcastModule) {
+              var fetchVoiceList = function fetchVoiceList(page) {
+                function apiSuccess(data) {
+                  console.log("data", data);
+
+                  if (data.code == 200) {
+                    randerVoliceList(data.data, 5);
+                    EZUIKit.state.page = data.page.page; // 濡傛灉鐢ㄦ埛璇煶鍒楄〃涓虹┖
+
+                    if (page == 0 && data.data.length == 0 && !EZUIKit.state.fetchDefaultList) {
+                      // 鑾峰彇鐢ㄦ埛璇煶涓虹┖
+                      EZUIKit.state.fetchDefaultList = true;
+                      fetchVoiceList(0);
+                    }
+                  }
+                }
+
+                request(domain + '/api/lapp/voice/query', 'POST', {
+                  accessToken: _this.opt.accessToken,
+                  pageStart: page,
+                  pageSize: EZUIKit.state.pageSize,
+                  "default": EZUIKit.state.fetchDefaultList ? 'true' : 'false'
+                }, '', apiSuccess);
+              };
+
+              var randerVoliceList = function randerVoliceList(data) {
+                console.log("renderVoliceList", data);
+
+                if (data && data.length > 0) {
+                  for (var i = 0; i < data.length; i++) {
+                    var voiceItem = document.createElement('li');
+                    voiceItem.innerHTML = "<li class='voice-item' id='voice-item-" + i + "' data-time=" + (data[i]["duration"] || 20) + " data-url=" + data[i]["fileUrl"] + ">" + (data[i]["voiceName"].length > 10 ? data[i]["voiceName"].substr(0, 10) + "..." : data[i]["voiceName"]) + "</li>";
+                    document.getElementsByClassName('voice-list-ul')[0].append(voiceItem); // "<li class='voice-item' id='voice-item-" + i + "' data-time=" + (data[i]["duration"] || 20) + " data-url=" + data[i]["fileUrl"] + ">" + (data[i]["voiceName"].length > 10 ? (data[i]["voiceName"].substr(0, 10) + "...") : data[i]["voiceName"]) + "</li>";
+                    // $("#voice-list ul").append("<li class='voice-item' id='voice-item-" + i + "' data-time=" + (data[i]["duration"] || 20) + " data-url=" + data[i]["fileUrl"] + ">" + (data[i]["voiceName"].length > 10 ? (data[i]["voiceName"].substr(0, 10) + "...") : data[i]["voiceName"]) + "</li>");
+
+                    voiceItem.onclick = function (e) {
+                      console.log("鐐瑰嚮鍏冪礌", e.target, e.target.dataset.url);
+                      var voiceUrl = e.target.dataset.url;
+                      var time = e.target.dataset.time;
+                      playListOfVoice(voiceUrl, time);
+                    };
+                  }
+
+                  if (data.length === EZUIKit.state.pageSize) {
+                    document.getElementById('voice-list-end').innerHTML = "鍚戜笅婊氬姩鍔犺浇鏇村";
+                  } else {
+                    document.getElementById('voice-list-end').innerHTML = "娌℃湁鏇村鏁版嵁浜�";
+                  }
+                }
+              };
+
+              var playListOfVoice = function playListOfVoice(voiceUrl, time) {
+                console.log("鎾斁璇煶", voiceUrl, time); // decoder && decoder.closeSound(0);
+
+                function apiSuccess(data) {
+                  console.log("data.data", data.data);
+
+                  if (data.code == 200) {
+                    // $("#startBroadcast").show();
+                    // $("#stopBroadcast").hide();
+                    countTime('sub', parseInt(time));
+                  } else if (data.code == "10001") {
+                    window.layer.msg("鏈壘鍒板綋鍓嶈闊�");
+                  } else {
+                    window.layer.msg(data.msg || '鍙戦�佸け璐ワ紝璇风◢鍚庡啀璇�');
+                  } // padding = false;
+
+                }
+
+                request(domain + '/api/lapp/voice/send', 'POST', {
+                  accessToken: _this.opt.accessToken,
+                  deviceSerial: _this.opt.deviceSerial,
+                  channelNo: _this.opt.channelNo,
+                  fileUrl: voiceUrl
+                }, '', apiSuccess);
+              }; // 鑷畾涔夎闊�
+              // 瀵硅
+
+
+              var startBroadcastDOM = document.createElement('div');
+              var stopBroadcastDOM = document.createElement('div');
+              startBroadcastDOM.setAttribute("class", 'broadcast off');
+              stopBroadcastDOM.setAttribute("class", "broadcast on hide");
+              startBroadcastDOM.innerHTML = ' <span title="璇煶鎾姤">' + '  <svg t="1583561695846" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"' + '    p-id="1126" width="16" height="16">' + '    <path' + '      d="M513.82044445 964.38044445c-8.192 0-15.47377778-2.73066667-21.84533334-8.192 0 0-46.42133333-41.87022222-99.21422222-86.47111112-89.20177778-73.728-117.41866667-88.29155555-123.79022222-90.112H35.04355555c-14.56355555 0-26.39644445-11.83288889-26.39644444-27.30666666V271.70133333c0-14.56355555 11.83288889-27.30666667 26.39644444-27.30666666H246.21511111c7.28177778-2.73066667 37.31911111-15.47377778 137.44355556-91.02222222 58.25422222-43.69066667 111.04711111-86.47111111 111.04711111-86.47111112 5.46133333-4.55111111 12.74311111-7.28177778 20.02488889-7.28177778 4.55111111 0 10.01244445 0.91022222 14.56355555 3.6408889 10.92266667 5.46133333 18.20444445 17.29422222 18.20444445 30.03733333v837.40444444c0 12.74311111-7.28177778 25.48622222-19.11466667 30.94755556-5.46133333 1.82044445-10.01244445 2.73066667-14.56355555 2.73066667zM270.79111111 724.992c19.11466667 0 48.24177778 8.192 167.48088889 106.496 16.384 13.65333333 33.67822222 28.21688889 51.88266667 43.69066667l5.46133333 4.55111111V139.71911111l-5.46133333 3.64088889c-22.75555555 17.29422222-44.60088889 34.58844445-65.536 50.06222222C293.54666667 291.72622222 264.41955555 299.008 245.30488889 299.008H82.37511111c-20.02488889 0-21.84533333 12.74311111-21.84533333 26.39644445V694.04444445c0 23.66577778 6.37155555 30.03733333 28.21688889 30.03733333h180.224l1.82044444 0.91022222z m520.64711111 162.01955555c-14.56355555 0-26.39644445-11.83288889-26.39644444-27.30666666 0-11.83288889 8.192-20.02488889 16.384-24.576 112.86755555-67.35644445 182.04444445-191.14666667 182.04444444-324.03911111 0-132.89244445-70.08711111-256.68266667-182.04444444-324.03911111-10.01244445-5.46133333-15.47377778-14.56355555-15.47377778-24.576 0-14.56355555 11.83288889-27.30666667 26.39644445-27.30666667 5.46133333 0 10.01244445 1.82044445 16.384 5.46133333 128.34133333 76.45866667 207.53066667 218.45333333 207.53066666 369.55022222 0 152.00711111-80.09955555 293.09155555-208.44088889 369.55022223-6.37155555 5.46133333-10.92266667 7.28177778-16.384 7.28177777z m-90.112-152.91733333c-14.56355555 0-26.39644445-11.83288889-26.39644444-27.30666667 0-10.01244445 4.55111111-18.20444445 12.74311111-23.66577777 61.89511111-34.58844445 100.12444445-100.12444445 100.12444444-171.12177778 0-70.08711111-37.31911111-134.71288889-96.48355555-170.21155555-8.192-4.55111111-12.74311111-13.65333333-12.74311111-23.66577778 0-14.56355555 11.83288889-27.30666667 26.39644444-27.30666667 4.55111111 0 11.83288889 2.73066667 15.47377778 4.55111111 74.63822222 44.60088889 121.96977778 127.43111111 121.96977778 215.72266667 0 90.112-48.24177778 173.85244445-125.61066667 218.45333333-1.82044445 0-9.10222222 4.55111111-15.47377778 4.55111111z"' + '      fill="#ffffff" p-id="1127"></path>' + '  </svg>' + '</span>' + '<span>璇煶鎾姤</span>';
+
+              startBroadcastDOM.onclick = function () {
+                this.setAttribute("class", "broadcast off hide");
+                stopBroadcastDOM.setAttribute("class", "broadcast on");
+              };
+
+              stopBroadcastDOM.innerHTML = '<div class="pop-hover">' + '  <div class="pop-hover-content">' + '    <div class="vioce-list" id="voice-list">' + '      <ul class="voice-list-ul">' + '      </ul>' + '      <div id="voice-list-end"></div>' + '    </div>' + '    <div id="voice-custom" style="text-align: center;">鑷畾涔夎闊�</div>' + '  </div>' + '</div>' + '<span title="璇煶鎾姤">' + '  <svg t="1583561695846" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"' + '    p-id="1126" width="16" height="16">' + '    <path' + '      d="M513.82044445 964.38044445c-8.192 0-15.47377778-2.73066667-21.84533334-8.192 0 0-46.42133333-41.87022222-99.21422222-86.47111112-89.20177778-73.728-117.41866667-88.29155555-123.79022222-90.112H35.04355555c-14.56355555 0-26.39644445-11.83288889-26.39644444-27.30666666V271.70133333c0-14.56355555 11.83288889-27.30666667 26.39644444-27.30666666H246.21511111c7.28177778-2.73066667 37.31911111-15.47377778 137.44355556-91.02222222 58.25422222-43.69066667 111.04711111-86.47111111 111.04711111-86.47111112 5.46133333-4.55111111 12.74311111-7.28177778 20.02488889-7.28177778 4.55111111 0 10.01244445 0.91022222 14.56355555 3.6408889 10.92266667 5.46133333 18.20444445 17.29422222 18.20444445 30.03733333v837.40444444c0 12.74311111-7.28177778 25.48622222-19.11466667 30.94755556-5.46133333 1.82044445-10.01244445 2.73066667-14.56355555 2.73066667zM270.79111111 724.992c19.11466667 0 48.24177778 8.192 167.48088889 106.496 16.384 13.65333333 33.67822222 28.21688889 51.88266667 43.69066667l5.46133333 4.55111111V139.71911111l-5.46133333 3.64088889c-22.75555555 17.29422222-44.60088889 34.58844445-65.536 50.06222222C293.54666667 291.72622222 264.41955555 299.008 245.30488889 299.008H82.37511111c-20.02488889 0-21.84533333 12.74311111-21.84533333 26.39644445V694.04444445c0 23.66577778 6.37155555 30.03733333 28.21688889 30.03733333h180.224l1.82044444 0.91022222z m520.64711111 162.01955555c-14.56355555 0-26.39644445-11.83288889-26.39644444-27.30666666 0-11.83288889 8.192-20.02488889 16.384-24.576 112.86755555-67.35644445 182.04444445-191.14666667 182.04444444-324.03911111 0-132.89244445-70.08711111-256.68266667-182.04444444-324.03911111-10.01244445-5.46133333-15.47377778-14.56355555-15.47377778-24.576 0-14.56355555 11.83288889-27.30666667 26.39644445-27.30666667 5.46133333 0 10.01244445 1.82044445 16.384 5.46133333 128.34133333 76.45866667 207.53066667 218.45333333 207.53066666 369.55022222 0 152.00711111-80.09955555 293.09155555-208.44088889 369.55022223-6.37155555 5.46133333-10.92266667 7.28177778-16.384 7.28177777z m-90.112-152.91733333c-14.56355555 0-26.39644445-11.83288889-26.39644444-27.30666667 0-10.01244445 4.55111111-18.20444445 12.74311111-23.66577777 61.89511111-34.58844445 100.12444445-100.12444445 100.12444444-171.12177778 0-70.08711111-37.31911111-134.71288889-96.48355555-170.21155555-8.192-4.55111111-12.74311111-13.65333333-12.74311111-23.66577778 0-14.56355555 11.83288889-27.30666667 26.39644444-27.30666667 4.55111111 0 11.83288889 2.73066667 15.47377778 4.55111111 74.63822222 44.60088889 121.96977778 127.43111111 121.96977778 215.72266667 0 90.112-48.24177778 173.85244445-125.61066667 218.45333333-1.82044445 0-9.10222222 4.55111111-15.47377778 4.55111111z"' + '      fill="#ff0000" p-id="1127"></path>' + '  </svg>' + '</span>' + '<span>璇煶鎾姤</span>'; // //鑷畾涔夎闊冲敜璧�
+              // document.getElementById("voice-custom").onclick = function(){
+              //   console.log("鏄剧ず鑷畾涔夎闊�");
+              // }
+
+              stopBroadcastDOM.onclick = function () {
+                this.setAttribute("class", "broadcast on hide");
+                startBroadcastDOM.setAttribute("class", "broadcast off");
+              };
+
+              footerContainer.appendChild(startBroadcastDOM);
+              footerContainer.appendChild(stopBroadcastDOM); // 鍙敜鑷畾涔夎瑷�
+
+              document.getElementById("voice-custom").onclick = function () {
+                console.log("鏄剧ず鑷畾涔夎闊�");
+                startSpeakDOM.setAttribute('class', 'speak off');
+              }; // 鑾峰彇璇煶鍒楄〃
+
+
+              fetchVoiceList(0);
+              var startSpeakDOM = document.createElement('div');
+              var stopSpeakDOM = document.createElement('div');
+              startSpeakDOM.setAttribute('class', 'speak off hide');
+              stopSpeakDOM.setAttribute('class', 'speak on hide');
+              startSpeakDOM.setAttribute('id', 'startSpeak');
+              stopSpeakDOM.setAttribute('id', 'stopSpeak');
+              startSpeakDOM.innerHTML = '<span title="鎸変綇璇磋瘽">' + '  <svg t="1581994757678" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"' + '    p-id="1639" width="16" height="16">' + '    <path' + '      d="M757.059829 393.846154v-52.512821h262.564103v52.512821H757.059829z m-420.102564 481.367521v96.273504h175.042735a8.752137 8.752137 0 0 1 8.752137 8.752137v35.008547a8.752137 8.752137 0 0 1-8.752137 8.752137H109.401709a8.752137 8.752137 0 0 1-8.752136-8.752137v-35.008547a8.752137 8.752137 0 0 1 8.752136-8.752137h175.042735v-96.273504C129.767932 875.213675 4.376068 749.821812 4.376068 595.145299V463.863248a26.25641 26.25641 0 1 1 52.512821 0v113.777778c0 140.174222 113.637744 253.811966 253.811966 253.811965s253.811966-113.637744 253.811966-253.811965V463.863248a26.25641 26.25641 0 1 1 52.51282 0v131.282051c0 154.676513-125.391863 280.068376-280.068376 280.068376z m-26.25641-96.273504c-111.178393 0-201.299145-90.120752-201.299146-201.299145V201.299145C109.401709 90.120752 199.522462 0 310.700855 0s201.299145 90.120752 201.299145 201.299145v376.341881c0 111.178393-90.120752 201.299145-201.299145 201.299145z m691.418803-280.068376H757.059829v-52.512821h245.059829v52.512821z m-17.504273 105.025641H757.059829v-52.512821h227.555556v52.512821z m-17.504274 105.025641H757.059829v-52.512821h210.051282v52.512821z m-8.752137 105.025641H757.059829v-52.512821h201.299145v52.512821z m-17.504273 105.025641H757.059829v-52.512821h183.794872v52.512821z m-26.25641 105.025641H757.059829v-52.512821h157.538462v52.512821z"' + '      p-id="1640" fill="#ffffff"></path>' + '  </svg>' + '</span>' + '<span>鎸変綇璇磋瘽</span>';
+              stopSpeakDOM.innerHTML = '<span title="鎸変綇璇磋瘽">' + '<svg t="1581994757678" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"' + '  p-id="1639" width="16" height="16">' + '  <path' + '    d="M757.059829 393.846154v-52.512821h262.564103v52.512821H757.059829z m-420.102564 481.367521v96.273504h175.042735a8.752137 8.752137 0 0 1 8.752137 8.752137v35.008547a8.752137 8.752137 0 0 1-8.752137 8.752137H109.401709a8.752137 8.752137 0 0 1-8.752136-8.752137v-35.008547a8.752137 8.752137 0 0 1 8.752136-8.752137h175.042735v-96.273504C129.767932 875.213675 4.376068 749.821812 4.376068 595.145299V463.863248a26.25641 26.25641 0 1 1 52.512821 0v113.777778c0 140.174222 113.637744 253.811966 253.811966 253.811965s253.811966-113.637744 253.811966-253.811965V463.863248a26.25641 26.25641 0 1 1 52.51282 0v131.282051c0 154.676513-125.391863 280.068376-280.068376 280.068376z m-26.25641-96.273504c-111.178393 0-201.299145-90.120752-201.299146-201.299145V201.299145C109.401709 90.120752 199.522462 0 310.700855 0s201.299145 90.120752 201.299145 201.299145v376.341881c0 111.178393-90.120752 201.299145-201.299145 201.299145z m691.418803-280.068376H757.059829v-52.512821h245.059829v52.512821z m-17.504273 105.025641H757.059829v-52.512821h227.555556v52.512821z m-17.504274 105.025641H757.059829v-52.512821h210.051282v52.512821z m-8.752137 105.025641H757.059829v-52.512821h201.299145v52.512821z m-17.504273 105.025641H757.059829v-52.512821h183.794872v52.512821z m-26.25641 105.025641H757.059829v-52.512821h157.538462v52.512821z"' + '    p-id="1640" fill="#ff0000"></path>' + '</svg>' + '</span>' + '<span>鏉惧紑鍙戦��</span>';
+              footerContainer.appendChild(startSpeakDOM);
+              footerContainer.appendChild(stopSpeakDOM);
+
+              document.getElementById("voice-list").onscroll = function (e) {
+                var sum = this.scrollHeight;
+                console.log("sum", sum, this.scrollTop, document.getElementById("voice-list").clientHeight);
+
+                if (sum <= this.scrollTop + this.clientHeight) {
+                  console.log("鎷栧姩鍒板簳锛屾墽琛屽姞杞�", EZUIKit.state.page);
+                  fetchVoiceList(++EZUIKit.state.page);
+                }
+              }; // $("#voice-list").unbind("scroll").bind("scroll", function (e) {
+              //   // console.log("e",e,this.scrollHeight, $(this).scrollTop() + $(this).height())
+              //   var sum = this.scrollHeight;
+              //   if (sum <= $(this).scrollTop() + $(this).height()) {
+              //     console.log("鎷栧姩鍒板簳锛屾墽琛屽姞杞�", page);
+              //     fetchVoiceList(++page);
+              //   }
+              //   loading = false;
+              // });
+              // time-area 
+
+
+              var timeAreaDOM = document.createElement('div');
+              timeAreaDOM.setAttribute('class', 'time-area');
+              timeAreaDOM.setAttribute('id', 'time-area');
+              timeAreaDOM.innerHTML = '00:00';
+              footerContainer.appendChild(timeAreaDOM); // 鎸変綇璇磋瘽
+
+              var recorder;
+
+              document.getElementById('startSpeak').onmousedown = function () {
+                if (EZUIKit.state.countTimer) {
+                  window.layer.msg("璇煶璁惧姝e繖锛岃绋嶅悗閲嶈瘯");
+                  return false;
+                }
+
+                console.log("鎸変綇璇磋瘽");
+                startSpeakDOM.setAttribute('class', 'speak off hide');
+                stopSpeakDOM.setAttribute('class', 'speak on'); // console.log("startRecording",startRecording);
+                // startRecording();
+
+                voiceInit();
+                countTime('add', 0);
+                setTimeout(function () {
+                  EZUIKit.state.recodeTime = 0;
+                  startRecording();
+                }, 1000);
+
+                if (EZUIKit.state.recodeTimer) {
+                  // 鍏堟竻绌鸿鏁板櫒
+                  clearInterval(EZUIKit.state.recodeTimer);
+                }
+
+                EZUIKit.state.recodeTimer = setInterval(function () {
+                  if (EZUIKit.state.recodeTime >= 59) {
+                    _this.stopTalk();
+
+                    countTime('destory', 0);
+                    this.setAttribute("class", "ptp-talk on hide");
+                    startTalkDOM.setAttribute("class", "ptp-talk off");
+                    window.layer.msg("涓嶈秴杩�1鍒嗛挓");
+                  } else {
+                    EZUIKit.state.recodeTime = EZUIKit.state.recodeTime + 1;
+                  }
+                }, 1000);
+                /** 褰曢煶鎺у埗 */
+
+                var audio_context;
+
+                function startUserMedia(stream) {
+                  var input = audio_context.createMediaStreamSource(stream);
+                  recorder = new window.Recorder(input);
+                }
+
+                function startRecording() {
+                  recorder && recorder.record();
+                }
+
+                function voiceInit() {
+                  console.log("run init");
+
+                  try {
+                    // webkit shim
+                    window.AudioContext = window.AudioContext || window.webkitAudioContext;
+                    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
+                    window.URL = window.URL || window.webkitURL;
+                    audio_context = new AudioContext();
+                    console.log('Audio context set up.');
+                    console.log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!'));
+                  } catch (e) {
+                    console.log("err", e);
+                    window.layer.msg('No web audio support in this browser!');
+                  }
+
+                  navigator.getUserMedia({
+                    audio: true
+                  }, startUserMedia, function (e) {
+                    console.log('No live audio input: ' + e);
+                  });
+                }
+              }; // 鏉惧紑鍙戦��
+
+
+              document.getElementById('stopSpeak').onmouseup = function () {
+                console.log("鏉惧紑鍙戦��");
+                stopSpeakDOM.setAttribute('class', 'speak on hide');
+                stopSpeakFun();
+
+                function stopSpeakFun() {
+                  countTime('destory', 0);
+
+                  if (EZUIKit.state.recodeTime < 1) {
+                    window.layer.msg("璇磋瘽鏃堕棿杩囩煭");
+                    clearInterval(EZUIKit.state.recodeTimer);
+                    return false;
+                  }
+
+                  clearInterval(EZUIKit.state.recodeTimer);
+                  wavUpload();
+                }
+
+                function wavUpload() {
+                  try {
+                    recorder && recorder.stop(); // createAudioDom();
+
+                    recorder && recorder.exportWAV(function (wav_file) {
+                      console.log("wav_file", wav_file);
+
+                      if (wav_file.size < 1000) {
+                        window.layer.msg("褰曢煶澶辫触锛岃閲嶈瘯"); // recodeTime = 0;
+
+                        EZUIKit.state.recodeTime = 0;
+                        return false;
+                      } // 娴嬭瘯
+
+
+                      countTime('sub', EZUIKit.state.recodeTime + 2); // 寤舵椂
+
+                      var formdata = new FormData(); // form 琛ㄥ崟 {key:value}
+
+                      formdata.append("voiceFile", wav_file); // form input type="file"
+
+                      formdata.append("accessToken", _this.opt.accessToken);
+                      formdata.append("deviceSerial", _this.opt.deviceSerial);
+                      formdata.append("channelNo", _this.opt.channelNo); // padding = true;
+
+                      function apiSuccess(data) {
+                        console.log("data.data", data.data);
+
+                        if (data.code == 200) {
+                          // $("#startBroadcast").show();
+                          // $("#stopBroadcast").hide();
+                          countTime('sub', EZUIKit.state.recodeTime + 2);
+                        } else if (data.code == "10001") {
+                          window.layer.msg("鏈壘鍒板綋鍓嶈闊�");
+                        } else {
+                          window.layer.msg(data.msg || '鍙戦�佸け璐ワ紝璇风◢鍚庡啀璇�');
+                        } // padding = false;
+
+                      }
+
+                      function apiError(err) {
+                        console.log("err", err);
+                      }
+
+                      request(domain + '/api/lapp/voice/sendonce', 'POST', {
+                        voiceFile: wav_file,
+                        accessToken: _this.opt.accessToken,
+                        deviceSerial: _this.opt.deviceSerial,
+                        channelNo: _this.opt.channelNo
+                      }, '', apiSuccess, apiError);
+                    });
+                    recorder && recorder.clear();
+                  } catch (err) {
+                    console.log(err);
+                  }
+                }
+              };
+            }
+          }
+        }
+      });
+    }); // iframe 浼犻�掓暟鎹�
+
+    var _this = this;
+
+    window.addEventListener("message", function (event) {
+      event.origin;
+      var id = _this.opt.id;
+
+      if (event.data.type) {
+        switch (event.data.type) {
+          case 'openSound':
+            if (id == event.data.id && params.openSoundCallBack) {
+              params.openSoundCallBack(event.data);
+            }
+
+            break;
+
+          case 'closeSound':
+            if (id == event.data.id && params.closeSoundCallBack) {
+              params.closeSoundCallBack(event.data);
+            }
+
+            break;
+
+          case 'capturePicture':
+            if (id == event.data.id && params.capturePictureCallBack) {
+              params.capturePictureCallBack(event.data);
+            }
+
+            break;
+
+          case 'startSave':
+            if (id == event.data.id && params.startSaveCallBack) {
+              params.startSaveCallBack(event.data);
+            }
+
+            break;
+
+          case 'stopSave':
+            if (id == event.data.id && params.stopSaveCallBack) {
+              params.stopSaveCallBack(event.data);
+            }
+
+            break;
+
+          case 'fullScreen':
+            if (id == event.data.id && params.fullScreenCallBack) {
+              params.fullScreenCallBack(event.data);
+            }
+
+            break;
+
+          case 'getOSDTime':
+            if (id == event.data.id && params.getOSDTimeCallBack) {
+              params.getOSDTimeCallBack(event.data);
+            }
+
+            break;
+
+          case 'handleSuccess':
+            if (id == event.data.id && params.handleSuccess) {
+              params.handleSuccess(event.data);
+            }
+
+            break;
+
+          case 'handleError':
+            if (id == event.data.id && params.handleError) {
+              params.handleError(event.data);
+            }
+
+            break;
+
+          case 'dblclick':
+            if (id == event.data.id && _this.opt.bSupporDoubleClickFull) {
+              if (_this.opt.fullScreenStatus === 0) {
+                _this.fullScreen();
+              } else {
+                _this.cancelFullScreen();
+              }
+            }
+
+            break;
+
+          case 'startTalk':
+            _this.startTalk(); // params.startTalk();
+
+
+            _this.closeSound();
+
+            break;
+
+          case 'stopTalk':
+            // window.stopTalk()
+            _this.stopTalk();
+
+            _this.openSound();
+
+            break;
+
+          case 'clickEventHandle':
+            console.log("event.data", event.data);
+
+            if (params.clickEventHandle) {
+              params.clickEventHandle(event.data);
+            }
+
+            break;
+
+          case 'removeEventHandle':
+            if (params.removeEventHandle) {
+              params.removeEventHandle(event.data);
+            }
+
+            break;
+
+          case 'esc':
+            if (params.clickEventHandle) {
+              params.clickEventHandle(event.data);
+            }
+
+            break;
+
+          case 'iframeFullScreen':
+            if (id == event.data.id) {
+              var requestFullScreen = function requestFullScreen(element) {
+                var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
+
+                if (requestMethod) {
+                  requestMethod.call(element);
+                } else if (typeof window.ActiveXObject !== "undefined") {
+                  var wscript = new ActiveXObject("WScript.Shell");
+
+                  if (wscript !== null) {
+                    wscript.SendKeys("{F11}");
+                  }
+                }
+              };
+
+              requestFullScreen(document.getElementById("EZUIKitPlayer-" + event.data.id));
+            }
+
+            break;
+        }
+      }
+    }); // 鍏ㄥ睆鍙樺寲鍥炶皟
+
+    function fullscreenchange(data) {
+      _this.opt.fullScreenStatus = data ? 1 : 0;
+
+      if (params.fullScreenChangeCallBack) {
+        params.fullScreenChangeCallBack({
+          data: data,
+          id: _this.opt.id
+        });
+      }
+    }
+
+    if (typeof document.fullScreen !== "undefined") {
+      document.addEventListener("fullscreenchange", function () {
+        var e = document.fullscreen || false;
+        fullscreenchange(e);
+      });
+    } else if (typeof document.webkitIsFullScreen !== "undefined") {
+      document.addEventListener("webkitfullscreenchange", function () {
+        var e = document.webkitIsFullScreen || false;
+        fullscreenchange(e);
+      });
+    } else if (typeof document.mozFullScreen !== "undefined") {
+      document.addEventListener("mozfullscreenchange", function () {
+        var e = document.mozFullScreen || false;
+        fullscreenchange(e);
+      });
+    }
+  }; // 鎾斁鐩稿叧API
+
+
+  EZUIKitPlayer.prototype.play = function (data) {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+
+    if (_typeof(data) === 'object' && data.url) {
+      this.opt.url = data.url;
+    }
+
+    if (_typeof(data) === 'object' && data.accessToken) {
+      this.opt.accessToken = data.accessToken;
+    }
+
+    if (typeof data === 'string') {
+      this.opt.url = data;
+    }
+
+    player.postMessage({
+      action: "play",
+      accessToken: this.opt.accessToken,
+      url: this.opt.url
+    }, domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    this.opt.videoLoading = true;
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'handleSuccess') {
+          setTimeout(function () {
+            _this.opt.videoLoading = false;
+          }, 1000);
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.stop = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("stop", domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'stop') {
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.openSound = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("openSound", domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'openSound') {
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.closeSound = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("closeSound", domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'closeSound') {
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.startSave = function (fileName) {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage({
+      action: "startSave",
+      fileName: fileName || 'default'
+    }, domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'startSave') {
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.stopSave = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("stopSave", domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'stopSave') {
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.fullScreen = function () {
+    if (this.opt.fullScreenStatus === 1) {
+      return false;
+    }
+
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+
+    if (navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {
+      // console.log('绉诲姩绔叏灞�');
+      var width = document.documentElement.clientWidth;
+      var height = document.documentElement.clientHeight; // wrapper = document.getElementById("test"),
+
+      var wrapper = document.body; //document.body 灞炴�ц繑鍥� <body> 鍏冪礌锛� document.documentElement 灞炴�ц繑鍥� <html> 鍏冪礌銆�
+
+      wrapper = document.getElementById(id);
+      var style = "";
+      style += "width:" + height + "px;"; // 娉ㄦ剰鏃嬭浆鍚庣殑瀹介珮鍒囨崲
+
+      style += "height:" + width + "px;";
+      style += "-webkit-transform: rotate(90deg); transform: rotate(90deg);"; // 娉ㄦ剰鏃嬭浆涓偣鐨勫鐞�
+
+      style += "-webkit-transform-origin: " + width / 2 + "px " + width / 2 + "px;";
+      style += "transform-origin: " + width / 2 + "px " + width / 2 + "px;";
+      style += 'position: fixed;top: 0;left: 0;z-index:10';
+      wrapper.style.cssText = style; // var cancelFullDOM = document.createElement('div');
+      // cancelFullDOM.id = id + "cancel-full-screen"
+      // var cancelFullDOMStyle="width:30px;height:"+height+"px;z-index:1000;position:fixed;top:0px;right:0px;";
+      // cancelFullDOMStyle += "background-image: url(https://resource.ys7cloud.com/group1/M00/00/7E/CtwQE1-01qeAH2wAAAABOliqQ5g167.png);"
+      // cancelFullDOMStyle += "background-size: contain;background-repeat:no-repeat;background-color:rgba(0,0,0,0.2)"
+      // cancelFullDOM.style = cancelFullDOMStyle;
+      // cancelFullDOM.onclick = function(){
+      //   _this.cancelFullScreen();
+      // }
+      // document.body.appendChild(cancelFullDOM);
+
+      setTimeout(function () {
+        player.postMessage('autoResize', domain + "/ezopen/h5/iframe");
+      }, 500);
+    } else {
+      // console.log('pc绔叏灞�');
+      var requestFullScreen = function requestFullScreen(element) {
+        var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
+
+        if (requestMethod) {
+          requestMethod.call(element);
+        } else if (typeof window.ActiveXObject !== "undefined") {
+          var wscript = new ActiveXObject("WScript.Shell");
+
+          if (wscript !== null) {
+            wscript.SendKeys("{F11}");
+          }
+        }
+      };
+
+      requestFullScreen(document.getElementById(id));
+    }
+
+    if (this.params.fullScreenCallBack) {
+      this.params.fullScreenCallBack(this.opt.id);
+    }
+
+    this.opt.fullScreenStatus = 1;
+  };
+
+  EZUIKitPlayer.prototype.cancelFullScreen = function () {
+    if (this.opt.fullScreenStatus === 0) {
+      return false;
+    }
+
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+
+    if (navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {
+      var width = document.getElementById(id).width;
+      var height = document.getElementById(id).height; // wrapper = document.getElementById("test"),
+
+      var wrapper = document.body; //document.body 灞炴�ц繑鍥� <body> 鍏冪礌锛� document.documentElement 灞炴�ц繑鍥� <html> 鍏冪礌銆�
+
+      wrapper = document.getElementById(id);
+      var style = "";
+      style += "width:" + width + "px;";
+      style += "height:" + height + "px;";
+      style += "-webkit-transform: none; transform: none;";
+      style += "-webkit-transform-origin: 0 0;";
+      style += "transform-origin: 0 0;";
+      wrapper.style.cssText = style;
+      setTimeout(function () {
+        player.postMessage("autoResize", domain + "/ezopen/h5/iframe");
+      }, 500);
+      var cancelFullDOMId = id + "cancel-full-screen";
+      var cancelFullDOM = document.getElementById(cancelFullDOMId);
+
+      if (cancelFullDOM) {
+        document.body.removeChild(cancelFullDOM);
+      }
+    } else {
+      if (document.exitFullscreen) {
+        document.exitFullscreen();
+      } else if (document.webkitCancelFullScreen) {
+        document.webkitCancelFullScreen();
+      } else if (document.mozCancelFullScreen) {
+        document.mozCancelFullScreen();
+      }
+    }
+
+    if (this.params.cancelFullScreenCallBack) {
+      this.params.cancelFullScreenCallBack(this.opt.id);
+    }
+
+    this.opt.fullScreenStatus = 0;
+  };
+
+  EZUIKitPlayer.prototype.capturePicture = function (fileName, isUndownload) {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage({
+      action: "capturePicture",
+      fileName: fileName || 'default',
+      isUndownload: isUndownload
+    }, domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'capturePicture') {
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.enableZoom = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("enableZoom", domain + "/ezopen/h5/iframe");
+  };
+
+  EZUIKitPlayer.prototype.closeZoom = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("closeZoom", domain + "/ezopen/h5/iframe");
+  };
+
+  EZUIKitPlayer.prototype.getOSDTime = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("getOSDTime", domain + "/ezopen/h5/iframe");
+
+    var _this = this;
+
+    var promise = new Promise(function (resolve, reject) {
+      window.addEventListener("message", function (event) {
+        var playId = _this.opt.id;
+
+        if (playId == event.data.id && event.data.type === 'getOSDTime') {
+          resolve(event.data);
+        }
+      });
+    });
+    return promise;
+  };
+
+  EZUIKitPlayer.prototype.autoResize = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("autoResize", domain + "/ezopen/h5/iframe");
+  };
+
+  EZUIKitPlayer.prototype.reSize = function (width, height) {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    var containerDOM = document.getElementById(this.opt.id);
+    containerDOM.style.width = width + 'px';
+    containerDOM.style.height = height + 'px';
+    document.getElementById(this.opt.id).style.width = width + 'px';
+    document.getElementById(this.opt.id).style.height = height + 'px';
+    var playDOM = document.getElementById(id);
+    playDOM.setAttribute("width", width);
+    playDOM.setAttribute("height", height);
+    playDOM.style.width = width + 'px';
+    playDOM.style.height = height + 'px';
+    setTimeout(function () {
+      player.postMessage({
+        action: 'autoResize'
+      }, domain + "/ezopen/h5/iframe");
+    }, 500);
+  };
+
+  EZUIKitPlayer.prototype.startTalk = function () {
+    console.log("鎵ц寮�濮嬪璁�");
+    console.log(this.opt);
+
+    var _this = this;
+
+    EZUIKit.opt = this.opt;
+
+    if (window.EZUIKit) {
+      window.EZUIKit.opt = this.opt;
+    }
+
+    var apiSuccess = function apiSuccess(data) {
+      if (data.code == 200) {
+        var apiResult = data.data;
+
+        if (apiResult) {
+          // 涓存椂灏唄ttps杞崲涓簑ebsocket
+          var rtcTrunk = apiResult.rtcUrl;
+
+          if (rtcTrunk.indexOf("ws") === -1) {
+            rtcTrunk = rtcTrunk.replace("https", "wss").replace("rtcgw", "rtcgw-ws");
+          }
+
+          _this.opt.rtcUrl = rtcTrunk;
+          _this.opt.ttsUrl = "tts://" + apiResult.ttsUrl;
+          var talk = "talk://" + _this.opt.deviceSerial + ":0:" + _this.opt.channelNo + ":cas.ys7.com:6500";
+          _this.opt.talkLink = _this.opt.ttsUrl + "/" + talk;
+          _this.opt.stream = apiResult.stream;
+          window.startTalk();
+        }
+      }
+    };
+
+    request(_this.opt.apiDomain, 'POST', {
+      accessToken: _this.opt.accessToken,
+      deviceSerial: _this.opt.deviceSerial,
+      channelNo: _this.opt.channelNo
+    }, '', apiSuccess);
+  };
+
+  EZUIKitPlayer.prototype.stopTalk = function () {
+    console.log("鎵ц缁撴潫瀵硅");
+    window.stopTalk();
+  };
+
+  EZUIKitPlayer.prototype.edit = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage("edit", domain + "/ezopen/h5/iframe");
+  };
+
+  EZUIKitPlayer.prototype.btnReRender = function (data) {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage({
+      action: "btnReRender",
+      data: data
+    }, domain + "/ezopen/h5/iframe");
+  };
+
+  EZUIKitPlayer.prototype.changePlayUrl = function (data) {
+    if (data.deviceSerial) {
+      this.opt.deviceSerial = data.deviceSerial;
+    }
+
+    if (data.channelNo) {
+      this.opt.channelNo = data.channelNo;
+    }
+
+    if (data.accessToken) {
+      this.opt.accessToken = data.accessToken;
+    }
+
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage({
+      action: "changePlayUrl",
+      data: data
+    }, domain + "/ezopen/h5/iframe");
+  };
+
+  EZUIKitPlayer.prototype.fetchThemeData = function () {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage({
+      action: "fetchThemeData"
+    }, domain + "/ezopen/h5/iframe");
+  };
+
+  EZUIKitPlayer.prototype.setThemeData = function (accessToken, header, footer) {
+    var id = 'EZUIKitPlayer-' + this.opt.id;
+    var player = document.getElementById(id).contentWindow;
+    player.postMessage({
+      action: "setThemeData",
+      data: {
+        accessToken: accessToken,
+        header: header,
+        footer: footer
+      }
+    }, domain + "/ezopen/h5/iframe");
+  };
+  /**
+   * 瑙嗛鎾斁鍣�-缁撴潫
+   */
+
+
+  EZUIKit.EZUIKitPlayer = EZUIKitPlayer;
+  window.EZUIKitV3 = EZUIKit;
+  var EZUIKitV3 = EZUIKit;
+  return EZUIKitV3;
+});
+
+var EZUIKitV3$1 = EZUIKitV3;
+
+/**
+ * Created by wangweijie5 on 2016/12/16.
+ */
+
+var _createClass = 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);
+    }
+  }
+
+  return function (Constructor, protoProps, staticProps) {
+    if (protoProps) defineProperties(Constructor.prototype, protoProps);
+    if (staticProps) defineProperties(Constructor, staticProps);
+    return Constructor;
+  };
+}();
+
+function _classCallCheck(instance, Constructor) {
+  if (!(instance instanceof Constructor)) {
+    throw new TypeError("Cannot call a class as a function");
+  }
+}
+
+var __instance = function () {
+  var instance = void 0;
+  return function (newInstance) {
+    if (newInstance) instance = newInstance;
+    return instance;
+  };
+}();
+
+(function () {
+  function AudioRenderer() {
+    _classCallCheck(this, AudioRenderer);
+
+    if (__instance()) return __instance(); // 纭繚鍙湁鍗曚緥
+
+    if (AudioRenderer.unique !== undefined) {
+      return AudioRenderer.unique;
+    }
+
+    AudioRenderer.unique = this;
+    this.oAudioContext = null;
+    this.currentVolume = 80; // 鍒濆闊抽噺
+
+    this.bSetVolume = false;
+    this.gainNode = null;
+    this.iWndNum = -1; // 绐楀彛鍙�
+
+    this.mVolumes = new Map(); // 鐢ㄤ簬瀛樺偍鎵�鏈夐煶閲�
+    // Init AudioContext
+
+    var AudioContext = window.AudioContext || window.webkitAudioContext;
+    this.oAudioContext = new AudioContext();
+
+    this.writeString = function (view, offset, string) {
+      for (var i = 0; i < string.length; i++) {
+        view.setUint8(offset + i, string.charCodeAt(i));
+      }
+    };
+
+    this.setBufferToDataview = function (output, offset, input) {
+      for (var i = 0; i < input.length; i++, offset++) {
+        output.setUint8(offset, input[i]);
+      }
+    };
+
+    __instance(this);
+  }
+  /**
+   * @synopsis 闊抽鎾斁
+   *
+   *  @param dataBuf [IN] 闊抽缂撳瓨
+   *  @param dataLen [IN] 缂撳瓨闀垮害
+   *  @param audioInfo [IN] 闊抽鍙傛暟
+   *
+   * @returns 鐘舵�佺爜
+   */
+
+
+  _createClass(AudioRenderer, [{
+    key: 'Play',
+    value: function Play(dataBuf, dataLen, audioInfo) {
+      var bufferData = new ArrayBuffer(44 + dataLen);
+      var viewTalk = new DataView(bufferData);
+      var sampleRates = audioInfo.samplesPerSec;
+      var channels = audioInfo.channels;
+      var bitsPerSample = audioInfo.bitsPerSample; //console.log("audiorender sampleRates"+sampleRates+"channels:"+channels+"bitsPerSample:"+bitsPerSample);
+
+      /* RIFF identifier */
+
+      this.writeString(viewTalk, 0, 'RIFF');
+      /* file length */
+
+      viewTalk.setUint32(4, 32 + dataLen * 2, true);
+      /* RIFF type */
+
+      this.writeString(viewTalk, 8, 'WAVE');
+      /* format chunk identifier */
+
+      this.writeString(viewTalk, 12, 'fmt ');
+      /* format chunk length */
+
+      viewTalk.setUint32(16, 16, true);
+      /* sample format (raw) */
+
+      viewTalk.setUint16(20, 1, true);
+      /* channel count */
+
+      viewTalk.setUint16(22, channels, true);
+      /* sample rate */
+
+      viewTalk.setUint32(24, sampleRates, true);
+      /* byte rate (sample rate * block align) */
+
+      viewTalk.setUint32(28, sampleRates * 2, true);
+      /* block align (channel count * bytes per sample)/8 */
+
+      viewTalk.setUint16(32, channels * bitsPerSample / 8, true);
+      /* bits per sample */
+
+      viewTalk.setUint16(34, bitsPerSample, true);
+      /* data chunk identifier */
+
+      this.writeString(viewTalk, 36, 'data');
+      /* data chunk length */
+
+      viewTalk.setUint32(40, dataLen, true);
+      this.setBufferToDataview(viewTalk, 44, dataBuf);
+      var self = this;
+      this.oAudioContext.decodeAudioData(viewTalk.buffer, function (buffer) {
+        var bufferSource = self.oAudioContext.createBufferSource();
+
+        if (bufferSource == null) {
+          return -1;
+        }
+
+        bufferSource.buffer = buffer;
+        bufferSource.start(0);
+
+        if (self.gainNode == null || self.bSetVolume) {
+          self.gainNode = self.oAudioContext.createGain(); // self.gainNode.gain.value = self.currentVolume;
+          // // self.currentVolume = self.gainNode.gain.value;
+          // self.gainNode.connect(self.oAudioContext.destination);
+
+          self.bSetVolume = false;
+        }
+
+        self.gainNode.gain.value = self.currentVolume / 100; // self.currentVolume = self.gainNode.gain.value;
+
+        self.gainNode.connect(self.oAudioContext.destination);
+        bufferSource.connect(self.gainNode);
+      }, function (e) {
+        console.log("decode error");
+        return -1;
+      });
+      return 0;
+    }
+    /**
+     * @synopsis 鍋滄鎾斁
+     *
+     * @returns 杩斿洖闊抽噺
+     */
+
+  }, {
+    key: 'Stop',
+    value: function Stop() {
+      if (this.gainNode != null) {
+        this.gainNode.disconnect();
+        this.gainNode = null;
+      } // this.oAudioContext.close();
+      // AudioRenderer.unique = undefined;
+      // __instance() = null;
+
+
+      return true;
+    }
+    /**
+     * @synopsis 璁剧疆闊抽噺
+     *
+     *  @param iVolume [IN] 闊抽噺
+     *
+     * @returns 鐘舵�佺爜
+     */
+
+  }, {
+    key: 'SetVolume',
+    value: function SetVolume(iVolume) {
+      this.bSetVolume = true;
+      this.currentVolume = iVolume; // 鍌ㄥ瓨褰撳墠绐楀彛璁剧疆闊抽噺鍊�
+
+      this.mVolumes.set(this.iWndNum, this.currentVolume);
+      return true;
+    }
+    /**
+     * @synopsis 璁剧疆绐楀彛鍙�
+     *
+     *  @param iWndNum [IN] 绐楀彛鍙�
+     *
+     * @returns 鐘舵�佺爜
+     */
+
+  }, {
+    key: 'SetWndNum',
+    value: function SetWndNum(iWndNum) {
+      this.iWndNum = iWndNum; // 鑾峰彇褰撳墠绐楀彛璁剧疆闊抽噺鍊�
+
+      var iVolume = this.mVolumes.get(iWndNum);
+
+      if (iVolume == undefined) {
+        iVolume = 80; // 榛樿闊抽噺
+      }
+
+      this.currentVolume = iVolume;
+      return true;
+    }
+    /**
+     * @synopsis 鑾峰彇闊抽噺
+     *
+     * @returns 杩斿洖闊抽噺
+     */
+
+  }, {
+    key: 'GetVolume',
+    value: function GetVolume() {
+      // 鑾峰彇褰撳墠绐楀彛璁剧疆闊抽噺鍊�
+      var iVolume = this.mVolumes.get(this.iWndNum);
+
+      if (iVolume == undefined) {
+        iVolume = 80; // 榛樿闊抽噺
+      }
+
+      return iVolume;
+    }
+  }]);
+
+  window.AudioRenderer = AudioRenderer;
+  return AudioRenderer;
+})();
+
+//attribute淇グ绗︾敤浜庡0鏄庣敱娴忚鍣紙javascript锛変紶杈撶粰椤剁偣鐫�鑹插櫒鐨勫彉閲忓�硷紱
+// vertexPos鍗虫垜浠畾涔夌殑椤剁偣鍧愭爣锛�
+// gl_Position鏄竴涓唴寤虹殑浼犲嚭鍙橀噺銆�
+
+var vertexYUVShader = ['attribute vec4 vertexPos;', 'attribute vec2 texturePos;', 'varying vec2 textureCoord;', 'void main()', '{', 'gl_Position = vertexPos;', 'textureCoord = texturePos;', '}'].join('\n'); //鍍忕礌鐫�鑹插櫒(yuv->rgb)
+
+var fragmentYUVShader = ['precision highp float;', 'varying highp vec2 textureCoord;', 'uniform sampler2D ySampler;', 'uniform sampler2D uSampler;', 'uniform sampler2D vSampler;', 'const mat4 YUV2RGB = mat4', '(', '1.1643828125, 0, 1.59602734375, -.87078515625,', '1.1643828125, -.39176171875, -.81296875, .52959375,', '1.1643828125, 2.017234375, 0, -1.081390625,', '0, 0, 0, 1', ');', 'void main(void) {', 'highp float y = texture2D(ySampler,  textureCoord).r;', 'highp float u = texture2D(uSampler,  textureCoord).r;', 'highp float v = texture2D(vSampler,  textureCoord).r;', 'gl_FragColor = vec4(y, u, v, 1) * YUV2RGB;', '}'].join('\n');
+
+(function (root, factory) {
+  // root.SuperRender = factory();
+  window.SuperRender = factory();
+})(undefined, function () {
+  function RenderManager(canvas) {
+    this.canvasElement = document.getElementById(canvas);
+    this.initContextGL();
+
+    if (this.contextGL) {
+      this.YUVProgram = this.initProgram(vertexYUVShader, fragmentYUVShader);
+      this.initBuffers();
+      this.initTextures();
+    }
+  }
+  /**
+   * 鍒濆鍖朩ebGL涓婁笅鏂�
+   */
+
+  RenderManager.prototype.initContextGL = function () {
+    var canvas = this.canvasElement;
+    var gl = null;
+
+    try {
+      gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
+    } catch (e) {
+      gl = null;
+    }
+
+    if (!gl || typeof gl.getParameter !== "function") {
+      gl = null;
+    }
+
+    this.contextGL = gl;
+    console.log("WebGL1.0");
+  };
+  /**
+   * 鍒濆鍖栫潃鑹插櫒绋嬪簭
+   * @param vertexShaderScript    椤剁偣鐫�鑹插櫒鑴氭湰
+   * @param fragmentShaderScript  鐗囨鐫�鑹插櫒鑴氭湰
+   */
+
+
+  RenderManager.prototype.initProgram = function (vertexShaderScript, fragmentShaderScript) {
+    var gl = this.contextGL;
+    var vertexShader = gl.createShader(gl.VERTEX_SHADER); //鍒涘缓瀹氱偣鐫�鑹插櫒
+
+    gl.shaderSource(vertexShader, vertexShaderScript);
+    gl.compileShader(vertexShader);
+
+    if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
+      console.log('Vertex shader failed to compile: ' + gl.getShaderInfoLog(vertexShader));
+    }
+
+    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
+    gl.shaderSource(fragmentShader, fragmentShaderScript);
+    gl.compileShader(fragmentShader);
+
+    if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
+      console.log('Fragment shader failed to compile: ' + gl.getShaderInfoLog(fragmentShader));
+    }
+
+    var program = gl.createProgram();
+    gl.attachShader(program, vertexShader);
+    gl.attachShader(program, fragmentShader);
+    gl.linkProgram(program);
+
+    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+      console.log('Program failed to compile: ' + gl.getProgramInfoLog(program));
+    }
+
+    gl.deleteShader(vertexShader);
+    gl.deleteShader(fragmentShader);
+    return program;
+  };
+  /**
+   * 鍒濆鍖栨暟鎹紦瀛�
+   */
+
+
+  RenderManager.prototype.initBuffers = function () {
+    var gl = this.contextGL;
+    var vertexPosBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 1, -1, 1, 1, -1, -1, -1]), gl.STATIC_DRAW);
+    gl.bindBuffer(gl.ARRAY_BUFFER, null);
+    var texturePosBuffer = gl.createBuffer();
+    gl.bindBuffer(gl.ARRAY_BUFFER, texturePosBuffer);
+    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 0, 0, 0, 1, 1, 0, 1]), gl.DYNAMIC_DRAW);
+    gl.bindBuffer(gl.ARRAY_BUFFER, null);
+    this.vertexPosBuffer = vertexPosBuffer;
+    this.texturePosBuffer = texturePosBuffer;
+  };
+  /**
+   * 鍒涘缓绾圭悊
+   */
+
+
+  RenderManager.prototype.initTexture = function () {
+    var gl = this.contextGL;
+    var textureRef = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, textureRef);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+    gl.bindTexture(gl.TEXTURE_2D, null);
+    return textureRef;
+  };
+  /**
+   * 鍒濆鍖朰UV绾圭悊
+   */
+
+
+  RenderManager.prototype.initTextures = function () {
+    var gl = this.contextGL;
+    var program = this.YUVProgram;
+    gl.useProgram(program);
+    var yTextureRef = this.initTexture();
+    var ySamplerRef = gl.getUniformLocation(program, 'ySampler');
+    gl.uniform1i(ySamplerRef, 0);
+    this.yTextureRef = yTextureRef;
+    var uTextureRef = this.initTexture();
+    var uSamplerRef = gl.getUniformLocation(program, 'uSampler');
+    gl.uniform1i(uSamplerRef, 1);
+    this.uTextureRef = uTextureRef;
+    var vTextureRef = this.initTexture();
+    var vSamplerRef = gl.getUniformLocation(program, 'vSampler');
+    gl.uniform1i(vSamplerRef, 2);
+    this.vTextureRef = vTextureRef;
+    gl.useProgram(null);
+  };
+  /**
+   * 鏄剧ず甯ф暟鎹�
+   * @param nWidth    瀹藉害
+   * @param nHeight   楂樺害
+   * @param nHeight   甯ф暟鎹�
+   */
+
+
+  RenderManager.prototype.SR_DisplayFrameData = function (nWidth, nHeight, pData, dWidth, dHeight) {
+    if (nWidth <= 0 || nHeight <= 0) {
+      return;
+    }
+
+    var gl = this.contextGL;
+
+    if (null == pData) {
+      gl.clearColor(0.0, 0.0, 0.0, 0.0);
+      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+      return;
+    }
+
+    var canvas = this.canvasElement;
+    this.nWindowWidth = canvas.width;
+    this.nWindowHeight = canvas.height;
+    var nWindowWidth = this.nWindowWidth;
+    var nWindowHeight = this.nWindowHeight;
+    gl.clearColor(0.8, 0.8, 1.0, 1.0);
+    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+    gl.viewport(0, 0, nWindowWidth, nWindowHeight);
+    this.updateFrameData(nWidth, nHeight, pData, dWidth, dHeight);
+    var program = this.YUVProgram;
+    gl.useProgram(program);
+    var vertexPosBuffer = this.vertexPosBuffer;
+    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
+    var vertexPosRef = gl.getAttribLocation(program, 'vertexPos');
+    gl.enableVertexAttribArray(vertexPosRef);
+    gl.vertexAttribPointer(vertexPosRef, 2, gl.FLOAT, false, 0, 0);
+    gl.bindBuffer(gl.ARRAY_BUFFER, null);
+    var texturePosBuffer = this.texturePosBuffer;
+    gl.bindBuffer(gl.ARRAY_BUFFER, texturePosBuffer);
+    var texturePosRef = gl.getAttribLocation(program, 'texturePos');
+    gl.enableVertexAttribArray(texturePosRef);
+    gl.vertexAttribPointer(texturePosRef, 2, gl.FLOAT, false, 0, 0);
+    gl.bindBuffer(gl.ARRAY_BUFFER, null);
+    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+    gl.disableVertexAttribArray(vertexPosRef);
+    gl.disableVertexAttribArray(texturePosRef);
+    gl.useProgram(null);
+  };
+  /**
+   * 涓婁紶YUV鏁版嵁鍒扮汗鐞�
+   * @param nWidth    瀹藉害
+   * @param nHeight   楂樺害
+   * @param nHeight   甯ф暟鎹�
+   */
+
+
+  RenderManager.prototype.updateFrameData = function (width, height, data, dWidth, dHeight) {
+    var gl = this.contextGL;
+    var yTextureRef = this.yTextureRef;
+    var uTextureRef = this.uTextureRef;
+    var vTextureRef = this.vTextureRef;
+    var i420Data = data; // debugger;
+
+    if (width == dWidth && height == dHeight) {
+      var yDataLength = width * height;
+      var yData = i420Data.subarray(0, yDataLength);
+      gl.activeTexture(gl.TEXTURE0);
+      gl.bindTexture(gl.TEXTURE_2D, yTextureRef);
+      gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width, height, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, yData);
+      var cbDataLength = width / 2 * height / 2;
+      var cbData = i420Data.subarray(width * height, width * height + cbDataLength);
+      gl.activeTexture(gl.TEXTURE2);
+      gl.bindTexture(gl.TEXTURE_2D, vTextureRef);
+      gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width / 2, height / 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, cbData);
+      var crDataLength = cbDataLength;
+      var crData = i420Data.subarray(width * height + width * height / 4, width * height + width * height / 4 + crDataLength);
+      gl.activeTexture(gl.TEXTURE1);
+      gl.bindTexture(gl.TEXTURE_2D, uTextureRef);
+      gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, width / 2, height / 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, crData);
+    } else {
+      // //瑁佸壀瀹�
+      var yDataLength = dWidth * dHeight;
+      var yData = new Uint8Array(yDataLength);
+
+      for (var i = 0; i < dHeight; i++) {
+        //var ySonData=new Uint8Array(dWidth) ;
+        var ySonData = i420Data.subarray(i * width, i * width + dWidth);
+
+        for (var j = 0; j < dWidth; j++) {
+          yData[i * dWidth + j] = ySonData[j];
+        }
+      }
+
+      gl.activeTexture(gl.TEXTURE0);
+      gl.bindTexture(gl.TEXTURE_2D, yTextureRef);
+      gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, dWidth, dHeight, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, yData);
+      yData = null;
+      ySonData = null;
+      var cbDataLength = dWidth / 2 * dHeight / 2;
+      var cbData = new Uint8Array(cbDataLength); //var cbSonData=new Uint8Array(dWidth/2) ;
+
+      for (var i = 0; i < dHeight / 2; i++) {
+        var cbSonData = i420Data.subarray(width * height + i * width / 2, width * height + i * width / 2 + dWidth / 2);
+
+        for (var j = 0; j < dWidth / 2; j++) {
+          cbData[i * dWidth / 2 + j] = cbSonData[j];
+        }
+      }
+
+      gl.activeTexture(gl.TEXTURE2);
+      gl.bindTexture(gl.TEXTURE_2D, vTextureRef);
+      gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, dWidth / 2, dHeight / 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, cbData);
+      cbData = null;
+      cbSonData = null;
+      var crDataLength = cbDataLength;
+      var crData = new Uint8Array(crDataLength);
+
+      for (var i = 0; i < dHeight / 2; i++) {
+        var crSonData = i420Data.subarray(width * height * 5 / 4 + i * width / 2, width * height * 5 / 4 + i * width / 2 + dWidth / 2);
+
+        for (var j = 0; j < dWidth / 2; j++) {
+          crData[i * dWidth / 2 + j] = crSonData[j];
+        }
+      }
+
+      gl.activeTexture(gl.TEXTURE1);
+      gl.bindTexture(gl.TEXTURE_2D, uTextureRef);
+      gl.texImage2D(gl.TEXTURE_2D, 0, gl.LUMINANCE, dWidth / 2, dHeight / 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, crData);
+      crData = null;
+      crSonData = null;
+    }
+  };
+  /**
+   * 璁剧疆鏄剧ず鍖哄煙
+   * @param stDisplayRect    鏄剧ず鍖哄煙
+   */
+
+
+  RenderManager.prototype.SR_SetDisplayRect = function (stDisplayRect) {
+    var gl = this.contextGL;
+    var nWindowWidth = this.nWindowWidth;
+    var nWindowHeight = this.nWindowHeight;
+    var texturePosValues = null;
+
+    if (stDisplayRect && nWindowWidth > 0 && nWindowHeight > 0) {
+      var fLeft = stDisplayRect.left / nWindowWidth;
+      var fTop = stDisplayRect.top / nWindowHeight;
+      var fRight = stDisplayRect.right / nWindowWidth;
+      var fBottom = stDisplayRect.bottom / nWindowHeight;
+      texturePosValues = new Float32Array([fRight, fTop, fLeft, fTop, fRight, fBottom, fLeft, fBottom]);
+    } else {
+      texturePosValues = new Float32Array([1, 0, 0, 0, 1, 1, 0, 1]);
+    }
+
+    var texturePosBuffer = this.texturePosBuffer;
+    gl.bindBuffer(gl.ARRAY_BUFFER, texturePosBuffer);
+    gl.bufferSubData(gl.ARRAY_BUFFER, 0, texturePosValues);
+    gl.bindBuffer(gl.ARRAY_BUFFER, null);
+  };
+  /**
+   * 閲婃斁鏄剧ず璧勬簮
+   */
+
+
+  RenderManager.prototype.SR_Destroy = function () {
+    var gl = this.contextGL;
+    var YUVProgram = this.YUVProgram;
+    gl.deleteProgram(YUVProgram);
+    var vertexPosBuffer = this.vertexPosBuffer;
+    var texturePosBuffer = this.texturePosBuffer;
+    gl.deleteBuffer(vertexPosBuffer);
+    gl.deleteBuffer(texturePosBuffer);
+    var yTextureRef = this.yTextureRef;
+    var uTextureRef = this.uTextureRef;
+    var vTextureRef = this.vTextureRef;
+    gl.deleteTexture(yTextureRef);
+    gl.deleteTexture(uTextureRef);
+    gl.deleteTexture(vTextureRef); //gl.getExtension('WEBGL_lose_context').loseContext();
+  };
+
+  return RenderManager;
+});
+
+var matchTemplate = function matchTemplate(templateName, params) {
+  var IFRAMETEMPLATE = ['theme', 'standard'];
+  var LOCALTEMPLATE = ['pcLive', 'pcRec', 'mobileLive', 'mobileRec', 'noData', 'security', 'voice', 'simple'];
+
+  if (typeof templateName === 'undefined') {
+    if (params.themeData) {
+      return {
+        templateType: 'themeData',
+        templateId: 'themeData'
+      };
+    }
+
+    return {
+      templateType: 'local',
+      templateId: ''
+    };
+  }
+
+  if (typeof templateName === 'string') {
+    if (templateName.length === 32) {
+      return {
+        templateType: 'remote',
+        templateId: templateName
+      };
+    } else if (IFRAMETEMPLATE.indexOf(templateName) !== -1) {
+      // 绮剧畝鐗堜笖涓嶄娇鐢ㄥご閮紝搴曢儴锛屼粎鎾斁瑙嗛锛屽缓璁娇鐢ㄦ寜闇�鍔犺浇閬垮厤iframe鍐呭瓨棰濆娑堣��
+      if (templateName === 'simple' && typeof params.header === 'undefined' && typeof params.footer === 'undefined') {
+        return {
+          templateType: 'local',
+          templateId: ''
+        };
+      }
+
+      return {
+        templateType: 'iframe',
+        templateId: templateName
+      };
+    } else if (LOCALTEMPLATE.indexOf(templateName) !== -1) {
+      return {
+        templateType: 'local',
+        templateId: templateName
+      };
+    }
+  }
+};
+
+var isVersion2Available = function isVersion2Available() {
+  var ua = window.navigator.userAgent.toLowerCase(); //鑾峰彇鐢ㄦ埛绔俊鎭�
+
+  var info = {
+    sa: /version.*safari/.test(ua),
+    //鍖归厤Safari娴忚鍣�
+    ch: /chrome/.test(ua),
+    //鍖归厤Chrome娴忚鍣�
+    ff: /gecko/.test(ua) && !/webkit/.test(ua) //鍖归厤Firefox娴忚鍣�
+
+  };
+  var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+
+  if (isMobile) {
+    return false;
+  } else if (info.ch) {
+    var getChromeVersion = function getChromeVersion() {
+      var arr = window.navigator.userAgent.split(' ');
+      var chromeVersion = '';
+
+      for (var i = 0; i < arr.length; i++) {
+        if (/chrome/i.test(arr[i])) chromeVersion = arr[i];
+      }
+
+      if (chromeVersion) {
+        return Number(chromeVersion.split('/')[1].split('.')[0]);
+      } else {
+        return false;
+      }
+    };
+
+    return getChromeVersion() > 91 && !!window.SharedArrayBuffer;
+  }
+
+  return false;
+};
+
+var EZUIKitPlayer = /*#__PURE__*/function () {
+  function EZUIKitPlayer(params) {
+    var _this = this;
+
+    _classCallCheck$1(this, EZUIKitPlayer);
+
+    var _params$autoplay = params.autoplay,
+        autoplay = _params$autoplay === void 0 ? true : _params$autoplay; // 濡傛灉璁剧疆浜嗘ā鏉匡紙闄ょ簿绠�鐗堬級锛屾澶勪笉鑷姩鎾斁锛屾牴鎹ā鏉垮垽鏂槸鍚︽墽琛岃嚜鍔ㄦ挱鏀�:
+
+    if (params.template && params.template !== "simple" || params.themeData) {
+      autoplay = false;
+    }
+
+    this.params = params;
+    this.autoplay = autoplay;
+    window.EZUIKit[params.id] = {
+      state: {
+        EZUIKitPlayer: {
+          init: window.EZUIKit[params.id] && window.EZUIKit[params.id].state && window.EZUIKit[params.id].state.EZUIKitPlayer.init || false,
+          themeInit: window.EZUIKit[params.id] && window.EZUIKit[params.id].state && window.EZUIKit[params.id].state.EZUIKitPlayer.themeInit || false,
+          talkInit: window.EZUIKit[params.id] && window.EZUIKit[params.id].state && window.EZUIKit[params.id].state.EZUIKitPlayer.talkInit || false
+        }
+      }
+    };
+
+    if (matchTemplate(this.params.template, params).templateType !== 'iframe') {
+      this.Monitor = new Monitor({
+        env: !(typeof params.disableMonitor !== 'undefined' && params.disableMonitor) ? 'online' : 'test12'
+      }, this);
+      this.id = params.id;
+      this.width = params.width;
+      this.height = params.height;
+      this.url = params.url;
+      this.accessToken = params.accessToken;
+      this.themeId = matchTemplate(params.template, params).templateId;
+      this.id = params.id;
+      this.audio = true;
+      this.poster = params.poster;
+      this.speed = 1;
+      this.disabledTimeLine = false;
+      this.disabledPTZ = false;
+      this.enableSharedArrayBufferGuide = false;
+      this.capacity = {};
+      this.env = {
+        domain: "https://open.ys7.com"
+      };
+      var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+      this.isMobile = isMobile; // 鍏煎澶氭鍒濆鍖�
+
+      if (document.getElementById("".concat(this.id, "-wrap"))) {
+        document.getElementById("".concat(this.id, "-wrap")).innerHTML = "";
+        document.getElementById("".concat(this.id, "-wrap")).id = this.id;
+      }
+
+      this.staticPath = isVersion2Available() ? "https://open.ys7.com/console/ezuikit_static/v6/v2" : "https://open.ys7.com/console/ezuikit_static/v6/v1";
+
+      if (typeof params.staticPath === 'string') {
+        if (params.staticPath.startsWith("http")) {
+          this.staticPath = params.staticPath;
+        } else {
+          this.staticPath = window.location.protocol + '//' + window.location.host + params.staticPath;
+        }
+
+        if (isVersion2Available()) {
+          this.staticPath += '/v2';
+        } else {
+          this.staticPath += '/v1';
+        }
+      }
+
+      if (typeof params.audio !== 'undefined') {
+        this.audio = params.audio;
+      }
+
+      if (typeof params.env !== 'undefined') {
+        this.env = Object.assign(this.env, params.env);
+      }
+
+      if (typeof params.isMobile !== 'undefined') {
+        this.isMobile = params.isMobile;
+      }
+
+      if (typeof params.disabledTimeLine !== 'undefined') {
+        this.disabledTimeLine = params.disabledTimeLine;
+      }
+
+      if (typeof params.disabledPTZ !== 'undefined') {
+        this.disabledPTZ = params.disabledPTZ;
+      }
+
+      if (typeof params.enableSharedArrayBufferGuide !== 'undefined') {
+        this.enableSharedArrayBufferGuide = params.enableSharedArrayBufferGuide;
+      }
+
+      var pluginUrl = "".concat(this.staticPath, "/js/jsPluginV1-1.0.0.min.js");
+
+      if (isVersion2Available()) {
+        console.log("鍚敤澶氱嚎绋嬭В鏋愯棰�");
+        pluginUrl = "".concat(this.staticPath, "/js/jsPluginV2-2.0.1.min.js");
+      } else {
+        // 鏄惁寮曞鐢ㄦ埛寮�鍚胺姝屽疄楠屽 Google Labs 鐗规��
+        //enableSharedArrayBufferGuide
+        var getChromeVersion = function getChromeVersion() {
+          var arr = navigator.userAgent.split(' ');
+          var chromeVersion = '';
+
+          for (var i = 0; i < arr.length; i++) {
+            if (/chrome/i.test(arr[i])) {
+              chromeVersion = arr[i];
+            }
+          }
+
+          if (chromeVersion) {
+            return Number(chromeVersion.split('/')[1].split('.')[0]);
+          }
+
+          return false;
+        }; // pc绔� 璋锋瓕娴忚鍣� 鐗堟湰92 ~ 105
+
+
+        if (!isMobile && 91 < getChromeVersion < 106 && this.enableSharedArrayBufferGuide) {
+          console.log("鎻愮ず鐢ㄦ埛寮�鍚胺姝屽疄楠屽鐗规��");
+          var wapDomId = "".concat(this.id, "-wrap");
+          var guideDom = document.createElement("div");
+          var guideSpan = document.createElement("span");
+          guideSpan.innerHTML = "鎮ㄥ綋鍓嶆祻瑙堝櫒鍙互寮�鍚胺姝屽疄楠屽澶氱嚎绋嬬壒鎬э紝鑾峰彇鏇村ソ鎾斁浣撻獙锛岄伩鍏嶆祻瑙堝櫒鍗¢】鍙婂穿婧�,璇﹁";
+          guideDom.appendChild(guideSpan);
+          var guideLink = document.createElement("a");
+          guideLink.href = "https://open.ys7.com/help/384";
+          guideLink.setAttribute("target", "_blank");
+          guideDom.appendChild(guideLink);
+          guideLink.innerHTML = "寮�鍚鏄�"; //guideDom.innerHTML = "鎮ㄧ殑娴忚鍣ㄥ綋鍓嶄娇鐢ㄥ崟杩涚▼鎾斁瑙嗛锛屽彲鑳藉洜鍐呭瓨鍗犵敤杩囬珮瀵艰嚧娴忚鍣ㄥ崱椤�,鎮ㄥ彲鍙傝�兟疯胺姝屾祻瑙堝櫒寮�鍚绾跨▼锛堥摼鎺ワ級路寮�鍚胺姝屽疄楠屽澶氱嚎绋嬬壒鎬э紝鑾峰彇鏇村ソ鎾斁浣撻獙";
+
+          guideDom.id = "".concat(this.id, "-guide");
+          guideDom.style = "font-size:12px;color:red;";
+          setTimeout(function () {
+            if (document.getElementById(wapDomId)) {
+              document.getElementById(wapDomId).insertBefore(guideDom, document.getElementById(_this.id));
+            }
+          }, 5000);
+        }
+      }
+
+      this.pluginStatus = new Status(this, this.id);
+      addJs(pluginUrl, function () {
+        if (_this.autoplay) {
+          _this.initTime = new Date().getTime();
+
+          _this.Monitor.dclog({
+            url: _this.url,
+            action: 0,
+            text: 'startInit'
+          });
+
+          _this.Monitor.localInfoLog({
+            Serial: matchEzopenUrl(_this.url).deviceSerial,
+            Channel: matchEzopenUrl(_this.url).channelNo,
+            Ver: isVersion2Available() ? "v7.0.0" : "v6.0.0",
+            ExterVer: isVersion2Available() ? "v7.0.0" : "v6.0.0"
+          });
+
+          var initEZUIKitPlayerPromise = _this.initEZUIKitPlayer(params);
+
+          var getRealUrlPromise = _this._getRealUrlPromise(params.accessToken, params.url);
+
+          Promise.all([initEZUIKitPlayerPromise, getRealUrlPromise]).then(function (values) {
+            if (values[1]) {
+              _this.playStartTime = new Date().getTime();
+
+              _this._pluginPlay(values[1], function () {
+                console.log("鑷姩鎾斁鎴愬姛");
+
+                _this.Monitor.dclog({
+                  url: _this.url,
+                  action: 202,
+                  d: new Date().getTime() - _this.initTime,
+                  text: 'autoPlaySuccess'
+                });
+              }, function () {
+                console.log("鑷姩鎾斁澶辫触");
+
+                _this.Monitor.dclog({
+                  url: _this.url,
+                  action: 402,
+                  d: new Date().getTime() - _this.initTime,
+                  text: 'autoPlayError'
+                });
+              });
+            } else {
+              console.log("promise of one", values);
+            }
+
+            window.EZUIKit[params.id].state.EZUIKitPlayer.init = true;
+
+            if (document.getElementById("".concat(params.id, "canvas_draw0"))) {
+              document.getElementById("".concat(params.id, "canvas_draw0")).style.border = "none";
+            }
+          })["catch"](function (err) {
+            console.log("err", err);
+
+            _this.pluginStatus.loadingSetText({
+              text: err && err.msg || "鑾峰彇鎾斁鍦板潃澶辫触",
+              color: 'red'
+            });
+          });
+        } else {
+          _this.initTime = new Date().getTime();
+
+          _this.Monitor.dclog({
+            url: _this.url,
+            action: 0,
+            text: 'startInit'
+          });
+
+          _this.Monitor.localInfoLog({
+            Serial: matchEzopenUrl(_this.url).deviceSerial,
+            Channel: matchEzopenUrl(_this.url).channelNo,
+            Ver: isVersion2Available() ? "v7.0.0" : "v6.0.0"
+          });
+
+          var initEZUIKitPlayerPromise = _this.initEZUIKitPlayer(params);
+
+          initEZUIKitPlayerPromise.then(function (data) {
+            console.log("鍒濆鍖栨垚鍔�", data);
+            window.EZUIKit[params.id].state.EZUIKitPlayer.init = true;
+
+            if (document.getElementById("".concat(params.id, "canvas_draw0"))) {
+              document.getElementById("".concat(params.id, "canvas_draw0")).style.border = "none";
+            }
+
+            _this.Monitor.dclog({
+              url: _this.url,
+              action: 201,
+              d: new Date().getTime() - _this.initTime,
+              text: 'initSuccess'
+            });
+          });
+        }
+      }, function () {
+        if (isVersion2Available()) {
+          return !!window.JSPluginV2;
+        }
+
+        return !!window.JSPluginV1;
+      });
+
+      if (params.plugin && params.plugin.indexOf("talk") !== -1) {
+        this.Talk = new Talk(this);
+        window.EZUIKit[params.id].state.EZUIKitPlayer.talkInit = true;
+      }
+
+      this.getDeviceCapacity();
+    } else {
+      return new EZUIKitV3$1.EZUIKitPlayer(params);
+    }
+  }
+
+  _createClass$1(EZUIKitPlayer, [{
+    key: "initEZUIKitPlayer",
+    value: function initEZUIKitPlayer(params) {
+      var _this2 = this;
+
+      var id = params.id,
+          _params$width = params.width,
+          width = _params$width === void 0 ? 600 : _params$width,
+          _params$height = params.height,
+          height = _params$height === void 0 ? 400 : _params$height;
+
+      if (!params.width || !params.height) {
+        var videoDOMBounding = document.getElementById(id).getBoundingClientRect();
+
+        if (!params.width && videoDOMBounding.width > 0) {
+          width = videoDOMBounding.width;
+        }
+
+        if (!params.height && videoDOMBounding.height > 0) {
+          height = videoDOMBounding.height;
+        }
+      }
+
+      if (!document.getElementById("".concat(id, "-wrap"))) {
+        var wapDom = document.createElement("div");
+        wapDom.id = "".concat(id, "-wrap");
+        wapDom.style = "display:inline-block;width:".concat(width, "px;position:relative;vertical-align: bottom;");
+        document.getElementById(id).parentNode.insertBefore(wapDom, document.getElementById(id));
+        document.getElementById(id).parentNode.removeChild(document.getElementById(id)); // wapDom.appendChild(document.getElementById(id));
+
+        wapDom.innerHTML = "<div id=".concat(id, "></div>");
+        document.getElementById(id).style = "display:inline-block;width:".concat(width, "px;height:").concat(height, "px;");
+        document.getElementById(id).style.verticalAlign = "top";
+      }
+
+      if (this.themeId) {
+        this.Theme = new Theme(this, params.id);
+        window.EZUIKit[params.id].state.EZUIKitPlayer.themeInit = true;
+        this.Monitor.dclog({
+          url: this.url,
+          action: 2,
+          text: this.themeId
+        });
+
+        if (typeof this.params.handleThemeChange === 'function') {
+          this.handleThemeChange = this.params.handleThemeChange;
+        }
+      } // 鍒濆鍖朚essage妯″潡
+
+
+      var pluginMessage = new Message(this, id);
+      this.Message = pluginMessage;
+
+      var initDecoder = function initDecoder(resolve, reject) {
+        var jSPlugin;
+
+        if (isVersion2Available()) {
+          jSPlugin = new window.JSPluginV2({
+            szId: id,
+            iType: 2,
+            iWidth: width,
+            iHeight: height,
+            iMaxSplit: 1,
+            iCurrentSplit: 1,
+            szBasePath: "",
+            staticPath: _this2.staticPath,
+            oStyle: {
+              border: "none",
+              background: "#000000"
+            }
+          }); // 澧炲姞瑙嗛瀹瑰櫒
+          //var pluginStatus = new Status(this, id);
+
+          _this2.pluginStatus.loadingStart(id);
+
+          _this2.pluginStatus.loadingSetText({
+            text: '鍒濆鍖栨挱鏀惧櫒瀹屾垚'
+          });
+
+          jSPlugin.EventCallback = {
+            pluginErrorHandler: function pluginErrorHandler(iWndIndex, iErrorCode, oError) {
+              //鎻掍欢閿欒鍥炶皟
+              console.log(iWndIndex, iErrorCode, oError);
+
+              if (iErrorCode === 1003) {
+                console.log("鏂祦");
+
+                _this2.pluginStatus.loadingSetText({
+                  text: "杩炴帴鏂紑锛岃閲嶈瘯",
+                  color: 'red'
+                });
+
+                if (typeof _this2.params.handleError === 'function') {
+                  _this2.params.handleError({
+                    msg: "杩炴帴鏂紑锛岃閲嶈瘯",
+                    retcode: 1003,
+                    id: _this2.params.id,
+                    type: "handleError"
+                  });
+                }
+              }
+            }
+          };
+          _this2.env = {
+            domain: "https://open.ys7.com"
+          };
+
+          if (typeof params.env !== 'undefined') {
+            _this2.env = Object.assign(_this2.env, params.env);
+          }
+
+          if (typeof params.handleTalkSuccess !== 'undefined') {
+            _this2.handleTalkSuccess = params.handleTalkSuccess;
+          }
+
+          if (typeof params.handleTalkError !== 'undefined') {
+            _this2.handleTalkError = params.handleTalkError;
+          }
+
+          _this2.errorHander = new Code();
+          _this2.jSPlugin = jSPlugin; // if (this.themeId) {
+          //   this.Theme = new Theme(this, id);
+          //   window.EZUIKit[params.id].state.EZUIKitPlayer.themeInit = true;
+          // }
+
+          var checkTimer = setInterval(function () {
+            if (_this2.jSPlugin.Module && _this2.jSPlugin.Module._JSPlayM4_GetSDKVersion && _this2.jSPlugin.Module._JSPlayM4_GetSDKVersion()) {
+              clearInterval(checkTimer);
+
+              if (typeof _this2.params.handleInitSuccess === 'function') {
+                _this2.params.handleInitSuccess({
+                  retcode: 0,
+                  id: _this2.params.id,
+                  type: "handleInitSuccess"
+                });
+              }
+
+              resolve({
+                meta: {
+                  retcode: 200,
+                  msg: "鍒濆鍖栨垚鍔�"
+                }
+              });
+            }
+          }, 50);
+        } else {
+          jSPlugin = new window.JSPluginV1({
+            szId: id,
+            iType: 2,
+            iWidth: width,
+            iHeight: height,
+            iMaxSplit: 1,
+            iCurrentSplit: 1,
+            szBasePath: "",
+            staticPath: _this2.staticPath,
+            oStyle: {
+              border: "none",
+              background: "#000000"
+            }
+          }); // 澧炲姞瑙嗛瀹瑰櫒
+          //var pluginStatus = new Status(this, id);
+
+          _this2.pluginStatus.loadingStart(id);
+
+          _this2.pluginStatus.loadingSetText({
+            text: '鍒濆鍖栨挱鏀惧櫒瀹屾垚'
+          });
+
+          jSPlugin.EventCallback = {
+            loadEventHandler: function loadEventHandler() {},
+            zoomEventResponse: function
+              /*iMode, aPoint*/
+            zoomEventResponse() {//鐢靛瓙鏀惧ぇ鍥炶皟
+            },
+            windowEventSelect: function windowEventSelect(iWndIndex) {//鎻掍欢閫変腑绐楀彛鍥炶皟
+            },
+            pluginErrorHandler: function pluginErrorHandler(iWndIndex, iErrorCode, oError) {
+              //鎻掍欢閿欒鍥炶皟
+              console.log(iWndIndex, iErrorCode, oError);
+
+              if (iErrorCode === 1003) {
+                console.log("鏂祦");
+
+                _this2.pluginStatus.loadingSetText({
+                  text: "杩炴帴鏂紑锛岃閲嶈瘯",
+                  color: 'red'
+                });
+
+                if (typeof _this2.params.handleError === 'function') {
+                  _this2.params.handleError({
+                    msg: "杩炴帴鏂紑锛岃閲嶈瘯",
+                    retcode: 1003,
+                    id: _this2.params.id,
+                    type: "handleError"
+                  });
+                }
+              }
+            },
+            windowEventOver: function windowEventOver(iWndIndex) {},
+            windowEventOut: function windowEventOut(iWndIndex) {},
+            windowEventUp: function windowEventUp(iWndIndex) {},
+            windowFullCcreenChange: function windowFullCcreenChange(bFull) {},
+            firstFrameDisplay: function firstFrameDisplay(iWndIndex, iWidth, iHeight) {
+              console.log(iWidth, iHeight);
+              jSPlugin.JS_SetCanFullScreen(false);
+
+              _this2.pluginStatus.loadingClear();
+            },
+            performanceLack: function performanceLack() {},
+            mouseEvent: function mouseEvent(iMouseEventType, iMouseX, iMouseY) {}
+          };
+          _this2.env = {
+            domain: "https://open.ys7.com"
+          };
+
+          if (typeof params.env !== 'undefined') {
+            _this2.env = Object.assign(_this2.env, params.env);
+          }
+
+          if (typeof params.handleTalkSuccess !== 'undefined') {
+            _this2.handleTalkSuccess = params.handleTalkSuccess;
+          }
+
+          if (typeof params.handleTalkError !== 'undefined') {
+            _this2.handleTalkError = params.handleTalkError;
+          }
+
+          _this2.errorHander = new Code();
+          _this2.jSPlugin = jSPlugin; // if (this.themeId) {
+          //   this.Theme = new Theme(this, id);
+          //   window.EZUIKit[params.id].state.EZUIKitPlayer.themeInit = true;
+          // }
+          // 寰呴渶瑕佹敼閫爌lugin锛屽紓姝ュ垽鏂紱
+
+          if (typeof _this2.params.handleInitSuccess === 'function') {
+            _this2.params.handleInitSuccess({
+              retcode: 0,
+              id: _this2.params.id,
+              type: "handleInitSuccess"
+            });
+          }
+
+          resolve({
+            meta: {
+              retcode: 200,
+              msg: "鍒濆鍖栨垚鍔�"
+            }
+          });
+        }
+      };
+
+      var initDecoderPromise = new Promise(initDecoder);
+      return initDecoderPromise;
+    }
+  }, {
+    key: "_getRealUrlPromise",
+    value: function _getRealUrlPromise(accessToken, url) {
+      var _this3 = this;
+
+      var apiDomain = this.env.domain;
+
+      if (this.env) {
+        apiDomain = this.env.domain;
+      }
+
+      var getRealUrlPromise = function getRealUrlPromise(resolve, reject) {
+        var realUrl = '';
+        var apiUrl = apiDomain + "/api/lapp/live/url/ezopen";
+        var data = new FormData();
+        data.append("ezopen", url);
+        data.append("isFlv", "false");
+        data.append("userAgent", window.navigator.userAgent);
+        data.append("isHttp", "false");
+        data.append("accessToken", accessToken);
+        fetch(apiUrl, {
+          method: "POST",
+          // headers: {
+          //   'Content-Type': 'application/json'
+          // },
+          body: data
+        }).then(function (response) {
+          return response.json();
+        }).then(function (data) {
+          if (data.code == 200 || data.retcode == 0) {
+            var playUrl = "";
+            var stream = "";
+
+            if (data.ext && data.ext.token) {
+              realUrl += data.data;
+              stream = data.ext.token;
+              playUrl = data.data;
+            } else if (data.data && data.data.token) {
+              realUrl += data.data.url;
+              stream = data.data.token;
+              playUrl = data.data.url;
+            }
+
+            var type = url.indexOf('live') !== -1 ? 'live' : 'playback';
+
+            if (type === 'live') {
+              realUrl = realUrl + '&ssn=' + stream + '&auth=1&biz=4&cln=100';
+            } else {
+              realUrl = realUrl + '&ssn=' + stream + '&auth=1&cln=100';
+            }
+
+            console.log(realUrl); // 璁剧疆绉橀挜 - 濡傛灉鍦板潃涓寘鍚閽ュ弬鏁帮紝鎾斁鍓嶉厤缃埌JSPlugin瀵瑰簲瀹炰緥涓�
+
+            var validateCode = getQueryString('checkCode', realUrl);
+
+            if (validateCode) {
+              if (typeof _this3.jSPlugin.decoderVersion !== 'undefined' && _this3.jSPlugin.decoderVersion === '2.0') {
+                _this3.validateCode = validateCode;
+              } else {
+                console.log("璁剧疆瀵嗛挜", validateCode);
+
+                _this3.jSPlugin.JS_SetSecretKey(0, validateCode);
+              }
+            } // 鍥炴斁澶勭悊
+
+
+            if (realUrl.indexOf('playback') !== -1) {
+              var wsBegin = getQueryString('begin', playUrl) || getQueryString('begin', url);
+              var wsEnd = getQueryString('end', playUrl) || getQueryString('end', url); // 鍏煎鍚勭鏃堕棿鏍煎紡
+
+              if (!wsBegin) {
+                var defaultDate = new Date();
+                realUrl = realUrl + '&begin=' + defaultDate.Format('yyyyMMdd') + 'T000000Z';
+              } else {
+                realUrl = realUrl.replace('&begin=' + getQueryString('begin', playUrl), '&begin=' + formatRecTime(wsBegin, '000000'));
+
+                if (!getQueryString('begin', realUrl)) {
+                  realUrl += '&begin=' + formatRecTime(wsBegin, '000000');
+                }
+              }
+
+              if (!wsEnd) {
+                realUrl = realUrl + '&end=' + formatRecTime(getQueryString('begin', realUrl).substr(0, 8), '235959');
+              } else {
+                realUrl = realUrl.replace('&end=' + getQueryString('end', playUrl), '&end=' + formatRecTime(wsEnd, '235959'));
+
+                if (!getQueryString('end', realUrl)) {
+                  realUrl += '&end=' + formatRecTime(wsEnd, '235959');
+                }
+              } // api閿欒澶勭悊
+
+
+              if (!getQueryString('stream', playUrl)) {
+                realUrl = realUrl.replace('stream', '&stream');
+              }
+
+              if (url.indexOf('.cloud') !== -1) {
+                var recAPISuccess = function recAPISuccess(data) {
+                  if (data.code == 200) {
+                    var recSliceArr = [];
+
+                    if (data.data && data.data.files && data.data.files.length > 0) {
+                      var dataArr = data.data.files;
+                      var nextFileTime = new Date().getTime();
+                      var isAll = data.data.isAll; // mock
+                      // var number = 0;
+                      //isAll = false;
+
+                      if (isAll) {
+                        recSliceArr = recSliceArrFun(dataArr);
+                        var recSliceArrJSON = JSON.stringify(recSliceArr).replace('\\', '');
+                        realUrl += '&recSlice=' + recSliceArrJSON.replace('\\', '') + '&r=' + Math.random();
+                        resolve(realUrl);
+                      } else {
+                        // 浜戝瓨鍌ㄥ洖璋冧簨鍔�
+                        var recTransaction = function recTransaction() {
+                          function recAPIV2Success(data) {
+                            if (data.data && data.data.files && data.data.files.length > 0) {
+                              //if(number < 2 ) {
+                              if (data.data.isAll == false) {
+                                if (data.data.files) {
+                                  dataArr = dataArr.concat(data.data.files);
+                                }
+
+                                nextFileTime = data.data.nextFileTime > 0 ? data.data.nextFileTime : new Date().getTime();
+                                recTransaction();
+                              } else {
+                                recSliceArr = recSliceArrFun(dataArr);
+                                var recSliceArrJSON = JSON.stringify(recSliceArr).replace('\\', '');
+                                realUrl += '&recSlice=' + recSliceArrJSON.replace('\\', '') + '&r=' + Math.random();
+                                resolve(realUrl);
+                              } // mock
+                              //number = number + 1;
+
+                            } else {
+                              recSliceArr = recSliceArrFun(dataArr);
+                              var recSliceArrJSON = JSON.stringify(recSliceArr).replace('\\', '');
+                              realUrl += '&recSlice=' + recSliceArrJSON.replace('\\', '') + '&r=' + Math.random();
+                              resolve(realUrl);
+                            }
+                          }
+
+                          recSliceParams.startTime = nextFileTime;
+                          request(recSliceUrl, 'POST', recSliceParams, '', recAPIV2Success);
+                        };
+
+                        recTransaction();
+                      }
+                    } else {
+                      reject({
+                        retcode: -1,
+                        msg: "鏈壘鍒板綍鍍忕墖娈�"
+                      });
+                    }
+                  } else {
+                    reject({
+                      retcode: -1,
+                      msg: "鏈壘鍒板綍鍍忕墖娈�"
+                    });
+                  }
+
+                  function recSliceArrFun(data) {
+                    var downloadPathArr = [];
+                    data.forEach(function (item, index) {
+                      if (downloadPathArr.length == 0 || item.downloadPath !== downloadPathArr[downloadPathArr.length - 1].downloadPath) {
+                        downloadPathArr.push({
+                          downloadPath: item.downloadPath,
+                          ownerId: item.ownerId,
+                          iStorageVersion: item.iStorageVersion,
+                          videoType: item.videoType,
+                          iPlaySpeed: 0,
+                          startTime: item.startTime,
+                          endTime: item.endTime
+                        });
+                      } else {
+                        downloadPathArr[downloadPathArr.length - 1].endTime = item.endTime;
+                      }
+                    });
+                    return downloadPathArr;
+                  }
+                };
+
+                //浜戝瓨鍌ㄥ洖鏀�
+                // 璋冪敤鍥炴斁API鎺ュ彛鑾峰彇鍥炴斁鐗囨 - start
+                var recBegin = reRormatRecTime(getQueryString('begin', realUrl));
+                var recEnd = reRormatRecTime(getQueryString('end', realUrl));
+                var deviceSerial = getQueryString('serial', realUrl);
+                var channelNo = getQueryString('chn', realUrl);
+                var recSliceUrl = apiDomain + "/api/lapp/video/by/time";
+                var recSliceParams = {
+                  accessToken: _this3.accessToken,
+                  recType: 1,
+                  deviceSerial: deviceSerial,
+                  channelNo: channelNo,
+                  startTime: recBegin,
+                  endTime: recEnd,
+                  version: '2.0'
+                };
+                request(recSliceUrl, 'POST', recSliceParams, '', recAPISuccess);
+              } else {
+                // 鏈湴鍥炴斁
+                //alarm rec - start
+                if (url.indexOf('alarmId') !== -1) {
+                  var _recAPISuccess = function _recAPISuccess(data) {
+                    if (data.code == 200) {
+                      var recSliceArr = [];
+
+                      if (data.data) {
+                        recSliceArr = recSliceArrFun([data.data]);
+                        var recSliceArrJSON = JSON.stringify(recSliceArr).replace('\\', '');
+                        realUrl += '&recSlice=' + recSliceArrJSON.replace('\\', '');
+                        console.log("realUrl", realUrl, data.data.recType);
+
+                        if (data.data.recType == 1) {
+                          realUrl = realUrl.replace('/playback', '/cloudplayback');
+                        } else {
+                          realUrl = realUrl.replace('/cloudplayback', '/playback');
+                        } // _this.opt.sources[0] = realUrl;
+
+
+                        resolve(realUrl); // request(nodeUrl, 'GET', '', '', nodeSuccess, nodeError);
+                      }
+                    }
+
+                    function recSliceArrFun(data) {
+                      var downloadPathArr = [];
+                      data.forEach(function (item, index) {
+                        if (downloadPathArr.length == 0 || item.downloadPath !== downloadPathArr[downloadPathArr.length - 1].downloadPath) {
+                          downloadPathArr.push({
+                            downloadPath: item.downloadPath,
+                            ownerId: item.ownerId,
+                            iStorageVersion: item.iStorageVersion,
+                            videoType: item.videoType,
+                            iPlaySpeed: 0,
+                            startTime: item.startTime,
+                            endTime: item.endTime
+                          });
+                        } else {
+                          downloadPathArr[downloadPathArr.length - 1].endTime = item.endTime;
+                        }
+                      });
+                      console.log("downloadPathArr", downloadPathArr);
+                      return downloadPathArr;
+                    }
+                  };
+
+                  console.log("杩涘叆alarmId鍥炴斁"); // 璋冪敤鍥炴斁API鎺ュ彛鑾峰彇鍥炴斁鐗囨 - start
+
+                  var alarmId = getQueryString('alarmId', realUrl);
+                  var recBegin = reRormatRecTime(getQueryString('begin', realUrl));
+                  var recEnd = reRormatRecTime(getQueryString('end', realUrl));
+                  var deviceSerial = getQueryString('serial', realUrl);
+                  var channelNo = getQueryString('chn', realUrl);
+                  var recSliceUrl = apiDomain + "/api/lapp/video/by/id";
+                  var recSliceParams = {
+                    accessToken: _this3.accessToken,
+                    // recType: 1,
+                    deviceSerial: deviceSerial,
+                    channelNo: channelNo,
+                    alarmId: alarmId // startTime:recBegin,
+                    // endTime:recEnd
+
+                  };
+                  request(recSliceUrl, 'POST', recSliceParams, '', _recAPISuccess);
+                } else {
+                  // arlar rec - end
+                  // request(nodeUrl, 'GET', '', '', nodeSuccess, nodeError);
+                  resolve(realUrl);
+                }
+              }
+            } else {
+              resolve(realUrl);
+            }
+          } else {
+            _this3.pluginStatus.loadingSetText({
+              text: data.msg,
+              color: 'red'
+            });
+
+            if (typeof _this3.params.handleError === 'function') {
+              _this3.params.handleError({
+                retcode: data.code,
+                msg: data.msg,
+                id: _this3.params.id,
+                type: "handleError"
+              });
+            }
+
+            reject(data);
+          } // fetch real url end
+
+        });
+      };
+
+      return new Promise(function (resolve, reject) {
+        return getRealUrlPromise(resolve, reject);
+      }); // 鏍煎紡鍖栧洖鏀炬椂闂�
+
+      function formatRecTime(time, defaultTime) {
+        // 鐢ㄦ埛鏍煎紡 鏃犻渶鏇存敼 => 20182626T000000Z
+        // return time
+        // 鐢ㄦ埛鏍煎紡闇�瑕佹洿鏀�
+        //鐢ㄦ埛鏃堕棿闀垮害涓� 14 20181226000000  =銆� 20181226000000
+        // 鐢ㄦ埛闀垮害涓�12     201812260000    =銆� 201812260000 + defaultTime鍚庨潰2浣�
+        // 鐢ㄦ埛闀垮害涓�10     2018122600      =銆� 201812260000 + defaultTime鍚庨潰4浣�
+        // 鐢ㄦ埛闀垮害涓�8     20181226         =銆� 201812260000 + defaultTime鍚庨潰6浣�
+        // 缁撴灉 20181226000000 14浣�
+        // 鎻掑叆 TZ
+        var reg = /^[0-9]{8}T[0-9]{6}Z$/;
+
+        if (reg.test(time)) {
+          // 鐢ㄦ埛鏍煎紡 鏃犻渶鏇存敼 => 20182626T000000Z
+          return time;
+        } else if (/[0-9]{8,14}/.test(time)) {
+          var start = 6 - (14 - time.length);
+          var end = defaultTime.length;
+          var standardTime = time + defaultTime.substring(start, end);
+          return standardTime.slice(0, 8) + 'T' + standardTime.slice(8) + 'Z';
+        }
+
+        throw new Error('鍥炴斁鏃堕棿鏍煎紡鏈夎锛岃纭');
+      }
+
+      function reRormatRecTime(time) {
+        var year = time.slice(0, 4);
+        var month = time.slice(4, 6);
+        var day = time.slice(6, 8);
+        var hour = time.slice(9, 11);
+        var minute = time.slice(11, 13);
+        var second = time.slice(13, 15);
+        var date = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second; // if (_this.opt.domain !== 'open') {
+        //   return new Date(date.replace(/-/g, '/')).getTime() + (8 * 60 * 60 * 1000);
+        // }
+
+        return new Date(date.replace(/-/g, '/')).getTime();
+      }
+    }
+  }, {
+    key: "_pluginPlay",
+    value: function _pluginPlay(data, successCallback, errorCallback) {
+      var _this4 = this;
+
+      console.log("get real url result ===", data);
+
+      if (!data) {
+        return false;
+      }
+
+      function getPlayParams(url) {
+        var websocketConnectUrl = url.split('?')[0].replace('/live', '').replace('/playback', '');
+        var websocketStreamingParam = (url.indexOf('/live') === -1 ? url.indexOf('cloudplayback') !== -1 ? '/cloudplayback?' : '/playback?' : '/live?') + url.split('?')[1];
+
+        if (websocketStreamingParam.indexOf('/playback') !== -1) {
+          websocketStreamingParam = websocketStreamingParam.replace("stream=2", 'stream=1');
+        } // 鏈湴鍥炴斁浠呮敮鎸佷富鐮佹祦
+
+
+        return {
+          websocketConnectUrl: websocketConnectUrl,
+          websocketStreamingParam: websocketStreamingParam
+        };
+      }
+
+      var wsUrl = getPlayParams(data).websocketConnectUrl;
+
+      if (this.env && this.env.wsUrl) {
+        wsUrl = this.env.wsUrl;
+      }
+
+      var wsParams = {
+        playURL: getPlayParams(data).websocketStreamingParam
+      };
+      this.jSPlugin.JS_Play(wsUrl, wsParams, 0).then(function () {
+        console.log("鎾斁鎴愬姛");
+
+        if (_this4.validateCode && typeof _this4.jSPlugin.decoderVersion !== 'undefined' && _this4.jSPlugin.decoderVersion === '2.0') {
+          _this4.jSPlugin.JS_SetSecretKey(0, _this4.validateCode);
+        }
+
+        _this4.pluginStatus.loadingClear();
+
+        _this4.pluginStatus.setPlayStatus({
+          play: true,
+          loading: false
+        });
+
+        if (_this4.Theme) {
+          _this4.Theme.setDecoderState({
+            play: true
+          });
+
+          var isOpenSound = lodash.findIndex(_this4.Theme.themeData.footer.btnList, function (v) {
+            return v.iconId === 'sound' && v.isrender === 1 && v.defaultActive === 1;
+          }) > -1;
+          _this4.audio = isOpenSound;
+        }
+
+        if (_this4.audio) {
+          setTimeout(function () {
+            _this4.openSound();
+          }, 500);
+        }
+
+        if (typeof _this4.params.handleSuccess === 'function') {
+          _this4.params.handleSuccess({
+            retcode: 0,
+            id: _this4.params.id,
+            type: "handleSuccess"
+          });
+        }
+
+        successCallback();
+
+        _this4.Monitor.dclog({
+          url: _this4.url,
+          action: 211,
+          d: new Date().getTime() - _this4.playStartTime,
+          text: 'startPlaySuccess'
+        });
+
+        _this4.Monitor.playLog({
+          Enc: _this4.url.indexOf("@") === -1 ? 0 : 1,
+          // 0 涓嶅姞瀵� 1 鍔犲瘑
+          PlTp: _this4.url.indexOf("back") === -1 ? 1 : 2,
+          // 1 鐩存挱 2 鍥炴斁
+          Via: 2,
+          // 2 鏈嶅姟绔彇娴�
+          ErrCd: 0,
+          Cost: new Date().getTime() - _this4.playStartTime,
+          // 姣鏁�
+          Serial: matchEzopenUrl(_this4.url).deviceSerial,
+          Channel: matchEzopenUrl(_this4.url).channelNo,
+          Ver: isVersion2Available() ? "v7.0.0" : "v6.0.0"
+        });
+      }, function (err) {
+        console.log("err", err);
+        var msg = '鎾斁澶辫触锛岃妫�鏌ヨ澶囧強瀹㈡埛绔綉缁�';
+        var retcode = -1;
+
+        if (err && err.oError && err.oError.errorCode) {
+          var errorInfo = _this4.errorHander.matchErrorInfo(err.oError.errorCode);
+
+          msg = errorInfo && errorInfo.description ? errorInfo.description : '鎾斁澶辫触锛岃妫�鏌ヨ澶囧強瀹㈡埛绔綉缁�';
+          retcode = err.oError.errorCode;
+        }
+
+        _this4.pluginStatus.loadingSetText({
+          text: msg,
+          color: 'red'
+        });
+
+        if (typeof _this4.params.handleError === 'function') {
+          _this4.params.handleError({
+            retcode: retcode,
+            msg: msg,
+            id: _this4.params.id,
+            type: "handleError"
+          });
+        }
+
+        errorCallback();
+
+        _this4.Monitor.dclog({
+          url: _this4.url,
+          action: 411,
+          d: new Date().getTime() - _this4.playStartTime,
+          text: 'startPlayError'
+        });
+
+        _this4.Monitor.playLog({
+          Enc: _this4.url.indexOf("@") === -1 ? 0 : 1,
+          // 0 涓嶅姞瀵� 1 鍔犲瘑
+          PlTp: _this4.url.indexOf("back") === -1 ? 1 : 2,
+          // 1 鐩存挱 2 鍥炴斁
+          Via: 2,
+          // 2 鏈嶅姟绔彇娴�
+          ErrCd: retcode,
+          Cost: -1,
+          // 姣鏁�
+          Serial: matchEzopenUrl(_this4.url).deviceSerial,
+          Channel: matchEzopenUrl(_this4.url).channelNo,
+          Ver: isVersion2Available() ? "v7.0.0" : "v6.0.0"
+        });
+      });
+    }
+  }, {
+    key: "play",
+    value: function play(options) {
+      var _this5 = this;
+
+      if (this.jSPlugin.bPlay) {
+        return false;
+      }
+
+      this.pluginStatus.setPlayStatus({
+        play: false,
+        loading: true
+      });
+      this.playStartTime = new Date().getTime();
+      this.Monitor.dclog({
+        url: this.url,
+        action: 1,
+        d: new Date().getTime() - this.initTime,
+        text: 'startPlay'
+      });
+
+      if (options) {
+        if (typeof options.url === 'string') {
+          this.url = options.url;
+        }
+
+        if (typeof options.accessToken === 'string') {
+          this.accessToken = options.accessToken;
+        }
+
+        if (this.Theme && (typeof options.url === 'string' || typeof options.accessToken === 'string')) {
+          this.Theme.getDeviceInfo();
+        }
+      }
+
+      var promise = new Promise(function (resolve, reject) {
+        _this5._getRealUrlPromise(_this5.accessToken, _this5.url).then(function (data) {
+          _this5._pluginPlay(data, function () {
+            return resolve(true);
+          }, function () {
+            return reject(false);
+          });
+        })["catch"](function (err) {
+          var msg = err.msg ? err.msg : '鎾斁澶辫触锛岃妫�鏌ヨ澶囧強瀹㈡埛绔綉缁�';
+
+          _this5.pluginStatus.loadingSetText({
+            text: msg,
+            color: 'red'
+          });
+
+          if (typeof _this5.params.handleError === 'function') {
+            _this5.params.handleError({
+              retcode: err.oError ? err.oError.errorCode : -1,
+              msg: msg,
+              id: _this5.params.id,
+              type: "handleError"
+            });
+          }
+
+          reject(false);
+        });
+      });
+      return promise;
+    }
+  }, {
+    key: "stop",
+    value: function stop() {
+      var _this6 = this;
+
+      if (!this.jSPlugin.bPlay) {
+        console.log("褰撳墠闈炴挱鏀剧姸鎬�");
+        var promise = new Promise(function (resolve, reject) {
+          reject({
+            retcode: -1,
+            msg: "褰撳墠闈炴挱鏀剧姸鎬�"
+          });
+        });
+        return promise;
+      }
+
+      this.pluginStatus.setPlayStatus({
+        loading: true
+      });
+      return this.jSPlugin.JS_Stop(0).then(function () {
+        console.log("鍋滄鎴愬姛");
+
+        _this6.pluginStatus.setPlayStatus({
+          play: false,
+          loading: false
+        });
+
+        if (_this6.Theme) {
+          _this6.Theme.setDecoderState({
+            play: false
+          });
+        }
+      });
+    }
+  }, {
+    key: "changeVideoLevel",
+    value: function changeVideoLevel(level) {
+      var _this7 = this;
+      var initUrl = this.url;
+      var url = level ? initUrl.replace(".live", ".hd.live") : initUrl.replace(".hd.live", ".live");
+      this.jSPlugin.playURL = level ? this.jSPlugin.playURL.replace("stream=2", "stream=1") : this.jSPlugin.playURL.replace("stream=1", "stream=2");
+      console.log("changeVideoLevel", url, this.jSPlugin.playURL);
+      this.url = url;
+      var promise = new Promise(function (resolve, reject) {
+        _this7.pause().then(function () {
+          console.log("鏆傚仠鎴愬姛");
+
+          _this7.resume().then(function (data) {
+            console.log("鎭㈠鎴愬姛");
+          });
+        })["catch"](function () {
+          console.log("鏆傚仠澶辫触");
+
+          _this7.resume().then(function (data) {
+            console.log("鎭㈠鎴愬姛");
+          });
+        });
+      });
+      return promise;
+    }
+  }, {
+    key: "changePlayUrl",
+    value: function changePlayUrl(options) {
+      var _this8 = this;
+
+      var initUrl = this.url;
+      var url = matchUrl(initUrl, options);
+      console.log("changePlayUrl", url);
+      this.url = url;
+      var promise = new Promise(function (resolve, reject) {
+        _this8.stop().then(function () {
+          console.log("changePlayUrl stop success"); // 浜戝彴鍒濆鍖�
+
+          if (_this8.Theme && _this8.Theme.Ptz) {
+            _this8.Theme.setDecoderState({
+              pantile: false
+            });
+
+            _this8.Theme.Ptz.hide();
+          } // 褰曞埗鍒濆鍖�
+
+
+          if (_this8.Theme) {
+            _this8.Theme.setDecoderState({
+              recordvideo: false
+            });
+          } // 鐢靛瓙鏀惧ぇ鍒濆鍖�
+
+
+          if (_this8.Theme) {
+            _this8.Theme.setDecoderState({
+              zoom: false
+            });
+
+            if (_this8.Zoom) {
+              _this8.Zoom.stopZoom();
+            }
+          } // 瀵硅鍒濆鍖�
+
+
+          if (_this8.Theme && _this8.Theme.decoderState.state.talk) {
+            _this8.stopTalk();
+
+            _this8.Theme.setDecoderState({
+              talk: false
+            });
+          }
+
+          if (options.accessToken) {
+            _this8.accessToken = options.accessToken;
+            return _this8.play({
+              accessToken: options.accessToken,
+              url: url
+            }).then(function () {
+              console.log("changePlayUrl replay success"); // 褰撳墠澶勪簬缃戦〉鍏ㄥ睆鐘舵��
+
+              if (_this8.Theme && _this8.Theme.decoderState.state.webExpend) {
+                _this8.Theme.webExpend();
+              } // 褰撳墠澶勪簬鍏ㄥ睆鐘舵��
+
+
+              if (_this8.Theme && _this8.Theme.decoderState.state.expend) {
+                _this8.Theme.expend();
+              }
+
+              resolve(url);
+            })["catch"](function (err) {
+              reject(url);
+            });
+          }
+
+          _this8.play(url).then(function () {
+            console.log("changePlayUrl replay success"); // 褰撳墠澶勪簬缃戦〉鍏ㄥ睆鐘舵��
+
+            if (_this8.Theme && _this8.Theme.decoderState.state.webExpend) {
+              _this8.Theme.webExpend();
+            } // 褰撳墠澶勪簬鍏ㄥ睆鐘舵��
+
+
+            if (_this8.Theme && _this8.Theme.decoderState.state.expend) {
+              _this8.Theme.expend();
+            }
+
+            resolve(url);
+          })["catch"](function (err) {
+            reject(url);
+          });
+        })["catch"](function (err) {
+          console.log("鍒囨崲杩囩▼鍋滄澶辫触", err);
+
+          if (options.accessToken) {
+            _this8.accessToken = options.accessToken;
+            return _this8.play({
+              accessToken: options.accessToken,
+              url: url
+            }).then(function () {
+              resolve(url);
+            })["catch"](function (err) {
+              reject(url);
+            });
+          }
+
+          _this8.play(url).then(function () {
+            resolve(url);
+          })["catch"](function (err) {
+            reject(url);
+          });
+        });
+      });
+      /**
+      * 鍖归厤鎾斁鍦板潃 鐢ㄦ埛鎾斁鍦板潃鍒囨崲
+      * options
+      * type | string | live,rec
+      * hd | boolean | true,false
+      * deviceSerial
+      * channelNO
+      * begin
+      * end
+      */
+
+      function matchUrl(matchInitUrl, matchOptions) {
+        if (matchOptions.url) {
+          return matchOptions.url;
+        }
+
+        var type = matchInitUrl.split("/")[4].split(".")[matchInitUrl.split("/")[4].split(".").length - 1].split("?")[0];
+
+        if (type === 'rec' && matchInitUrl.indexOf(".cloud.rec") !== -1) {
+          type = 'cloud.rec';
+        }
+
+        if (matchOptions.type) {
+          type = matchOptions.type;
+        }
+
+        var deviceSerial = matchInitUrl.split("/")[3];
+
+        if (matchOptions.deviceSerial) {
+          deviceSerial = matchOptions.deviceSerial;
+        }
+
+        var channelNo = matchInitUrl.split("/")[4].split(".")[0];
+
+        if (matchOptions.channelNo) {
+          channelNo = matchOptions.channelNo;
+        } // 濡傛灉鍒囨崲璁惧锛屼箣鍓嶈澶囨湁楠岃瘉鐮侊紝鏂拌澶囨棤楠岃瘉鐮侊紝寤鸿浼犵┖楠岃瘉鐮�,娓呯悊楠岃瘉鐮侊紙闄嶄綆瑙g爜娑堣�楋級
+
+
+        var validCode = matchInitUrl.split("/")[2].split("@").length === 2 ? matchInitUrl.split("/")[2].split("@")[0] : "";
+
+        if (typeof matchOptions.validCode !== 'undefined') {
+          validCode = matchOptions.validCode;
+        }
+
+        var hd = typeof matchOptions.hd === 'undefined' ? matchInitUrl.indexOf('.hd') !== -1 : matchOptions.hd;
+        var result = "ezopen://".concat(validCode ? "".concat(validCode, "@") : "", "open.ys7.com/").concat(deviceSerial, "/").concat(channelNo).concat(hd ? '.hd' : '', ".").concat(type);
+
+        if (type === 'live') {
+          return result;
+        }
+
+        result = "ezopen://".concat(validCode ? "".concat(validCode, "@") : "", "open.ys7.com/").concat(deviceSerial, "/").concat(channelNo, ".").concat(type);
+
+        if (matchOptions.begin && matchOptions.end) {
+          result += "?begin=".concat(matchOptions.begin, "&end=").concat(matchOptions.end);
+        } else if (matchOptions.begin) {
+          result += "?begin=".concat(matchOptions.begin);
+        } else if (getQueryString("begin", matchInitUrl)) {
+          result += "?begin=".concat(getQueryString("begin", matchInitUrl));
+        }
+
+        return result;
+      }
+
+      return promise;
+    }
+  }, {
+    key: "getOSDTime",
+    value: function getOSDTime() {
+      var _this9 = this;
+
+      var promise = new Promise(function (resolve, reject) {
+        _this9.jSPlugin.JS_GetOSDTime(0).then(function (data) {
+          resolve({
+            code: 0,
+            retcode: 0,
+            data: data
+          }); // 鍏煎鏃х増鏈琧allback
+
+          if (typeof _this9.params.getOSDTimeCallBack === 'function') {
+            _this9.params.getOSDTimeCallBack({
+              id: _this9.id,
+              type: 'getOSDTime',
+              code: 0,
+              data: data
+            });
+          }
+        })["catch"](function (err) {
+          reject({
+            code: -1,
+            retcode: -1,
+            data: err
+          }); // 鍏煎鏃х増鏈琧allback
+
+          if (typeof _this9.params.getOSDTimeCallBack === 'function') {
+            _this9.params.getOSDTimeCallBack({
+              id: _this9.id,
+              type: 'getOSDTime',
+              code: -1,
+              data: -1
+            });
+          }
+        });
+      });
+      return promise;
+    }
+  }, {
+    key: "capturePicture",
+    value: function capturePicture(name) {
+      var _this10 = this;
+
+      var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
+      var capturePictureRT = this.jSPlugin.JS_CapturePicture(0, name, "JPEG", callback, !!callback);
+
+      if (isPromise(capturePictureRT)) {
+        // 鍏煎鏃х増鏈琧allback
+        if (typeof this.params.capturePictureCallBack === 'function') {
+          capturePictureRT.then(function () {
+            _this10.params.capturePictureCallBack({
+              id: _this10.id,
+              type: 'capturePicture',
+              code: 0
+            });
+          })["catch"](function () {
+            _this10.params.capturePictureCallBack({
+              id: _this10.id,
+              type: 'capturePicture',
+              code: -1
+            });
+          });
+        }
+
+        return capturePictureRT;
+      }
+
+      return new Promise(function (resolve) {
+        resolve(capturePictureRT);
+      });
+    }
+  }, {
+    key: "startSave",
+    value: function startSave(name) {
+      var _this11 = this;
+
+      var startSaveRT = this.jSPlugin.JS_StartSave(0, name);
+
+      if (isPromise(startSaveRT)) {
+        // 鍏煎鏃х増鏈琧allback
+        if (typeof this.params.startSaveCallBack === 'function') {
+          startSaveRT.then(function () {
+            _this11.params.startSaveCallBack({
+              id: _this11.id,
+              type: 'startSave',
+              code: 0
+            });
+          })["catch"](function () {
+            _this11.params.startSaveCallBack({
+              id: _this11.id,
+              type: 'startSave',
+              code: -1
+            });
+          });
+        }
+
+        return startSaveRT;
+      }
+
+      if (this.Theme) {
+        this.Theme.setDecoderState({
+          recordvideo: true
+        });
+      }
+
+      return new Promise(function (resolve) {
+        resolve(startSaveRT);
+      });
+    }
+  }, {
+    key: "stopSave",
+    value: function stopSave() {
+      var _this12 = this;
+
+      var stopSaveRT = this.jSPlugin.JS_StopSave(0);
+
+      if (isPromise(stopSaveRT)) {
+        // 鍏煎鏃х増鏈琧allback
+        if (typeof this.params.startSaveCallBack === 'function') {
+          stopSaveRT.then(function () {
+            _this12.params.stopSaveCallBack({
+              id: _this12.id,
+              type: 'stopSave',
+              code: 0
+            });
+          })["catch"](function () {
+            _this12.params.stopSaveCallBack({
+              id: _this12.id,
+              type: 'stopSave',
+              code: -1
+            });
+          });
+        }
+
+        return stopSaveRT;
+      }
+
+      if (this.Theme) {
+        this.Theme.setDecoderState({
+          recordvideo: false
+        });
+      }
+
+      return new Promise(function (resolve) {
+        resolve(stopSaveRT);
+      });
+    }
+  }, {
+    key: "openSound",
+    value: function openSound() {
+      var openSoundRT = this.jSPlugin.JS_OpenSound(0);
+      console.log("鎵撳紑澹伴煶", openSoundRT);
+
+      if (isPromise(openSoundRT)) {
+        return openSoundRT;
+      }
+
+      if (this.Theme) {
+        this.Theme.setDecoderState({
+          sound: true
+        });
+      } // 鍏煎鏃х増鏈琧allback
+
+
+      if (typeof this.params.openSoundCallBack === 'function') {
+        this.params.openSoundCallBack({
+          id: this.id,
+          type: 'openSound',
+          code: openSoundRT
+        });
+      }
+
+      return new Promise(function (resolve) {
+        resolve(openSoundRT);
+      });
+    }
+  }, {
+    key: "closeSound",
+    value: function closeSound() {
+      var closeSoundRT = this.jSPlugin.JS_CloseSound(0);
+
+      if (isPromise(closeSoundRT)) {
+        return closeSoundRT;
+      }
+
+      if (this.Theme) {
+        this.Theme.setDecoderState({
+          sound: false
+        });
+      } // 鍏煎鏃х増鏈琧allback
+
+
+      if (typeof this.params.closeSoundCallBack === 'function') {
+        this.params.closeSoundCallBack({
+          id: this.id,
+          type: 'closeSound',
+          code: closeSoundRT
+        });
+      }
+
+      return new Promise(function (resolve) {
+        resolve(closeSoundRT);
+      });
+    }
+  }, {
+    key: "enableZoom",
+    value: function enableZoom() {
+      var enableZoomRT = this.jSPlugin.JS_EnableZoom(0);
+
+      if (isPromise(enableZoomRT)) {
+        return enableZoomRT;
+      }
+
+      return new Promise(function (resolve) {
+        resolve(enableZoomRT);
+      });
+    }
+  }, {
+    key: "closeZoom",
+    value: function closeZoom() {
+      var closeZoomRT = this.jSPlugin.JS_DisableZoom(0);
+
+      if (isPromise(closeZoomRT)) {
+        return closeZoomRT;
+      }
+
+      return new Promise(function (resolve) {
+        resolve(closeZoomRT);
+      });
+    }
+  }, {
+    key: "setPoster",
+    value: function setPoster(url) {
+      // this.pluginStatus.setPoster(url);
+      if (isVersion2Available()) {
+        if (document.getElementById("".concat(this.id))) {
+          document.getElementById("".concat(this.id)).style.backgroundImage = "url(".concat(url, ")");
+          document.getElementById("".concat(this.id)).style.backgroundSize = "cover";
+        }
+      } else {
+        if (document.getElementById("".concat(this.id, "canvas0"))) {
+          document.getElementById("".concat(this.id, "canvas0")).style.backgroundImage = "url(".concat(url, ")");
+          document.getElementById("".concat(this.id, "canvas0")).style.backgroundSize = "cover";
+        }
+      }
+    }
+  }, {
+    key: "reSize",
+    value: function reSize(width, height) {
+      var headerHeight = 0;
+      var timeLineHeight = 0;
+      this.params.height = height;
+      this.params.width = width; //鎬讳綋楂樺害鍖呭惈妯℃澘
+
+      if (this.Theme && this.Theme.isNeedRenderHeader && document.getElementById("".concat(this.id, "-headControl"))) {
+        headerHeight = parseInt(document.getElementById("".concat(this.id, "-headControl")).style.height, 10);
+      }
+
+      if (this.Theme && this.Theme.isNeedRenderTimeLine && !this.isMobile) {
+        timeLineHeight = 48;
+      }
+
+      height = height - headerHeight - timeLineHeight;
+      this.width = width;
+      this.height = height;
+      document.getElementById("".concat(this.id, "-wrap")).style = "width:".concat(width, "px;position:relative;display:inline-block;vertical-align: bottom;");
+      document.getElementById("".concat(this.id)).style.width = width + 'px';
+      document.getElementById("".concat(this.id)).style.height = height + 'px';
+
+      if (this.jSPlugin && this.jSPlugin.bPlay) {
+        if (this.jSPlugin) {
+          this.jSPlugin.iHeight = height;
+          this.jSPlugin.iWidth = width;
+        }
+
+        this.jSPlugin.JS_Resize(width, height);
+      } else {
+        if (document.getElementById("".concat(this.id, "-player"))) {
+          document.getElementById("".concat(this.id, "-player")).style.width = width;
+          document.getElementById("".concat(this.id, "-player")).style.height = height;
+        }
+
+        var scale = 1;
+
+        if (document.getElementById("".concat(this.id, "canvas0"))) {
+          var isNeedScale = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i);
+
+          if (isNeedScale) {
+            scale = 2;
+          }
+
+          document.getElementById("".concat(this.id, "canvas0")).style.width = width * scale;
+          document.getElementById("".concat(this.id, "canvas0")).style.height = height * scale;
+          document.getElementById("".concat(this.id, "canvas0")).width = width * scale;
+          document.getElementById("".concat(this.id, "canvas0")).height = height * scale;
+          document.getElementById("".concat(this.id, "canvas0")).parentNode.style.width = width * scale;
+          document.getElementById("".concat(this.id, "canvas0")).parentNode.style.height = height * scale;
+          document.getElementById("".concat(this.id, "canvas_draw0")).height = height * scale;
+        }
+
+        if (this.jSPlugin) {
+          this.jSPlugin.iHeight = height * scale;
+          this.jSPlugin.iWidth = width * scale;
+        }
+      }
+    }
+  }, {
+    key: "fast",
+    value: function fast(next) {
+      var _this13 = this;
+
+      var speed = this.speed;
+
+      if (next) {
+        var fastRT = this.jSPlugin.JS_Fast(0, next);
+      } else {
+        if (speed === 1) {
+          speed = 2;
+        } else if (speed === 2) {
+          speed = 4;
+        } else {
+          if (typeof this.params.handleError === 'function') {
+            this.params.handleError({
+              msg: "鎾斁閫熷害鏈�澶т负4鍊嶉�熷害",
+              retcode: 1003,
+              id: this.id,
+              type: "handleError"
+            });
+          }
+
+          return new Promise(function (resolve, reject) {
+            _this13.speed = speed;
+            reject({
+              code: -1,
+              data: {
+                speed: speed,
+                result: "鎾斁閫熷害鏈�澶т负4鍊嶉�熷害"
+              }
+            });
+          });
+        }
+
+        var fastRT = this.jSPlugin.JS_Fast(0);
+      }
+
+      return new Promise(function (resolve) {
+        _this13.speed = speed;
+        resolve({
+          code: 0,
+          data: {
+            speed: speed,
+            result: fastRT
+          }
+        });
+      });
+    }
+  }, {
+    key: "slow",
+    value: function slow() {
+      var _this14 = this;
+
+      var speed = this.speed;
+
+      if (speed === 4) {
+        speed = 2;
+      } else if (speed === 2) {
+        speed = 1;
+      } else {
+        if (typeof this.params.handleError === 'function') {
+          this.params.handleError({
+            msg: "鎾斁閫熷害鏈�灏忎负1鍊嶉�熷害",
+            retcode: 1003,
+            id: this.id,
+            type: "handleError"
+          });
+        }
+
+        return new Promise(function (resolve, reject) {
+          _this14.speed = speed;
+          reject({
+            code: -1,
+            data: {
+              speed: speed,
+              result: "鎾斁閫熷害鏈�灏忎负1鍊嶉�熷害"
+            }
+          });
+        });
+      }
+
+      var slowRT = this.jSPlugin.JS_Slow(0);
+      return new Promise(function (resolve) {
+        _this14.speed = speed;
+        resolve({
+          code: 0,
+          data: {
+            speed: speed,
+            result: slowRT
+          }
+        });
+      });
+    }
+  }, {
+    key: "seek",
+    value: function seek(startTime, endTime) {
+      var url = this.url;
+      var currentDay = (getQueryString('begin', url) || new Date().Format('yyyyMMdd')).substr(0, 8);
+      endTime = formatRecTime(currentDay, '235959');
+
+      if (startTime.length === 6) {
+        startTime = formatRecTime(currentDay, startTime);
+      } else if (startTime.length === 16) {
+        if (startTime.substr(0, 8) !== currentDay) {
+          if (typeof this.params.handleError === 'function') {
+            this.params.handleError({
+              msg: "seek鏃堕棿涓嶈兘璺ㄦ棩鏈�",
+              retcode: -1,
+              id: this.id,
+              type: "handleError"
+            });
+          }
+
+          return false;
+        }
+      } else {
+        if (typeof this.params.handleError === 'function') {
+          this.params.handleError({
+            msg: "seek鏃堕棿鏍煎紡閿欒",
+            retcode: -1,
+            id: this.id,
+            type: "handleError"
+          });
+        }
+
+        return false;
+      } // 鏍煎紡鍖栧洖鏀炬椂闂�
+
+
+      function formatRecTime(time, defaultTime) {
+        // 鐢ㄦ埛鏍煎紡 鏃犻渶鏇存敼 => 20182626T000000Z
+        // return time
+        // 鐢ㄦ埛鏍煎紡闇�瑕佹洿鏀�
+        //鐢ㄦ埛鏃堕棿闀垮害涓� 14 20181226000000  =銆� 20181226000000
+        // 鐢ㄦ埛闀垮害涓�12     201812260000    =銆� 201812260000 + defaultTime鍚庨潰2浣�
+        // 鐢ㄦ埛闀垮害涓�10     2018122600      =銆� 201812260000 + defaultTime鍚庨潰4浣�
+        // 鐢ㄦ埛闀垮害涓�8     20181226         =銆� 201812260000 + defaultTime鍚庨潰6浣�
+        // 缁撴灉 20181226000000 14浣�
+        // 鎻掑叆 TZ
+        var reg = /^[0-9]{8}T[0-9]{6}Z$/;
+
+        if (reg.test(time)) {
+          // 鐢ㄦ埛鏍煎紡 鏃犻渶鏇存敼 => 20182626T000000Z
+          return time;
+        } else if (/[0-9]{8,14}/.test(time)) {
+          var start = 6 - (14 - time.length);
+          var end = defaultTime.length;
+          var standardTime = time + defaultTime.substring(start, end);
+          return standardTime.slice(0, 8) + 'T' + standardTime.slice(8) + 'Z';
+        }
+
+        throw new Error('鍥炴斁鏃堕棿鏍煎紡鏈夎锛岃纭');
+      }
+
+      var seekRT = this.jSPlugin.JS_Seek(0, startTime, endTime);
+      console.log("seekRT", seekRT);
+
+      if (isPromise(seekRT)) {
+        return seekRT;
+      }
+
+      return new Promise(function (resolve) {
+        resolve(seekRT);
+      });
+    }
+  }, {
+    key: "fullScreen",
+    value: function fullScreen() {
+      var _this15 = this;
+
+      var promise = requestFullScreenPromise(document.getElementById("".concat(this.id)));
+      promise.then(function (data) {
+        console.log("鍏ㄥ睆promise", window.screen.availWidth);
+
+        _this15.jSPlugin.JS_Resize(window.screen.availWidth, window.screen.availHeight); // 鍏煎鏃х増鏈琧allback
+
+
+        if (typeof _this15.params.fullScreenCallBack === 'function') {
+          _this15.params.fullScreenCallBack({
+            id: _this15.id,
+            type: 'fullScreen',
+            code: 0
+          });
+        }
+      }); //  鐩戝惉鍏ㄥ睆浜嬩欢瑙﹀彂
+
+      var fullscreenchange = function fullscreenchange() {
+        var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
+
+        if (!isFullScreen) {
+          _this15.jSPlugin.JS_Resize(_this15.width, _this15.height);
+        } // 鍏煎鏃х増鏈琧allback
+
+
+        if (typeof _this15.params.fullScreenChangeCallBack === 'function') {
+          _this15.params.fullScreenChangeCallBack({
+            id: _this15.id,
+            type: 'fullScreen',
+            code: isFullScreen
+          });
+        }
+      };
+
+      ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange'].forEach(function (item) {
+        window.addEventListener(item, function (data) {
+          return fullscreenchange();
+        });
+      });
+    }
+  }, {
+    key: "cancelFullScreen",
+    value: function cancelFullScreen() {
+      var _this16 = this;
+
+      var cancelPromise = cancelFullScreenPromise();
+      cancelPromise.then(function (data) {
+        console.log("鍙栨秷鍏ㄥ睆", data, _this16.jSPlugin);
+
+        _this16.jSPlugin.JS_Resize(_this16.width, _this16.height);
+      });
+    }
+  }, {
+    key: "startTalk",
+    value: function startTalk() {
+      this.Talk.startTalk();
+    }
+  }, {
+    key: "stopTalk",
+    value: function stopTalk() {
+      this.Talk.stopTalk();
+    }
+  }, {
+    key: "destroy",
+    value: function destroy() {
+      var destroyRT = this.jSPlugin.JS_DestroyWorker(0);
+
+      if (this.Theme) {
+        this.Theme = null;
+        window.EZUIKit[this.params.id].state.EZUIKitPlayer.themeInit = false;
+      }
+
+      if (isPromise(destroyRT)) {
+        return destroyRT;
+      }
+
+      return new Promise(function (resolve) {
+        resolve(destroyRT);
+      });
+    }
+  }, {
+    key: "getDeviceCapacity",
+    value: function getDeviceCapacity() {
+      var _this17 = this;
+
+      var apiDomain = this.env.domain;
+
+      if (this.env) {
+        apiDomain = this.env.domain;
+      }
+
+      var capacityUrl = apiDomain + "/api/lapp/device/capacity";
+
+      var capacitySuccess = function capacitySuccess(data) {
+        if (data.code == 200 && data.data) {
+          _this17.capacity = data.data;
+        }
+      };
+
+      var capacityParams = {
+        accessToken: this.accessToken,
+        deviceSerial: matchEzopenUrl(this.url).deviceSerial
+      };
+      request(capacityUrl, 'POST', capacityParams, '', capacitySuccess);
+    }
+  }, {
+    key: "pause",
+    value: function pause() {
+      return this.jSPlugin.JS_Pause(0);
+    }
+  }, {
+    key: "resume",
+    value: function resume(time) {
+      return this.jSPlugin.JS_Resume(time);
+    }
+  }]);
+
+  return EZUIKitPlayer;
+}();
+
+(function (global, factory) {
+
+  if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && _typeof(module.exports) === "object") {
+    module.exports = global.document ? factory(global, true) : function (w) {
+      if (!w.document) {
+        throw new Error("EZUIPlayer requires a window with a document");
+      }
+
+      return factory(w);
+    };
+  } else {
+    factory(global);
+  } // Pass this if window is not defined yet
+
+})(typeof window !== "undefined" ? window : undefined, function (window, noGlobal) {
+  var EZUIKit = {
+    Core: Core,
+    HLS: HLS,
+    FLV: FLV,
+    EZUIKitPlayer: EZUIKitPlayer
+  };
+  window.EZUIKit = EZUIKit;
+  return EZUIKit;
+});
diff --git a/static/logo.png b/static/logo.png
new file mode 100644
index 0000000..19bdf71
--- /dev/null
+++ b/static/logo.png
Binary files differ
diff --git a/static/splash.png b/static/splash.png
new file mode 100644
index 0000000..eb17b17
--- /dev/null
+++ b/static/splash.png
Binary files differ

--
Gitblit v1.9.3