/** * * SmartEarthSDK 基于Cesium的三维web开发 * @author 张丹钊、金磊、薛鹏、张恒 * */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.SmartEarth = {})); })(this, (function (exports) { 'use strict'; /** * 配置文件 * * @author 张丹钊 */ let configData = { testModel: 'Workers/Model/xiaoche.glb', modelAxis: 'Workers/Model/axis.gltf', flyModel: 'Workers/Model/fly.glb', divpoint: 'Workers/image/divpoint.png', divpoint1: 'Workers/image/divpoint1.png', richtextpoint: 'Workers/image/richtextpoint1.png', mark: 'Workers/image/mark.png', mark1: 'Workers/image/mark1.png', TrailLine: 'Workers/image/TrailLine.png', road: 'Workers/image/road.jpg', colors3: 'Workers/image/colors3.png', loading: 'Workers/image/loading.gif', smog: 'Workers/image/smog.png', penquan: 'Workers/image/penquan.png', fire: 'Workers/image/fire.png', fire2: 'Workers/image/fire2.png', bottomplane: 'Workers/image/bottomplane.jpg', wall: 'Workers/image/ggy.jpg', rotate: 'Workers/image/rotate.png', move: 'Workers/image/move.png', draw: 'Workers/image/cursor/draw.cur', water: 'Workers/image/waterNormals.jpg', movingRiver: 'Workers/image/movingRiver.png', effectCircle: 'Workers/image/circle.png', scanCircle: 'Workers/image/scan.png', particles: 'Workers/image/particles.png', trafficLight: { l_go: 'Workers/image/trafficLights/l-go.png', l_wait: 'Workers/image/trafficLights/l-wait.png', l_stop: 'Workers/image/trafficLights/l-stop.png', l_null: 'Workers/image/trafficLights/l-null.png', go: 'Workers/image/trafficLights/go.png', wait: 'Workers/image/trafficLights/wait.png', stop: 'Workers/image/trafficLights/stop.png', null: 'Workers/image/trafficLights/null.png', r_go: 'Workers/image/trafficLights/r-go.png', r_wait: 'Workers/image/trafficLights/r-wait.png', r_stop: 'Workers/image/trafficLights/r-stop.png', r_null: 'Workers/image/trafficLights/r-null.png', bg: 'Workers/image/trafficLights/bg.png', } }; var configData$1 = Object.freeze(configData); /** * 如果未定义,则返回第一个参数,否则返回第二个参数。 * 用于设置参数的默认值。 * * @author 张丹钊 * * @function * * @param {*} a * @param {*} b * @returns {*} 如果未定义,则返回第一个参数,否则返回第二个参数。 * * @example * param = SmartEarth.defaultValue(param, 'default'); */ function defaultValue(a, b) { if (a !== undefined && a !== null) { return a; } return b; } //This file is automatically rebuilt by the Cesium build process. var PolylineTrailLinkSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ czm_material material = czm_getDefaultMaterial(materialInput);\n\ vec2 st = materialInput.st;\n\ if(twoColor){\n\ if(st.s ',ff不会 oXmlHttp.send(null); if (oXmlHttp.status === 404) { console.log(url + ' is not found'); } else { Skipthis.includeJsText(document.body || document.head, oXmlHttp.responseText); } }; /** * Echarts扩展 * * @alias CombineEcharts * @author 张丹钊 * @constructor * * @param {Viewer} viewer 地图视图。 * * @example * echartsTool = SmartEarth.CombineEcharts(Viewer); */ function CombineEcharts(viewer) { this._mapContainer = viewer; if (!window.echarts) { let SkipTool = new Skip(false); SkipTool.addJs(window.SmartEarthRootUrl + 'Workers/echarts.min.js'); } this.Init(viewer); } /** * 设置Echarts对应的参数 * * @param {Object} [option] Echarts对应的参数。 * @param {Boolean} [isClear=false] 是否清除原先图层。 * */ CombineEcharts.prototype.setOption = function (option, isClear) { if (this._echartsContainer && isClear) { this.clear(); } !this._overlay && (this._overlay = this._createChartOverlay()); this._overlay.setOption(option); return this; }; CombineEcharts.prototype._createChartOverlay = function () { var t = this._mapContainer.scene; t.canvas.setAttribute('tabIndex', 0); var e = document.createElement('div'); e.style.position = 'absolute'; e.style.top = '0px'; e.style.left = '0px'; e.style.width = t.canvas.width + 'px'; e.style.height = t.canvas.height + 'px'; e.style.pointerEvents = 'none'; e.setAttribute('id', 'smartearth-cesium-echarts'); e.setAttribute('class', 'echartMap'); this._mapContainer.container.appendChild(e); this._echartsContainer = e; return echarts.init(e) }; /** * 清除图层 * */ CombineEcharts.prototype.clear = function () { this._echartsContainer && (this._mapContainer.container.removeChild(this._echartsContainer), (this._echartsContainer = null)), this._overlay && (this._overlay.dispose(), (this._overlay = null)); }; /** * 清除图层 * */ CombineEcharts.prototype.deleteObject = CombineEcharts.prototype.clear; /** * 更新图层 * * @param {Object} [option] Echarts对应的参数。 * */ CombineEcharts.prototype.updateOverlay = function (option) { this._overlay && this._overlay.setOption(option); }; CombineEcharts.prototype.getMap = function () { return this._mapContainer }; CombineEcharts.prototype.getOverlay = function () { return this._overlay }; /** * 显示图层 * */ CombineEcharts.prototype.show = function () { document.getElementById(this._id).style.visibility = 'visible'; }; /** * 隐藏图层 * */ CombineEcharts.prototype.hide = function () { document.getElementById(this._id).style.visibility = 'hidden'; }; /** * 隐藏图层 * */ CombineEcharts.prototype.Init = function (viewer) { //坐标转换及事件监听 (function (e) { var t = {}; function n(r) { if (t[r]) return t[r].exports; var i = t[r] = { i: r, l: !1, exports: {} }; return e[r].call(i.exports, i, i.exports, n), i.l = !0, i.exports } n.m = e, n.c = t, n.d = function (e, t, r) { n.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: r }); }, n.r = function (e) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 }); }, n.t = function (e, t) { if (1 & t && (e = n(e)), 8 & t) return e; if (4 & t && "object" == typeof e && e && e.__esModule) return e; var r = Object.create(null); if (n.r(r), Object.defineProperty(r, "default", { enumerable: !0, value: e }), 2 & t && "string" != typeof e) for (var i in e) n.d(r, i, function (t) { return e[t] }.bind(null, i)); return r }, n.n = function (e) { var t = e && e.__esModule ? function () { return e. default } : function () { return e }; return n.d(t, "a", t), t }, n.o = function (e, t) { return Object.prototype.hasOwnProperty.call(e, t) }, n.p = "", n(n.s = 0); })([function (e, t, n) { e.exports = n(1); }, function (e, t, n) { echarts ? n(2).load() : console.error("missing echarts lib"); }, function (e, t, n) { function r(e, t) { for (var n = 0; n < t.length; n++) { var r = t[n]; r.enumerable = r.enumerable || !1, r.configurable = !0, "value" in r && (r.writable = !0), Object.defineProperty(e, r.key, r); } } n.r(t); var i = function () { function e(t, n) { ! function (e, t) { if (!(e instanceof t)) throw new TypeError("Cannot call a class as a function") }(this, e), this._viewer = t, this.dimensions = ["lng", "lat"], this._mapOffset = [0, 0], this._api = n; } var t, n, i; return t = e, i = [{ key: "create", value: function (t, n) { var r; t.eachComponent("GLMap", function (t) { (r = new e(viewer, n)).setMapOffset(t.__mapOffset || [0, 0]), t.coordinateSystem = r; }), t.eachSeries(function (e) { "GLMap" === e.get("coordinateSystem") && (e.coordinateSystem = r); }); } }, { key: "dimensions", get: function () { return ["lng", "lat"] } }], (n = [{ key: "setMapOffset", value: function (e) { return this._mapOffset = e, this } }, { key: "getViewer", value: function () { return this._viewer } }, { key: "dataToPoint", value: function (e) { if (this._viewer && this._viewer.scene) { var t = this._viewer.scene, n = [0, 0], r = Cesium.Cartesian3.fromDegrees(e[0], e[1]); if (!r) return n; if (t.mode === Cesium.SceneMode.SCENE3D && Cesium.Cartesian3.angleBetween(t.camera.position, r) > Cesium.Math.toRadians(80)) return !1; var i = t.cartesianToCanvasCoordinates(r); return i ? [i.x - this._mapOffset[0], i.y - this._mapOffset[1]] : [] } else { return [] } } }, { key: "pointToData", value: function (e) { var t = this._mapOffset, n = viewer.scene.globe.ellipsoid, r = new Cesium.cartesian3(e[1] + t, e[2] + t[2], 0), i = n.cartesianToCartographic(r); return [i.lng, i.lat] } }, { key: "getViewRect", value: function () { var e = this._api; return new echarts.graphic.BoundingRect(0, 0, e.getWidth(), e.getHeight()) } }, { key: "getRoamTransform", value: function () { return echarts.matrix.create() } }]) && r(t.prototype, n), i && r(t, i), e }(); echarts.extendComponentModel({ type: "GLMap", getViewer: function () { return viewer }, defaultOption: { roam: !1 } }); echarts.extendComponentView({ type: "GLMap", init: function (e, t) { this.api = t; this.dispose(); viewer.scene.postRender.addEventListener(this.moveHandler, this); }, moveHandler: function (e, t) { this.api.dispatchAction({ type: "GLMapRoam" }); }, render: function (e, t, n) { }, dispose: function (e) { viewer.scene.postRender.removeEventListener(this.moveHandler, this); } }); function a() { echarts.registerCoordinateSystem("GLMap", i), echarts.registerAction({ type: "GLMapRoam", event: "GLMapRoam", update: "updateLayout" }, function (e, t) { }); } n.d(t, "load", function () { return a }); }]); }; /** * CIMServer查询工具 * * @alias CIMServerTool * @author 张丹钊 * @constructor * * @param {String} url CIMServer服务地址。 */ function CIMServerTool(url) { this.serverUrl = url; } /** * 查询场景列表。 * * @param {Function} [callback] 回调函数。 * */ CIMServerTool.prototype.getSceneList = function (callback) { $.ajax({ url: this.serverUrl + "/scene/sceneList", type: "get", success: function (data) { (callback && typeof callback === 'function') && data && callback(JSON.parse(data)); } }); }; /** * 查询详细信息。 * * @param {Object} [option] 请求参数。 * @param {String} [option.database] 对应的信息库名 * @param {String} [option.type='building'] 查询类型 * @param {String} [option.id] id * @param {Boolean} [option.returnGeometry=true] 是否返回Geometry * @param {Boolean} [option.returnChildren=true] 是否返回子集 * @param {Function} [callback] 回调函数。 * */ CIMServerTool.prototype.query = function (option, callback) { var database = option.database; var params = { type: defaultValue(option.type, 'building'), id: option.id, returnGeometry: defaultValue(option.returnGeometry, true), returnChildren: defaultValue(option.returnChildren, true), }; $.ajax({ url: this.serverUrl + "/" + database + "/query?version=v2.1", type: 'post', async: true, data: params, success: function (data) { (callback && typeof callback === 'function') && data && callback(JSON.parse(data)); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert("error:" + XMLHttpRequest.status); } }); }; /** * 自动录屏*录制桌面 * * @alias Recorder * @author 张丹钊 * @constructor * * @param {String} [path='test.mp4'] 保存文件名。 * @param {Number} [videoBPS=5120000] 视频bps。 */ function Recorder(path, videoBPS) { this.mediaOutputPath = path || 'test.mp4'; this.videoBPS = videoBPS || 5120000; } /** * 开始录制 * */ Recorder.prototype.startRecord = function () { navigator.mediaDevices.getDisplayMedia({ video: true, audio: true }).then(Mediastream => { this.createRecorder(Mediastream); }).catch(err => { this.getUserMediaError(err); }); }; /** * 获取媒体源失败 */ Recorder.prototype.getUserMediaError = function (err) { console.log('mediaError', err); }; /** * 开始视频录制 * */ Recorder.prototype.createRecorder = function (stream) { console.log('start record'); var options = { videoBitsPerSecond: this.videoBPS }; this.recorder = new MediaRecorder(stream, options); this.recorder.start(); var chunks = []; this.recorder.onstop = event => { let blob = new Blob(chunks, { type: 'video/mp4' }); this.saveMedia(blob); }; this.recorder.ondataavailable = event => { chunks.push(event.data); }; }; /** * 数据转换并保存成MP4 * */ Recorder.prototype.saveMedia = function (blob) { let url = window.URL.createObjectURL(blob); var a = document.createElement('a'); a.innerHTML = "test"; a.download = this.mediaOutputPath; a.href = url; a.click(); }; /** * 停止录制视频 * */ Recorder.prototype.stopRecord = function () { this.recorder.stop(); }; const CoordTransform_BD_FACTOR = (3.14159265358979324 * 3000.0) / 180.0; const CoordTransform_PI = 3.1415926535897932384626; const CoordTransform_RADIUS = 6378245.0; const CoordTransform_EE = 0.00669342162296594323; /** * 坐标转换 */ const CoordTransform = { /** * BD-09 To GCJ-02 * @param lng * @param lat * @returns {number[]} */ BD09ToGCJ02(lng, lat) { let x = +lng - 0.0065; let y = +lat - 0.006; let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * CoordTransform_BD_FACTOR); let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * CoordTransform_BD_FACTOR); let gg_lng = z * Math.cos(theta); let gg_lat = z * Math.sin(theta); return [gg_lng, gg_lat] }, /** * GCJ-02 To BD-09 * @param lng * @param lat * @returns {number[]} * @constructor */ GCJ02ToBD09(lng, lat) { lat = +lat; lng = +lng; let z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * CoordTransform_BD_FACTOR); let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * CoordTransform_BD_FACTOR); let bd_lng = z * Math.cos(theta) + 0.0065; let bd_lat = z * Math.sin(theta) + 0.006; return [bd_lng, bd_lat] }, /** * WGS-84 To GCJ-02 * @param lng * @param lat * @returns {number[]} */ WGS84ToGCJ02(lng, lat) { lat = +lat; lng = +lng; if (this.out_of_china(lng, lat)) { return [lng, lat] } else { let d = this.delta(lng, lat); return [lng + d[0], lat + d[1]] } }, /** * GCJ-02 To WGS-84 * @param lng * @param lat * @returns {number[]} * @constructor */ GCJ02ToWGS84(lng, lat) { lat = +lat; lng = +lng; if (this.out_of_china(lng, lat)) { return [lng, lat] } else { let d = this.delta(lng, lat); let mgLng = lng + d[0]; let mgLat = lat + d[1]; return [lng * 2 - mgLng, lat * 2 - mgLat] } }, /** * * @param lng * @param lat * @returns {number[]} */ delta(lng, lat) { let dLng = this.transformLng(lng - 105, lat - 35); let dLat = this.transformLat(lng - 105, lat - 35); const radLat = (lat / 180) * CoordTransform_PI; let magic = Math.sin(radLat); magic = 1 - CoordTransform_EE * magic * magic; const sqrtMagic = Math.sqrt(magic); dLng = (dLng * 180) / ((CoordTransform_RADIUS / sqrtMagic) * Math.cos(radLat) * CoordTransform_PI); dLat = (dLat * 180) / (((CoordTransform_RADIUS * (1 - CoordTransform_EE)) / (magic * sqrtMagic)) * CoordTransform_PI); return [dLng, dLat] }, /** * * @param lng * @param lat * @returns {number} */ transformLng(lng, lat) { lat = +lat; lng = +lng; let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)); ret += ((20.0 * Math.sin(6.0 * lng * CoordTransform_PI) + 20.0 * Math.sin(2.0 * lng * CoordTransform_PI)) * 2.0) / 3.0; ret += ((20.0 * Math.sin(lng * CoordTransform_PI) + 40.0 * Math.sin((lng / 3.0) * CoordTransform_PI)) * 2.0) / 3.0; ret += ((150.0 * Math.sin((lng / 12.0) * CoordTransform_PI) + 300.0 * Math.sin((lng / 30.0) * CoordTransform_PI)) * 2.0) / 3.0; return ret }, /** * * @param lng * @param lat * @returns {number} */ transformLat(lng, lat) { lat = +lat; lng = +lng; let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)); ret += ((20.0 * Math.sin(6.0 * lng * CoordTransform_PI) + 20.0 * Math.sin(2.0 * lng * CoordTransform_PI)) * 2.0) / 3.0; ret += ((20.0 * Math.sin(lat * CoordTransform_PI) + 40.0 * Math.sin((lat / 3.0) * CoordTransform_PI)) * 2.0) / 3.0; ret += ((160.0 * Math.sin((lat / 12.0) * CoordTransform_PI) + 320 * Math.sin((lat * CoordTransform_PI) / 30.0)) * 2.0) / 3.0; return ret }, /** * * @param lng * @param lat * @returns {boolean} */ out_of_china(lng, lat) { lat = +lat; lng = +lng; return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55) } }; //颜色阶梯过渡(均匀渐变)Gradient算法 //Gradient = Start+ (End-Start) / Step * N /** * 颜色阶梯过渡(均匀渐变)Gradient算法 * @param {*} startColor * @param {*} endColor * @param {*} step * @author 张丹钊 */ function gradientColor(startColor, endColor, step) { if (startColor && endColor) { if (startColor[0] !== '#') { startColor = this.colorHex(startColor); } if (endColor[0] !== '#') { endColor = this.colorHex(endColor); } var startRGB = this.colorRgb(startColor);//转换为rgb数组模式 var startR = startRGB[0]; var startG = startRGB[1]; var startB = startRGB[2]; var endRGB = this.colorRgb(endColor); var endR = endRGB[0]; var endG = endRGB[1]; var endB = endRGB[2]; var sR = (endR - startR) / step;//总差值 var sG = (endG - startG) / step; var sB = (endB - startB) / step; var colorArr = []; for (var i = 0; i < step; i++) { //计算每一步的hex值 var hex = this.colorHex('rgb(' + parseInt((sR * i + startR)) + ',' + parseInt((sG * i + startG)) + ',' + parseInt((sB * i + startB)) + ')'); colorArr.push(hex); } return colorArr; } return this; } // 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式) gradientColor.prototype.colorRgb = function (sColor) { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; var sColor = sColor.toLowerCase(); if (sColor && reg.test(sColor)) { if (sColor.length === 4) { var sColorNew = "#"; for (var i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } //处理六位的颜色值 var sColorChange = []; for (var i = 1; i < 7; i += 2) { sColorChange.push(parseInt("0x" + sColor.slice(i, i + 2))); } return sColorChange; } else { return sColor; } }; // 将rgb表示方式转换为hex表示方式 gradientColor.prototype.colorHex = function (rgb) { var _this = rgb; var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; if (/^(rgb|RGB)/.test(_this)) { var str = _this.replace(/(rgb|RGB)*/g, ""); str = str.replace("(", "").replace(")", ""); var aColor = str.split(","); var strHex = "#"; for (var i = 0; i < aColor.length; i++) { var hex = Number(aColor[i]).toString(16); hex = hex.length === 1 ? 0 + '' + hex : hex;// 保证每个rgb的值为2位 if (hex === "0") { hex += hex; } strHex += hex; } if (strHex.length !== 7) { strHex = _this; } return strHex; } else if (reg.test(_this)) { var aNum = _this.replace(/#/, "").split(""); if (aNum.length === 6) { return _this; } else if (aNum.length === 3) { var numHex = "#"; for (var i = 0; i < aNum.length; i += 1) { numHex += (aNum[i] + aNum[i]); } return numHex; } } else { return _this; } }; function t$5(e, t) { for (var n = 0; n < e.length; n++) if (t(e[n])) return n } /** * * 程序池 * * @alias WorkerPool * @author 张恒 * @constructor * */ function WorkerPool(e) { e = e || []; if (!Cesium.defined(e.workerPath)) throw new Cesium.DeveloperError("workerPath is required."); this._workerPath = e.workerPath, this._poolSize = Cesium.defaultValue(e.poolSize, 16), this._workers = [], this._defered = []; }Object.defineProperties(WorkerPool.prototype, { errorEvent: { get: function () { return this.errorEvent } }, poolSize: { get: function () { return this._poolSize } } }), WorkerPool.prototype.queueWorkItem = function (e, t) { var n = Cesium.when.defer(), r = null, i = 999999; for (var s = 0; s < this._workers.length; s++) { var r = this._workers[s]; this._workers[s].jobQueueSize < i && (r = this._workers[s], i = this._workers[s].jobQueueSize); } if (i > 0 && this._workers.length < this.poolSize) { r = new Worker(this._workerPath); var o = this; r.addEventListener("message", function (e) { o.onWorkerMessage(e); }, !1), r.addEventListener("error", function (e) { o.onWorkerError(e); }, !1), r.jobQueueSize = 0, this._workers.push(r), r.id = Cesium.createGuid(); } e.workerId = r.id; var u = Cesium.createGuid(); return e.deferedId = u, this._defered[u] = n, r.jobQueueSize++, r.postMessage(e, t), n }; WorkerPool.prototype.trimPool = function (e) { var t = this; if (e == undefined) { this.timerId != null && clearTimeout(this.timerId), this.timerId = setTimeout(function () { t.trimPool(!0); }, 5e3); return } for (var n = 0; n < this._workers.length; n++) this._workers[n].jobQueueSize == 0 && (this._workers[n].terminate(), this._workers.splice(n, 1), n--); this._workers.length ? this.timerId = setTimeout(function () { t.trimPool(!0); }, 5e3) : this.timerId = null; }; WorkerPool.prototype.onWorkerMessage = function (e) { var n = e.data, r = t$5(this._workers, function (e) { return e.id === n.workerId }); if (r != undefined) { var i = this._workers[r]; i.jobQueueSize--, this.trimPool(); } var s = this._defered[n.deferedId]; delete this._defered[n.deferedId], s.resolve(n); }; WorkerPool.prototype.onWorkerError = function (e) { console.log(e); }; let WMTSWorker = new Map(); /** * wmts Capabilities信息 * @param {*} url * @author 张丹钊 */ function WMTSGetCapabilities(url) { url = url.replaceAll('//', '/'); url = url.replace('http:/', 'http://'); url = url.replace('https:/', 'https://'); if (WMTSWorker.has(url)) { return WMTSWorker.get(url); } else { let workerPool = new WorkerPool({ workerPath: SmartEarthRootUrl + "Workers/xhrworker.js" }); let promise = workerPool.queueWorkItem({ type: "get", url: url, }); promise.then(e => { e.xmlObj = xmlStr2XmlObj(e.xmlText); promise.resolve(e); }); WMTSWorker.set(url, promise); return promise; } } /** * xml字符串转换xml对象数据 * @param {Object} xmlStr */ function xmlStr2XmlObj(xmlStr) { let xmlObj = {}; if (document.all) { let xmlDom = new ActiveXObject("Microsoft.XMLDOM"); xmlDom.loadXML(xmlStr); xmlObj = xmlDom; } else { xmlObj = new DOMParser().parseFromString(xmlStr, "text/xml"); } return xmlObj; } /** * xml字符串转换json数据 * @param {Object} xml */ function xmlObj2json(xml) { if (!xml) return {}; // quick fail if (typeof xml === 'string') { xml = xmlStr2XmlObj(xml); } if (xml.nodeType == 3 || xml.nodeType == 4) return xml.nodeValue; // Find xml root node let root = xml.nodeType == 9 ? xml.documentElement : xml; return xml2json(root); } /** * xml转换json数据 * @param {Object} xml */ function xml2json(xml) { try { let obj = {}; if (xml.children.length > 0) { for (let i = 0; i < xml.children.length; i++) { let item = xml.children.item(i); let nodeName = item.nodeName; nodeName = nodeName.split(":"); nodeName = nodeName[1] || nodeName[0]; if (typeof (obj[nodeName]) == "undefined") { obj[nodeName] = xml2json(item); } else { if (typeof (obj[nodeName].push) == "undefined") { let old = obj[nodeName]; obj[nodeName] = []; obj[nodeName].push(old); } obj[nodeName].push(xml2json(item)); } } } else if (xml.attributes && xml.attributes.length && !xml.textContent) { let data = {}; for (let i = 0, attribute; i < xml.attributes.length; i++) { attribute = xml.attributes[i]; if (attribute.split) { attribute = attribute.split("="); data[attribute[0]] = attribute[1]; }else { data[attribute.name] = attribute.textContent; } } return data; } else { obj = xml.textContent; } return obj; } catch (e) { console.log(e.message); } } const ContentState = { UNLOADED : 0, LOADING : 1, PARSING : 2, READY : 3, FAILED : 4 }; var ContentState$1 = Object.freeze(ContentState); var tmp = {}; /* pako 1.0.4 nodeca/pako */(function(f){tmp = f();})(function(){return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r);}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1); } _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start // convert string to array (typed, when possible) exports.string2buf = function (str) { var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; // count binary size for (m_pos = 0; m_pos < str_len; m_pos++) { c = str.charCodeAt(m_pos); if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { c2 = str.charCodeAt(m_pos + 1); if ((c2 & 0xfc00) === 0xdc00) { c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); m_pos++; } } buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; } // allocate buffer buf = new utils.Buf8(buf_len); // convert for (i = 0, m_pos = 0; i < buf_len; m_pos++) { c = str.charCodeAt(m_pos); if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { c2 = str.charCodeAt(m_pos + 1); if ((c2 & 0xfc00) === 0xdc00) { c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); m_pos++; } } if (c < 0x80) { /* one byte */ buf[i++] = c; } else if (c < 0x800) { /* two bytes */ buf[i++] = 0xC0 | (c >>> 6); buf[i++] = 0x80 | (c & 0x3f); } else if (c < 0x10000) { /* three bytes */ buf[i++] = 0xE0 | (c >>> 12); buf[i++] = 0x80 | (c >>> 6 & 0x3f); buf[i++] = 0x80 | (c & 0x3f); } else { /* four bytes */ buf[i++] = 0xf0 | (c >>> 18); buf[i++] = 0x80 | (c >>> 12 & 0x3f); buf[i++] = 0x80 | (c >>> 6 & 0x3f); buf[i++] = 0x80 | (c & 0x3f); } } return buf; }; // Helper (used in 2 places) function buf2binstring(buf, len) { // use fallback for big arrays to avoid stack overflow if (len < 65537) { if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) { return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len)); } } var result = ''; for (var i = 0; i < len; i++) { result += String.fromCharCode(buf[i]); } return result; } // Convert byte array to binary string exports.buf2binstring = function (buf) { return buf2binstring(buf, buf.length); }; // Convert binary string (typed, when possible) exports.binstring2buf = function (str) { var buf = new utils.Buf8(str.length); for (var i = 0, len = buf.length; i < len; i++) { buf[i] = str.charCodeAt(i); } return buf; }; // convert array to string exports.buf2string = function (buf, max) { var i, out, c, c_len; var len = max || buf.length; // Reserve max possible length (2 words per char) // NB: by unknown reasons, Array is significantly faster for // String.fromCharCode.apply than Uint16Array. var utf16buf = new Array(len * 2); for (out = 0, i = 0; i < len;) { c = buf[i++]; // quick process ascii if (c < 0x80) { utf16buf[out++] = c; continue; } c_len = _utf8len[c]; // skip 5 & 6 byte codes if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; } // apply mask on first byte c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; // join the rest while (c_len > 1 && i < len) { c = (c << 6) | (buf[i++] & 0x3f); c_len--; } // terminated by end of string? if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } if (c < 0x10000) { utf16buf[out++] = c; } else { c -= 0x10000; utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); utf16buf[out++] = 0xdc00 | (c & 0x3ff); } } return buf2binstring(utf16buf, out); }; // Calculate max possible position in utf8 buffer, // that will not break sequence. If that's not possible // - (very small limits) return max size as is. // // buf[] - utf8 bytes array // max - length limit (mandatory); exports.utf8border = function (buf, max) { var pos; max = max || buf.length; if (max > buf.length) { max = buf.length; } // go back from last position, until start of sequence found pos = max - 1; while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } // Fuckup - very small and broken sequence, // return max, because we should return something anyway. if (pos < 0) { return max; } // If we came to start of buffer - that means vuffer is too small, // return max too. if (pos === 0) { return max; } return (pos + _utf8len[buf[pos]] > max) ? pos : max; }; },{"./common":1}],3:[function(require,module,exports){ // Note: adler32 takes 12% for level 0 and 2% for level 6. // It doesn't worth to make additional optimizationa as in original. // Small size is preferable. function adler32(adler, buf, len, pos) { var s1 = (adler & 0xffff) |0, s2 = ((adler >>> 16) & 0xffff) |0, n = 0; while (len !== 0) { // Set limit ~ twice less than 5552, to keep // s2 in 31-bits, because we force signed ints. // in other case %= will fail. n = len > 2000 ? 2000 : len; len -= n; do { s1 = (s1 + buf[pos++]) |0; s2 = (s2 + s1) |0; } while (--n); s1 %= 65521; s2 %= 65521; } return (s1 | (s2 << 16)) |0; } module.exports = adler32; },{}],4:[function(require,module,exports){ module.exports = { /* Allowed flush values; see deflate() and inflate() below for details */ Z_NO_FLUSH: 0, Z_PARTIAL_FLUSH: 1, Z_SYNC_FLUSH: 2, Z_FULL_FLUSH: 3, Z_FINISH: 4, Z_BLOCK: 5, Z_TREES: 6, /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ Z_OK: 0, Z_STREAM_END: 1, Z_NEED_DICT: 2, Z_ERRNO: -1, Z_STREAM_ERROR: -2, Z_DATA_ERROR: -3, //Z_MEM_ERROR: -4, Z_BUF_ERROR: -5, //Z_VERSION_ERROR: -6, /* compression levels */ Z_NO_COMPRESSION: 0, Z_BEST_SPEED: 1, Z_BEST_COMPRESSION: 9, Z_DEFAULT_COMPRESSION: -1, Z_FILTERED: 1, Z_HUFFMAN_ONLY: 2, Z_RLE: 3, Z_FIXED: 4, Z_DEFAULT_STRATEGY: 0, /* Possible values of the data_type field (though see inflate()) */ Z_BINARY: 0, Z_TEXT: 1, //Z_ASCII: 1, // = Z_TEXT (deprecated) Z_UNKNOWN: 2, /* The deflate compression method */ Z_DEFLATED: 8 //Z_NULL: null // Use -1 or null inline, depending on var type }; },{}],5:[function(require,module,exports){ // Note: we can't get significant speed boost here. // So write code to minimize size - no pregenerated tables // and array tools dependencies. // Use ordinary array, since untyped makes no boost here function makeTable() { var c, table = []; for (var n = 0; n < 256; n++) { c = n; for (var k = 0; k < 8; k++) { c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); } table[n] = c; } return table; } // Create table on load. Just 255 signed longs. Not a problem. var crcTable = makeTable(); function crc32(crc, buf, len, pos) { var t = crcTable, end = pos + len; crc ^= -1; for (var i = pos; i < end; i++) { crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; } return (crc ^ (-1)); // >>> 0; } module.exports = crc32; },{}],6:[function(require,module,exports){ function GZheader() { /* true if compressed data believed to be text */ this.text = 0; /* modification time */ this.time = 0; /* extra flags (not used when writing a gzip file) */ this.xflags = 0; /* operating system */ this.os = 0; /* pointer to extra field or Z_NULL if none */ this.extra = null; /* extra field length (valid if extra != Z_NULL) */ this.extra_len = 0; // Actually, we don't need it in JS, // but leave for few code modifications // // Setup limits is not necessary because in js we should not preallocate memory // for inflate use constant limit in 65536 bytes // /* space at extra (only when reading header) */ // this.extra_max = 0; /* pointer to zero-terminated file name or Z_NULL */ this.name = ''; /* space at name (only when reading header) */ // this.name_max = 0; /* pointer to zero-terminated comment or Z_NULL */ this.comment = ''; /* space at comment (only when reading header) */ // this.comm_max = 0; /* true if there was or will be a header crc */ this.hcrc = 0; /* true when done reading gzip header (not used when writing a gzip file) */ this.done = false; } module.exports = GZheader; },{}],7:[function(require,module,exports){ // See state defs from inflate.js var BAD = 30; /* got a data error -- remain here until reset */ var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state.mode === LEN strm.avail_in >= 6 strm.avail_out >= 258 start >= strm.avail_out state.bits < 8 On return, state.mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm.avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm.avail_out >= 258 for each loop to avoid checking for output space. */ module.exports = function inflate_fast(strm, start) { var state; var _in; /* local strm.input */ var last; /* have enough input while in < last */ var _out; /* local strm.output */ var beg; /* inflate()'s initial strm.output */ var end; /* while out < end, enough space available */ //#ifdef INFLATE_STRICT var dmax; /* maximum distance from zlib header */ //#endif var wsize; /* window size or zero if not using window */ var whave; /* valid bytes in the window */ var wnext; /* window write index */ // Use `s_window` instead `window`, avoid conflict with instrumentation tools var s_window; /* allocated sliding window, if wsize != 0 */ var hold; /* local strm.hold */ var bits; /* local strm.bits */ var lcode; /* local strm.lencode */ var dcode; /* local strm.distcode */ var lmask; /* mask for first level of length codes */ var dmask; /* mask for first level of distance codes */ var here; /* retrieved table entry */ var op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ var len; /* match length, unused bytes */ var dist; /* match distance */ var from; /* where to copy match from */ var from_source; var input, output; // JS specific, because we have no pointers /* copy state to local variables */ state = strm.state; //here = state.here; _in = strm.next_in; input = strm.input; last = _in + (strm.avail_in - 5); _out = strm.next_out; output = strm.output; beg = _out - (start - strm.avail_out); end = _out + (strm.avail_out - 257); //#ifdef INFLATE_STRICT dmax = state.dmax; //#endif wsize = state.wsize; whave = state.whave; wnext = state.wnext; s_window = state.window; hold = state.hold; bits = state.bits; lcode = state.lencode; dcode = state.distcode; lmask = (1 << state.lenbits) - 1; dmask = (1 << state.distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ top: do { if (bits < 15) { hold += input[_in++] << bits; bits += 8; hold += input[_in++] << bits; bits += 8; } here = lcode[hold & lmask]; dolen: for (;;) { // Goto emulation op = here >>> 24/*here.bits*/; hold >>>= op; bits -= op; op = (here >>> 16) & 0xff/*here.op*/; if (op === 0) { /* literal */ //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? // "inflate: literal '%c'\n" : // "inflate: literal 0x%02x\n", here.val)); output[_out++] = here & 0xffff/*here.val*/; } else if (op & 16) { /* length base */ len = here & 0xffff/*here.val*/; op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += input[_in++] << bits; bits += 8; } len += hold & ((1 << op) - 1); hold >>>= op; bits -= op; } //Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += input[_in++] << bits; bits += 8; hold += input[_in++] << bits; bits += 8; } here = dcode[hold & dmask]; dodist: for (;;) { // goto emulation op = here >>> 24/*here.bits*/; hold >>>= op; bits -= op; op = (here >>> 16) & 0xff/*here.op*/; if (op & 16) { /* distance base */ dist = here & 0xffff/*here.val*/; op &= 15; /* number of extra bits */ if (bits < op) { hold += input[_in++] << bits; bits += 8; if (bits < op) { hold += input[_in++] << bits; bits += 8; } } dist += hold & ((1 << op) - 1); //#ifdef INFLATE_STRICT if (dist > dmax) { strm.msg = 'invalid distance too far back'; state.mode = BAD; break top; } //#endif hold >>>= op; bits -= op; //Tracevv((stderr, "inflate: distance %u\n", dist)); op = _out - beg; /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state.sane) { strm.msg = 'invalid distance too far back'; state.mode = BAD; break top; } // (!) This block is disabled in zlib defailts, // don't enable it for binary compatibility //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR // if (len <= op - whave) { // do { // output[_out++] = 0; // } while (--len); // continue top; // } // len -= op - whave; // do { // output[_out++] = 0; // } while (--op > whave); // if (op === 0) { // from = _out - dist; // do { // output[_out++] = output[from++]; // } while (--len); // continue top; // } //#endif } from = 0; // window index from_source = s_window; if (wnext === 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { output[_out++] = s_window[from++]; } while (--op); from = _out - dist; /* rest from output */ from_source = output; } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { output[_out++] = s_window[from++]; } while (--op); from = 0; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { output[_out++] = s_window[from++]; } while (--op); from = _out - dist; /* rest from output */ from_source = output; } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { output[_out++] = s_window[from++]; } while (--op); from = _out - dist; /* rest from output */ from_source = output; } } while (len > 2) { output[_out++] = from_source[from++]; output[_out++] = from_source[from++]; output[_out++] = from_source[from++]; len -= 3; } if (len) { output[_out++] = from_source[from++]; if (len > 1) { output[_out++] = from_source[from++]; } } } else { from = _out - dist; /* copy direct from output */ do { /* minimum length is three */ output[_out++] = output[from++]; output[_out++] = output[from++]; output[_out++] = output[from++]; len -= 3; } while (len > 2); if (len) { output[_out++] = output[from++]; if (len > 1) { output[_out++] = output[from++]; } } } } else if ((op & 64) === 0) { /* 2nd level distance code */ here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; continue dodist; } else { strm.msg = 'invalid distance code'; state.mode = BAD; break top; } break; // need to emulate goto via "continue" } } else if ((op & 64) === 0) { /* 2nd level length code */ here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; continue dolen; } else if (op & 32) { /* end-of-block */ //Tracevv((stderr, "inflate: end of block\n")); state.mode = TYPE; break top; } else { strm.msg = 'invalid literal/length code'; state.mode = BAD; break top; } break; // need to emulate goto via "continue" } } while (_in < last && _out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; _in -= len; bits -= len << 3; hold &= (1 << bits) - 1; /* update state and return */ strm.next_in = _in; strm.next_out = _out; strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); state.hold = hold; state.bits = bits; return; }; },{}],8:[function(require,module,exports){ var utils = require('../utils/common'); var adler32 = require('./adler32'); var crc32 = require('./crc32'); var inflate_fast = require('./inffast'); var inflate_table = require('./inftrees'); var CODES = 0; var LENS = 1; var DISTS = 2; /* Public constants ==========================================================*/ /* ===========================================================================*/ /* Allowed flush values; see deflate() and inflate() below for details */ //var Z_NO_FLUSH = 0; //var Z_PARTIAL_FLUSH = 1; //var Z_SYNC_FLUSH = 2; //var Z_FULL_FLUSH = 3; var Z_FINISH = 4; var Z_BLOCK = 5; var Z_TREES = 6; /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ var Z_OK = 0; var Z_STREAM_END = 1; var Z_NEED_DICT = 2; //var Z_ERRNO = -1; var Z_STREAM_ERROR = -2; var Z_DATA_ERROR = -3; var Z_MEM_ERROR = -4; var Z_BUF_ERROR = -5; //var Z_VERSION_ERROR = -6; /* The deflate compression method */ var Z_DEFLATED = 8; /* STATES ====================================================================*/ /* ===========================================================================*/ var HEAD = 1; /* i: waiting for magic header */ var FLAGS = 2; /* i: waiting for method and flags (gzip) */ var TIME = 3; /* i: waiting for modification time (gzip) */ var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ var EXLEN = 5; /* i: waiting for extra length (gzip) */ var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ var NAME = 7; /* i: waiting for end of file name (gzip) */ var COMMENT = 8; /* i: waiting for end of comment (gzip) */ var HCRC = 9; /* i: waiting for header crc (gzip) */ var DICTID = 10; /* i: waiting for dictionary check value */ var DICT = 11; /* waiting for inflateSetDictionary() call */ var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ var STORED = 14; /* i: waiting for stored size (length and complement) */ var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ var COPY = 16; /* i/o: waiting for input or output to copy stored block */ var TABLE = 17; /* i: waiting for dynamic block table lengths */ var LENLENS = 18; /* i: waiting for code length code lengths */ var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ var LEN_ = 20; /* i: same as LEN below, but only first time in */ var LEN = 21; /* i: waiting for length/lit/eob code */ var LENEXT = 22; /* i: waiting for length extra bits */ var DIST = 23; /* i: waiting for distance code */ var DISTEXT = 24; /* i: waiting for distance extra bits */ var MATCH = 25; /* o: waiting for output space to copy string */ var LIT = 26; /* o: waiting for output space to write literal */ var CHECK = 27; /* i: waiting for 32-bit check value */ var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ var DONE = 29; /* finished check, done -- remain here until reset */ var BAD = 30; /* got a data error -- remain here until reset */ var MEM = 31; /* got an inflate() memory error -- remain here until reset */ var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ /* ===========================================================================*/ var ENOUGH_LENS = 852; var ENOUGH_DISTS = 592; //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); var MAX_WBITS = 15; /* 32K LZ77 window */ var DEF_WBITS = MAX_WBITS; function zswap32(q) { return (((q >>> 24) & 0xff) + ((q >>> 8) & 0xff00) + ((q & 0xff00) << 8) + ((q & 0xff) << 24)); } function InflateState() { this.mode = 0; /* current inflate mode */ this.last = false; /* true if processing last block */ this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ this.havedict = false; /* true if dictionary provided */ this.flags = 0; /* gzip header method and flags (0 if zlib) */ this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ this.check = 0; /* protected copy of check value */ this.total = 0; /* protected copy of output count */ // TODO: may be {} this.head = null; /* where to save gzip header information */ /* sliding window */ this.wbits = 0; /* log base 2 of requested window size */ this.wsize = 0; /* window size or zero if not using window */ this.whave = 0; /* valid bytes in the window */ this.wnext = 0; /* window write index */ this.window = null; /* allocated sliding window, if needed */ /* bit accumulator */ this.hold = 0; /* input bit accumulator */ this.bits = 0; /* number of bits in "in" */ /* for string and stored block copying */ this.length = 0; /* literal or length of data to copy */ this.offset = 0; /* distance back to copy string from */ /* for table and code decoding */ this.extra = 0; /* extra bits needed */ /* fixed and dynamic code tables */ this.lencode = null; /* starting table for length/literal codes */ this.distcode = null; /* starting table for distance codes */ this.lenbits = 0; /* index bits for lencode */ this.distbits = 0; /* index bits for distcode */ /* dynamic table building */ this.ncode = 0; /* number of code length code lengths */ this.nlen = 0; /* number of length code lengths */ this.ndist = 0; /* number of distance code lengths */ this.have = 0; /* number of code lengths in lens[] */ this.next = null; /* next available space in codes[] */ this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ this.work = new utils.Buf16(288); /* work area for code table building */ /* because we don't have pointers in js, we use lencode and distcode directly as buffers so we don't need codes */ //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ this.distdyn = null; /* dynamic table for distance codes (JS specific) */ this.sane = 0; /* if false, allow invalid distance too far */ this.back = 0; /* bits back of last unprocessed length/lit */ this.was = 0; /* initial length of match */ } function inflateResetKeep(strm) { var state; if (!strm || !strm.state) { return Z_STREAM_ERROR; } state = strm.state; strm.total_in = strm.total_out = state.total = 0; strm.msg = ''; /*Z_NULL*/ if (state.wrap) { /* to support ill-conceived Java test suite */ strm.adler = state.wrap & 1; } state.mode = HEAD; state.last = 0; state.havedict = 0; state.dmax = 32768; state.head = null/*Z_NULL*/; state.hold = 0; state.bits = 0; //state.lencode = state.distcode = state.next = state.codes; state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); state.sane = 1; state.back = -1; //Tracev((stderr, "inflate: reset\n")); return Z_OK; } function inflateReset(strm) { var state; if (!strm || !strm.state) { return Z_STREAM_ERROR; } state = strm.state; state.wsize = 0; state.whave = 0; state.wnext = 0; return inflateResetKeep(strm); } function inflateReset2(strm, windowBits) { var wrap; var state; /* get the state */ if (!strm || !strm.state) { return Z_STREAM_ERROR; } state = strm.state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 1; if (windowBits < 48) { windowBits &= 15; } } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) { return Z_STREAM_ERROR; } if (state.window !== null && state.wbits !== windowBits) { state.window = null; } /* update state and reset the rest of it */ state.wrap = wrap; state.wbits = windowBits; return inflateReset(strm); } function inflateInit2(strm, windowBits) { var ret; var state; if (!strm) { return Z_STREAM_ERROR; } //strm.msg = Z_NULL; /* in case we return an error */ state = new InflateState(); //if (state === Z_NULL) return Z_MEM_ERROR; //Tracev((stderr, "inflate: allocated\n")); strm.state = state; state.window = null/*Z_NULL*/; ret = inflateReset2(strm, windowBits); if (ret !== Z_OK) { strm.state = null/*Z_NULL*/; } return ret; } function inflateInit(strm) { return inflateInit2(strm, DEF_WBITS); } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ var virgin = true; var lenfix, distfix; // We have no pointers in JS, so keep tables separate function fixedtables(state) { /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { var sym; lenfix = new utils.Buf32(512); distfix = new utils.Buf32(32); /* literal/length table */ sym = 0; while (sym < 144) { state.lens[sym++] = 8; } while (sym < 256) { state.lens[sym++] = 9; } while (sym < 280) { state.lens[sym++] = 7; } while (sym < 288) { state.lens[sym++] = 8; } inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 }); /* distance table */ sym = 0; while (sym < 32) { state.lens[sym++] = 5; } inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 }); /* do this just once */ virgin = false; } state.lencode = lenfix; state.lenbits = 9; state.distcode = distfix; state.distbits = 5; } /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ function updatewindow(strm, src, end, copy) { var dist; var state = strm.state; /* if it hasn't been done already, allocate space for the window */ if (state.window === null) { state.wsize = 1 << state.wbits; state.wnext = 0; state.whave = 0; state.window = new utils.Buf8(state.wsize); } /* copy state->wsize or less output bytes into the circular window */ if (copy >= state.wsize) { utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0); state.wnext = 0; state.whave = state.wsize; } else { dist = state.wsize - state.wnext; if (dist > copy) { dist = copy; } //zmemcpy(state->window + state->wnext, end - copy, dist); utils.arraySet(state.window, src, end - copy, dist, state.wnext); copy -= dist; if (copy) { //zmemcpy(state->window, end - copy, copy); utils.arraySet(state.window, src, end - copy, copy, 0); state.wnext = copy; state.whave = state.wsize; } else { state.wnext += dist; if (state.wnext === state.wsize) { state.wnext = 0; } if (state.whave < state.wsize) { state.whave += dist; } } } return 0; } function inflate(strm, flush) { var state; var input, output; // input/output buffers var next; /* next input INDEX */ var put; /* next output INDEX */ var have, left; /* available input and output */ var hold; /* bit buffer */ var bits; /* bits in bit buffer */ var _in, _out; /* save starting available input and output */ var copy; /* number of stored or match bytes to copy */ var from; /* where to copy match bytes from */ var from_source; var here = 0; /* current decoding table entry */ var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) //var last; /* parent table entry */ var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) var len; /* length to copy for repeats, bits to drop */ var ret; /* return code */ var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ var opts; var n; // temporary var for NEED_BITS var order = /* permutation of code lengths */ [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; if (!strm || !strm.state || !strm.output || (!strm.input && strm.avail_in !== 0)) { return Z_STREAM_ERROR; } state = strm.state; if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ //--- LOAD() --- put = strm.next_out; output = strm.output; left = strm.avail_out; next = strm.next_in; input = strm.input; have = strm.avail_in; hold = state.hold; bits = state.bits; //--- _in = have; _out = left; ret = Z_OK; inf_leave: // goto emulation for (;;) { switch (state.mode) { case HEAD: if (state.wrap === 0) { state.mode = TYPEDO; break; } //=== NEEDBITS(16); while (bits < 16) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ state.check = 0/*crc32(0L, Z_NULL, 0)*/; //=== CRC2(state.check, hold); hbuf[0] = hold & 0xff; hbuf[1] = (hold >>> 8) & 0xff; state.check = crc32(state.check, hbuf, 2, 0); //===// //=== INITBITS(); hold = 0; bits = 0; //===// state.mode = FLAGS; break; } state.flags = 0; /* expect zlib header */ if (state.head) { state.head.done = false; } if (!(state.wrap & 1) || /* check if zlib header allowed */ (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { strm.msg = 'incorrect header check'; state.mode = BAD; break; } if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { strm.msg = 'unknown compression method'; state.mode = BAD; break; } //--- DROPBITS(4) ---// hold >>>= 4; bits -= 4; //---// len = (hold & 0x0f)/*BITS(4)*/ + 8; if (state.wbits === 0) { state.wbits = len; } else if (len > state.wbits) { strm.msg = 'invalid window size'; state.mode = BAD; break; } state.dmax = 1 << len; //Tracev((stderr, "inflate: zlib header ok\n")); strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; state.mode = hold & 0x200 ? DICTID : TYPE; //=== INITBITS(); hold = 0; bits = 0; //===// break; case FLAGS: //=== NEEDBITS(16); */ while (bits < 16) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// state.flags = hold; if ((state.flags & 0xff) !== Z_DEFLATED) { strm.msg = 'unknown compression method'; state.mode = BAD; break; } if (state.flags & 0xe000) { strm.msg = 'unknown header flags set'; state.mode = BAD; break; } if (state.head) { state.head.text = ((hold >> 8) & 1); } if (state.flags & 0x0200) { //=== CRC2(state.check, hold); hbuf[0] = hold & 0xff; hbuf[1] = (hold >>> 8) & 0xff; state.check = crc32(state.check, hbuf, 2, 0); //===// } //=== INITBITS(); hold = 0; bits = 0; //===// state.mode = TIME; /* falls through */ case TIME: //=== NEEDBITS(32); */ while (bits < 32) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// if (state.head) { state.head.time = hold; } if (state.flags & 0x0200) { //=== CRC4(state.check, hold) hbuf[0] = hold & 0xff; hbuf[1] = (hold >>> 8) & 0xff; hbuf[2] = (hold >>> 16) & 0xff; hbuf[3] = (hold >>> 24) & 0xff; state.check = crc32(state.check, hbuf, 4, 0); //=== } //=== INITBITS(); hold = 0; bits = 0; //===// state.mode = OS; /* falls through */ case OS: //=== NEEDBITS(16); */ while (bits < 16) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// if (state.head) { state.head.xflags = (hold & 0xff); state.head.os = (hold >> 8); } if (state.flags & 0x0200) { //=== CRC2(state.check, hold); hbuf[0] = hold & 0xff; hbuf[1] = (hold >>> 8) & 0xff; state.check = crc32(state.check, hbuf, 2, 0); //===// } //=== INITBITS(); hold = 0; bits = 0; //===// state.mode = EXLEN; /* falls through */ case EXLEN: if (state.flags & 0x0400) { //=== NEEDBITS(16); */ while (bits < 16) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// state.length = hold; if (state.head) { state.head.extra_len = hold; } if (state.flags & 0x0200) { //=== CRC2(state.check, hold); hbuf[0] = hold & 0xff; hbuf[1] = (hold >>> 8) & 0xff; state.check = crc32(state.check, hbuf, 2, 0); //===// } //=== INITBITS(); hold = 0; bits = 0; //===// } else if (state.head) { state.head.extra = null/*Z_NULL*/; } state.mode = EXTRA; /* falls through */ case EXTRA: if (state.flags & 0x0400) { copy = state.length; if (copy > have) { copy = have; } if (copy) { if (state.head) { len = state.head.extra_len - state.length; if (!state.head.extra) { // Use untyped array for more conveniend processing later state.head.extra = new Array(state.head.extra_len); } utils.arraySet( state.head.extra, input, next, // extra field is limited to 65536 bytes // - no need for additional size check copy, /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ len ); //zmemcpy(state.head.extra + len, next, // len + copy > state.head.extra_max ? // state.head.extra_max - len : copy); } if (state.flags & 0x0200) { state.check = crc32(state.check, input, copy, next); } have -= copy; next += copy; state.length -= copy; } if (state.length) { break inf_leave; } } state.length = 0; state.mode = NAME; /* falls through */ case NAME: if (state.flags & 0x0800) { if (have === 0) { break inf_leave; } copy = 0; do { // TODO: 2 or 1 bytes? len = input[next + copy++]; /* use constant limit because in js we should not preallocate memory */ if (state.head && len && (state.length < 65536 /*state.head.name_max*/)) { state.head.name += String.fromCharCode(len); } } while (len && copy < have); if (state.flags & 0x0200) { state.check = crc32(state.check, input, copy, next); } have -= copy; next += copy; if (len) { break inf_leave; } } else if (state.head) { state.head.name = null; } state.length = 0; state.mode = COMMENT; /* falls through */ case COMMENT: if (state.flags & 0x1000) { if (have === 0) { break inf_leave; } copy = 0; do { len = input[next + copy++]; /* use constant limit because in js we should not preallocate memory */ if (state.head && len && (state.length < 65536 /*state.head.comm_max*/)) { state.head.comment += String.fromCharCode(len); } } while (len && copy < have); if (state.flags & 0x0200) { state.check = crc32(state.check, input, copy, next); } have -= copy; next += copy; if (len) { break inf_leave; } } else if (state.head) { state.head.comment = null; } state.mode = HCRC; /* falls through */ case HCRC: if (state.flags & 0x0200) { //=== NEEDBITS(16); */ while (bits < 16) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// if (hold !== (state.check & 0xffff)) { strm.msg = 'header crc mismatch'; state.mode = BAD; break; } //=== INITBITS(); hold = 0; bits = 0; //===// } if (state.head) { state.head.hcrc = ((state.flags >> 9) & 1); state.head.done = true; } strm.adler = state.check = 0; state.mode = TYPE; break; case DICTID: //=== NEEDBITS(32); */ while (bits < 32) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// strm.adler = state.check = zswap32(hold); //=== INITBITS(); hold = 0; bits = 0; //===// state.mode = DICT; /* falls through */ case DICT: if (state.havedict === 0) { //--- RESTORE() --- strm.next_out = put; strm.avail_out = left; strm.next_in = next; strm.avail_in = have; state.hold = hold; state.bits = bits; //--- return Z_NEED_DICT; } strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; state.mode = TYPE; /* falls through */ case TYPE: if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } /* falls through */ case TYPEDO: if (state.last) { //--- BYTEBITS() ---// hold >>>= bits & 7; bits -= bits & 7; //---// state.mode = CHECK; break; } //=== NEEDBITS(3); */ while (bits < 3) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// state.last = (hold & 0x01)/*BITS(1)*/; //--- DROPBITS(1) ---// hold >>>= 1; bits -= 1; //---// switch ((hold & 0x03)/*BITS(2)*/) { case 0: /* stored block */ //Tracev((stderr, "inflate: stored block%s\n", // state.last ? " (last)" : "")); state.mode = STORED; break; case 1: /* fixed block */ fixedtables(state); //Tracev((stderr, "inflate: fixed codes block%s\n", // state.last ? " (last)" : "")); state.mode = LEN_; /* decode codes */ if (flush === Z_TREES) { //--- DROPBITS(2) ---// hold >>>= 2; bits -= 2; //---// break inf_leave; } break; case 2: /* dynamic block */ //Tracev((stderr, "inflate: dynamic codes block%s\n", // state.last ? " (last)" : "")); state.mode = TABLE; break; case 3: strm.msg = 'invalid block type'; state.mode = BAD; } //--- DROPBITS(2) ---// hold >>>= 2; bits -= 2; //---// break; case STORED: //--- BYTEBITS() ---// /* go to byte boundary */ hold >>>= bits & 7; bits -= bits & 7; //---// //=== NEEDBITS(32); */ while (bits < 32) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { strm.msg = 'invalid stored block lengths'; state.mode = BAD; break; } state.length = hold & 0xffff; //Tracev((stderr, "inflate: stored length %u\n", // state.length)); //=== INITBITS(); hold = 0; bits = 0; //===// state.mode = COPY_; if (flush === Z_TREES) { break inf_leave; } /* falls through */ case COPY_: state.mode = COPY; /* falls through */ case COPY: copy = state.length; if (copy) { if (copy > have) { copy = have; } if (copy > left) { copy = left; } if (copy === 0) { break inf_leave; } //--- zmemcpy(put, next, copy); --- utils.arraySet(output, input, next, copy, put); //---// have -= copy; next += copy; left -= copy; put += copy; state.length -= copy; break; } //Tracev((stderr, "inflate: stored end\n")); state.mode = TYPE; break; case TABLE: //=== NEEDBITS(14); */ while (bits < 14) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; //--- DROPBITS(5) ---// hold >>>= 5; bits -= 5; //---// state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; //--- DROPBITS(5) ---// hold >>>= 5; bits -= 5; //---// state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; //--- DROPBITS(4) ---// hold >>>= 4; bits -= 4; //---// //#ifndef PKZIP_BUG_WORKAROUND if (state.nlen > 286 || state.ndist > 30) { strm.msg = 'too many length or distance symbols'; state.mode = BAD; break; } //#endif //Tracev((stderr, "inflate: table sizes ok\n")); state.have = 0; state.mode = LENLENS; /* falls through */ case LENLENS: while (state.have < state.ncode) { //=== NEEDBITS(3); while (bits < 3) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); //--- DROPBITS(3) ---// hold >>>= 3; bits -= 3; //---// } while (state.have < 19) { state.lens[order[state.have++]] = 0; } // We have separate tables & no pointers. 2 commented lines below not needed. //state.next = state.codes; //state.lencode = state.next; // Switch to use dynamic table state.lencode = state.lendyn; state.lenbits = 7; opts = { bits: state.lenbits }; ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); state.lenbits = opts.bits; if (ret) { strm.msg = 'invalid code lengths set'; state.mode = BAD; break; } //Tracev((stderr, "inflate: code lengths ok\n")); state.have = 0; state.mode = CODELENS; /* falls through */ case CODELENS: while (state.have < state.nlen + state.ndist) { for (;;) { here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ here_bits = here >>> 24; here_op = (here >>> 16) & 0xff; here_val = here & 0xffff; if ((here_bits) <= bits) { break; } //--- PULLBYTE() ---// if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; //---// } if (here_val < 16) { //--- DROPBITS(here.bits) ---// hold >>>= here_bits; bits -= here_bits; //---// state.lens[state.have++] = here_val; } else { if (here_val === 16) { //=== NEEDBITS(here.bits + 2); n = here_bits + 2; while (bits < n) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// //--- DROPBITS(here.bits) ---// hold >>>= here_bits; bits -= here_bits; //---// if (state.have === 0) { strm.msg = 'invalid bit length repeat'; state.mode = BAD; break; } len = state.lens[state.have - 1]; copy = 3 + (hold & 0x03);//BITS(2); //--- DROPBITS(2) ---// hold >>>= 2; bits -= 2; //---// } else if (here_val === 17) { //=== NEEDBITS(here.bits + 3); n = here_bits + 3; while (bits < n) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// //--- DROPBITS(here.bits) ---// hold >>>= here_bits; bits -= here_bits; //---// len = 0; copy = 3 + (hold & 0x07);//BITS(3); //--- DROPBITS(3) ---// hold >>>= 3; bits -= 3; //---// } else { //=== NEEDBITS(here.bits + 7); n = here_bits + 7; while (bits < n) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// //--- DROPBITS(here.bits) ---// hold >>>= here_bits; bits -= here_bits; //---// len = 0; copy = 11 + (hold & 0x7f);//BITS(7); //--- DROPBITS(7) ---// hold >>>= 7; bits -= 7; //---// } if (state.have + copy > state.nlen + state.ndist) { strm.msg = 'invalid bit length repeat'; state.mode = BAD; break; } while (copy--) { state.lens[state.have++] = len; } } } /* handle error breaks in while */ if (state.mode === BAD) { break; } /* check for end-of-block code (better have one) */ if (state.lens[256] === 0) { strm.msg = 'invalid code -- missing end-of-block'; state.mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state.lenbits = 9; opts = { bits: state.lenbits }; ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); // We have separate tables & no pointers. 2 commented lines below not needed. // state.next_index = opts.table_index; state.lenbits = opts.bits; // state.lencode = state.next; if (ret) { strm.msg = 'invalid literal/lengths set'; state.mode = BAD; break; } state.distbits = 6; //state.distcode.copy(state.codes); // Switch to use dynamic table state.distcode = state.distdyn; opts = { bits: state.distbits }; ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); // We have separate tables & no pointers. 2 commented lines below not needed. // state.next_index = opts.table_index; state.distbits = opts.bits; // state.distcode = state.next; if (ret) { strm.msg = 'invalid distances set'; state.mode = BAD; break; } //Tracev((stderr, 'inflate: codes ok\n')); state.mode = LEN_; if (flush === Z_TREES) { break inf_leave; } /* falls through */ case LEN_: state.mode = LEN; /* falls through */ case LEN: if (have >= 6 && left >= 258) { //--- RESTORE() --- strm.next_out = put; strm.avail_out = left; strm.next_in = next; strm.avail_in = have; state.hold = hold; state.bits = bits; //--- inflate_fast(strm, _out); //--- LOAD() --- put = strm.next_out; output = strm.output; left = strm.avail_out; next = strm.next_in; input = strm.input; have = strm.avail_in; hold = state.hold; bits = state.bits; //--- if (state.mode === TYPE) { state.back = -1; } break; } state.back = 0; for (;;) { here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/ here_bits = here >>> 24; here_op = (here >>> 16) & 0xff; here_val = here & 0xffff; if (here_bits <= bits) { break; } //--- PULLBYTE() ---// if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; //---// } if (here_op && (here_op & 0xf0) === 0) { last_bits = here_bits; last_op = here_op; last_val = here_val; for (;;) { here = state.lencode[last_val + ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; here_bits = here >>> 24; here_op = (here >>> 16) & 0xff; here_val = here & 0xffff; if ((last_bits + here_bits) <= bits) { break; } //--- PULLBYTE() ---// if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; //---// } //--- DROPBITS(last.bits) ---// hold >>>= last_bits; bits -= last_bits; //---// state.back += last_bits; } //--- DROPBITS(here.bits) ---// hold >>>= here_bits; bits -= here_bits; //---// state.back += here_bits; state.length = here_val; if (here_op === 0) { //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? // "inflate: literal '%c'\n" : // "inflate: literal 0x%02x\n", here.val)); state.mode = LIT; break; } if (here_op & 32) { //Tracevv((stderr, "inflate: end of block\n")); state.back = -1; state.mode = TYPE; break; } if (here_op & 64) { strm.msg = 'invalid literal/length code'; state.mode = BAD; break; } state.extra = here_op & 15; state.mode = LENEXT; /* falls through */ case LENEXT: if (state.extra) { //=== NEEDBITS(state.extra); n = state.extra; while (bits < n) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; //--- DROPBITS(state.extra) ---// hold >>>= state.extra; bits -= state.extra; //---// state.back += state.extra; } //Tracevv((stderr, "inflate: length %u\n", state.length)); state.was = state.length; state.mode = DIST; /* falls through */ case DIST: for (;;) { here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/ here_bits = here >>> 24; here_op = (here >>> 16) & 0xff; here_val = here & 0xffff; if ((here_bits) <= bits) { break; } //--- PULLBYTE() ---// if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; //---// } if ((here_op & 0xf0) === 0) { last_bits = here_bits; last_op = here_op; last_val = here_val; for (;;) { here = state.distcode[last_val + ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; here_bits = here >>> 24; here_op = (here >>> 16) & 0xff; here_val = here & 0xffff; if ((last_bits + here_bits) <= bits) { break; } //--- PULLBYTE() ---// if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; //---// } //--- DROPBITS(last.bits) ---// hold >>>= last_bits; bits -= last_bits; //---// state.back += last_bits; } //--- DROPBITS(here.bits) ---// hold >>>= here_bits; bits -= here_bits; //---// state.back += here_bits; if (here_op & 64) { strm.msg = 'invalid distance code'; state.mode = BAD; break; } state.offset = here_val; state.extra = (here_op) & 15; state.mode = DISTEXT; /* falls through */ case DISTEXT: if (state.extra) { //=== NEEDBITS(state.extra); n = state.extra; while (bits < n) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; //--- DROPBITS(state.extra) ---// hold >>>= state.extra; bits -= state.extra; //---// state.back += state.extra; } //#ifdef INFLATE_STRICT if (state.offset > state.dmax) { strm.msg = 'invalid distance too far back'; state.mode = BAD; break; } //#endif //Tracevv((stderr, "inflate: distance %u\n", state.offset)); state.mode = MATCH; /* falls through */ case MATCH: if (left === 0) { break inf_leave; } copy = _out - left; if (state.offset > copy) { /* copy from window */ copy = state.offset - copy; if (copy > state.whave) { if (state.sane) { strm.msg = 'invalid distance too far back'; state.mode = BAD; break; } // (!) This block is disabled in zlib defailts, // don't enable it for binary compatibility //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR // Trace((stderr, "inflate.c too far\n")); // copy -= state.whave; // if (copy > state.length) { copy = state.length; } // if (copy > left) { copy = left; } // left -= copy; // state.length -= copy; // do { // output[put++] = 0; // } while (--copy); // if (state.length === 0) { state.mode = LEN; } // break; //#endif } if (copy > state.wnext) { copy -= state.wnext; from = state.wsize - copy; } else { from = state.wnext - copy; } if (copy > state.length) { copy = state.length; } from_source = state.window; } else { /* copy from output */ from_source = output; from = put - state.offset; copy = state.length; } if (copy > left) { copy = left; } left -= copy; state.length -= copy; do { output[put++] = from_source[from++]; } while (--copy); if (state.length === 0) { state.mode = LEN; } break; case LIT: if (left === 0) { break inf_leave; } output[put++] = state.length; left--; state.mode = LEN; break; case CHECK: if (state.wrap) { //=== NEEDBITS(32); while (bits < 32) { if (have === 0) { break inf_leave; } have--; // Use '|' insdead of '+' to make sure that result is signed hold |= input[next++] << bits; bits += 8; } //===// _out -= left; strm.total_out += _out; state.total += _out; if (_out) { strm.adler = state.check = /*UPDATE(state.check, put - _out, _out);*/ (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); } _out = left; // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too if ((state.flags ? hold : zswap32(hold)) !== state.check) { strm.msg = 'incorrect data check'; state.mode = BAD; break; } //=== INITBITS(); hold = 0; bits = 0; //===// //Tracev((stderr, "inflate: check matches trailer\n")); } state.mode = LENGTH; /* falls through */ case LENGTH: if (state.wrap && state.flags) { //=== NEEDBITS(32); while (bits < 32) { if (have === 0) { break inf_leave; } have--; hold += input[next++] << bits; bits += 8; } //===// if (hold !== (state.total & 0xffffffff)) { strm.msg = 'incorrect length check'; state.mode = BAD; break; } //=== INITBITS(); hold = 0; bits = 0; //===// //Tracev((stderr, "inflate: length matches trailer\n")); } state.mode = DONE; /* falls through */ case DONE: ret = Z_STREAM_END; break inf_leave; case BAD: ret = Z_DATA_ERROR; break inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: /* falls through */ default: return Z_STREAM_ERROR; } } // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ //--- RESTORE() --- strm.next_out = put; strm.avail_out = left; strm.next_in = next; strm.avail_in = have; state.hold = hold; state.bits = bits; //--- if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && (state.mode < CHECK || flush !== Z_FINISH))) { if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ; } _in -= strm.avail_in; _out -= strm.avail_out; strm.total_in += _in; strm.total_out += _out; state.total += _out; if (state.wrap && _out) { strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); } strm.data_type = state.bits + (state.last ? 64 : 0) + (state.mode === TYPE ? 128 : 0) + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { ret = Z_BUF_ERROR; } return ret; } function inflateEnd(strm) { if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { return Z_STREAM_ERROR; } var state = strm.state; if (state.window) { state.window = null; } strm.state = null; return Z_OK; } function inflateGetHeader(strm, head) { var state; /* check state */ if (!strm || !strm.state) { return Z_STREAM_ERROR; } state = strm.state; if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } /* save header structure */ state.head = head; head.done = false; return Z_OK; } function inflateSetDictionary(strm, dictionary) { var dictLength = dictionary.length; var state; var dictid; var ret; /* check state */ if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; } state = strm.state; if (state.wrap !== 0 && state.mode !== DICT) { return Z_STREAM_ERROR; } /* check for correct dictionary identifier */ if (state.mode === DICT) { dictid = 1; /* adler32(0, null, 0)*/ /* dictid = adler32(dictid, dictionary, dictLength); */ dictid = adler32(dictid, dictionary, dictLength, 0); if (dictid !== state.check) { return Z_DATA_ERROR; } } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary, dictLength, dictLength); if (ret) { state.mode = MEM; return Z_MEM_ERROR; } state.havedict = 1; // Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } exports.inflateReset = inflateReset; exports.inflateReset2 = inflateReset2; exports.inflateResetKeep = inflateResetKeep; exports.inflateInit = inflateInit; exports.inflateInit2 = inflateInit2; exports.inflate = inflate; exports.inflateEnd = inflateEnd; exports.inflateGetHeader = inflateGetHeader; exports.inflateSetDictionary = inflateSetDictionary; exports.inflateInfo = 'pako inflate (from Nodeca project)'; /* Not implemented exports.inflateCopy = inflateCopy; exports.inflateGetDictionary = inflateGetDictionary; exports.inflateMark = inflateMark; exports.inflatePrime = inflatePrime; exports.inflateSync = inflateSync; exports.inflateSyncPoint = inflateSyncPoint; exports.inflateUndermine = inflateUndermine; */ },{"../utils/common":1,"./adler32":3,"./crc32":5,"./inffast":7,"./inftrees":9}],9:[function(require,module,exports){ var utils = require('../utils/common'); var MAXBITS = 15; var ENOUGH_LENS = 852; var ENOUGH_DISTS = 592; //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); var CODES = 0; var LENS = 1; var DISTS = 2; var lbase = [ /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 ]; var lext = [ /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 ]; var dbase = [ /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 ]; var dext = [ /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64 ]; module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) { var bits = opts.bits; //here = opts.here; /* table entry for duplication */ var len = 0; /* a code's length in bits */ var sym = 0; /* index of code symbols */ var min = 0, max = 0; /* minimum and maximum code lengths */ var root = 0; /* number of index bits for root table */ var curr = 0; /* number of index bits for current table */ var drop = 0; /* code bits to drop for sub-table */ var left = 0; /* number of prefix codes available */ var used = 0; /* code entries in table used */ var huff = 0; /* Huffman code */ var incr; /* for incrementing code, index */ var fill; /* index for replicating entries */ var low; /* low bits for current root entry */ var mask; /* mask for low root bits */ var next; /* next available space in table */ var base = null; /* base value table to use */ var base_index = 0; // var shoextra; /* extra bits table to use */ var end; /* use base and extra for symbol > end */ var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */ var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */ var extra = null; var extra_index = 0; var here_bits, here_op, here_val; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) { count[len] = 0; } for (sym = 0; sym < codes; sym++) { count[lens[lens_index + sym]]++; } /* bound code lengths, force root to be within code lengths */ root = bits; for (max = MAXBITS; max >= 1; max--) { if (count[max] !== 0) { break; } } if (root > max) { root = max; } if (max === 0) { /* no symbols to code at all */ //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ //table.bits[opts.table_index] = 1; //here.bits = (var char)1; //table.val[opts.table_index++] = 0; //here.val = (var short)0; table[table_index++] = (1 << 24) | (64 << 16) | 0; //table.op[opts.table_index] = 64; //table.bits[opts.table_index] = 1; //table.val[opts.table_index++] = 0; table[table_index++] = (1 << 24) | (64 << 16) | 0; opts.bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) { if (count[min] !== 0) { break; } } if (root < min) { root = min; } /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) { return -1; } /* over-subscribed */ } if (left > 0 && (type === CODES || max !== 1)) { return -1; /* incomplete set */ } /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) { offs[len + 1] = offs[len] + count[len]; } /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) { if (lens[lens_index + sym] !== 0) { work[offs[lens[lens_index + sym]]++] = sym; } } /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ // poor man optimization - use if-else instead of switch, // to avoid deopts in old v8 if (type === CODES) { base = extra = work; /* dummy value--not used */ end = 19; } else if (type === LENS) { base = lbase; base_index -= 257; extra = lext; extra_index -= 257; end = 256; } else { /* DISTS */ base = dbase; extra = dext; end = -1; } /* initialize opts for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = table_index; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = -1; /* trigger new sub-table when len > root */ used = 1 << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type === LENS && used > ENOUGH_LENS) || (type === DISTS && used > ENOUGH_DISTS)) { return 1; } /* process all codes and make table entries */ for (;;) { /* create table entry */ here_bits = len - drop; if (work[sym] < end) { here_op = 0; here_val = work[sym]; } else if (work[sym] > end) { here_op = extra[extra_index + work[sym]]; here_val = base[base_index + work[sym]]; } else { here_op = 32 + 64; /* end of block */ here_val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1 << (len - drop); fill = 1 << curr; min = fill; /* save offset to next table */ do { fill -= incr; table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; } while (fill !== 0); /* backwards increment the len-bit code huff */ incr = 1 << (len - 1); while (huff & incr) { incr >>= 1; } if (incr !== 0) { huff &= incr - 1; huff += incr; } else { huff = 0; } /* go to next symbol, update count, len */ sym++; if (--count[len] === 0) { if (len === max) { break; } len = lens[lens_index + work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) !== low) { /* if first time, transition to sub-tables */ if (drop === 0) { drop = root; } /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = 1 << curr; while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) { break; } curr++; left <<= 1; } /* check for enough space */ used += 1 << curr; if ((type === LENS && used > ENOUGH_LENS) || (type === DISTS && used > ENOUGH_DISTS)) { return 1; } /* point entry in root table to sub-table */ low = huff & mask; /*table.op[low] = curr; table.bits[low] = root; table.val[low] = next - opts.table_index;*/ table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff !== 0) { //table.op[next + huff] = 64; /* invalid code marker */ //table.bits[next + huff] = len - drop; //table.val[next + huff] = 0; table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; } /* set return parameters */ //opts.table_index += used; opts.bits = root; return 0; }; },{"../utils/common":1}],10:[function(require,module,exports){ module.exports = { 2: 'need dictionary', /* Z_NEED_DICT 2 */ 1: 'stream end', /* Z_STREAM_END 1 */ 0: '', /* Z_OK 0 */ '-1': 'file error', /* Z_ERRNO (-1) */ '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ '-3': 'data error', /* Z_DATA_ERROR (-3) */ '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ }; },{}],11:[function(require,module,exports){ function ZStream() { /* next input byte */ this.input = null; // JS specific, because we have no pointers this.next_in = 0; /* number of bytes available at input */ this.avail_in = 0; /* total number of input bytes read so far */ this.total_in = 0; /* next output byte should be put there */ this.output = null; // JS specific, because we have no pointers this.next_out = 0; /* remaining free space at output */ this.avail_out = 0; /* total number of bytes output so far */ this.total_out = 0; /* last error message, NULL if no error */ this.msg = ''/*Z_NULL*/; /* not visible by applications */ this.state = null; /* best guess about the data type: binary or text */ this.data_type = 2/*Z_UNKNOWN*/; /* adler32 value of the uncompressed data */ this.adler = 0; } module.exports = ZStream; },{}],"/lib/inflate.js":[function(require,module,exports){ var zlib_inflate = require('./zlib/inflate'); var utils = require('./utils/common'); var strings = require('./utils/strings'); var c = require('./zlib/constants'); var msg = require('./zlib/messages'); var ZStream = require('./zlib/zstream'); var GZheader = require('./zlib/gzheader'); var toString = Object.prototype.toString; /** * class Inflate * * Generic JS-style wrapper for zlib calls. If you don't need * streaming behaviour - use more simple functions: [[inflate]] * and [[inflateRaw]]. **/ /* internal * inflate.chunks -> Array * * Chunks of output data, if [[Inflate#onData]] not overriden. **/ /** * Inflate.result -> Uint8Array|Array|String * * Uncompressed result, generated by default [[Inflate#onData]] * and [[Inflate#onEnd]] handlers. Filled after you push last chunk * (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you * push a chunk with explicit flush (call [[Inflate#push]] with * `Z_SYNC_FLUSH` param). **/ /** * Inflate.err -> Number * * Error code after inflate finished. 0 (Z_OK) on success. * Should be checked if broken data possible. **/ /** * Inflate.msg -> String * * Error message, if [[Inflate.err]] != 0 **/ /** * new Inflate(options) * - options (Object): zlib inflate options. * * Creates new inflator instance with specified params. Throws exception * on bad params. Supported options: * * - `windowBits` * - `dictionary` * * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) * for more information on these. * * Additional options, for internal needs: * * - `chunkSize` - size of generated data chunks (16K by default) * - `raw` (Boolean) - do raw inflate * - `to` (String) - if equal to 'string', then result will be converted * from utf8 to utf16 (javascript) string. When string output requested, * chunk length can differ from `chunkSize`, depending on content. * * By default, when no options set, autodetect deflate/gzip data format via * wrapper header. * * ##### Example: * * ```javascript * var pako = require('pako') * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); * * var inflate = new pako.Inflate({ level: 3}); * * inflate.push(chunk1, false); * inflate.push(chunk2, true); // true -> last chunk * * if (inflate.err) { throw new Error(inflate.err); } * * console.log(inflate.result); * ``` **/ function Inflate(options) { if (!(this instanceof Inflate)) return new Inflate(options); this.options = utils.assign({ chunkSize: 16384, windowBits: 0, to: '' }, options || {}); var opt = this.options; // Force window size for `raw` data, if not set directly, // because we have no header for autodetect. if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { opt.windowBits = -opt.windowBits; if (opt.windowBits === 0) { opt.windowBits = -15; } } // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate if ((opt.windowBits >= 0) && (opt.windowBits < 16) && !(options && options.windowBits)) { opt.windowBits += 32; } // Gzip header has no info about windows size, we can do autodetect only // for deflate. So, if window size not set, force it to max when gzip possible if ((opt.windowBits > 15) && (opt.windowBits < 48)) { // bit 3 (16) -> gzipped data // bit 4 (32) -> autodetect gzip/deflate if ((opt.windowBits & 15) === 0) { opt.windowBits |= 15; } } this.err = 0; // error code, if happens (0 = Z_OK) this.msg = ''; // error message this.ended = false; // used to avoid multiple onEnd() calls this.chunks = []; // chunks of compressed data this.strm = new ZStream(); this.strm.avail_out = 0; var status = zlib_inflate.inflateInit2( this.strm, opt.windowBits ); if (status !== c.Z_OK) { throw new Error(msg[status]); } this.header = new GZheader(); zlib_inflate.inflateGetHeader(this.strm, this.header); } /** * Inflate#push(data[, mode]) -> Boolean * - data (Uint8Array|Array|ArrayBuffer|String): input data * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH. * * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with * new output chunks. Returns `true` on success. The last data block must have * mode Z_FINISH (or `true`). That will flush internal pending buffers and call * [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you * can use mode Z_SYNC_FLUSH, keeping the decompression context. * * On fail call [[Inflate#onEnd]] with error code and return false. * * We strongly recommend to use `Uint8Array` on input for best speed (output * format is detected automatically). Also, don't skip last param and always * use the same type in your code (boolean or number). That will improve JS speed. * * For regular `Array`-s make sure all elements are [0..255]. * * ##### Example * * ```javascript * push(chunk, false); // push one of data chunks * ... * push(chunk, true); // push last chunk * ``` **/ Inflate.prototype.push = function (data, mode) { var strm = this.strm; var chunkSize = this.options.chunkSize; var dictionary = this.options.dictionary; var status, _mode; var next_out_utf8, tail, utf8str; var dict; // Flag to properly process Z_BUF_ERROR on testing inflate call // when we check that all output data was flushed. var allowBufError = false; if (this.ended) { return false; } _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH); // Convert data if needed if (typeof data === 'string') { // Only binary strings can be decompressed on practice strm.input = strings.binstring2buf(data); } else if (toString.call(data) === '[object ArrayBuffer]') { strm.input = new Uint8Array(data); } else { strm.input = data; } strm.next_in = 0; strm.avail_in = strm.input.length; do { if (strm.avail_out === 0) { strm.output = new utils.Buf8(chunkSize); strm.next_out = 0; strm.avail_out = chunkSize; } status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */ if (status === c.Z_NEED_DICT && dictionary) { // Convert data if needed if (typeof dictionary === 'string') { dict = strings.string2buf(dictionary); } else if (toString.call(dictionary) === '[object ArrayBuffer]') { dict = new Uint8Array(dictionary); } else { dict = dictionary; } status = zlib_inflate.inflateSetDictionary(this.strm, dict); } if (status === c.Z_BUF_ERROR && allowBufError === true) { status = c.Z_OK; allowBufError = false; } if (status !== c.Z_STREAM_END && status !== c.Z_OK) { this.onEnd(status); this.ended = true; return false; } if (strm.next_out) { if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) { if (this.options.to === 'string') { next_out_utf8 = strings.utf8border(strm.output, strm.next_out); tail = strm.next_out - next_out_utf8; utf8str = strings.buf2string(strm.output, next_out_utf8); // move tail strm.next_out = tail; strm.avail_out = chunkSize - tail; if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); } this.onData(utf8str); } else { this.onData(utils.shrinkBuf(strm.output, strm.next_out)); } } } // When no more input data, we should check that internal inflate buffers // are flushed. The only way to do it when avail_out = 0 - run one more // inflate pass. But if output data not exists, inflate return Z_BUF_ERROR. // Here we set flag to process this error properly. // // NOTE. Deflate does not return error in this case and does not needs such // logic. if (strm.avail_in === 0 && strm.avail_out === 0) { allowBufError = true; } } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END); if (status === c.Z_STREAM_END) { _mode = c.Z_FINISH; } // Finalize on the last chunk. if (_mode === c.Z_FINISH) { status = zlib_inflate.inflateEnd(this.strm); this.onEnd(status); this.ended = true; return status === c.Z_OK; } // callback interim results if Z_SYNC_FLUSH. if (_mode === c.Z_SYNC_FLUSH) { this.onEnd(c.Z_OK); strm.avail_out = 0; return true; } return true; }; /** * Inflate#onData(chunk) -> Void * - chunk (Uint8Array|Array|String): ouput data. Type of array depends * on js engine support. When string output requested, each chunk * will be string. * * By default, stores data blocks in `chunks[]` property and glue * those in `onEnd`. Override this handler, if you need another behaviour. **/ Inflate.prototype.onData = function (chunk) { this.chunks.push(chunk); }; /** * Inflate#onEnd(status) -> Void * - status (Number): inflate status. 0 (Z_OK) on success, * other if not. * * Called either after you tell inflate that the input stream is * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH) * or if an error happened. By default - join collected chunks, * free memory and fill `results` / `err` properties. **/ Inflate.prototype.onEnd = function (status) { // On success - join if (status === c.Z_OK) { if (this.options.to === 'string') { // Glue & convert here, until we teach pako to send // utf8 alligned strings to onData this.result = this.chunks.join(''); } else { this.result = utils.flattenChunks(this.chunks); } } this.chunks = []; this.err = status; this.msg = this.strm.msg; }; /** * inflate(data[, options]) -> Uint8Array|Array|String * - data (Uint8Array|Array|String): input data to decompress. * - options (Object): zlib inflate options. * * Decompress `data` with inflate/ungzip and `options`. Autodetect * format via wrapper header by default. That's why we don't provide * separate `ungzip` method. * * Supported options are: * * - windowBits * * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) * for more information. * * Sugar (options): * * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify * negative windowBits implicitly. * - `to` (String) - if equal to 'string', then result will be converted * from utf8 to utf16 (javascript) string. When string output requested, * chunk length can differ from `chunkSize`, depending on content. * * * ##### Example: * * ```javascript * var pako = require('pako') * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) * , output; * * try { * output = pako.inflate(input); * } catch (err) * console.log(err); * } * ``` **/ function inflate(input, options) { var inflator = new Inflate(options); inflator.push(input, true); // That will never happens, if you don't cheat with options :) if (inflator.err) { throw inflator.msg || msg[inflator.err]; } return inflator.result; } /** * inflateRaw(data[, options]) -> Uint8Array|Array|String * - data (Uint8Array|Array|String): input data to decompress. * - options (Object): zlib inflate options. * * The same as [[inflate]], but creates raw data, without wrapper * (header and adler32 crc). **/ function inflateRaw(input, options) { options = options || {}; options.raw = true; return inflate(input, options); } /** * ungzip(data[, options]) -> Uint8Array|Array|String * - data (Uint8Array|Array|String): input data to decompress. * - options (Object): zlib inflate options. * * Just shortcut to [[inflate]], because it autodetects format * by header.content. Done for convenience. **/ exports.Inflate = Inflate; exports.inflate = inflate; exports.inflateRaw = inflateRaw; exports.ungzip = inflate; },{"./utils/common":1,"./utils/strings":2,"./zlib/constants":4,"./zlib/gzheader":6,"./zlib/inflate":8,"./zlib/messages":10,"./zlib/zstream":11}]},{},[])("/lib/inflate.js") }); var pako = tmp; //! Use DXT1 compression. var kDxt1 = ( 1 << 0 ); //! Use DXT3 compression. var kDxt3 = ( 1 << 1 ); //! Use DXT5 compression. var kDxt5 = ( 1 << 2 ); var krgb565 = ( 1 << 5 ); function Unpack565(packed0, packed1, colour, offset) { var value = packed0 | (packed1 << 8); var red = (value >> 11) & 0x1f; var green = (value >> 5) & 0x3f; var blue = value & 0x1f; colour[offset + 0] = ( red << 3 ) | ( red >> 2 ); colour[offset + 1] = ( green << 2 ) | ( green >> 4 ); colour[offset + 2] = ( blue << 3 ) | ( blue >> 2 ); colour[offset + 3] = 255; return value; } function DecompressColour(rgba, block, nOffset, isDxt1) { var codes = new Uint8Array(16); var a = Unpack565(block[nOffset + 0], block[nOffset + 1], codes, 0); var b = Unpack565(block[nOffset + 2], block[nOffset + 3], codes, 4); for (var i = 0; i < 3; i++) { var c = codes[i]; var d = codes[4 + i]; if (isDxt1 && a <= b) { codes[8 + i] = ( c + d ) / 2; codes[12 + i] = 0; } else { codes[8 + i] = ( 2 * c + d ) / 3; codes[12 + i] = ( c + 2 * d ) / 3; } } codes[8 + 3] = 255; codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255; var indices = new Uint8Array(16); for (var i = 0; i < 4; ++i) { var packed = block[nOffset + 4 + i]; indices[4 * i + 0] = packed & 0x3; indices[4 * i + 1] = ( packed >> 2 ) & 0x3; indices[4 * i + 2] = ( packed >> 4 ) & 0x3; indices[4 * i + 3] = ( packed >> 6 ) & 0x3; } for (var i = 0; i < 16; ++i) { var offset = 4 * indices[i]; for (var j = 0; j < 4; ++j) rgba[4 * i + j] = codes[offset + j]; } } function DecompressAlphaDxt3(rgba, block, nOffset) { // unpack the alpha values pairwise for (var i = 0; i < 8; ++i) { // quantise down to 4 bits var quant = bytes[nOffset + i]; // unpack the values var lo = quant & 0x0f; var hi = quant & 0xf0; // convert back up to bytes rgba[8 * i + 3] = lo | ( lo << 4 ); rgba[8 * i + 7] = hi | ( hi >> 4 ); } } function DecompressAlphaDxt5(rgba, block, nOffset) { var alpha0 = block[nOffset + 0]; var alpha1 = block[nOffset + 1]; var codes = new Uint8Array(8); codes[0] = alpha0; codes[1] = alpha1; if (alpha0 <= alpha1) { // use 5-alpha codebook for (var i = 1; i < 5; ++i) codes[1 + i] = ( ( 5 - i ) * alpha0 + i * alpha1 ) / 5; codes[6] = 0; codes[7] = 255; } else { // use 7-alpha codebook for (var i = 1; i < 7; ++i) codes[1 + i] = ( ( 7 - i ) * alpha0 + i * alpha1 ) / 7; } var indices = new Uint8Array(16); var nOffset = nOffset + 2; var nBegin = 0; for (var i = 0; i < 2; ++i) { // grab 3 bytes var value = 0; for (var j = 0; j < 3; ++j) { var byte = block[nOffset++]; value |= ( byte << 8 * j ); } // unpack 8 3-bit values from it for (var j = 0; j < 8; ++j) { var index = ( value >> 3 * j ) & 0x7; indices[nBegin++] = index; } } for (var i = 0; i < 16; ++i) rgba[4 * i + 3] = codes[indices[i]]; } function Decompress(rgba, block, nOffset, flags) { var nOffset2 = 0; if (( flags & ( kDxt3 | kDxt5 ) ) != 0) nOffset2 = 8; DecompressColour(rgba, block, nOffset + nOffset2, ( flags & kDxt1 ) != 0); if (( flags & kDxt3 ) != 0) { DecompressAlphaDxt3(rgba, block, nOffset); } else if (( flags & kDxt5 ) != 0) { DecompressAlphaDxt5(rgba, block, nOffset); } } function DecompressImage565(rgb565, width, height, blocks) { var c = new Uint16Array(4); var dst = rgb565; var m = 0; var dstI = 0; var i = 0; var r0 = 0, g0 = 0, b0 = 0, r1 = 0, g1 = 0, b1 = 0; var blockWidth = width / 4; var blockHeight = height / 4; for (var blockY = 0; blockY < blockHeight; blockY++) { for (var blockX = 0; blockX < blockWidth; blockX++) { i = 4 * ((blockHeight - blockY) * blockWidth + blockX); c[0] = blocks[i]; c[1] = blocks[i + 1]; r0 = c[0] & 0x1f; g0 = c[0] & 0x7e0; b0 = c[0] & 0xf800; r1 = c[1] & 0x1f; g1 = c[1] & 0x7e0; b1 = c[1] & 0xf800; // Interpolate between c0 and c1 to get c2 and c3. ~ // Note that we approximate 1/3 as 3/8 and 2/3 as 5/8 for // speed. This also appears to be what the hardware DXT // decoder in many GPUs does :) c[2] = ((5 * r0 + 3 * r1) >> 3) | (((5 * g0 + 3 * g1) >> 3) & 0x7e0) | (((5 * b0 + 3 * b1) >> 3) & 0xf800); c[3] = ((5 * r1 + 3 * r0) >> 3) | (((5 * g1 + 3 * g0) >> 3) & 0x7e0) | (((5 * b1 + 3 * b0) >> 3) & 0xf800); m = blocks[i + 2]; dstI = (blockY * 4) * width + blockX * 4; dst[dstI] = c[m & 0x3]; dst[dstI + 1] = c[(m >> 2) & 0x3]; dst[dstI + 2] = c[(m >> 4) & 0x3]; dst[dstI + 3] = c[(m >> 6) & 0x3]; dstI += width; dst[dstI] = c[(m >> 8) & 0x3]; dst[dstI + 1] = c[(m >> 10) & 0x3]; dst[dstI + 2] = c[(m >> 12) & 0x3]; dst[dstI + 3] = c[(m >> 14)]; m = blocks[i + 3]; dstI += width; dst[dstI] = c[m & 0x3]; dst[dstI + 1] = c[(m >> 2) & 0x3]; dst[dstI + 2] = c[(m >> 4) & 0x3]; dst[dstI + 3] = c[(m >> 6) & 0x3]; dstI += width; dst[dstI] = c[(m >> 8) & 0x3]; dst[dstI + 1] = c[(m >> 10) & 0x3]; dst[dstI + 2] = c[(m >> 12) & 0x3]; dst[dstI + 3] = c[(m >> 14)]; } } return dst; } /*! @brief Decompresses an image in memory. @param rgba Storage for the decompressed pixels. @param width The width of the source image. @param height The height of the source image. @param blocks The compressed DXT blocks. @param flags Compression flags. The decompressed pixels will be written as a contiguous array of width*height 16 rgba values, with each component as 1 byte each. In memory this is: { r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, however, DXT1 will be used by default if none is specified. All other flags are ignored. Internally this function calls squish::Decompress for each block. */ function DecompressImage(rgba, width, height, blocks, flags) { var bytesPerBlock = ( ( flags & kDxt1 ) != 0 ) ? 8 : 16; var nOffset = 0; for (var y = 0; y < height; y += 4) { for (var x = 0; x < width; x += 4) { var targetRgba = new Uint8Array(4 * 16); Decompress(targetRgba, blocks, nOffset, flags); var nOffsetTarget = 0; for (var py = 0; py < 4; ++py) { for (var px = 0; px < 4; ++px) { var sx = x + px; var sy = y + py; if (sx < width && sy < height) { // flip Y var nBegin = 4 * ( width * (height - sy) + sx ); for (var i = 0; i < 4; ++i) { rgba[nBegin++] = targetRgba[nOffsetTarget++]; } } else { nOffsetTarget += 4; } } } // advance nOffset += bytesPerBlock; } } } function DXTTextureDecode(options){ } DXTTextureDecode.decode = function(out, width, height, block, format){ if (out == null || block == null || height == 0 || width == 0) { return; } var flags = 0; //有alpha通道,转为RGBA,否则转为rgb565 // S3MPixelFormat.BGR -> 11 //S3MPixelFormat.LUMINANCE_ALPHA -> 5 if (format > 11 || format === 5) { flags = kDxt5; } else { flags = kDxt1 | krgb565; } if ((flags & kDxt1) && (flags & krgb565)) { DecompressImage565(out, width, height, block); } else { DecompressImage(out, width, height, block, flags); } }; // This file is part of meshoptimizer library and is distributed under the terms of MIT License. // Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) var MeshoptDecoder = (function() { // Built with clang version 11.0.0 (https://github.com/llvm/llvm-project 176249bd6732a8044d457092ed932768724a6f06) // Built from meshoptimizer 0.17 var wasm_base = "B9h79tEBBBE8fV9gBB9gVUUUUUEU9gIUUUB9gEUEU9gIUUUEUIKQBEEEDDDILLLVE9wEEEVIEBEOWEUEC+Q/IEKR/LEdO9tw9t9vv95DBh9f9f939h79t9f9j9h229f9jT9vv7BB8a9tw79o9v9wT9f9kw9j9v9kw9WwvTw949C919m9mwvBEy9tw79o9v9wT9f9kw9j9v9kw69u9kw949C919m9mwvBDe9tw79o9v9wT9f9kw9j9v9kw69u9kw949Twg91w9u9jwBIl9tw79o9v9wT9f9kw9j9v9kws9p2Twv9P9jTBLk9tw79o9v9wT9f9kw9j9v9kws9p2Twv9R919hTBVl9tw79o9v9wT9f9kw9j9v9kws9p2Twvt949wBOL79iv9rBRQ+x8yQDBK/qMEZU8jJJJJBCJ/EB9rGV8kJJJJBC9+HODNADCEFAL0MBCUHOAIrBBC+gE9HMBAVAIALFGRAD9rADZ1JJJBHWCJ/ABAD9uC/wfBgGOCJDAOCJD6eHdAICEFHLCBHQDNINAQAE9PMEAdAEAQ9rAQAdFAE6eHKDNDNADtMBAKCSFGOC9wgHXAOCL4CIFCD4HMAWCJDFHpCBHSALHZINDNARAZ9rAM9PMBCBHLXIKAZAMFHLDNAXtMBCBHhCBHIINDNARAL9rCk9PMBCBHLXVKAWCJ/CBFAIFHODNDNDNDNDNAZAICO4FrBBAhCOg4CIgpLBEDIBKAO9CB83IBAOCWF9CB83IBXIKAOALrBLALrBBGoCO4GaAaCIsGae86BBAOCEFALCLFAaFGarBBAoCL4CIgGcAcCIsGce86BBAOCDFAaAcFGarBBAoCD4CIgGcAcCIsGce86BBAOCIFAaAcFGarBBAoCIgGoAoCIsGoe86BBAOCLFAaAoFGarBBALrBEGoCO4GcAcCIsGce86BBAOCVFAaAcFGarBBAoCL4CIgGcAcCIsGce86BBAOCOFAaAcFGarBBAoCD4CIgGcAcCIsGce86BBAOCRFAaAcFGarBBAoCIgGoAoCIsGoe86BBAOCWFAaAoFGarBBALrBDGoCO4GcAcCIsGce86BBAOCdFAaAcFGarBBAoCL4CIgGcAcCIsGce86BBAOCQFAaAcFGarBBAoCD4CIgGcAcCIsGce86BBAOCKFAaAcFGarBBAoCIgGoAoCIsGoe86BBAOCXFAaAoFGorBBALrBIGLCO4GaAaCIsGae86BBAOCMFAoAaFGorBBALCL4CIgGaAaCIsGae86BBAOCpFAoAaFGorBBALCD4CIgGaAaCIsGae86BBAOCSFAoAaFGOrBBALCIgGLALCIsGLe86BBAOALFHLXDKAOALrBWALrBBGoCL4GaAaCSsGae86BBAOCEFALCWFAaFGarBBAoCSgGoAoCSsGoe86BBAOCDFAaAoFGorBBALrBEGaCL4GcAcCSsGce86BBAOCIFAoAcFGorBBAaCSgGaAaCSsGae86BBAOCLFAoAaFGorBBALrBDGaCL4GcAcCSsGce86BBAOCVFAoAcFGorBBAaCSgGaAaCSsGae86BBAOCOFAoAaFGorBBALrBIGaCL4GcAcCSsGce86BBAOCRFAoAcFGorBBAaCSgGaAaCSsGae86BBAOCWFAoAaFGorBBALrBLGaCL4GcAcCSsGce86BBAOCdFAoAcFGorBBAaCSgGaAaCSsGae86BBAOCQFAoAaFGorBBALrBVGaCL4GcAcCSsGce86BBAOCKFAoAcFGorBBAaCSgGaAaCSsGae86BBAOCXFAoAaFGorBBALrBOGaCL4GcAcCSsGce86BBAOCMFAoAcFGorBBAaCSgGaAaCSsGae86BBAOCpFAoAaFGorBBALrBRGLCL4GaAaCSsGae86BBAOCSFAoAaFGOrBBALCSgGLALCSsGLe86BBAOALFHLXEKAOAL8pBB83BBAOCWFALCWF8pBB83BBALCZFHLKAhCDFHhAICZFGIAX6MBKKDNALMBCBHLXIKDNAKtMBAWASFrBBHhCBHOApHIINAIAWCJ/CBFAOFrBBGZCE4CBAZCEg9r7AhFGh86BBAIADFHIAOCEFGOAK9HMBKKApCEFHpALHZASCEFGSAD9HMBKKABAQAD2FAWCJDFAKAD2Z1JJJB8aAWAWCJDFAKCUFAD2FADZ1JJJB8aKAKCBALeAQFHQALMBKC9+HOXEKCBC99ARAL9rADCAADCA0eseHOKAVCJ/EBF8kJJJJBAOK+OoEZU8jJJJJBC/AE9rGV8kJJJJBC9+HODNAECI9uGRChFAL0MBCUHOAIrBBGWC/wEgC/gE9HMBAWCSgGdCE0MBAVC/ABFCfECJEZ+JJJJB8aAVCuF9CU83IBAVC8wF9CU83IBAVCYF9CU83IBAVCAF9CU83IBAVCkF9CU83IBAVCZF9CU83IBAV9CU83IWAV9CU83IBAIALFC9wFHQAICEFGWARFHKDNAEtMBCMCSAdCEseHXABHICBHdCBHMCBHpCBHLCBHOINDNAKAQ9NMBC9+HOXIKDNDNAWrBBGRC/vE0MBAVC/ABFARCL4CU7AOFCSgCITFGSYDLHZASYDBHhDNARCSgGSAX9PMBAVARCU7ALFCSgCDTFYDBAdASeHRAStHSDNDNADCD9HMBABAh87EBABCLFAR87EBABCDFAZ87EBXEKAIAhbDBAICWFARbDBAICLFAZbDBKAdASFHdAVC/ABFAOCITFGoARbDBAoAZbDLAVALCDTFARbDBAVC/ABFAOCEFCSgGOCITFGZAhbDBAZARbDLALASFHLAOCEFHOXDKDNDNASCSsMBAMASFASC987FCEFHMXEKAK8sBBGSCfEgHRDNDNASCU9MMBAKCEFHKXEKAK8sBEGSCfBgCRTARCfBgvHRDNASCU9MMBAKCDFHKXEKAK8sBDGSCfBgCpTARvHRDNASCU9MMBAKCIFHKXEKAK8sBIGSCfBgCxTARvHRDNASCU9MMBAKCLFHKXEKAKrBLC3TARvHRAKCVFHKKARCE4CBARCEg9r7AMFHMKDNDNADCD9HMBABAh87EBABCLFAM87EBABCDFAZ87EBXEKAIAhbDBAICWFAMbDBAICLFAZbDBKAVC/ABFAOCITFGRAMbDBARAZbDLAVALCDTFAMbDBAVC/ABFAOCEFCSgGOCITFGRAhbDBARAMbDLALCEFHLAOCEFHOXEKDNARCPE0MBAVALAQARCSgFrBBGSCL4GZ9rCSgCDTFYDBAdCEFGhAZeHRAVALAS9rCSgCDTFYDBAhAZtGoFGhASCSgGZeHSAZtHZDNDNADCD9HMBABAd87EBABCLFAS87EBABCDFAR87EBXEKAIAdbDBAICWFASbDBAICLFARbDBKAVALCDTFAdbDBAVC/ABFAOCITFGaARbDBAaAdbDLAVALCEFGLCSgCDTFARbDBAVC/ABFAOCEFCSgCITFGaASbDBAaARbDLAVALAoFCSgGLCDTFASbDBAVC/ABFAOCDFCSgGOCITFGRAdbDBARASbDLAOCEFHOALAZFHLAhAZFHdXEKAdCBAKrBBGaeGZARC/+EsGcFHRAaCSgHhDNDNAaCL4GoMBARCEFHSXEKARHSAVALAo9rCSgCDTFYDBHRKDNDNAhMBASCEFHdXEKASHdAVALAa9rCSgCDTFYDBHSKDNDNActMBAKCEFHaXEKAK8sBEGaCfEgHZDNDNAaCU9MMBAKCDFHaXEKAK8sBDGaCfBgCRTAZCfBgvHZDNAaCU9MMBAKCIFHaXEKAK8sBIGaCfBgCpTAZvHZDNAaCU9MMBAKCLFHaXEKAK8sBLGaCfBgCxTAZvHZDNAaCU9MMBAKCVFHaXEKAKCOFHaAKrBVC3TAZvHZKAZCE4CBAZCEg9r7AMFGMHZKDNDNAoCSsMBAaHcXEKAa8sBBGKCfEgHRDNDNAKCU9MMBAaCEFHcXEKAa8sBEGKCfBgCRTARCfBgvHRDNAKCU9MMBAaCDFHcXEKAa8sBDGKCfBgCpTARvHRDNAKCU9MMBAaCIFHcXEKAa8sBIGKCfBgCxTARvHRDNAKCU9MMBAaCLFHcXEKAaCVFHcAarBLC3TARvHRKARCE4CBARCEg9r7AMFGMHRKDNDNAhCSsMBAcHKXEKAc8sBBGKCfEgHSDNDNAKCU9MMBAcCEFHKXEKAc8sBEGKCfBgCRTASCfBgvHSDNAKCU9MMBAcCDFHKXEKAc8sBDGKCfBgCpTASvHSDNAKCU9MMBAcCIFHKXEKAc8sBIGKCfBgCxTASvHSDNAKCU9MMBAcCLFHKXEKAcCVFHKAcrBLC3TASvHSKASCE4CBASCEg9r7AMFGMHSKDNDNADCD9HMBABAZ87EBABCLFAS87EBABCDFAR87EBXEKAIAZbDBAICWFASbDBAICLFARbDBKAVC/ABFAOCITFGaARbDBAaAZbDLAVALCDTFAZbDBAVC/ABFAOCEFCSgCITFGaASbDBAaARbDLAVALCEFGLCSgCDTFARbDBAVC/ABFAOCDFCSgCITFGRAZbDBARASbDLAVALAotAoCSsvFGLCSgCDTFASbDBALAhtAhCSsvFHLAOCIFHOKAWCEFHWABCOFHBAICXFHIAOCSgHOALCSgHLApCIFGpAE6MBKKCBC99AKAQseHOKAVC/AEF8kJJJJBAOK/tLEDU8jJJJJBCZ9rHVC9+HODNAECVFAL0MBCUHOAIrBBC/+EgC/QE9HMBAV9CB83IWAICEFHOAIALFC98FHIDNAEtMBDNADCDsMBINDNAOAI6MBC9+SKAO8sBBGDCfEgHLDNDNADCU9MMBAOCEFHOXEKAO8sBEGDCfBgCRTALCfBgvHLDNADCU9MMBAOCDFHOXEKAO8sBDGDCfBgCpTALvHLDNADCU9MMBAOCIFHOXEKAO8sBIGDCfBgCxTALvHLDNADCU9MMBAOCLFHOXEKAOrBLC3TALvHLAOCVFHOKAVCWFALCEgCDTvGDALCD4CBALCE4CEg9r7ADYDBFGLbDBABALbDBABCLFHBAECUFGEMBXDKKINDNAOAI6MBC9+SKAO8sBBGDCfEgHLDNDNADCU9MMBAOCEFHOXEKAO8sBEGDCfBgCRTALCfBgvHLDNADCU9MMBAOCDFHOXEKAO8sBDGDCfBgCpTALvHLDNADCU9MMBAOCIFHOXEKAO8sBIGDCfBgCxTALvHLDNADCU9MMBAOCLFHOXEKAOrBLC3TALvHLAOCVFHOKABALCD4CBALCE4CEg9r7AVCWFALCEgCDTvGLYDBFGD87EBALADbDBABCDFHBAECUFGEMBKKCBC99AOAIseHOKAOK+lVOEUE99DUD99EUD99DNDNADCL9HMBAEtMEINDNDNjBBBzjBBB+/ABCDFGD8sBB+yAB8sBBGI+yGL+L+TABCEFGV8sBBGO+yGR+L+TGWjBBBB9gGdeAWjBB/+9CAWAWnjBBBBAWAdeGQAQ+MGKAICU9KeALmGLALnAQAKAOCU9KeARmGQAQnmm+R+VGRnmGW+LjBBB9P9dtMBAW+oHIXEKCJJJJ94HIKADAI86BBDNDNjBBBzjBBB+/AQjBBBB9geAQARnmGW+LjBBB9P9dtMBAW+oHDXEKCJJJJ94HDKAVAD86BBDNDNjBBBzjBBB+/ALjBBBB9geALARnmGW+LjBBB9P9dtMBAW+oHDXEKCJJJJ94HDKABAD86BBABCLFHBAECUFGEMBXDKKAEtMBINDNDNjBBBzjBBB+/ABCLFGD8uEB+yAB8uEBGI+yGL+L+TABCDFGV8uEBGO+yGR+L+TGWjBBBB9gGdeAWjB/+fsAWAWnjBBBBAWAdeGQAQ+MGKAICU9KeALmGLALnAQAKAOCU9KeARmGQAQnmm+R+VGRnmGW+LjBBB9P9dtMBAW+oHIXEKCJJJJ94HIKADAI87EBDNDNjBBBzjBBB+/AQjBBBB9geAQARnmGW+LjBBB9P9dtMBAW+oHDXEKCJJJJ94HDKAVAD87EBDNDNjBBBzjBBB+/ALjBBBB9geALARnmGW+LjBBB9P9dtMBAW+oHDXEKCJJJJ94HDKABAD87EBABCWFHBAECUFGEMBKKK/SILIUI99IUE99DNAEtMBCBHIABHLINDNDNj/zL81zALCOF8uEBGVCIv+y+VGOAL8uEB+ynGRjB/+fsnjBBBzjBBB+/ARjBBBB9gemGW+LjBBB9P9dtMBAW+oHdXEKCJJJJ94HdKALCLF8uEBHQALCDF8uEBHKABAVCEFCIgAIvCETFAd87EBDNDNAOAK+ynGWjB/+fsnjBBBzjBBB+/AWjBBBB9gemGX+LjBBB9P9dtMBAX+oHKXEKCJJJJ94HKKABAVCDFCIgAIvCETFAK87EBDNDNAOAQ+ynGOjB/+fsnjBBBzjBBB+/AOjBBBB9gemGX+LjBBB9P9dtMBAX+oHQXEKCJJJJ94HQKABAVCUFCIgAIvCETFAQ87EBDNDNjBBJzARARn+TAWAWn+TAOAOn+TGRjBBBBARjBBBB9ge+RjB/+fsnjBBBzmGR+LjBBB9P9dtMBAR+oHQXEKCJJJJ94HQKABAVCIgAIvCETFAQ87EBALCWFHLAICLFHIAECUFGEMBKKK6BDNADCD4AE2GEtMBINABABYDBGDCWTCW91+yADCk91ClTCJJJ/8IF++nuDBABCLFHBAECUFGEMBKKK9TEIUCBCBYDJ1JJBGEABCIFC98gFGBbDJ1JJBDNDNABzBCZTGD9NMBCUHIABAD9rCffIFCZ4NBCUsMEKAEHIKAIK/lEEEUDNDNAEABvCIgtMBABHIXEKDNDNADCZ9PMBABHIXEKABHIINAIAEYDBbDBAICLFAECLFYDBbDBAICWFAECWFYDBbDBAICXFAECXFYDBbDBAICZFHIAECZFHEADC9wFGDCS0MBKKADCL6MBINAIAEYDBbDBAECLFHEAICLFHIADC98FGDCI0MBKKDNADtMBINAIAErBB86BBAICEFHIAECEFHEADCUFGDMBKKABK/AEEDUDNDNABCIgtMBABHIXEKAECfEgC+B+C+EW2HLDNDNADCZ9PMBABHIXEKABHIINAIALbDBAICXFALbDBAICWFALbDBAICLFALbDBAICZFHIADC9wFGDCS0MBKKADCL6MBINAIALbDBAICLFHIADC98FGDCI0MBKKDNADtMBINAIAE86BBAICEFHIADCUFGDMBKKABKKKEBCJWKLZ9kBB"; var wasm_simd = "B9h79tEBBBE5V9gBB9gVUUUUUEU9gIUUUB9gDUUB9gEUEUIMXBBEBEEDIDIDLLVE9wEEEVIEBEOWEUEC+Q/aEKR/LEdO9tw9t9vv95DBh9f9f939h79t9f9j9h229f9jT9vv7BB8a9tw79o9v9wT9f9kw9j9v9kw9WwvTw949C919m9mwvBDy9tw79o9v9wT9f9kw9j9v9kw69u9kw949C919m9mwvBLe9tw79o9v9wT9f9kw9j9v9kw69u9kw949Twg91w9u9jwBVl9tw79o9v9wT9f9kw9j9v9kws9p2Twv9P9jTBOk9tw79o9v9wT9f9kw9j9v9kws9p2Twv9R919hTBWl9tw79o9v9wT9f9kw9j9v9kws9p2Twvt949wBQL79iv9rBKQ/j6XLBZIK9+EVU8jJJJJBCZ9rHBCBHEINCBHDCBHIINABCWFADFAICJUAEAD4CEgGLe86BBAIALFHIADCEFGDCW9HMBKAEC+Q+YJJBFAI86BBAECITC+Q1JJBFAB8pIW83IBAECEFGECJD9HMBKK1HLSUD97EUO978jJJJJBCJ/KB9rGV8kJJJJBC9+HODNADCEFAL0MBCUHOAIrBBC+gE9HMBAVAIALFGRAD9rAD/8QBBCJ/ABAD9uC/wfBgGOCJDAOCJD6eHWAICEFHOCBHdDNINAdAE9PMEAWAEAd9rAdAWFAE6eHQDNDNADtMBAQCSFGLC9wgGKCI2HXAKCETHMALCL4CIFCD4HpCBHSINAOHZCBHhDNINDNARAZ9rAp9PMBCBHOXVKAVCJ/CBFAhAK2FHoAZApFHOCBHIDNAKC/AB6MBARAO9rC/gB6MBCBHLINAoALFHIDNDNDNDNDNAZALCO4FrBBGaCIgpLBEDIBKAICBPhPKLBXIKAIAOPBBLAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlGcCDP+MEAcPMBZEhDoIaLcVxOqRlC+D+G+MkPhP9OGxCIPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLBAOCLFAlPqBFAqC+Q+YJJBFrBBFHOXDKAIAOPBBWAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlC+P+e+8/4BPhP9OGxCSPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLBAOCWFAlPqBFAqC+Q+YJJBFrBBFHOXEKAIAOPBBBPKLBAOCZFHOKDNDNDNDNDNAaCD4CIgpLBEDIBKAICBPhPKLZXIKAIAOPBBLAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlGcCDP+MEAcPMBZEhDoIaLcVxOqRlC+D+G+MkPhP9OGxCIPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLZAOCLFAlPqBFAqC+Q+YJJBFrBBFHOXDKAIAOPBBWAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlC+P+e+8/4BPhP9OGxCSPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLZAOCWFAlPqBFAqC+Q+YJJBFrBBFHOXEKAIAOPBBBPKLZAOCZFHOKDNDNDNDNDNAaCL4CIgpLBEDIBKAICBPhPKLAXIKAIAOPBBLAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlGcCDP+MEAcPMBZEhDoIaLcVxOqRlC+D+G+MkPhP9OGxCIPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLAAOCLFAlPqBFAqC+Q+YJJBFrBBFHOXDKAIAOPBBWAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlC+P+e+8/4BPhP9OGxCSPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLAAOCWFAlPqBFAqC+Q+YJJBFrBBFHOXEKAIAOPBBBPKLAAOCZFHOKDNDNDNDNDNAaCO4pLBEDIBKAICBPhPKL8wXIKAIAOPBBLAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlGcCDP+MEAcPMBZEhDoIaLcVxOqRlC+D+G+MkPhP9OGxCIPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGaCITC+Q1JJBFPBIBAaC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGaCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKL8wAOCLFAlPqBFAaC+Q+YJJBFrBBFHOXDKAIAOPBBWAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlC+P+e+8/4BPhP9OGxCSPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGaCITC+Q1JJBFPBIBAaC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGaCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKL8wAOCWFAlPqBFAaC+Q+YJJBFrBBFHOXEKAIAOPBBBPKL8wAOCZFHOKALC/ABFHIALCJEFAK0MEAIHLARAO9rC/fB0MBKKDNAIAK9PMBAICI4HLINDNARAO9rCk9PMBCBHOXRKAoAIFHaDNDNDNDNDNAZAICO4FrBBALCOg4CIgpLBEDIBKAaCBPhPKLBXIKAaAOPBBLAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlGcCDP+MEAcPMBZEhDoIaLcVxOqRlC+D+G+MkPhP9OGxCIPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLBAOCLFAlPqBFAqC+Q+YJJBFrBBFHOXDKAaAOPBBWAOPBBBGcCLP+MEAcPMBZEhDoIaLcVxOqRlC+P+e+8/4BPhP9OGxCSPSP8jGcP5B9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBAqC+Q+YJJBFPBBBGlAlPMBBBBBBBBBBBBBBBBAcP5E9CJf/8/4/w/g/AB9+9Cu1+nGqCITC+Q1JJBFPBIBP9uPMBEDILVORZhoacxqlPpAxAcP9SPKLBAOCWFAlPqBFAqC+Q+YJJBFrBBFHOXEKAaAOPBBBPKLBAOCZFHOKALCDFHLAICZFGIAK6MBKKDNAOtMBAOHZAhCEFGhCLsMDXEKKCBHOXIKDNAKtMBAVCJDFASFHIAVASFPBDBHlCBHaINAIAVCJ/CBFAaFGLPBLBGxCEP9tAxCEPSGcP9OP9hP9RGxALAKFPBLBGkCEP9tAkAcP9OP9hP9RGkPMBZEhDoIaLcVxOqRlGyALAMFPBLBG8aCEP9tA8aAcP9OP9hP9RG8aALAXFPBLBGeCEP9tAeAcP9OP9hP9RGePMBZEhDoIaLcVxOqRlG3PMBEZhDIoaLVcxORqlGcAcPMBEDIBEDIBEDIBEDIAlP9uGlPeBbDBAIADFGLAlAcAcPMLVORLVORLVORLVORP9uGlPeBbDBALADFGLAlAcAcPMWdQKWdQKWdQKWdQKP9uGlPeBbDBALADFGLAlAcAcPMXMpSXMpSXMpSXMpSP9uGlPeBbDBALADFGLAlAyA3PMWdkyQK8aeXM35pS8e8fGcAcPMBEDIBEDIBEDIBEDIP9uGlPeBbDBALADFGLAlAcAcPMLVORLVORLVORLVORP9uGlPeBbDBALADFGLAlAcAcPMWdQKWdQKWdQKWdQKP9uGlPeBbDBALADFGLAlAcAcPMXMpSXMpSXMpSXMpSP9uGlPeBbDBALADFGLAlAxAkPMWkdyQ8aKeX3M5p8eS8fGxA8aAePMWkdyQ8aKeX3M5p8eS8fGkPMBEZhDIoaLVcxORqlGcAcPMBEDIBEDIBEDIBEDIP9uGlPeBbDBALADFGLAlAcAcPMLVORLVORLVORLVORP9uGlPeBbDBALADFGLAlAcAcPMWdQKWdQKWdQKWdQKP9uGlPeBbDBALADFGLAlAcAcPMXMpSXMpSXMpSXMpSP9uGlPeBbDBALADFGLAlAxAkPMWdkyQK8aeXM35pS8e8fGcAcPMBEDIBEDIBEDIBEDIP9uGlPeBbDBALADFGLAlAcAcPMLVORLVORLVORLVORP9uGlPeBbDBALADFGLAlAcAcPMWdQKWdQKWdQKWdQKP9uGlPeBbDBALADFGLAlAcAcPMXMpSXMpSXMpSXMpSP9uGlPeBbDBALADFHIAaCZFGaAK6MBKKASCLFGSAD6MBKKABAdAD2FAVCJDFAQAD2/8QBBAVAVCJDFAQCUFAD2FAD/8QBBKAQCBAOeAdFHdAOMBKC9+HOXEKCBC99ARAO9rADCAADCA0eseHOKAVCJ/KBF8kJJJJBAOKWBZ+BJJJBK+KoEZU8jJJJJBC/AE9rGV8kJJJJBC9+HODNAECI9uGRChFAL0MBCUHOAIrBBGWC/wEgC/gE9HMBAWCSgGdCE0MBAVC/ABFCfECJE/8KBAVCuF9CU83IBAVC8wF9CU83IBAVCYF9CU83IBAVCAF9CU83IBAVCkF9CU83IBAVCZF9CU83IBAV9CU83IWAV9CU83IBAIALFC9wFHQAICEFGWARFHKDNAEtMBCMCSAdCEseHXABHICBHdCBHMCBHpCBHLCBHOINDNAKAQ9NMBC9+HOXIKDNDNAWrBBGRC/vE0MBAVC/ABFARCL4CU7AOFCSgCITFGSYDLHZASYDBHhDNARCSgGSAX9PMBAVARCU7ALFCSgCDTFYDBAdASeHRAStHSDNDNADCD9HMBABAh87EBABCLFAR87EBABCDFAZ87EBXEKAIAhbDBAICWFARbDBAICLFAZbDBKAdASFHdAVC/ABFAOCITFGoARbDBAoAZbDLAVALCDTFARbDBAVC/ABFAOCEFCSgGOCITFGZAhbDBAZARbDLALASFHLAOCEFHOXDKDNDNASCSsMBAMASFASC987FCEFHMXEKAK8sBBGSCfEgHRDNDNASCU9MMBAKCEFHKXEKAK8sBEGSCfBgCRTARCfBgvHRDNASCU9MMBAKCDFHKXEKAK8sBDGSCfBgCpTARvHRDNASCU9MMBAKCIFHKXEKAK8sBIGSCfBgCxTARvHRDNASCU9MMBAKCLFHKXEKAKrBLC3TARvHRAKCVFHKKARCE4CBARCEg9r7AMFHMKDNDNADCD9HMBABAh87EBABCLFAM87EBABCDFAZ87EBXEKAIAhbDBAICWFAMbDBAICLFAZbDBKAVC/ABFAOCITFGRAMbDBARAZbDLAVALCDTFAMbDBAVC/ABFAOCEFCSgGOCITFGRAhbDBARAMbDLALCEFHLAOCEFHOXEKDNARCPE0MBAVALAQARCSgFrBBGSCL4GZ9rCSgCDTFYDBAdCEFGhAZeHRAVALAS9rCSgCDTFYDBAhAZtGoFGhASCSgGZeHSAZtHZDNDNADCD9HMBABAd87EBABCLFAS87EBABCDFAR87EBXEKAIAdbDBAICWFASbDBAICLFARbDBKAVALCDTFAdbDBAVC/ABFAOCITFGaARbDBAaAdbDLAVALCEFGLCSgCDTFARbDBAVC/ABFAOCEFCSgCITFGaASbDBAaARbDLAVALAoFCSgGLCDTFASbDBAVC/ABFAOCDFCSgGOCITFGRAdbDBARASbDLAOCEFHOALAZFHLAhAZFHdXEKAdCBAKrBBGaeGZARC/+EsGcFHRAaCSgHhDNDNAaCL4GoMBARCEFHSXEKARHSAVALAo9rCSgCDTFYDBHRKDNDNAhMBASCEFHdXEKASHdAVALAa9rCSgCDTFYDBHSKDNDNActMBAKCEFHaXEKAK8sBEGaCfEgHZDNDNAaCU9MMBAKCDFHaXEKAK8sBDGaCfBgCRTAZCfBgvHZDNAaCU9MMBAKCIFHaXEKAK8sBIGaCfBgCpTAZvHZDNAaCU9MMBAKCLFHaXEKAK8sBLGaCfBgCxTAZvHZDNAaCU9MMBAKCVFHaXEKAKCOFHaAKrBVC3TAZvHZKAZCE4CBAZCEg9r7AMFGMHZKDNDNAoCSsMBAaHcXEKAa8sBBGKCfEgHRDNDNAKCU9MMBAaCEFHcXEKAa8sBEGKCfBgCRTARCfBgvHRDNAKCU9MMBAaCDFHcXEKAa8sBDGKCfBgCpTARvHRDNAKCU9MMBAaCIFHcXEKAa8sBIGKCfBgCxTARvHRDNAKCU9MMBAaCLFHcXEKAaCVFHcAarBLC3TARvHRKARCE4CBARCEg9r7AMFGMHRKDNDNAhCSsMBAcHKXEKAc8sBBGKCfEgHSDNDNAKCU9MMBAcCEFHKXEKAc8sBEGKCfBgCRTASCfBgvHSDNAKCU9MMBAcCDFHKXEKAc8sBDGKCfBgCpTASvHSDNAKCU9MMBAcCIFHKXEKAc8sBIGKCfBgCxTASvHSDNAKCU9MMBAcCLFHKXEKAcCVFHKAcrBLC3TASvHSKASCE4CBASCEg9r7AMFGMHSKDNDNADCD9HMBABAZ87EBABCLFAS87EBABCDFAR87EBXEKAIAZbDBAICWFASbDBAICLFARbDBKAVC/ABFAOCITFGaARbDBAaAZbDLAVALCDTFAZbDBAVC/ABFAOCEFCSgCITFGaASbDBAaARbDLAVALCEFGLCSgCDTFARbDBAVC/ABFAOCDFCSgCITFGRAZbDBARASbDLAVALAotAoCSsvFGLCSgCDTFASbDBALAhtAhCSsvFHLAOCIFHOKAWCEFHWABCOFHBAICXFHIAOCSgHOALCSgHLApCIFGpAE6MBKKCBC99AKAQseHOKAVC/AEF8kJJJJBAOK/tLEDU8jJJJJBCZ9rHVC9+HODNAECVFAL0MBCUHOAIrBBC/+EgC/QE9HMBAV9CB83IWAICEFHOAIALFC98FHIDNAEtMBDNADCDsMBINDNAOAI6MBC9+SKAO8sBBGDCfEgHLDNDNADCU9MMBAOCEFHOXEKAO8sBEGDCfBgCRTALCfBgvHLDNADCU9MMBAOCDFHOXEKAO8sBDGDCfBgCpTALvHLDNADCU9MMBAOCIFHOXEKAO8sBIGDCfBgCxTALvHLDNADCU9MMBAOCLFHOXEKAOrBLC3TALvHLAOCVFHOKAVCWFALCEgCDTvGDALCD4CBALCE4CEg9r7ADYDBFGLbDBABALbDBABCLFHBAECUFGEMBXDKKINDNAOAI6MBC9+SKAO8sBBGDCfEgHLDNDNADCU9MMBAOCEFHOXEKAO8sBEGDCfBgCRTALCfBgvHLDNADCU9MMBAOCDFHOXEKAO8sBDGDCfBgCpTALvHLDNADCU9MMBAOCIFHOXEKAO8sBIGDCfBgCxTALvHLDNADCU9MMBAOCLFHOXEKAOrBLC3TALvHLAOCVFHOKABALCD4CBALCE4CEg9r7AVCWFALCEgCDTvGLYDBFGD87EBALADbDBABCDFHBAECUFGEMBKKCBC99AOAIseHOKAOK/xVDIUO978jJJJJBCA9rGI8kJJJJBDNDNADCL9HMBDNAEC98gGLtMBABHDCBHVINADADPBBBGOCkP+rECkP+sEP/6EGRAOCWP+rECkP+sEP/6EARP/gEAOCZP+rECkP+sEP/6EGWP/gEP/kEP/lEGdCBPhP+2EGQARCJJJJ94PhGKP9OP9RP/kEGRjBB/+9CPaARARP/mEAdAdP/mEAWAQAWAKP9OP9RP/kEGRARP/mEP/kEP/kEP/jEP/nEGWP/mEjBBN0PaGQP/kECfEPhP9OAOCJJJ94PhP9OP9QARAWP/mEAQP/kECWP+rECJ/+IPhP9OP9QAdAWP/mEAQP/kECZP+rECJJ/8RPhP9OP9QPKBBADCZFHDAVCLFGVAL6MBKKALAE9PMEAIAECIgGVCDTGDvCBCZAD9r/8KBAIABALCDTFGLAD/8QBBDNAVtMBAIAIPBLBGOCkP+rECkP+sEP/6EGRAOCWP+rECkP+sEP/6EARP/gEAOCZP+rECkP+sEP/6EGWP/gEP/kEP/lEGdCBPhP+2EGQARCJJJJ94PhGKP9OP9RP/kEGRjBB/+9CPaARARP/mEAdAdP/mEAWAQAWAKP9OP9RP/kEGRARP/mEP/kEP/kEP/jEP/nEGWP/mEjBBN0PaGQP/kECfEPhP9OAOCJJJ94PhP9OP9QARAWP/mEAQP/kECWP+rECJ/+IPhP9OP9QAdAWP/mEAQP/kECZP+rECJJ/8RPhP9OP9QPKLBKALAIAD/8QBBXEKABAEC98gGDZ+HJJJBADAE9PMBAIAECIgGLCITGVFCBCAAV9r/8KBAIABADCITFGDAV/8QBBAIALZ+HJJJBADAIAV/8QBBKAICAF8kJJJJBK+yIDDUR97DNAEtMBCBHDINABCZFGIAIPBBBGLCBPhGVCJJ98P3ECJJ98P3IGOP9OABPBBBGRALPMLVORXMpScxql358e8fCffEPhP9OP/6EARALPMBEDIWdQKZhoaky8aeGLCZP+sEP/6EGWP/gEALCZP+rECZP+sEP/6EGdP/gEP/kEP/lEGLjB/+fsPaAdALAVP+2EGVAdCJJJJ94PhGQP9OP9RP/kEGdAdP/mEALALP/mEAWAVAWAQP9OP9RP/kEGLALP/mEP/kEP/kEP/jEP/nEGWP/mEjBBN0PaGVP/kECZP+rEAdAWP/mEAVP/kECffIPhP9OP9QGdALAWP/mEAVP/kECUPSCBPlDCBPlICBPlOCBPlRCBPlQCBPlKCBPlpCBPlSP9OGLPMWdkyQK8aeXM35pS8e8fP9QPKBBABARAOP9OAdALPMBEZhDIoaLVcxORqlP9QPKBBABCAFHBADCLFGDAE6MBKKK94EIU8jJJJJBCA9rGI8kJJJJBABAEC98gGLZ+JJJJBDNALAE9PMBAIAECIgGVCITGEFCBCAAE9r/8KBAIABALCITFGBAE/8QBBAIAVZ+JJJJBABAIAE/8QBBKAICAF8kJJJJBK/hILDUE97EUV978jJJJJBCZ9rHDDNAEtMBCBHIINADABPBBBGLABCZFGVPBBBGOPMLVORXMpScxql358e8fGRCZP+sEGWCLP+rEPKLBABjBBJzPaj/zL81zPaAWCIPhP9QP/6EP/nEGWALAOPMBEDIWdQKZhoaky8aeGLCZP+rECZP+sEP/6EP/mEGOAOP/mEAWALCZP+sEP/6EP/mEGdAdP/mEAWARCZP+rECZP+sEP/6EP/mEGRARP/mEP/kEP/kEP/lECBPhP+4EP/jEjB/+fsPaGWP/mEjBBN0PaGLP/kECffIPhGQP9OAdAWP/mEALP/kECZP+rEP9QGdARAWP/mEALP/kECZP+rEAOAWP/mEALP/kEAQP9OP9QGWPMBEZhDIoaLVcxORqlGLP5BADPBLBPeB+t+J83IBABCWFALP5EADPBLBPeE+t+J83IBAVAdAWPMWdkyQK8aeXM35pS8e8fGWP5BADPBLBPeD+t+J83IBABCkFAWP5EADPBLBPeI+t+J83IBABCAFHBAICLFGIAE6MBKKK/3EDIUE978jJJJJBC/AB9rHIDNADCD4AE2GLC98gGVtMBCBHDABHEINAEAEPBBBGOCWP+rECWP+sEP/6EAOCkP+sEClP+rECJJJ/8IPhP+uEP/mEPKBBAECZFHEADCLFGDAV6MBKKDNAVAL9PMBAIALCIgGDCDTGEvCBC/ABAE9r/8KBAIABAVCDTFGVAE/8QBBDNADtMBAIAIPBLBGOCWP+rECWP+sEP/6EAOCkP+sEClP+rECJJJ/8IPhP+uEP/mEPKLBKAVAIAE/8QBBKK9TEIUCBCBYDJ1JJBGEABCIFC98gFGBbDJ1JJBDNDNABzBCZTGD9NMBCUHIABAD9rCffIFCZ4NBCUsMEKAEHIKAIKKKEBCJWKLZ9tBB"; // Uses bulk-memory and simd extensions var detector = new Uint8Array([0,97,115,109,1,0,0,0,1,4,1,96,0,0,3,3,2,0,0,5,3,1,0,1,12,1,0,10,22,2,12,0,65,0,65,0,65,0,252,10,0,0,11,7,0,65,0,253,15,26,11]); // Used to unpack wasm var wasmpack = new Uint8Array([32,0,65,2,1,106,34,33,3,128,11,4,13,64,6,253,10,7,15,116,127,5,8,12,40,16,19,54,20,9,27,255,113,17,42,67,24,23,146,148,18,14,22,45,70,69,56,114,101,21,25,63,75,136,108,28,118,29,73,115]); if (typeof WebAssembly !== 'object') { // This module requires WebAssembly to function return { supported: false, }; } var wasm = wasm_base; if (WebAssembly.validate(detector)) { wasm = wasm_simd; } var instance; var promise = WebAssembly.instantiate(unpack(wasm), {}) .then(function(result) { instance = result.instance; instance.exports.__wasm_call_ctors(); }); function unpack(data) { var result = new Uint8Array(data.length); for (var i = 0; i < data.length; ++i) { var ch = data.charCodeAt(i); result[i] = ch > 96 ? ch - 71 : ch > 64 ? ch - 65 : ch > 47 ? ch + 4 : ch > 46 ? 63 : 62; } var write = 0; for (var i = 0; i < data.length; ++i) { result[write++] = (result[i] < 60) ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; } return result.buffer.slice(0, write); } function decode(fun, target, count, size, source, filter) { var sbrk = instance.exports.sbrk; var count4 = (count + 3) & ~3; // pad for SIMD filter var tp = sbrk(count4 * size); var sp = sbrk(source.length); var heap = new Uint8Array(instance.exports.memory.buffer); heap.set(source, sp); var res = fun(tp, count, size, sp, source.length); if (res == 0 && filter) { filter(tp, count4, size); } target.set(heap.subarray(tp, tp + count * size)); sbrk(tp - sbrk(0)); if (res != 0) { throw new Error("Malformed buffer data: " + res); } } var filters = { // legacy index-based enums for glTF 0: "", 1: "meshopt_decodeFilterOct", 2: "meshopt_decodeFilterQuat", 3: "meshopt_decodeFilterExp", // string-based enums for glTF NONE: "", OCTAHEDRAL: "meshopt_decodeFilterOct", QUATERNION: "meshopt_decodeFilterQuat", EXPONENTIAL: "meshopt_decodeFilterExp", }; var decoders = { // legacy index-based enums for glTF 0: "meshopt_decodeVertexBuffer", 1: "meshopt_decodeIndexBuffer", 2: "meshopt_decodeIndexSequence", // string-based enums for glTF ATTRIBUTES: "meshopt_decodeVertexBuffer", TRIANGLES: "meshopt_decodeIndexBuffer", INDICES: "meshopt_decodeIndexSequence", }; return { ready: promise, supported: true, decodeVertexBuffer: function(target, count, size, source, filter) { decode(instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]); }, decodeIndexBuffer: function(target, count, size, source) { decode(instance.exports.meshopt_decodeIndexBuffer, target, count, size, source); }, decodeIndexSequence: function(target, count, size, source) { decode(instance.exports.meshopt_decodeIndexSequence, target, count, size, source); }, decodeGltfBuffer: function(target, count, size, source, mode, filter) { decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]); } }; })(); function S3ModelParser() { } S3ModelParser.s3tc = true; S3ModelParser.pvrtc = false; S3ModelParser.etc1 = false; const S3MBVertexTag = { SV_Unkown : 0, SV_Standard : 1, SV_Compressed : 2, SV_DracoCompressed: 3 }; const S3MBVertexTagV3 = { Standard : 0, Draco : 1, MeshOpt : 2 }; const AttrTypeMap = { 0 : Uint32Array.BYTES_PER_ELEMENT, 1 : Float32Array.BYTES_PER_ELEMENT, 2 : Float64Array.BYTES_PER_ELEMENT, }; const S3MPixelFormat$2 = { LUMINANCE_8 : 1, LUMINANCE_16 : 2, ALPHA : 3, ALPHA_4_LUMINANCE_4 : 4, LUMINANCE_ALPHA : 5, RGB_565 : 6, BGR565 : 7, RGB : 10, BGR : 11, ARGB : 12, ABGR : 13, BGRA : 14, WEBP : 25, RGBA : 28, DXT1 : 17, DXT2 : 18, DXT3 : 19, DXT4 : 20, DXT5 : 21, CRN_DXT5 : 26, STANDARD_CRN : 27 }; const VertexCompressOption$1 = { SVC_Vertex : 1, SVC_Normal : 2, SVC_VertexColor : 4, SVC_SecondColor : 8, SVC_TexutreCoord : 16, SVC_TexutreCoordIsW : 32 }; const AttributeType = { Invalid : 0, Position : 1, PositionW : 2, Normal : 4, Tangent : 8, FirstTexcoord : 16, SecondTexcoord : 32, Color : 64, SecondColor : 128, Custom0 : 512, Custom1 : 1024 }; function unZip(buffer, bytesOffset) { let dataZip = new Uint8Array(buffer, bytesOffset); return pako.inflate(dataZip).buffer; } function getStringFromTypedArray(uint8Array, byteOffset, byteLength) { var byteOffset = 0; var byteLength = uint8Array.byteLength; var codeType = 'utf-8'; uint8Array = uint8Array.subarray(byteOffset, byteOffset + byteLength); var decoder = new TextDecoder(codeType); return decoder.decode(uint8Array); } function parseString(buffer, view, bytesOffset) { let length = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let stringBufferView = new Uint8Array(buffer, bytesOffset, length); let string = getStringFromTypedArray(stringBufferView); bytesOffset += length; return { string : string, bytesOffset : bytesOffset, length : length } } function parseGeode(buffer, view, bytesOffset, geodes) { let geode = {}; let skeletonNames = []; let geoMatrix = new Array(16); for(let i = 0; i < 16; i++){ geoMatrix[i] = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; } geode.matrix = geoMatrix; geode.skeletonNames = skeletonNames; let skeletonCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let i = 0; i < skeletonCount; i++){ let res = parseString(buffer, view, bytesOffset); skeletonNames.push(res.string); bytesOffset = res.bytesOffset; } geodes.push(geode); return bytesOffset; } function parsePageLOD(buffer, view, bytesOffset, pageLods, version) { let pageLOD = {}; pageLOD.rangeList = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; pageLOD.rangeMode = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let center = {}; center.x = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; center.y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; center.z = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; let radius = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; pageLOD.boundingSphere = { center : center, radius : radius }; if(version === 3){ const obbCenter = {}; obbCenter.x = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; obbCenter.y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; obbCenter.z = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const xExtent = {}; xExtent.x = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; xExtent.y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; xExtent.z = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const yExtent = {}; yExtent.x = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; yExtent.y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; yExtent.z = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const zExtent = {}; zExtent.x = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; zExtent.y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; zExtent.z = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; pageLOD.obb = { xExtent: xExtent, yExtent: yExtent, zExtent: zExtent, obbCenter: obbCenter }; } let res = parseString(buffer, view, bytesOffset); let strChildTile = res.string; bytesOffset = res.bytesOffset; let index = strChildTile.indexOf('Geometry'); if(index !== -1){ let ignoreString = strChildTile.substring(index); strChildTile = strChildTile.replace(ignoreString, ''); } pageLOD.childTile = strChildTile; pageLOD.geodes = []; let geodeCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let i = 0; i < geodeCount; i++){ bytesOffset = parseGeode(buffer, view, bytesOffset, pageLOD.geodes); } pageLods.push(pageLOD); //animations if(version === 3){ let resAnimations = parseString(buffer, view, bytesOffset); bytesOffset = resAnimations.bytesOffset; } return bytesOffset; } function parseGroupNode(buffer, view, bytesOffset, result) { let groupNode = {}; let pageLods = []; view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let count = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let i = 0; i < count; i++){ bytesOffset = parsePageLOD(buffer, view, bytesOffset, pageLods, result.version); } groupNode.pageLods = pageLods; let align = bytesOffset % 4; if(align !== 0){ bytesOffset += (4 - align); } result.groupNode = groupNode; return bytesOffset; } function parseVertex(buffer, view, bytesOffset, vertexPackage) { let verticesCount = view.getUint32(bytesOffset, true); vertexPackage.verticesCount = verticesCount; bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if(bytesOffset <= 0){ return bytesOffset; } let vertexDimension = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let vertexStride = view.getUint16(bytesOffset, true); vertexStride = vertexDimension * Float32Array.BYTES_PER_ELEMENT; bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let byteLength = verticesCount * vertexDimension * Float32Array.BYTES_PER_ELEMENT; let vertexBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation['aPosition'] = attributes.length; attributes.push({ index: attrLocation['aPosition'], typedArray: vertexBuffer, componentsPerAttribute: vertexDimension, componentDatatype: 5126, offsetInBytes: 0, strideInBytes: vertexStride, normalize: false }); return bytesOffset; } function parseNormal(buffer, view, bytesOffset, vertexPackage) { let normalCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if(normalCount <= 0){ return bytesOffset; } let normalDimension = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let normalStride = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let byteLength = normalCount * normalDimension * Float32Array.BYTES_PER_ELEMENT; let normalBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation['aNormal'] = attributes.length; attributes.push({ index: attrLocation['aNormal'], typedArray: normalBuffer, componentsPerAttribute : normalDimension, componentDatatype : 5126, offsetInBytes: 0, strideInBytes: normalStride, normalize: false }); return bytesOffset; } function parseVertexColor(buffer, view, bytesOffset, vertexPackage) { let colorCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let verticesCount = vertexPackage.verticesCount; let vertexColor; if (colorCount > 0){ view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; bytesOffset += Uint8Array.BYTES_PER_ELEMENT * 2; let byteLength = colorCount * Uint8Array.BYTES_PER_ELEMENT * 4; let typedArray = new Uint8Array(buffer, bytesOffset, byteLength); vertexColor = typedArray.slice(0, byteLength); bytesOffset += byteLength; } else { vertexColor = new Uint8Array(4 * verticesCount); for (let m = 0; m < verticesCount; m++) { vertexColor[m * 4] = 255; vertexColor[m * 4 + 1] = 255; vertexColor[m * 4 + 2] = 255; vertexColor[m * 4 + 3] = 255; } } let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation['aColor'] = attributes.length; attributes.push({ index: attrLocation['aColor'], typedArray: vertexColor, componentsPerAttribute: 4, componentDatatype: 5121, offsetInBytes: 0, strideInBytes: 4, normalize: true }); vertexPackage.vertexColor = vertexColor; return bytesOffset; } function parseSecondColor(buffer, view, bytesOffset, vertexPackage) { let secondColorCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if (secondColorCount <= 0){ return bytesOffset; } view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; bytesOffset += Uint8Array.BYTES_PER_ELEMENT * 2; let byteLength = secondColorCount * Uint8Array.BYTES_PER_ELEMENT * 4; let secColorBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation['aSecondColor'] = attributes.length; attributes.push({ index: attrLocation['aSecondColor'], typedArray: secColorBuffer, componentsPerAttribute: 4, componentDatatype: 5121, offsetInBytes: 0, strideInBytes: 4, normalize: true }); return bytesOffset; } function parseTexCoord(buffer, view, bytesOffset, vertexPackage) { let count = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; bytesOffset += Uint16Array.BYTES_PER_ELEMENT; for(let i = 0; i < count; i++) { let texCoordCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let dimension = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let byteLength = texCoordCount * dimension * Float32Array.BYTES_PER_ELEMENT; let texCoordBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; let str = 'aTexCoord' + i; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation[str] = attributes.length; attributes.push({ index: attrLocation[str], typedArray: texCoordBuffer, componentsPerAttribute: dimension, componentDatatype: 5126, offsetInBytes: 0, strideInBytes: dimension * Float32Array.BYTES_PER_ELEMENT, normalize: false }); } return bytesOffset; } function parseInstanceInfo(buffer, view, bytesOffset, vertexPackage) { let count = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; for (let i=0; i < count; i++){ let texCoordCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let texDimensions = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let byteLength = texCoordCount * texDimensions * Float32Array.BYTES_PER_ELEMENT; if(texDimensions === 17 || texDimensions === 29){ let instanceBuffer = new Uint8Array(buffer, bytesOffset, byteLength); vertexPackage.instanceCount = texCoordCount; vertexPackage.instanceMode = texDimensions; vertexPackage.instanceBuffer = instanceBuffer; vertexPackage.instanceIndex = 1; let len = texDimensions * texCoordCount * 4; let vertexColorInstance = instanceBuffer.slice(0, len); vertexPackage.vertexColorInstance = vertexColorInstance; let byteStride; if(texDimensions === 17){ byteStride = Float32Array.BYTES_PER_ELEMENT * 17; attrLocation['uv2'] = attributes.length; attributes.push({ index: attrLocation['uv2'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 0, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv3'] = attributes.length; attributes.push({ index: attrLocation['uv3'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 4 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv4'] = attributes.length; attributes.push({ index: attrLocation['uv4'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 8 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['secondary_colour'] = attributes.length; attributes.push({ index:attrLocation['secondary_colour'], componentsPerAttribute:4, componentDatatype:5126, normalize:false, offsetInBytes:12*Float32Array.BYTES_PER_ELEMENT, strideInBytes:byteStride, instanceDivisor:1 }); attrLocation['uv6'] = attributes.length; attributes.push({ index: attrLocation['uv6'], componentsPerAttribute: 4, componentDatatype: 5121, normalize: true, offsetInBytes: 16 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); } else if (texDimensions === 29) { byteStride = Float32Array.BYTES_PER_ELEMENT * 29; attrLocation['uv1'] = attributes.length; attributes.push({ index: attrLocation['uv1'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 0, strideInBytes: byteStride, instanceDivisor: 1, byteLength: byteLength }); attrLocation['uv2'] = attributes.length; attributes.push({ index: attrLocation['uv2'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 4 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv3'] = attributes.length; attributes.push({ index: attrLocation['uv3'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 8 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv4'] = attributes.length; attributes.push({ index: attrLocation['uv4'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 12 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv5'] = attributes.length; attributes.push({ index: attrLocation['uv5'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 16 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv6'] = attributes.length; attributes.push({ index: attrLocation['uv6'], componentsPerAttribute: 4, componentDatatype: 5126, normalize: false, offsetInBytes: 20 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv7'] = attributes.length; attributes.push({ index: attrLocation['uv7'], componentsPerAttribute: 3, componentDatatype: 5126, normalize: false, offsetInBytes: 24 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['secondary_colour'] = attributes.length; attributes.push({ index: attrLocation['secondary_colour'], componentsPerAttribute: 4, componentDatatype: 5121, normalize: true, offsetInBytes: 27 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); attrLocation['uv9'] = attributes.length; attributes.push({ index: attrLocation['uv9'], componentsPerAttribute: 4, componentDatatype: 5121, normalize: true, offsetInBytes: 28 * Float32Array.BYTES_PER_ELEMENT, strideInBytes: byteStride, instanceDivisor: 1 }); } } else { let len = texCoordCount * texDimensions; vertexPackage.instanceBounds = new Float32Array(len); for(let k = 0; k < len; k++){ vertexPackage.instanceBounds[k] = view.getFloat32(bytesOffset + k * Float32Array.BYTES_PER_ELEMENT, true); } } bytesOffset += byteLength; } return bytesOffset; } function parseVertexAttrExtension(buffer, view, bytesOffset, vertexPackage) { const attrCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let i = 0;i < attrCount;i++){ const count = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; const dimension = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; const attrType = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; const byteLength = count * dimension * AttrTypeMap[attrType]; const attrBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; const attributes = vertexPackage.vertexAttributes; const attrLocation = vertexPackage.attrLocation; const str = 'aCustom' + i; attrLocation[str] = attributes.length; attributes.push({ index: attrLocation[str], typedArray: attrBuffer, componentsPerAttribute: dimension, componentDatatype: 5126, offsetInBytes: 0, strideInBytes: 0, normalize: false }); } return bytesOffset; } function parseCompressVertex(buffer, view, bytesOffset, vertexPackage) { let verticesCount = view.getUint32(bytesOffset, true); vertexPackage.verticesCount = verticesCount; bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if(bytesOffset <= 0){ return bytesOffset; } let vertexDimension = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let vertexStride = view.getUint16(bytesOffset, true); vertexStride = vertexDimension * Int16Array.BYTES_PER_ELEMENT; bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let vertCompressConstant = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; let minVerticesValue = {}; minVerticesValue.x = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; minVerticesValue.y = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; minVerticesValue.z = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; minVerticesValue.w = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; vertexPackage.vertCompressConstant = vertCompressConstant; vertexPackage.minVerticesValue = minVerticesValue; let byteLength = verticesCount * vertexDimension * Int16Array.BYTES_PER_ELEMENT; let vertexBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation['aPosition'] = attributes.length; attributes.push({ index: attrLocation['aPosition'], typedArray: vertexBuffer, componentsPerAttribute: vertexDimension, componentDatatype: 5122, offsetInBytes: 0, strideInBytes: vertexStride, normalize: false }); return bytesOffset; } function parseCompressNormal(buffer, view, bytesOffset, vertexPackage) { let normalCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if(normalCount <= 0){ return bytesOffset; } view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let normalStride = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let byteLength = normalCount * 2 * Int16Array.BYTES_PER_ELEMENT; let normalBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation['aNormal'] = attributes.length; attributes.push({ index: attrLocation['aNormal'], typedArray: normalBuffer, componentsPerAttribute : 2, componentDatatype : 5122, offsetInBytes: 0, strideInBytes: normalStride, normalize: false }); return bytesOffset; } function parseCompressTexCoord(buffer, view, bytesOffset, vertexPackage) { vertexPackage.texCoordCompressConstant = []; vertexPackage.minTexCoordValue = []; let count = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; bytesOffset += Uint16Array.BYTES_PER_ELEMENT; for(let i = 0; i < count; i++){ let bNeedTexCoordZ = view.getUint8(bytesOffset, true); bytesOffset += Uint8Array.BYTES_PER_ELEMENT; bytesOffset += Uint8Array.BYTES_PER_ELEMENT * 3; let texCoordCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let dimension = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; let texCoordCompressConstant = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; vertexPackage.texCoordCompressConstant.push(texCoordCompressConstant); let minTexCoordValue = {}; minTexCoordValue.x = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; minTexCoordValue.y = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; minTexCoordValue.z = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; minTexCoordValue.w = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; vertexPackage.minTexCoordValue.push(minTexCoordValue); let byteLength = texCoordCount * dimension * Int16Array.BYTES_PER_ELEMENT; let texCoordBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; let align = bytesOffset % 4; if(align !== 0){ bytesOffset += (4 - align); } let str = 'aTexCoord' + i; let attributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; attrLocation[str] = attributes.length; attributes.push({ index: attrLocation[str], typedArray: texCoordBuffer, componentsPerAttribute: dimension, componentDatatype: 5122, offsetInBytes: 0, strideInBytes: dimension * Int16Array.BYTES_PER_ELEMENT, normalize: false }); if(bNeedTexCoordZ){ byteLength = texCoordCount * Float32Array.BYTES_PER_ELEMENT; let texCoordZBuffer = new Uint8Array(buffer, bytesOffset, byteLength); bytesOffset += byteLength; vertexPackage.texCoordZMatrix = true; str = 'aTexCoordZ' + i; attrLocation[str] = attributes.length; attributes.push({ index: attrLocation[str], typedArray: texCoordZBuffer, componentsPerAttribute: 1, componentDatatype: 5126, offsetInBytes: 0, strideInBytes: Float32Array.BYTES_PER_ELEMENT, normalize: false }); } } return bytesOffset; } function parseTangent(buffer, view, bytesOffset, vertexPackage) { const nCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if (nCount <= 0) { return bytesOffset; } const nDimension = view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; view.getUint16(bytesOffset, true); bytesOffset += Uint16Array.BYTES_PER_ELEMENT; const byteLength = nCount * nDimension * Float32Array.BYTES_PER_ELEMENT; bytesOffset += byteLength; return bytesOffset; } function parseStandardSkeleton(buffer, view, bytesOffset, vertexPackage, version) { if(version === 3){ view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } bytesOffset = parseVertex(buffer, view, bytesOffset, vertexPackage); bytesOffset = parseNormal(buffer, view, bytesOffset, vertexPackage); bytesOffset = parseVertexColor(buffer, view, bytesOffset, vertexPackage); if(version !== 3){ bytesOffset = parseSecondColor(buffer, view, bytesOffset, vertexPackage); } bytesOffset = parseTexCoord(buffer, view, bytesOffset, vertexPackage); bytesOffset = parseInstanceInfo(buffer, view, bytesOffset, vertexPackage); if(version === 3){ bytesOffset = parseVertexAttrExtension(buffer, view, bytesOffset, vertexPackage); const describeResult = parseString(buffer, view, bytesOffset); bytesOffset = describeResult.bytesOffset; vertexPackage.customVertexAttribute = JSON.parse(describeResult.string); const attr = 'aCustom' + vertexPackage.customVertexAttribute['TextureCoordMatrix']; const attr2 = 'aCustom' + vertexPackage.customVertexAttribute['VertexWeight']; if(vertexPackage.attrLocation[attr] !== undefined){ vertexPackage.attrLocation['aTextureCoordMatrix'] = vertexPackage.attrLocation[attr]; delete vertexPackage.attrLocation[attr]; } if(vertexPackage.attrLocation[attr2] !== undefined){ vertexPackage.attrLocation['aVertexWeight'] = vertexPackage.attrLocation[attr2]; delete vertexPackage.attrLocation[attr2]; } let nAlign = bytesOffset % 4; if(nAlign){ nAlign = 4 - nAlign; } bytesOffset += nAlign; bytesOffset = parseTangent(buffer, view, bytesOffset); } return bytesOffset; } function loadMeshOpt(vertexCount, attrType, attributeDim, oriBuffer, vertexPackage, compressOptions) { let nAttrSize = 0; let pDecodeVertices; const attributes = vertexPackage.vertexAttributes; const attrLocation = vertexPackage.attrLocation; switch (attrType) { case AttributeType.Normal: case AttributeType.FirstTexcoord: case AttributeType.SecondTexcoord: nAttrSize = Uint16Array.BYTES_PER_ELEMENT * 2; if((compressOptions & 0x10) === 0 && (attrType === AttributeType.FirstTexcoord || attrType === AttributeType.SecondTexcoord)){ nAttrSize = Float32Array.BYTES_PER_ELEMENT * 2; } pDecodeVertices = new Uint8Array(vertexCount * nAttrSize); break; case AttributeType.Color: case AttributeType.SecondColor: nAttrSize = Uint8Array.BYTES_PER_ELEMENT * 4; pDecodeVertices = new Uint8Array(vertexCount * 4); break; case AttributeType.Custom0: nAttrSize = Float32Array.BYTES_PER_ELEMENT * attributeDim; pDecodeVertices = new Uint8Array(vertexCount * attributeDim * 4); break; case AttributeType.Custom1: nAttrSize = Float32Array.BYTES_PER_ELEMENT * attributeDim; pDecodeVertices = new Uint8Array(vertexCount * attributeDim * 4); break; default: nAttrSize = Uint16Array.BYTES_PER_ELEMENT * 4; pDecodeVertices = new Uint8Array(vertexCount * nAttrSize); break; } // decompress MeshoptDecoder.decodeVertexBuffer(pDecodeVertices, vertexCount, nAttrSize, oriBuffer, oriBuffer.length); let pTexCoords, componentDatatype; switch (attrType) { case AttributeType.Position: attrLocation['aPosition'] = attributes.length; attributes.push({ index: attrLocation['aPosition'], typedArray: new Uint16Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 2), componentsPerAttribute: 4, componentDatatype: 5122,//SHORT offsetInBytes: 0, strideInBytes: 0, normalize: false }); vertexPackage.verticesCount = vertexCount; break; case AttributeType.Normal: attrLocation['aNormal'] = attributes.length; attributes.push({ index: attrLocation['aNormal'], typedArray: new Int16Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 2), componentsPerAttribute: 2, componentDatatype: 5122,//SHORT offsetInBytes: 0, strideInBytes: 0, normalize: false }); break; case AttributeType.FirstTexcoord: if((compressOptions & 0x10) === 0){ componentDatatype = 5126;//FLOAT; pTexCoords = new Float32Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 4); } else { componentDatatype = 5122;//SHORT pTexCoords = new Uint16Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 2); } attrLocation['aTexCoord0'] = attributes.length; attributes.push({ index: attrLocation['aTexCoord0'], typedArray: pTexCoords, componentsPerAttribute: 2, componentDatatype: componentDatatype, offsetInBytes: 0, strideInBytes: 0, normalize: false }); break; case AttributeType.SecondTexcoord: if((compressOptions & 0x10) === 0){ componentDatatype = 5126;//FLOAT; pTexCoords = new Float32Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 4); } else { componentDatatype = 5122;//SHORT pTexCoords = new Uint16Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 2); } attrLocation['aTexCoord1'] = attributes.length; attributes.push({ index: attrLocation['aTexCoord1'], typedArray: pTexCoords, componentsPerAttribute: 2, componentDatatype: componentDatatype, offsetInBytes: 0, strideInBytes: 0, normalize: false }); break; case AttributeType.Color: attrLocation['aColor'] = attributes.length; attributes.push({ index: attrLocation['aColor'], typedArray: pDecodeVertices, componentsPerAttribute: 4, componentDatatype: 5121,//UNSIGNED_BYTE, offsetInBytes: 0, strideInBytes: 0, normalize: true }); break; case AttributeType.SecondColor: attrLocation['aSecondColor'] = attributes.length; attributes.push({ index: attrLocation['aSecondColor'], typedArray: pDecodeVertices, componentsPerAttribute: 4, componentDatatype: 5120,//BYTE, offsetInBytes: 0, strideInBytes: 0, normalize: false }); break; case AttributeType.Custom0: attrLocation['aCustom0'] = attributes.length; attributes.push({ index: attrLocation['aCustom0'], typedArray: new Float32Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 4), componentsPerAttribute: attributeDim, componentDatatype: 5126,//FLOAT, offsetInBytes: 0, strideInBytes: 0, normalize: false }); break; case AttributeType.Custom1: attrLocation['aCustom1'] = attributes.length; attributes.push({ index: attrLocation['aCustom1'], typedArray: new Float32Array(pDecodeVertices.buffer, 0, pDecodeVertices.length / 4), componentsPerAttribute: attributeDim, componentDatatype: 5126,//FLOAT, offsetInBytes: 0, strideInBytes: 0, normalize: false }); break; } } function parseMeshOptSkeleton(buffer, view, bytesOffset, vertexPackage, version) { const compressOptions = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; vertexPackage.compressOptions = compressOptions; const nBlockSize = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; vertexPackage.minVerticesValue = {x : 0, y : 0, z : 0, w : 0}; vertexPackage.minTexCoordValue = [{x : 0, y : 0}, {x : 0, y : 0}]; vertexPackage.texCoordCompressConstant = [{x : 0, y : 0, z : 0}, {x : 0, y : 0, z : 0}]; for(let i = 0; i < nBlockSize; i++) { // 顶点数据 const nVertexCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; // 顶点量化参数 vertexPackage.vertCompressConstant = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; vertexPackage.minVerticesValue.x = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; vertexPackage.minVerticesValue.y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; vertexPackage.minVerticesValue.z = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; // 纹理坐标量化参数 const texCoordScale0X = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const texCoordScale0Y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const vecMinTexCoord0X = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const vecMinTexCoord0Y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const texCoordScale1X = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const texCoordScale1Y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const vecMinTexCoord1X = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; const vecMinTexCoord1Y = view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; vertexPackage.minTexCoordValue[0].x = vecMinTexCoord0X; vertexPackage.minTexCoordValue[0].y = vecMinTexCoord0Y; vertexPackage.minTexCoordValue[1].x = vecMinTexCoord1X; vertexPackage.minTexCoordValue[1].y = vecMinTexCoord1Y; vertexPackage.texCoordCompressConstant[0].x = texCoordScale0X; vertexPackage.texCoordCompressConstant[0].y = texCoordScale0Y; vertexPackage.texCoordCompressConstant[1].x = texCoordScale1X; vertexPackage.texCoordCompressConstant[1].y = texCoordScale1Y; const size = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; for(let j = 0; j < size; j++) { const attrType = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; let attributeDim = 0; if (attrType === AttributeType.Custom0 || attrType === AttributeType.Custom1) { attributeDim = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; } const nVertexBufferSize = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; const oriBuffer = new Uint8Array(buffer, bytesOffset, nVertexBufferSize); bytesOffset += Uint8Array.BYTES_PER_ELEMENT * nVertexBufferSize; // 四字节对齐 let nAlign = bytesOffset % 4; if(nAlign){ nAlign = 4 - nAlign; } bytesOffset += nAlign; loadMeshOpt(nVertexCount, attrType, attributeDim, oriBuffer, vertexPackage, compressOptions); } let describeString = parseString(buffer, view, bytesOffset); bytesOffset = describeString.bytesOffset; vertexPackage.customVertexAttribute = JSON.parse(describeString.string); let attr = 'aCustom' + vertexPackage.customVertexAttribute['TextureCoordMatrix']; let attr2 = 'aCustom' + vertexPackage.customVertexAttribute['VertexWeight']; if(vertexPackage.attrLocation[attr] !== undefined){ vertexPackage.attrLocation['aTextureCoordMatrix'] = vertexPackage.attrLocation[attr]; if(i === nBlockSize - 1){ delete vertexPackage.attrLocation[attr]; } } if(vertexPackage.attrLocation[attr2] !== undefined){ vertexPackage.attrLocation['aVertexWeight'] = vertexPackage.attrLocation[attr2]; if(i === nBlockSize - 1){ delete vertexPackage.attrLocation[attr2]; } } // 四字节对齐 let nAlign = bytesOffset % 4; if(nAlign){ nAlign = 4 - nAlign; } bytesOffset += nAlign; } return bytesOffset; } function parseMeshOpIndexPackage(buffer, view, bytesOffset, arrIndexPackage, version){ const indexPackageCount = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; for (let k = 0; k < indexPackageCount; k++){ const indexPackage = {}; const indexCount = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; if(indexCount < 1){ continue ; } const indexType = view.getInt8(bytesOffset, true); bytesOffset += Int8Array.BYTES_PER_ELEMENT; view.getInt8(bytesOffset, true); bytesOffset += Int8Array.BYTES_PER_ELEMENT; const operationType = view.getInt8(bytesOffset, true); bytesOffset += Int8Array.BYTES_PER_ELEMENT; view.getInt8(bytesOffset, true); bytesOffset += Int8Array.BYTES_PER_ELEMENT; const nIndexBufferSize = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; let oriIndexBuffer; if(operationType !== 13){ oriIndexBuffer = new Uint8Array(buffer, bytesOffset, nIndexBufferSize); bytesOffset += Uint8Array.BYTES_PER_ELEMENT * nIndexBufferSize; } else { oriIndexBuffer = new Uint32Array(buffer, bytesOffset, nIndexBufferSize); bytesOffset += Uint32Array.BYTES_PER_ELEMENT * nIndexBufferSize; } // 四字节对齐 let nAlign = bytesOffset % 4; if(nAlign){ nAlign = 4 - nAlign; } bytesOffset += nAlign; let decodeIndices; if(operationType !== 13){ decodeIndices = new Uint8Array(indexCount * Uint32Array.BYTES_PER_ELEMENT); MeshoptDecoder.decodeIndexBuffer(decodeIndices, indexCount, Uint32Array.BYTES_PER_ELEMENT, oriIndexBuffer); }else { decodeIndices = oriIndexBuffer; } const numCount = view.getInt32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; indexPackage.indexType = indexType; const indexBuffer = indexType === 0 ? new Uint16Array(indexCount) : new Uint32Array(indexCount); indexPackage.indicesCount = indexCount; const indexBufferInt32 = new Uint32Array(decodeIndices.buffer, decodeIndices.byteOffset, decodeIndices.byteLength / 4); indexBuffer.set(indexBufferInt32, 0); indexPackage.indicesTypedArray = indexBuffer; indexPackage.primitiveType = operationType; for(let j = 0; j < numCount; j++) { const result = parseString(buffer, view, bytesOffset); bytesOffset = result.bytesOffset; indexPackage.materialCode = result.string; } arrIndexPackage.push(indexPackage); // 四字节对齐 nAlign = bytesOffset % 4; if(nAlign){ nAlign = 4 - nAlign; } bytesOffset += nAlign; } return bytesOffset; } function parseCompressSkeleton(buffer, view, bytesOffset, vertexPackage) { let compressOptions = view.getUint32(bytesOffset, true); vertexPackage.compressOptions = compressOptions; bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if((compressOptions & VertexCompressOption$1.SVC_Vertex) === VertexCompressOption$1.SVC_Vertex){ bytesOffset = parseCompressVertex(buffer, view, bytesOffset, vertexPackage); } else { bytesOffset = parseVertex(buffer, view, bytesOffset, vertexPackage); } if((compressOptions & VertexCompressOption$1.SVC_Normal) === VertexCompressOption$1.SVC_Normal){ bytesOffset = parseCompressNormal(buffer, view, bytesOffset, vertexPackage); } else { bytesOffset = parseNormal(buffer, view, bytesOffset, vertexPackage); } bytesOffset = parseVertexColor(buffer, view, bytesOffset, vertexPackage); bytesOffset = parseSecondColor(buffer, view, bytesOffset, vertexPackage); if((compressOptions & VertexCompressOption$1.SVC_TexutreCoord) === VertexCompressOption$1.SVC_TexutreCoord){ bytesOffset = parseCompressTexCoord(buffer, view, bytesOffset, vertexPackage); } else { bytesOffset = parseTexCoord(buffer, view, bytesOffset, vertexPackage); } if((compressOptions & VertexCompressOption$1.SVC_TexutreCoordIsW) === VertexCompressOption$1.SVC_TexutreCoordIsW){ vertexPackage.textureCoordIsW = true; } bytesOffset = parseInstanceInfo(buffer, view, bytesOffset, vertexPackage); return bytesOffset; } function parseIndexPackage(buffer, view, bytesOffset, arrIndexPackage, version) { let count = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for (let i = 0; i < count; i++){ let indexPackage = {}; if(version === 3){ view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } let indexCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let indexType = view.getUint8(bytesOffset, true); bytesOffset += Uint8Array.BYTES_PER_ELEMENT; view.getUint8(bytesOffset, true); bytesOffset += Uint8Array.BYTES_PER_ELEMENT; let primitiveType = view.getUint8(bytesOffset, true); bytesOffset += Uint8Array.BYTES_PER_ELEMENT; bytesOffset += Uint8Array.BYTES_PER_ELEMENT; if(indexCount > 0){ let indexBuffer = null; let byteLength; if(indexType === 1 || indexType === 3){ byteLength = indexCount * Uint32Array.BYTES_PER_ELEMENT; indexBuffer = new Uint8Array(buffer, bytesOffset, byteLength); } else { byteLength = indexCount * Uint16Array.BYTES_PER_ELEMENT; indexBuffer = new Uint8Array(buffer, bytesOffset, byteLength); if(indexCount % 2 !== 0) { byteLength += 2; } } indexPackage.indicesTypedArray = indexBuffer; bytesOffset += byteLength; } indexPackage.indicesCount = indexCount; indexPackage.indexType = indexType; indexPackage.primitiveType = primitiveType; let passNameCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let j = 0; j < passNameCount; j++) { let res = parseString(buffer, view, bytesOffset); let passName = res.string; bytesOffset = res.bytesOffset; indexPackage.materialCode = passName; } let align = bytesOffset % 4; if(align !== 0){ let nReserved = 4 - bytesOffset % 4; bytesOffset += nReserved; } arrIndexPackage.push(indexPackage); } return bytesOffset; } function parseSkeleton(buffer, view, bytesOffset, geoPackage, version) { view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let count = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let i = 0; i < count; i++){ if(version === 3){ view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } let res = parseString(buffer, view, bytesOffset); let geometryName = res.string; bytesOffset = res.bytesOffset; let align = res.length % 4; if(align !== 0){ bytesOffset += (4 - align); } let tag = view.getUint32(bytesOffset, true); bytesOffset += Int32Array.BYTES_PER_ELEMENT; if(version === 3){ switch (tag){ case S3MBVertexTagV3.Standard : tag = S3MBVertexTag.SV_Standard;break; case S3MBVertexTagV3.Draco : tag = S3MBVertexTag.SV_DracoCompressed;break; case S3MBVertexTagV3.MeshOpt : tag = S3MBVertexTag.SV_Compressed;break; } } let vertexPackage = { vertexAttributes : [], attrLocation : {}, instanceCount : 0, instanceMode : 0, instanceIndex : -1 }; if(tag === S3MBVertexTag.SV_Standard){ bytesOffset = parseStandardSkeleton(buffer, view, bytesOffset, vertexPackage, version); } else if(tag === S3MBVertexTag.SV_Compressed && version === 3){ bytesOffset = parseMeshOptSkeleton(buffer, view, bytesOffset, vertexPackage); } else if(tag === S3MBVertexTag.SV_Compressed){ bytesOffset = parseCompressSkeleton(buffer, view, bytesOffset, vertexPackage); } let arrIndexPackage = []; if(tag === S3MBVertexTag.SV_Compressed && version === 3){ bytesOffset = parseMeshOpIndexPackage(buffer, view, bytesOffset, arrIndexPackage); } else { bytesOffset = parseIndexPackage(buffer, view, bytesOffset, arrIndexPackage, version); } let edgeGeometry = undefined; if(arrIndexPackage.length === 2 && arrIndexPackage[1].primitiveType === 13 && arrIndexPackage[1].indicesCount >= 3){ edgeGeometry = S3MEdgeProcessor.createEdgeDataByIndices(vertexPackage, arrIndexPackage[1]); } geoPackage[geometryName] = { vertexPackage: vertexPackage, arrIndexPackage: arrIndexPackage, edgeGeometry: edgeGeometry }; if(version === 3){ view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; view.getFloat64(bytesOffset, true); bytesOffset += Float64Array.BYTES_PER_ELEMENT; } } if(version !== 3){ let secColorSize = view.getUint32(bytesOffset, true); bytesOffset += secColorSize; bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } return bytesOffset; } function parseTexturePackage(buffer, view, bytesOffset, texturePackage) { view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let count = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let i = 0; i < count; i++){ let res = parseString(buffer, view, bytesOffset); let textureCode = res.string; bytesOffset = res.bytesOffset; let align = res.length % 4; if(align !== 0){ bytesOffset += (4 - align); } view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let width = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let height = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let compressType = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let size = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let pixelFormat = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let textureData = new Uint8Array(buffer, bytesOffset, size); bytesOffset += size; let internalFormat = (pixelFormat === S3MPixelFormat$2.RGB || pixelFormat === S3MPixelFormat$2.BGR) ? 33776 : 33779; if(compressType === 22){ internalFormat = 36196;//rgb_etc1 } if(!S3ModelParser.s3tc && (internalFormat === 33776 || internalFormat === 33779)) { let out = new Uint8Array(width * height * 4); DXTTextureDecode.decode(out, width, height, textureData, pixelFormat); textureData = out; compressType = 0; internalFormat = (pixelFormat === S3MPixelFormat$2.RGB || pixelFormat === S3MPixelFormat$2.RGB) ? 273 : 4369; } texturePackage[textureCode] = { id: textureCode, width: width, height: height, compressType: compressType, nFormat: pixelFormat, internalFormat : internalFormat, arrayBufferView: textureData }; } return bytesOffset; } function parseMaterial$1(buffer, view, bytesOffset, result) { let byteLength = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let materialBuffer = new Uint8Array(buffer, bytesOffset, byteLength); let strMaterials = getStringFromTypedArray(materialBuffer); bytesOffset += byteLength; result.materials = JSON.parse(strMaterials); return bytesOffset; } let colorScratch = { red : 0, green : 0, blue : 0, alpha : 0 }; let LEFT_16 = 65536; function parsePickInfo(buffer, view, bytesOffset, nOptions, geoPackage, version) { if(version === 3){ nOptions = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } if((nOptions & 1) === 1){ view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let count = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let i = 0; i < count; i++){ let res = parseString(buffer, view, bytesOffset); let geometryName = res.string; bytesOffset = res.bytesOffset; let selectInfoCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let pickInfo = {}; geoPackage[geometryName].pickInfo = pickInfo; let bInstanced = geoPackage[geometryName].vertexPackage.instanceIndex; if(bInstanced == -1){ //非实例化信息 let batchIds = new Float32Array(geoPackage[geometryName].vertexPackage.verticesCount); for(let j = 0; j < selectInfoCount; j++){ let nDictID = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let nSize = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let infos = []; for(let k = 0; k < nSize; k++){ let vertexColorOffset = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let vertexCount = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; batchIds.fill(j, vertexColorOffset, vertexColorOffset + vertexCount); infos.push({ vertexColorOffset: vertexColorOffset, vertexColorCount: vertexCount, batchId:j }); } pickInfo[nDictID] = infos; } createBatchIdAttribute(geoPackage[geometryName].vertexPackage,batchIds,undefined); }else { let instanceCount = geoPackage[geometryName].vertexPackage.instanceCount; let instanceArray = geoPackage[geometryName].vertexPackage.instanceBuffer; let instanceMode = geoPackage[geometryName].vertexPackage.instanceMode; let instanceIds = new Float32Array(instanceCount); let selectionId = []; for(let j = 0;j < selectInfoCount;j++){ let nDictID = view.getUint32(bytesOffset, true); selectionId.push(nDictID); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let nSize = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; for(let k = 0;k < nSize; k++){ view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; if(version === 3){ view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } } } let beginOffset = instanceMode === 17 ? 16 : 28; beginOffset *= Float32Array.BYTES_PER_ELEMENT; for(let j = 0;j < instanceCount; j++){ instanceIds[j] = j; let offset = j * instanceMode * Float32Array.BYTES_PER_ELEMENT + beginOffset; Cesium.Color.unpack(instanceArray, offset, colorScratch); let pickId = version === 2 ? selectionId[j] : colorScratch.red + colorScratch.green * 256 + colorScratch.blue * LEFT_16; if(pickInfo[pickId] === undefined){ pickInfo[pickId] = { vertexColorCount:1, instanceIds:[], vertexColorOffset:j }; } pickInfo[pickId].instanceIds.push(j); } createBatchIdAttribute(geoPackage[geometryName].vertexPackage,instanceIds,1); } } } return bytesOffset; } function createBatchIdAttribute(vertexPackage, typedArray, instanceDivisor){ let vertexAttributes = vertexPackage.vertexAttributes; let attrLocation = vertexPackage.attrLocation; let len = vertexAttributes.length; let attrName = instanceDivisor === 1 ? 'instanceId' : 'batchId'; attrLocation[attrName] = len; vertexAttributes.push({ index: len, typedArray: typedArray, componentsPerAttribute: 1, componentDatatype: 5126, offsetInBytes: 0, strideInBytes: 0, instanceDivisor: instanceDivisor }); } S3ModelParser.parseBuffer = function(buffer) { let bytesOffset = 0; let result = { version : undefined, groupNode : undefined, geoPackage : {}, matrials : undefined, texturePackage : {} }; let view = new DataView(buffer); result.version = view.getFloat32(bytesOffset, true); bytesOffset += Float32Array.BYTES_PER_ELEMENT; if (result.version >= 2.0) { view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } if(result.version >= 3) { view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; } view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; let unzipBuffer = unZip(buffer, bytesOffset); view = new DataView(unzipBuffer); bytesOffset = 0; let nOptions = view.getUint32(bytesOffset, true); bytesOffset += Uint32Array.BYTES_PER_ELEMENT; bytesOffset = parseGroupNode(unzipBuffer, view, bytesOffset, result); bytesOffset = parseSkeleton(unzipBuffer, view, bytesOffset, result.geoPackage, result.version); bytesOffset = parseTexturePackage(unzipBuffer, view, bytesOffset, result.texturePackage); bytesOffset = parseMaterial$1(unzipBuffer, view, bytesOffset, result); parsePickInfo(unzipBuffer, view, bytesOffset, nOptions, result.geoPackage, result.version); return result; }; const NOCOMPRESSED_RGBA = 0x1111; const NOCOMPRESSED_LA = 6410; function DDSTexture(context, id, options) { let gl = context._gl; this.contextId = context.id; this.textureId = id; this.layerId = options.layerId; this.rootName = options.rootName; this.context = context; this.width = options.width; this.height = options.height; this.compressType = options.compressType; this.internalFormat = options.internalFormat; this.pixelFormat = options.pixelFormat; this.arrayBufferView = options.arrayBufferView; this.wrapS = Cesium.defaultValue(options.wrapS, Cesium.TextureWrap.CLAMP_TO_EDGE); this.wrapT = Cesium.defaultValue(options.wrapT, Cesium.TextureWrap.CLAMP_TO_EDGE); this._target = gl.TEXTURE_2D; this._texture = undefined; this.refCount = 1; if(this.arrayBufferView){ this.init(); } } DDSTexture.prototype.init = function(){ let gl = this.context._gl; if(!this._texture){ this._texture = gl.createTexture(); } gl.bindTexture(gl.TEXTURE_2D, this._texture); let internalFormat = this.internalFormat; if(internalFormat === NOCOMPRESSED_LA || internalFormat === NOCOMPRESSED_RGBA){ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); } let i = 0; let offset = 0; let texWidth = this.width; let texHeight = this.height; let bMipMap = validateMipmap(this.arrayBufferView, internalFormat, texWidth, texHeight); do{ let levelSize = Cesium.PixelFormat.compressedTextureSizeInBytes(internalFormat, texWidth, texHeight); let subArrayBuffer = new Uint8Array(this.arrayBufferView.buffer, this.arrayBufferView.byteOffset + offset, levelSize); if(internalFormat === NOCOMPRESSED_RGBA){ gl.texImage2D(gl.TEXTURE_2D, i++, gl.RGBA, texWidth, texHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, subArrayBuffer); } else { gl.compressedTexImage2D(gl.TEXTURE_2D, i++, internalFormat, texWidth, texHeight, 0, subArrayBuffer); } texWidth = Math.max(texWidth >> 1,1); texHeight = Math.max(texHeight >> 1,1); offset += levelSize; } while (offset < this.arrayBufferView.byteLength && bMipMap); if (i > 1) { gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); } else { 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, this.wrapS); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT); gl.texParameteri(this._target, this.context._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, 1); gl.bindTexture(gl.TEXTURE_2D, null); this.arrayBufferView = undefined; this.ready = true; }; function validateMipmap(buffer, pixelFormat, width, height){ let len = buffer.length; let w = width, h = height; let totalBytes = 0; while(1){ let sizeInBytes = Cesium.PixelFormat.compressedTextureSizeInBytes(pixelFormat, w, h); totalBytes += sizeInBytes; w = w >> 1; h = h >> 1; if(w === 0 && h === 0){ break; } w = Math.max(w, 1); h = Math.max(h, 1); } return totalBytes === len; } DDSTexture.prototype.isDestroyed = function() { return false; }; DDSTexture.prototype.destroy = function() { let gl = this.context._gl; gl.deleteTexture(this._texture); this._texture = null; this.id = 0; Cesium.destroyObject(this); }; function MaterialPass(){ this.ambientColor = new Cesium.Color(); this.diffuseColor = new Cesium.Color(); this.specularColor = new Cesium.Color(0.0, 0.0, 0.0, 0.0); this.shininess = 50.0; this.bTransparentSorting = false; this.texMatrix = Cesium.Matrix4.clone(Cesium.Matrix4.IDENTITY, new Cesium.Matrix4()); this.textures = []; } MaterialPass.prototype.isDestroyed = function() { return false; }; MaterialPass.prototype.destroy = function(){ let length = this.textures.length; for(let i = 0;i < length;i++){ let texture = this.textures[i]; texture.destroy(); } this.textures.length = 0; this.ambientColor = undefined; this.diffuseColor = undefined; this.specularColor = undefined; return Cesium.destroyObject(this); }; //This file is automatically rebuilt by the Cesium build process. var S3MTilesVS = "attribute vec4 aPosition;\n\ #ifdef VertexColor\n\ attribute vec4 aColor;\n\ #endif\n\ #ifdef VertexNormal\n\ attribute vec3 aNormal;\n\ #endif\n\ #ifdef Instance\n\ attribute float instanceId;\n\ #else\n\ attribute float batchId;\n\ #endif\n\ #ifdef USE_VertexWeight\n\ attribute float aVertexWeight;\n\ #endif\n\ #ifdef USE_TextureCoordMatrix\n\ attribute vec2 aTextureCoordMatrix;\n\ #endif\n\ #ifdef TexCoord\n\ attribute vec4 aTexCoord0;\n\ varying vec4 vTexCoord;\n\ uniform mat4 uTexMatrix;\n\ #ifdef COMPUTE_TEXCOORD\n\ uniform float uTexture0Width;\n\ varying vec4 vTexMatrix;\n\ varying vec4 vTexCoordTransform;\n\ varying vec2 vIsRGBA;\n\ #endif\n\ #endif\n\ #ifdef TexCoord2\n\ attribute vec4 aTexCoord1;\n\ uniform float uTexture1Width;\n\ varying vec4 vTexMatrix2;\n\ #endif\n\ #ifdef InstanceBim\n\ attribute vec4 uv2;\n\ attribute vec4 uv3;\n\ attribute vec4 uv4;\n\ attribute vec4 secondary_colour;\n\ attribute vec4 uv6;\n\ #endif\n\ #ifdef InstancePipe\n\ attribute vec4 uv1;\n\ attribute vec4 uv2;\n\ attribute vec4 uv3;\n\ attribute vec4 uv4;\n\ attribute vec4 uv5;\n\ attribute vec4 uv6;\n\ attribute vec4 uv7;\n\ attribute vec4 secondary_colour;\n\ attribute vec4 uv9;\n\ #endif\n\ uniform vec4 uFillForeColor;\n\ uniform vec4 uSelectedColor;\n\ varying vec4 vSecondColor;\n\ varying vec4 vPositionMC;\n\ varying vec3 vPositionEC;\n\ #ifdef VertexNormal\n\ varying vec3 vNormalEC;\n\ #endif\n\ varying vec4 vColor;\n\ const float SHIFT_LEFT8 = 256.0;\n\ const float SHIFT_RIGHT8 = 1.0 / 256.0;\n\ const float SHIFT_RIGHT4 = 1.0 / 16.0;\n\ const float SHIFT_LEFT4 = 16.0;\n\ void getTextureMatrixFromZValue(in float nZ, inout float XTran, inout float YTran, inout float scale, inout float isRGBA)\n\ {\n\ if(nZ <= 0.0)\n\ {\n\ return;\n\ }\n\ float nDel8 = floor(nZ * SHIFT_RIGHT8);\n\ float nDel16 = floor(nDel8 * SHIFT_RIGHT8);\n\ float nDel20 = floor(nDel16 * SHIFT_RIGHT4);\n\ isRGBA = floor(nDel20);\n\ YTran = nZ - nDel8 * SHIFT_LEFT8;\n\ XTran = nDel8 - nDel16 * SHIFT_LEFT8;\n\ float nLevel = nDel16 - nDel20 * SHIFT_LEFT4;\n\ scale = 1.0 / pow(2.0, nLevel);\n\ }\n\ void operation(vec4 operationType, vec4 color, vec4 selectedColor, inout vec4 vertexColor)\n\ {\n\ float right_2 = operationType.x * 0.5;\n\ float right_4 = right_2 * 0.5;\n\ float right_8 = right_4 * 0.5;\n\ float right_16 = right_8 * 0.5;\n\ float isSetColor = fract(right_2);\n\ if(isSetColor > 0.1)\n\ {\n\ vertexColor *= color;\n\ }\n\ float isPicked = fract(floor(right_2)* 0.5);\n\ if(isPicked > 0.1)\n\ {\n\ vertexColor *= selectedColor;\n\ }\n\ float isHide = fract(floor(right_4)* 0.5);\n\ if(isHide > 0.1)\n\ {\n\ vertexColor.a = 0.0;\n\ }\n\ }\n\ #ifdef COMPRESS_TEXCOORD\n\ #ifdef TexCoord\n\ uniform vec2 decode_texCoord0_min;\n\ #endif\n\ #ifdef TexCoord2\n\ uniform vec2 decode_texCoord1_min;\n\ #endif\n\ #ifdef MeshOPT_Compress\n\ uniform vec3 decode_texCoord0_vNormConstant;\n\ uniform vec3 decode_texCoord1_vNormConstant;\n\ #else\n\ uniform float decode_texCoord0_normConstant;\n\ uniform float decode_texCoord1_normConstant;\n\ #endif\n\ #endif\n\ #ifdef COMPRESS_VERTEX\n\ uniform vec4 decode_position_min;\n\ uniform float decode_position_normConstant;\n\ #endif\n\ #ifdef COMPRESS_NORMAL\n\ uniform float normal_rangeConstant;\n\ #endif\n\ void main()\n\ {\n\ #ifdef COMPRESS_VERTEX\n\ vec4 vertexPos = vec4(1.0);\n\ vertexPos = decode_position_min + vec4(aPosition.xyz, 1.0) * decode_position_normConstant;\n\ #else\n\ vec4 vertexPos = aPosition;\n\ #endif\n\ #ifdef TexCoord\n\ #ifdef COMPRESS_TEXCOORD\n\ #ifdef MeshOPT_Compress\n\ vec2 texCoord0;\n\ texCoord0.x = aTexCoord0.x * decode_texCoord0_vNormConstant.x;\n\ texCoord0.y = aTexCoord0.y * decode_texCoord0_vNormConstant.y;\n\ vTexCoord.xy = decode_texCoord0_min + texCoord0.xy;\n\ #else\n\ vTexCoord.xy = decode_texCoord0_min.xy + aTexCoord0.xy * decode_texCoord0_normConstant;\n\ #endif\n\ #else\n\ vTexCoord.xy = aTexCoord0.xy;\n\ #endif\n\ #ifdef COMPUTE_TEXCOORD\n\ vTexMatrix = vec4(0.0,0.0,1.0,0.0);\n\ vIsRGBA.x = 0.0;\n\ vTexCoordTransform.x = aTexCoord0.z;\n\ #ifdef USE_TextureCoordMatrix\n\ vTexCoordTransform.x = aTextureCoordMatrix.x;\n\ #endif\n\ if(vTexCoordTransform.x < -90000.0)\n\ {\n\ vTexMatrix.z = -1.0;\n\ }\n\ getTextureMatrixFromZValue(floor(vTexCoordTransform.x), vTexMatrix.x, vTexMatrix.y, vTexMatrix.z, vIsRGBA.x);\n\ vTexMatrix.w = log2(uTexture0Width * vTexMatrix.z);\n\ #endif\n\ #endif\n\ #ifdef TexCoord2\n\ #ifdef COMPRESS_TEXCOORD\n\ #ifdef MeshOPT_Compress\n\ vec2 texCoord1;\n\ texCoord1.x = aTexCoord1.x * decode_texCoord1_vNormConstant.x;\n\ texCoord1.y = aTexCoord1.y * decode_texCoord1_vNormConstant.y;\n\ vTexCoord.zw = decode_texCoord1_min + texCoord1.xy;\n\ #else\n\ vTexCoord.zw = decode_texCoord1_min.xy + aTexCoord1.xy * decode_texCoord1_normConstant;\n\ #endif\n\ #else\n\ vTexCoord.zw = aTexCoord1.xy;\n\ #endif\n\ vTexMatrix2 = vec4(0.0,0.0,1.0,0.0);\n\ vIsRGBA.y = 0.0;\n\ vTexCoordTransform.y = aTexCoord1.z;\n\ #ifdef USE_TextureCoordMatrix\n\ vTexCoordTransform.y = aTextureCoordMatrix.y;\n\ #endif\n\ if(vTexCoordTransform.y < -90000.0)\n\ {\n\ vTexMatrix2.z = -1.0;\n\ }\n\ getTextureMatrixFromZValue(floor(vTexCoordTransform.y), vTexMatrix2.x, vTexMatrix2.y, vTexMatrix2.z, vIsRGBA.y);\n\ vTexMatrix2.w = log2(uTexture1Width * vTexMatrix.z);\n\ #endif\n\ vec4 vertexColor = uFillForeColor;\n\ #ifdef VertexColor\n\ vertexColor *= aColor;\n\ #endif\n\ #ifdef VertexNormal\n\ vec3 normal = aNormal;\n\ #ifdef COMPRESS_NORMAL\n\ #ifdef MeshOPT_Compress\n\ normal.x = aNormal.x / 127.0;\n\ normal.y = aNormal.y / 127.0;\n\ normal.z = 1.0 - abs(normal.x) - abs(normal.y);\n\ normal = normalize(normal);\n\ #else\n\ normal = czm_octDecode(aNormal.xy, normal_rangeConstant).zxy;\n\ #endif\n\ #endif\n\ #endif\n\ #ifdef InstanceBim\n\ mat4 worldMatrix;\n\ worldMatrix[0] = uv2;\n\ worldMatrix[1] = uv3;\n\ worldMatrix[2] = uv4;\n\ worldMatrix[3] = vec4(0, 0, 0, 1);\n\ vertexPos = vec4(vertexPos.xyz,1.0) * worldMatrix;\n\ vertexColor *= secondary_colour;\n\ #endif\n\ #ifdef InstancePipe\n\ mat4 worldMatrix;\n\ mat4 worldMatrix0;\n\ mat4 worldMatrix1;\n\ vec4 worldPos0;\n\ vec4 worldPos1;\n\ worldMatrix0[0] = uv1;\n\ worldMatrix0[1] = uv2;\n\ worldMatrix0[2] = uv3;\n\ worldMatrix0[3] = vec4( 0.0, 0.0, 0.0, 1.0 );\n\ worldMatrix1[0] = uv4;\n\ worldMatrix1[1] = uv5;\n\ worldMatrix1[2] = uv6;\n\ worldMatrix1[3] = vec4( 0.0, 0.0, 0.0, 1.0 );\n\ vec4 realVertex = vec4(vertexPos.xyz, 1.0);\n\ realVertex.x = realVertex.x * uv7.z;\n\ worldPos0 = realVertex * worldMatrix0;\n\ worldPos1 = realVertex * worldMatrix1;\n\ vertexColor *= secondary_colour;\n\ #ifdef TexCoord\n\ if(aTexCoord0.y > 0.5)\n\ {\n\ vec4 tex4Vec = uTexMatrix * vec4(uv7.y, aTexCoord0.x, 0.0, 1.0);\n\ vTexCoord.xy = tex4Vec.xy;\n\ vertexPos = worldPos1;\n\ worldMatrix = worldMatrix1;\n\ }\n\ else\n\ {\n\ vec4 tex4Vec = uTexMatrix * vec4(uv7.x, aTexCoord0.x, 0.0, 1.0);\n\ vTexCoord.xy = tex4Vec.xy;\n\ vertexPos = worldPos0;\n\ worldMatrix = worldMatrix0;\n\ }\n\ #endif\n\ #ifdef VertexNormal\n\ normal.x = normal.x * uv7.z;\n\ #endif\n\ #endif\n\ #ifdef Instance\n\ float index = instanceId;\n\ #else\n\ float index = batchId;\n\ #endif\n\ vec4 operationType = batchTable_operation(index);\n\ operation(operationType, vec4(1.0), uSelectedColor, vertexColor);\n\ vSecondColor = batchTable_pickColor(index);\n\ vec4 positionMC = vec4(vertexPos.xyz, 1.0);\n\ vColor = vertexColor;\n\ #ifdef VertexNormal\n\ vNormalEC = czm_normal * normal;\n\ #endif\n\ vPositionMC = positionMC;\n\ vPositionEC = (czm_modelView * positionMC).xyz;\n\ gl_Position = czm_modelViewProjection * vec4(vertexPos.xyz, 1.0);\n\ }\n\ "; //This file is automatically rebuilt by the Cesium build process. var S3MTilesFS = "#ifdef GL_OES_standard_derivatives\n\ #extension GL_OES_standard_derivatives : enable\n\ #endif\n\ #ifdef GL_EXT_shader_texture_lod\n\ #extension GL_EXT_shader_texture_lod : enable\n\ #endif\n\ uniform vec4 uDiffuseColor;\n\ #ifdef TexCoord\n\ varying vec4 vTexCoord;\n\ #ifdef COMPUTE_TEXCOORD\n\ uniform sampler2D uTexture;\n\ uniform float uTexture0Width;\n\ varying vec4 vTexCoordTransform;\n\ varying vec4 vTexMatrix;\n\ varying vec2 vIsRGBA;\n\ #endif\n\ #endif\n\ varying vec4 vColor;\n\ varying vec4 vSecondColor;\n\ varying vec4 vPositionMC;\n\ varying vec3 vPositionEC;\n\ #ifdef VertexNormal\n\ varying vec3 vNormalEC;\n\ #endif\n\ #ifdef TexCoord2\n\ uniform sampler2D uTexture2;\n\ uniform float uTexture1Width;\n\ varying vec4 vTexMatrix2;\n\ #endif\n\ #ifdef COMPUTE_TEXCOORD\n\ void calculateMipLevel(in vec2 inTexCoord, in float vecTile, in float fMaxMip, inout float mipLevel)\n\ {\n\ vec2 dx = dFdx(inTexCoord * vecTile);\n\ vec2 dy = dFdy(inTexCoord * vecTile);\n\ float dotX = dot(dx, dx);\n\ float dotY = dot(dy, dy);\n\ float dMax = max(dotX, dotY);\n\ float dMin = min(dotX, dotY);\n\ float offset = (dMax - dMin) / (dMax + dMin);\n\ offset = clamp(offset, 0.0, 1.0);\n\ float d = dMax * (1.0 - offset) + dMin * offset;\n\ mipLevel = 0.5 * log2(d);\n\ mipLevel = clamp(mipLevel, 0.0, fMaxMip - 1.62);\n\ }\n\ void calculateTexCoord(in vec3 inTexCoord, in float scale, in float XTran, in float YTran, in float fTile, in float mipLevel, inout vec2 outTexCoord)\n\ {\n\ if(inTexCoord.z < -9000.0)\n\ {\n\ outTexCoord = inTexCoord.xy;\n\ }\n\ else\n\ {\n\ vec2 fTexCoord = fract(inTexCoord.xy);\n\ float offset = 1.0 * pow(2.0, mipLevel) / fTile;\n\ fTexCoord = clamp(fTexCoord, offset, 1.0 - offset);\n\ outTexCoord.x = (fTexCoord.x + XTran) * scale;\n\ outTexCoord.y = (fTexCoord.y + YTran) * scale;\n\ }\n\ }\n\ vec4 getTexColorForS3M(sampler2D curTexture, vec3 oriTexCoord, float texTileWidth, float fMaxMipLev, float fTexCoordScale, vec2 vecTexCoordTranslate, float isRGBA)\n\ {\n\ vec4 color = vec4(1.0);\n\ float mipLevel = 0.0;\n\ #ifdef GL_OES_standard_derivatives\n\ calculateMipLevel(oriTexCoord.xy, texTileWidth, fMaxMipLev, mipLevel);\n\ #endif\n\ vec2 realTexCoord;\n\ calculateTexCoord(oriTexCoord, fTexCoordScale, vecTexCoordTranslate.x, vecTexCoordTranslate.y, texTileWidth, mipLevel, realTexCoord);\n\ if(isRGBA > 0.5)\n\ {\n\ vec2 rgbTexCoord;\n\ rgbTexCoord.x = (realTexCoord.x + vecTexCoordTranslate.x * fTexCoordScale) * 0.5;\n\ rgbTexCoord.y = (realTexCoord.y + vecTexCoordTranslate.y * fTexCoordScale) * 0.5;\n\ color = texture2D(curTexture, rgbTexCoord.xy, -10.0);\n\ vec2 vecAlphaTexCoord;\n\ vecAlphaTexCoord.x = rgbTexCoord.x;\n\ vecAlphaTexCoord.y = rgbTexCoord.y + fTexCoordScale * 0.5;\n\ color.a = texture2D(curTexture, vecAlphaTexCoord.xy, -10.0).r;\n\ }\n\ else\n\ {\n\ if(oriTexCoord.z < -9000.0)\n\ {\n\ color = texture2D(curTexture, realTexCoord.xy);\n\ }\n\ else\n\ {\n\ #ifdef GL_EXT_shader_texture_lod\n\ color = texture2DLodEXT(curTexture, realTexCoord.xy, mipLevel);\n\ #else\n\ color = texture2D(curTexture, realTexCoord.xy, mipLevel);\n\ #endif\n\ }\n\ }\n\ return color;\n\ }\n\ vec4 getTextureColor()\n\ {\n\ if(vTexMatrix.z < 0.0)\n\ {\n\ return vec4(1.0);\n\ }\n\ float texTileWidth0 = vTexMatrix.z * uTexture0Width;\n\ vec3 realTexCoord = vec3(vTexCoord.xy, vTexCoordTransform.x);\n\ vec4 FColor = getTexColorForS3M(uTexture, realTexCoord, texTileWidth0, vTexMatrix.w, vTexMatrix.z, vTexMatrix.xy, vIsRGBA.x);\n\ #ifdef TexCoord2\n\ float texTileWidth1 = vTexMatrix2.z * uTexture1Width;\n\ realTexCoord = vec3(vTexCoord.zw, vTexCoordTransform.y);\n\ vec4 SColor = getTexColorForS3M(uTexture2, realTexCoord, texTileWidth1, vTexMatrix2.w, vTexMatrix2.z, vTexMatrix2.xy, vIsRGBA.y);\n\ SColor.r = clamp(SColor.r, 0.0, 1.0);\n\ SColor.g = clamp(SColor.g, 0.0, 1.0);\n\ SColor.b = clamp(SColor.b, 0.0, 1.0);\n\ return FColor * SColor;\n\ #else\n\ return FColor;\n\ #endif\n\ }\n\ #endif\n\ vec4 SRGBtoLINEAR4(vec4 srgbIn)\n\ {\n\ #ifndef HDR\n\ vec3 linearOut = pow(srgbIn.rgb, vec3(2.2));\n\ return vec4(linearOut, srgbIn.a);\n\ #else\n\ return srgbIn;\n\ #endif\n\ }\n\ vec3 LINEARtoSRGB(vec3 linearIn)\n\ {\n\ #ifndef HDR\n\ return pow(linearIn, vec3(1.0/2.2));\n\ #else\n\ return linearIn;\n\ #endif\n\ }\n\ vec3 applyTonemapping(vec3 linearIn)\n\ {\n\ #ifndef HDR\n\ return czm_acesTonemapping(linearIn);\n\ #else\n\ return linearIn;\n\ #endif\n\ }\n\ vec3 computeNormal(in vec3 oriVertex)\n\ {\n\ vec3 normal = cross(vec3(dFdx(oriVertex.x), dFdx(oriVertex.y), dFdx(oriVertex.z)), vec3(dFdy(oriVertex.x), dFdy(oriVertex.y), dFdy(oriVertex.z)));\n\ normal = normalize(normal);\n\ return normal;\n\ }\n\ void main()\n\ {\n\ if(vColor.a < 0.1)\n\ {\n\ discard;\n\ }\n\ vec4 baseColorWithAlpha = vColor;\n\ #ifdef COMPUTE_TEXCOORD\n\ baseColorWithAlpha *= SRGBtoLINEAR4(getTextureColor());\n\ #endif\n\ if(baseColorWithAlpha.a < 0.1)\n\ {\n\ discard;\n\ }\n\ vec3 normal = vec3(0.0);\n\ #ifdef VertexNormal\n\ normal = normalize(vNormalEC);\n\ #endif\n\ normal = length(normal) > 0.1 ? normal : computeNormal(vPositionMC.xyz);\n\ vec3 color = baseColorWithAlpha.rgb;\n\ vec3 dirVectorEC = normalize(czm_lightDirectionEC);\n\ float dotProduct = dot( normal, dirVectorEC );\n\ float dirDiffuseWeight = max( dotProduct, 0.0 );\n\ dirDiffuseWeight = dirDiffuseWeight * 0.5 + 0.5;\n\ color += color * uDiffuseColor.rgb * dirDiffuseWeight;\n\ #ifdef TexCoord\n\ color = LINEARtoSRGB(color);\n\ #endif\n\ gl_FragColor = vec4(color, baseColorWithAlpha.a);\n\ }\n\ "; function S3MCreateVertexJob(){ this.context = undefined; this.model = undefined; this.index = undefined; } S3MCreateVertexJob.prototype.set = function(context, model, index) { this.context = context; this.model = model; this.index = index; }; S3MCreateVertexJob.prototype.execute = function(){ let context = this.context; let index = this.index; let vertexPackage = this.model.vertexPackage; let attr = vertexPackage.vertexAttributes[index]; if(!Cesium.defined(attr)){ throw new Cesium.DeveloperError('attribute is null'); } if(vertexPackage.instanceIndex !== -1 && !Cesium.defined(this.model.instanceBuffer)){ if(!Cesium.defined(vertexPackage.instanceBuffer)){ throw new Cesium.DeveloperError('instance buffer is null'); } this.model.instanceBuffer = Cesium.Buffer.createVertexBuffer({ context : context, typedArray : vertexPackage.instanceBuffer, usage : Cesium.BufferUsage.STATIC_DRAW }); } if(attr.instanceDivisor === 1 && !Cesium.defined(attr.typedArray)){ attr.vertexBuffer = this.model.instanceBuffer; return ; } if(!Cesium.defined(attr.vertexBuffer)){ attr.vertexBuffer = Cesium.Buffer.createVertexBuffer({ context : context, typedArray : attr.typedArray, usage : Cesium.BufferUsage.STATIC_DRAW }); attr.typedArray = null; delete attr.typedArray; } }; function S3MCreateIndexBufferJob(){ this.model = undefined; this.context = undefined; this.index = 0; } S3MCreateIndexBufferJob.prototype.set = function(context, model, index) { this.model = model; this.context = context; this.index = index; }; S3MCreateIndexBufferJob.prototype.execute = function(){ let context = this.context; let indexPackage = this.model.arrIndexPackage[this.index]; let verticesCount = this.model.vertexPackage.verticesCount; if(!Cesium.defined(indexPackage)){ throw new Cesium.DeveloperError('index package is null'); } if(Cesium.defined(indexPackage.indexBuffer)){ return ; } if(!Cesium.defined(indexPackage.indicesTypedArray)){ throw new Cesium.DeveloperError('index buffer is null'); } let indexDataType = Cesium.IndexDatatype.UNSIGNED_SHORT; if((indexPackage.indexType === 1 || verticesCount >= Cesium.Math.SIXTY_FOUR_KILOBYTES) && context.elementIndexUint) { indexDataType = Cesium.IndexDatatype.UNSIGNED_INT; } if(!Cesium.defined(indexPackage.indexBuffer)){ indexPackage.indexBuffer = Cesium.Buffer.createIndexBuffer({ context : context, typedArray : indexPackage.indicesTypedArray, usage : Cesium.BufferUsage.STATIC_DRAW, indexDatatype : indexDataType }); } indexPackage.indicesTypedArray = null; delete indexPackage.indicesTypedArray; }; const ProgramDefines = { VertexNormal : 'VertexNormal', VertexColor : 'VertexColor', TexCoord : 'TexCoord', TexCoord2 : 'TexCoord2', Instance : 'Instance', COMPRESS_VERTEX : 'COMPRESS_VERTEX', COMPRESS_NORMAL : 'COMPRESS_NORMAL', COMPRESS_COLOR : 'COMPRESS_COLOR', COMPRESS_TEXCOORD : 'COMPRESS_TEXCOORD', UseLineColor : 'USE_LINECOLOR', InstanceBim : 'InstanceBim', InstancePipe : 'InstancePipe', COMPUTE_TEXCOORD : 'COMPUTE_TEXCOORD' }; var ProgramDefines$1 = Object.freeze(ProgramDefines); const VertexCompressOptions = { SVC_Vertex : 1, SVC_Normal : 2, SVC_VertexColor : 4, SVC_SecondColor : 8, SVC_TexutreCoord : 16, SVC_TexutreCoordIsW : 32 }; var VertexCompressOption = Object.freeze(VertexCompressOptions); const InstanceMode = { BIM : 17, PIPELINE : 29 }; var InstanceMode$1 = Object.freeze(InstanceMode); function S3MCreateShaderProgramJob(){ this.model = undefined; this.context = undefined; } S3MCreateShaderProgramJob.prototype.set = function(context, model) { this.model = model; this.context = context; }; function getExtension(gl, names) { let length = names.length; for (let i = 0; i < length; ++i) { let extension = gl.getExtension(names[i]); if (extension) { return extension; } } return undefined; } S3MCreateShaderProgramJob.prototype.execute = function(){ const context = this.context; const model = this.model; const layer = model.layer; const vs = model.vs; const fs = model.fs; const attributeLocations = model.attributeLocations; const material = model.material; const vertexPackage = model.vertexPackage; let vsNew = model.batchTable ? model.batchTable.getVertexShaderCallback()(vs) : vs; if(context.texturelod === undefined){ context.texturelod = Cesium.defaultValue(getExtension(context._gl, ['EXT_shader_texture_lod']), false); } let vp = new Cesium.ShaderSource({ sources : [vsNew] }); let fp = new Cesium.ShaderSource({ sources : [fs] }); if(Cesium.defined(attributeLocations['aNormal'])) { vp.defines.push(ProgramDefines$1.VertexNormal); fp.defines.push(ProgramDefines$1.VertexNormal); } if(Cesium.defined(attributeLocations['aColor'])) { vp.defines.push(ProgramDefines$1.VertexColor); } if(material && material.textures.length > 0) { vp.defines.push(ProgramDefines$1.COMPUTE_TEXCOORD); fp.defines.push(ProgramDefines$1.COMPUTE_TEXCOORD); } if(material && material.textures.length === 2) { vp.defines.push(ProgramDefines$1.TexCoord2); fp.defines.push(ProgramDefines$1.TexCoord2); } if(Cesium.defined(attributeLocations['aTexCoord0'])) { vp.defines.push('TexCoord'); fp.defines.push('TexCoord'); } if(vertexPackage.instanceIndex > -1){ vp.defines.push(ProgramDefines$1.Instance); } if(vertexPackage.instanceMode === InstanceMode$1.BIM){ vp.defines.push(ProgramDefines$1.InstanceBim); } if(vertexPackage.instanceMode === InstanceMode$1.PIPELINE){ vp.defines.push(ProgramDefines$1.InstancePipe); } if(Cesium.defined(vertexPackage.compressOptions)){ let compressOptions = vertexPackage.compressOptions; if((compressOptions & VertexCompressOption.SVC_Vertex) === VertexCompressOption.SVC_Vertex){ vp.defines.push(ProgramDefines$1.COMPRESS_VERTEX); } if((compressOptions & VertexCompressOption.SVC_Normal) === VertexCompressOption.SVC_Normal){ vp.defines.push(ProgramDefines$1.COMPRESS_NORMAL); } if((compressOptions & VertexCompressOption.SVC_VertexColor) === VertexCompressOption.SVC_VertexColor){ vp.defines.push(ProgramDefines$1.COMPRESS_COLOR); } if((compressOptions & VertexCompressOption.SVC_TexutreCoord) === VertexCompressOption.SVC_TexutreCoord){ vp.defines.push(ProgramDefines$1.COMPRESS_TEXCOORD); } } if(Cesium.defined(model.arrIndexPackage) && model.arrIndexPackage.length > 0 && model.arrIndexPackage[0].primitiveType === 2){ fp.defines.push(ProgramDefines$1.UseLineColor); } if(Cesium.defined(vertexPackage.customVertexAttribute) && Cesium.defined(vertexPackage.customVertexAttribute['TextureCoordMatrix'])){ vp.defines.push('USE_TextureCoordMatrix'); } if(Cesium.defined(vertexPackage.customVertexAttribute) && Cesium.defined(vertexPackage.customVertexAttribute['VertexWeight'])){ vp.defines.push('USE_VertexWeight'); } if(layer._vertexCompressionType === 'MESHOPT') { vp.defines.push('MeshOPT_Compress'); } model.shaderProgram = Cesium.ShaderProgram.fromCache({ context : context, vertexShaderSource : vp, fragmentShaderSource : fp, attributeLocations : attributeLocations }); }; function RenderEntity(options) { this.layer = options.layer; this.vertexPackage = options.vertexPackage; this.arrIndexPackage = options.arrIndexPackage; this.vertexBufferToCreate = new Cesium.Queue(); this.indexBufferToCreate = new Cesium.Queue(); this.shaderProgramToCreate = new Cesium.Queue(); let i, j; for (i = 0, j = this.vertexPackage.vertexAttributes.length; i < j; i++) { this.vertexBufferToCreate.enqueue(i); } for (i = 0, j = this.arrIndexPackage.length; i < j; i++) { this.indexBufferToCreate.enqueue(i); } this.shaderProgramToCreate.enqueue(0); this.boundingVolume = options.boundingVolume; this.material = Cesium.defaultValue(options.material, new MaterialPass()); this.geoName = options.geoName; this.modelMatrix = options.modelMatrix; this.geoMatrix = options.geoMatrix; this.invGeoMatrix = Cesium.Matrix4.inverse(this.geoMatrix, new Cesium.Matrix4()); this.instanceCount = options.vertexPackage.instanceCount; this.attributeLocations = options.vertexPackage.attrLocation; this.shaderProgram = undefined; this.vertexArray = undefined; this.colorCommand = undefined; this.pickInfo = Cesium.defaultValue(options.pickInfo, {}); this.selectionInfoMap = new Cesium.AssociativeArray(); this.batchTable = undefined; this.batchTableDirty = false; this.idsOperationMap = new Cesium.AssociativeArray(); this.pickColorIdentifier = 'vSecondColor'; this.createBoundingBoxForInstance(); this.ready = false; } const _vertexBufferJob = new S3MCreateVertexJob(); const _indexBufferJob = new S3MCreateIndexBufferJob(); const _shaderProgramJob = new S3MCreateShaderProgramJob(); function createVertexBuffers(renderEntity, frameState) { let context = renderEntity.layer.context; let queue = renderEntity.vertexBufferToCreate; while (queue.length) { let index = queue.peek(); _vertexBufferJob.set(context, renderEntity, index); if (!frameState.jobScheduler.execute(_vertexBufferJob, Cesium.JobType.BUFFER)) { break; } queue.dequeue(); } } function createIndexBuffers(renderEntity, frameState) { let context = renderEntity.layer.context; let queue = renderEntity.indexBufferToCreate; while (queue.length) { let index = queue.peek(); _indexBufferJob.set(context, renderEntity, index); if (!frameState.jobScheduler.execute(_indexBufferJob, Cesium.JobType.BUFFER)) { break; } queue.dequeue(); } } function createShaderProgram(renderEntity, frameState) { let context = renderEntity.layer.context; let queue = renderEntity.shaderProgramToCreate; while (queue.length) { queue.peek(); _shaderProgramJob.set(context, renderEntity); if (!frameState.jobScheduler.execute(_shaderProgramJob, Cesium.JobType.PROGRAM)) { break; } queue.dequeue(); } } function createBatchTable(renderEntity, frameState) { if (Cesium.defined(renderEntity.batchTable) || !renderEntity.pickInfo) { return; } const context = renderEntity.layer.context; let attributes = []; attributes.push({ functionName: 'batchTable_operation', componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE, componentsPerAttribute: 4 }, { functionName: 'batchTable_pickColor', componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE, componentsPerAttribute: 4, normalize: true }); let pickInfo = renderEntity.pickInfo; let pickIds = Object.keys(pickInfo); let numberOfInstances = renderEntity.instanceCount > 0 ? renderEntity.instanceCount : pickIds.length; renderEntity.batchTable = new Cesium.BatchTable(context, attributes, numberOfInstances); } RenderEntity.prototype.createBuffers = function (frameState) { createVertexBuffers(this, frameState); createIndexBuffers(this, frameState); }; RenderEntity.prototype.createShaderProgram = function (frameState) { createShaderProgram(this, frameState); }; RenderEntity.prototype.createBatchTable = function (frameState) { createBatchTable(this); }; RenderEntity.prototype.createBoundingBoxForInstance = function () { let scratchPntCenter = new Cesium.Cartesian3(); const vertexPackage = this.vertexPackage; if (!Cesium.defined(vertexPackage) || vertexPackage.instanceIndex === -1 || !Cesium.defined(vertexPackage.instanceBounds)) { return; } let instanceBounds = vertexPackage.instanceBounds; let pntLU = new Cesium.Cartesian3(instanceBounds[0], instanceBounds[1], instanceBounds[2]); let pntRD = new Cesium.Cartesian3(instanceBounds[3], instanceBounds[4], instanceBounds[5]); let pntCenter = Cesium.Cartesian3.lerp(pntLU, pntRD, 0.5, scratchPntCenter); let dRadius = Cesium.Cartesian3.distance(pntCenter, pntLU); let vecCenter = new Cesium.Cartesian3(); Cesium.Matrix4.multiplyByPoint(this.modelMatrix, pntCenter, vecCenter); this.boundingVolume.center = vecCenter; this.boundingVolume.radius = dRadius; vertexPackage.instanceBounds = undefined; }; RenderEntity.prototype.initLayerSetting = function (layer) { if (Object.keys(layer._objsOperationList).length > 0) { this.updateObjsOperation(layer._objsOperationList); } }; RenderEntity.prototype.createPickIds = function () { let cartesian4Scratch = new Cesium.Cartesian4(); const layer = this.layer; const context = layer.context; const pickInfo = this.pickInfo; if (!Cesium.defined(pickInfo)) { return; } for (let id in pickInfo) { if (!pickInfo.hasOwnProperty(id)) { continue; } this.selectionInfoMap.set(id, pickInfo[id]); } let batchTable = this.batchTable; let selectionInfoMap = this.selectionInfoMap; let hash = selectionInfoMap._hash; for (let id in hash) { if (hash.hasOwnProperty(id)) { let selInfo = selectionInfoMap.get(id); let pickId; if (!Cesium.defined(pickId)) { pickId = context.createPickId({ primitive: layer, id: id }); } let pickColor = pickId.color; cartesian4Scratch.x = Cesium.Color.floatToByte(pickColor.red); cartesian4Scratch.y = Cesium.Color.floatToByte(pickColor.green); cartesian4Scratch.z = Cesium.Color.floatToByte(pickColor.blue); cartesian4Scratch.w = Cesium.Color.floatToByte(pickColor.alpha); let instanceIds = selInfo.instanceIds; if (this.instanceCount > 0) { instanceIds.map(function (instanceId) { batchTable.setBatchedAttribute(instanceId, 1, cartesian4Scratch); }); } else { let batchId = selInfo[0].batchId; batchTable.setBatchedAttribute(batchId, 1, cartesian4Scratch); } } } this.pickInfo = undefined; }; RenderEntity.prototype.updateBatchTableAttributes = function () { let ro = this; let idsOperationMap = this.idsOperationMap; for (let i = 0, j = idsOperationMap.length; i < j; i++) { let obj = idsOperationMap.values[i]; if (!obj.dirty) { continue; } obj.dirty = false; if (this.instanceCount > 0) { if (Array.isArray(obj.instanceIds)) { obj.instanceIds.map(function (instanceId) { ro.batchTable.setBatchedAttribute(instanceId, 0, obj.operationValue); }); } } else { if (Cesium.defined(obj.batchId)) { this.batchTable.setBatchedAttribute(obj.batchId, 0, obj.operationValue); } } } }; RenderEntity.prototype.updateObjsOperation = function (ids) { if (!this.ready || this.selectionInfoMap.length < 1) { return; } let selectValues = this.selectionInfoMap._hash; for (let id in selectValues) { if (!selectValues.hasOwnProperty(id)) { continue; } let operationType = ids[id]; if (!Cesium.defined(operationType)) { continue; } let selectInfo = selectValues[id][0]; let batchId = selectInfo.batchId; let instanceIds = selectInfo.instanceIds; let obj = this.idsOperationMap.get(id); if (!Cesium.defined(obj)) { obj = { batchId: batchId, instanceIds: instanceIds, operationValue: new Cesium.Cartesian4(), dirty: true }; } obj.dirty = true; obj.operationValue.x = (obj.operationValue.x & 0x01) | operationType; this.idsOperationMap.set(id, obj); this.batchTableDirty = true; } }; function S3MCacheFileRenderEntity(options) { RenderEntity.call(this, options); this.vs = S3MTilesVS; this.fs = S3MTilesFS; this.useLineColor = false; } S3MCacheFileRenderEntity.prototype = Object.create( RenderEntity.prototype ); S3MCacheFileRenderEntity.prototype.constructor = RenderEntity; function getOpaqueRenderState$1() { return Cesium.RenderState.fromCache({ cull : { enabled : false }, depthTest : { enabled : true, func : Cesium.DepthFunction.LESS_OR_EQUAL }, blending : Cesium.BlendingState.ALPHA_BLEND }); } function getTransparentRenderState() { return Cesium.RenderState.fromCache({ cull : { enabled : true }, depthTest : { enabled : true, func : Cesium.DepthFunction.LESS_OR_EQUAL }, blending : Cesium.BlendingState.ALPHA_BLEND }); } function getUniformMap$1(material, layer, ro) { const uniformMap = { uGeoMatrix : function() { return ro.geoMatrix; }, uTexMatrix : function() { return material.texMatrix; }, uFillForeColor : function(){ if(ro.useLineColor){ return layer.style3D.lineColor; } return layer.style3D.fillForeColor; }, uInverseGeoMatrix : function() { return ro.invGeoMatrix; }, uTexture : function() { return material.textures[0]; }, uTexture2 : function() { return material.textures[1]; }, uTexture0Width : function(){ return material.textures[0].width; }, uTexture1Width : function(){ return material.textures[1].width; }, uDiffuseColor : function() { return material.diffuseColor; }, uSelectedColor : function() { return layer._selectedColor; } }; const vertexPackage = ro.vertexPackage; const nCompressOptions = vertexPackage.compressOptions; if((nCompressOptions & VertexCompressOption.SVC_Vertex) === VertexCompressOption.SVC_Vertex){ uniformMap['decode_position_min'] = function() { return vertexPackage.minVerticesValue; }; uniformMap['decode_position_normConstant'] = function() { return vertexPackage.vertCompressConstant; }; } if((nCompressOptions & VertexCompressOption.SVC_Normal) === VertexCompressOption.SVC_Normal){ uniformMap['normal_rangeConstant'] = function() { return vertexPackage.normalRangeConstant; }; } if((nCompressOptions & VertexCompressOption.SVC_TexutreCoord) === VertexCompressOption.SVC_TexutreCoord){ if(vertexPackage.texCoordCompressConstant.length > 0){ uniformMap['decode_texCoord0_min'] = function() { return vertexPackage.minTexCoordValue[0]; }; uniformMap['decode_texCoord0_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[0]; }; uniformMap['decode_texCoord0_vNormConstant'] = function() { return vertexPackage.texCoordCompressConstant[0]; }; } if(vertexPackage.texCoordCompressConstant.length > 1){ uniformMap['decode_texCoord1_min'] = function() { return vertexPackage.minTexCoordValue[1]; }; uniformMap['decode_texCoord1_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[1]; }; uniformMap['decode_texCoord1_vNormConstant'] = function() { return vertexPackage.texCoordCompressConstant[1]; }; } if(vertexPackage.texCoordCompressConstant.length > 2){ uniformMap['decode_texCoord2_min'] = function() { return vertexPackage.minTexCoordValue[2]; }; uniformMap['decode_texCoord2_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[2]; }; } if(vertexPackage.texCoordCompressConstant.length > 3){ uniformMap['decode_texCoord3_min'] = function() { return vertexPackage.minTexCoordValue[3]; }; uniformMap['decode_texCoord3_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[3]; }; } if(vertexPackage.texCoordCompressConstant.length > 4){ uniformMap['decode_texCoord4_min'] = function() { return vertexPackage.minTexCoordValue[4]; }; uniformMap['decode_texCoord4_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[4]; }; } if(vertexPackage.texCoordCompressConstant.length > 5){ uniformMap['decode_texCoord5_min'] = function() { return vertexPackage.minTexCoordValue[5]; }; uniformMap['decode_texCoord5_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[5]; }; } if(vertexPackage.texCoordCompressConstant.length > 6){ uniformMap['decode_texCoord6_min'] = function() { return vertexPackage.minTexCoordValue[6]; }; uniformMap['decode_texCoord6_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[6]; }; } if(vertexPackage.texCoordCompressConstant.length > 7){ uniformMap['decode_texCoord7_min'] = function() { return vertexPackage.minTexCoordValue[7]; }; uniformMap['decode_texCoord7_normConstant'] = function() { return vertexPackage.texCoordCompressConstant[7]; }; } } return uniformMap; } S3MCacheFileRenderEntity.prototype.createCommand = function() { if(Cesium.defined(this.colorCommand) || this.vertexBufferToCreate.length !== 0 || this.indexBufferToCreate.length !== 0 || this.shaderProgramToCreate.length !== 0) { return ; } let layer = this.layer; let context = layer.context; let vertexPackage = this.vertexPackage; let arrIndexPackage = this.arrIndexPackage; let attributes = vertexPackage.vertexAttributes; if(arrIndexPackage.length < 1) { return ; } let indexPackage = arrIndexPackage[0]; let material = this.material; this.vertexArray = new Cesium.VertexArray({ context : context, attributes : attributes, indexBuffer : indexPackage.indexBuffer }); let primitiveType = Cesium.PrimitiveType.TRIANGLES; switch(indexPackage.primitiveType){ case 1 : primitiveType = Cesium.PrimitiveType.POINTS; break; case 2 : primitiveType = Cesium.PrimitiveType.LINES; break; case 4 : primitiveType = Cesium.PrimitiveType.TRIANGLES; break; } this.useLineColor = primitiveType === Cesium.PrimitiveType.LINES; this.colorCommand = new Cesium.DrawCommand({ primitiveType : primitiveType, modelMatrix : this.modelMatrix, boundingVolume : Cesium.BoundingSphere.clone(this.boundingVolume), pickId : this.pickColorIdentifier, vertexArray : this.vertexArray, shaderProgram : this.shaderProgram, pass : material.bTransparentSorting ? Cesium.Pass.TRANSLUCENT : Cesium.Pass.OPAQUE, renderState : material.bTransparentSorting ? getTransparentRenderState() : getOpaqueRenderState$1(), instanceCount : vertexPackage.instanceCount }); let uniformMap = getUniformMap$1(material, layer, this); if(this.batchTable){ uniformMap = this.batchTable.getUniformMapCallback()(uniformMap); } this.colorCommand.uniformMap = uniformMap; this.vertexPackage = undefined; this.arrIndexPackage = undefined; this.vs = undefined; this.fs = undefined; this.ready = true; }; S3MCacheFileRenderEntity.prototype.update = function(frameState, layer) { if(!this.ready) { this.createBatchTable(frameState); this.createPickIds(); this.createBuffers(frameState); this.createShaderProgram(frameState); this.createCommand(frameState); this.initLayerSetting(layer); return ; } if(this.batchTableDirty){ this.updateBatchTableAttributes(); this.batchTableDirty = false; } if(this.batchTable){ this.batchTable.update(frameState); } frameState.commandList.push(this.colorCommand); }; S3MCacheFileRenderEntity.prototype.isDestroyed = function() { return false; }; S3MCacheFileRenderEntity.prototype.destroy = function() { this.shaderProgram = this.shaderProgram && !this.shaderProgram.isDestroyed() && this.shaderProgram.destroy(); this.vertexArray = this.vertexArray && !this.vertexArray.isDestroyed() && this.vertexArray.destroy(); this.material = this.material && !this.material.isDestroyed() && this.material.destroy(); this.batchTable = this.batchTable && !this.batchTable.isDestroyed() && this.batchTable.destroy(); this.colorCommand = undefined; this.vertexPackage = null; this.arrIndexPackage = null; this.modelMatrix = undefined; this.pickInfo = undefined; this.selectionInfoMap = undefined; this.vs = undefined; this.fs = undefined; return Cesium.destroyObject(this); }; //This file is automatically rebuilt by the Cesium build process. var S3MTilesNoLightVS = "attribute vec4 aPosition;\n\ attribute vec4 aColor;\n\ #ifdef TexCoord\n\ attribute vec4 aTexCoord0;\n\ uniform float uTexture0Width;\n\ varying vec4 vTexCoord;\n\ varying vec4 vTexMatrix;\n\ varying vec4 vTexCoordTransform;\n\ #endif\n\ #ifdef VertexColor\n\ varying vec4 vColor;\n\ #endif\n\ const float SHIFT_LEFT8 = 256.0;\n\ const float SHIFT_RIGHT8 = 1.0 / 256.0;\n\ const float SHIFT_RIGHT4 = 1.0 / 16.0;\n\ const float SHIFT_LEFT4 = 16.0;\n\ void getTextureMatrixFromZValue(in float nZ, inout float XTran, inout float YTran, inout float scale)\n\ {\n\ if(nZ <= 0.0)\n\ {\n\ return;\n\ }\n\ float nDel8 = floor(nZ * SHIFT_RIGHT8);\n\ float nDel16 = floor(nDel8 * SHIFT_RIGHT8);\n\ float nDel20 = floor(nDel16 * SHIFT_RIGHT4);\n\ YTran = nZ - nDel8 * SHIFT_LEFT8;\n\ XTran = nDel8 - nDel16 * SHIFT_LEFT8;\n\ float nLevel = nDel16 - nDel20 * SHIFT_LEFT4;\n\ scale = 1.0 / pow(2.0, nLevel);\n\ }\n\ void main()\n\ {\n\ #ifdef TexCoord\n\ vTexCoord.xy = aTexCoord0.xy;\n\ vTexMatrix = vec4(0.0,0.0,1.0,0.0);\n\ vTexCoordTransform.x = aTexCoord0.z;\n\ if(vTexCoordTransform.x < -90000.0)\n\ {\n\ vTexMatrix.z = -1.0;\n\ }\n\ getTextureMatrixFromZValue(floor(vTexCoordTransform.x), vTexMatrix.x, vTexMatrix.y, vTexMatrix.z);\n\ vTexMatrix.w = log2(uTexture0Width * vTexMatrix.z);\n\ #endif\n\ vec4 vertexPos = aPosition;\n\ #ifdef VertexColor\n\ vColor = aColor;\n\ #endif\n\ gl_Position = czm_modelViewProjection * vec4(vertexPos.xyz, 1.0);\n\ }\n\ "; //This file is automatically rebuilt by the Cesium build process. var S3MTilesNoLightFS = "#ifdef GL_OES_standard_derivatives\n\ #extension GL_OES_standard_derivatives : enable\n\ #endif\n\ #ifdef GL_EXT_shader_texture_lod\n\ #extension GL_EXT_shader_texture_lod : enable\n\ #endif\n\ #ifdef TexCoord\n\ uniform sampler2D uTexture;\n\ uniform float uTexture0Width;\n\ varying vec4 vTexCoord;\n\ varying vec4 vTexCoordTransform;\n\ varying vec4 vTexMatrix;\n\ #endif\n\ #ifdef VertexColor\n\ varying vec4 vColor;\n\ #endif\n\ #ifdef TexCoord\n\ void calculateMipLevel(in vec2 inTexCoord, in float vecTile, in float fMaxMip, inout float mipLevel)\n\ {\n\ vec2 dx = dFdx(inTexCoord * vecTile);\n\ vec2 dy = dFdy(inTexCoord * vecTile);\n\ float dotX = dot(dx, dx);\n\ float dotY = dot(dy, dy);\n\ float dMax = max(dotX, dotY);\n\ float dMin = min(dotX, dotY);\n\ float offset = (dMax - dMin) / (dMax + dMin);\n\ offset = clamp(offset, 0.0, 1.0);\n\ float d = dMax * (1.0 - offset) + dMin * offset;\n\ mipLevel = 0.5 * log2(d);\n\ mipLevel = clamp(mipLevel, 0.0, fMaxMip - 1.62);\n\ }\n\ void calculateTexCoord(in vec3 inTexCoord, in float scale, in float XTran, in float YTran, in float fTile, in float mipLevel, inout vec2 outTexCoord)\n\ {\n\ if(inTexCoord.z < -9000.0)\n\ {\n\ outTexCoord = inTexCoord.xy;\n\ }\n\ else\n\ {\n\ vec2 fTexCoord = fract(inTexCoord.xy);\n\ float offset = 1.0 * pow(2.0, mipLevel) / fTile;\n\ fTexCoord = clamp(fTexCoord, offset, 1.0 - offset);\n\ outTexCoord.x = (fTexCoord.x + XTran) * scale;\n\ outTexCoord.y = (fTexCoord.y + YTran) * scale;\n\ }\n\ }\n\ vec4 getTexColorForS3M(sampler2D curTexture, vec3 oriTexCoord, float texTileWidth, float fMaxMipLev, float fTexCoordScale, vec2 vecTexCoordTranslate)\n\ {\n\ vec4 color = vec4(1.0);\n\ float mipLevel = 0.0;\n\ #ifdef GL_OES_standard_derivatives\n\ calculateMipLevel(oriTexCoord.xy, texTileWidth, fMaxMipLev, mipLevel);\n\ #endif\n\ vec2 realTexCoord;\n\ calculateTexCoord(oriTexCoord, fTexCoordScale, vecTexCoordTranslate.x, vecTexCoordTranslate.y, texTileWidth, mipLevel, realTexCoord);\n\ if(oriTexCoord.z < -9000.0)\n\ {\n\ color = texture2D(curTexture, realTexCoord.xy);\n\ }\n\ else\n\ {\n\ #ifdef GL_EXT_shader_texture_lod\n\ color = texture2DLodEXT(curTexture, realTexCoord.xy, mipLevel);\n\ #else\n\ color = texture2D(curTexture, realTexCoord.xy, mipLevel);\n\ #endif\n\ }\n\ return color;\n\ }\n\ vec4 getTextureColor()\n\ {\n\ if(vTexMatrix.z < 0.0)\n\ {\n\ return vec4(1.0);\n\ }\n\ float texTileWidth0 = vTexMatrix.z * uTexture0Width;\n\ vec3 realTexCoord = vec3(vTexCoord.xy, vTexCoordTransform.x);\n\ return getTexColorForS3M(uTexture, realTexCoord, texTileWidth0, vTexMatrix.w, vTexMatrix.z, vTexMatrix.xy);\n\ }\n\ #endif\n\ void main()\n\ {\n\ vec4 baseColorWithAlpha = vec4(1.0);\n\ #ifdef VertexColor\n\ vec4 baseColorWithAlpha = vColor;\n\ #endif\n\ #ifdef TexCoord\n\ baseColorWithAlpha *= getTextureColor();\n\ #endif\n\ gl_FragColor = baseColorWithAlpha;\n\ }\n\ "; function S3MObliqueRenderEntity(options) { RenderEntity.call(this, options); this.vs = S3MTilesNoLightVS; this.fs = S3MTilesNoLightFS; } S3MObliqueRenderEntity.prototype = Object.create( RenderEntity.prototype ); S3MObliqueRenderEntity.prototype.constructor = RenderEntity; function getOpaqueRenderState() { return Cesium.RenderState.fromCache({ cull : { enabled : true }, depthTest : { enabled : true, func : Cesium.DepthFunction.LESS_OR_EQUAL }, blending : Cesium.BlendingState.ALPHA_BLEND }); } function getUniformMap(material, layer, ro) { return { uGeoMatrix : function() { return ro.geoMatrix; }, uInverseGeoMatrix : function() { return ro.invGeoMatrix; }, uTexture : function() { return material.textures[0]; }, uTexture0Width : function(){ return material.textures[0].width; } }; } S3MObliqueRenderEntity.prototype.createCommand = function() { if(Cesium.defined(this.colorCommand) || this.vertexBufferToCreate.length !== 0 || this.indexBufferToCreate.length !== 0 || this.shaderProgramToCreate.length !== 0) { return ; } let layer = this.layer; let context = layer.context; let vertexPackage = this.vertexPackage; let arrIndexPackage = this.arrIndexPackage; let attributes = vertexPackage.vertexAttributes; if(arrIndexPackage.length < 1) { return ; } let indexPackage = arrIndexPackage[0]; let material = this.material; this.vertexArray = new Cesium.VertexArray({ context : context, attributes : attributes, indexBuffer : indexPackage.indexBuffer }); this.colorCommand = new Cesium.DrawCommand({ primitiveType : indexPackage.primitiveType, modelMatrix : this.modelMatrix, boundingVolume : Cesium.BoundingSphere.clone(this.boundingVolume), vertexArray : this.vertexArray, shaderProgram : this.shaderProgram, pass : material.bTransparentSorting ? Cesium.Pass.TRANSLUCENT : Cesium.Pass.OPAQUE, renderState : getOpaqueRenderState(), instanceCount : vertexPackage.instanceCount }); this.colorCommand.uniformMap = getUniformMap(material, layer, this); this.vertexPackage = undefined; this.arrIndexPackage = undefined; this.vs = undefined; this.fs = undefined; this.ready = true; }; S3MObliqueRenderEntity.prototype.update = function(frameState, layer) { if(!this.ready) { this.createBuffers(frameState); this.createShaderProgram(frameState); this.createCommand(frameState); this.initLayerSetting(layer); return ; } frameState.commandList.push(this.colorCommand); }; S3MObliqueRenderEntity.prototype.isDestroyed = function() { return false; }; S3MObliqueRenderEntity.prototype.destroy = function() { this.shaderProgram = this.shaderProgram && !this.shaderProgram.isDestroyed() && this.shaderProgram.destroy(); this.vertexArray = this.vertexArray && !this.vertexArray.isDestroyed() && this.vertexArray.destroy(); this.material = this.material && !this.material.isDestroyed() && this.material.destroy(); this.colorCommand = undefined; this.vertexPackage = null; this.arrIndexPackage = null; this.modelMatrix = undefined; this.pickInfo = undefined; this.selectionInfoMap = undefined; this.vs = undefined; this.fs = undefined; return Cesium.destroyObject(this); }; let S3MContentFactory = { 'OSGBFile' : function(options) { return new S3MObliqueRenderEntity(options); }, 'OSGBCacheFile' : function(options) { return new S3MCacheFileRenderEntity(options); } }; function S3MContentParser(){ } function parseMaterial(context, content, tile) { let materialTable = {}; let materials = content.materials.material; for(let i = 0,j = materials.length;i < j;i++){ let material = materials[i].material; let materialCode = material.id; let materialPass = new MaterialPass(); materialTable[materialCode] = materialPass; let ambient = material.ambient; materialPass.ambientColor = new Cesium.Color(ambient.r, ambient.g, ambient.b, ambient.a); let diffuse = material.diffuse; materialPass.diffuseColor = new Cesium.Color(diffuse.r, diffuse.g, diffuse.b, diffuse.a); let specular = material.specular; materialPass.specularColor = new Cesium.Color(specular.r, specular.g, specular.b, specular.a); materialPass.shininess = material.shininess; materialPass.bTransparentSorting = material.transparentsorting; let textureStates = material.textureunitstates; let len = textureStates.length; for(let k = 0;k < len;k++){ let textureState = textureStates[k].textureunitstate; let textureCode = textureState.id; let wrapS = textureState.addressmode.u === 0 ? Cesium.TextureWrap.REPEAT : Cesium.TextureWrap.CLAMP_TO_EDGE; let wrapT = textureState.addressmode.v === 0 ? Cesium.TextureWrap.REPEAT : Cesium.TextureWrap.CLAMP_TO_EDGE; materialPass.texMatrix = Cesium.Matrix4.unpack(textureState.texmodmatrix); let textureInfo = content.texturePackage[textureCode]; if(Cesium.defined(textureInfo) && textureInfo.arrayBufferView.byteLength > 0) { textureInfo.wrapS = wrapS; textureInfo.wrapT = wrapT; let keyword = tile.fileName + textureCode; let texture = context.textureCache.getTexture(keyword); if(!Cesium.defined(texture)){ if(Cesium.PixelFormat.isCompressedFormat(textureInfo.internalFormat)){ texture = new DDSTexture(context, textureCode, textureInfo); } else { let isPowerOfTwo = Cesium.Math.isPowerOfTwo(textureInfo.width) && Cesium.Math.isPowerOfTwo(textureInfo.height); texture = new Cesium.Texture({ context : context, source : { width : textureInfo.width, height : textureInfo.height, arrayBufferView : textureInfo.arrayBufferView }, sampler : new Cesium.Sampler({ minificationFilter : isPowerOfTwo ? context._gl.LINEAR_MIPMAP_LINEAR : context._gl.LINEAR, wrapS : wrapS, wrapT : wrapT }) }); if(isPowerOfTwo){ texture.generateMipmap(Cesium.MipmapHint.NICEST); } } context.textureCache.addTexture(keyword, texture); } materialPass.textures.push(texture); } } } return materialTable; } function calcBoundingVolumeForNormal(vertexPackage, modelMatrix){ let boundingSphere = new Cesium.BoundingSphere(); let v1 = new Cesium.Cartesian3(); let positionAttr = vertexPackage.vertexAttributes[0]; let dim = positionAttr.componentsPerAttribute; let isCompress = Cesium.defined(vertexPackage.compressOptions) && (vertexPackage.compressOptions & VertexCompressOption.SVC_Vertex) === VertexCompressOption.SVC_Vertex; let normConstant = 1.0; let minVertex; let vertexTypedArray; if(isCompress){ normConstant = vertexPackage.vertCompressConstant; minVertex = new Cesium.Cartesian3(vertexPackage.minVerticesValue.x, vertexPackage.minVerticesValue.y, vertexPackage.minVerticesValue.z); vertexTypedArray = new Uint16Array(positionAttr.typedArray.buffer, positionAttr.typedArray.byteOffset, positionAttr.typedArray.byteLength / 2); } else { vertexTypedArray = new Float32Array(positionAttr.typedArray.buffer, positionAttr.typedArray.byteOffset, positionAttr.typedArray.byteLength / 4); } let vertexArray = []; for(let t = 0; t < vertexPackage.verticesCount; t++){ Cesium.Cartesian3.fromArray(vertexTypedArray, dim * t, v1); if(isCompress){ v1 = Cesium.Cartesian3.multiplyByScalar(v1, normConstant, v1); v1 = Cesium.Cartesian3.add(v1, minVertex, v1); } vertexArray.push(Cesium.Cartesian3.clone(v1)); } Cesium.BoundingSphere.fromPoints(vertexArray, boundingSphere); Cesium.BoundingSphere.transform(boundingSphere, modelMatrix, boundingSphere); vertexArray.length = 0; return boundingSphere; } function calcBoundingVolumeForInstance(vertexPackage){ let scratchCenter = new Cesium.Cartesian3(); let boundingSphere = new Cesium.BoundingSphere(); let boundingsValues = vertexPackage.instanceBounds; if(!Cesium.defined(boundingsValues)){ return boundingSphere; } let pntLU = new Cesium.Cartesian3(boundingsValues[0], boundingsValues[1], boundingsValues[2]); let pntRD = new Cesium.Carteisan3(boundingsValues[3], boundingsValues[4], boundingsValues[5]); let center = new Cesium.Cartesian3.lerp(pntLU, pntRD, 0.5, scratchCenter); let radius = new Cesium.Cartesian3.distance(center, pntLU); boundingSphere.center = center; boundingSphere.radius = radius; return boundingSphere; } function calcBoundingVolume(vertexPackage, modelMatrix) { if(vertexPackage.instanceIndex > -1){ return calcBoundingVolumeForInstance(vertexPackage); } return calcBoundingVolumeForNormal(vertexPackage, modelMatrix); } function parseGeodes(layer, content, materialTable, pagelodNode, pagelod) { const scratchMatrix = new Cesium.Matrix3(); let geoMap = {}; let geodeList = pagelodNode.geodes; for(let i = 0,j = geodeList.length;i < j;i++){ let geodeNode = geodeList[i]; let geoMatrix = geodeNode.matrix; let modelMatrix = Cesium.Matrix4.multiply(layer.modelMatrix, geoMatrix, new Cesium.Matrix4()); let boundingVolume; if(Cesium.defined(pagelod.boundingVolume)) { if(pagelod.boundingVolume.sphere){ boundingVolume = new Cesium.BoundingSphere(pagelod.boundingVolume.sphere.center, pagelod.boundingVolume.sphere.radius); Cesium.BoundingSphere.transform(boundingVolume, layer.modelMatrix, boundingVolume); } else if(pagelod.boundingVolume.box){ const box = pagelod.boundingVolume.box; let center = new Cesium.Cartesian3(box.center.x, box.center.y, box.center.z); let vx = new Cesium.Cartesian4(box.xExtent.x, box.xExtent.y, box.xExtent.z, 0); let vy = new Cesium.Cartesian4(box.yExtent.x, box.yExtent.y, box.yExtent.z, 0); let vz = new Cesium.Cartesian4(box.zExtent.x, box.zExtent.y, box.zExtent.z, 0); let halfAxes = new Cesium.Matrix3(); Cesium.Matrix3.setColumn(halfAxes, 0, vx, halfAxes); Cesium.Matrix3.setColumn(halfAxes, 1, vy, halfAxes); Cesium.Matrix3.setColumn(halfAxes, 2, vz, halfAxes); center = Cesium.Matrix4.multiplyByPoint(layer.modelMatrix, center, center); const rotationScale = Cesium.Matrix4.getMatrix3(layer.modelMatrix, scratchMatrix); halfAxes = Cesium.Matrix3.multiply(rotationScale, halfAxes, halfAxes); boundingVolume = new Cesium.OrientedBoundingBox(center, halfAxes); } } let skeletonNames = geodeNode.skeletonNames; for(let m = 0,n = skeletonNames.length;m < n; m++){ let geoName = skeletonNames[m]; let geoPackage = content.geoPackage[geoName]; let vertexPackage = geoPackage.vertexPackage; let arrIndexPackage = geoPackage.arrIndexPackage; let pickInfo = geoPackage.pickInfo; let material; if(arrIndexPackage.length > 0) { material = materialTable[arrIndexPackage[0].materialCode]; } let geodeBoundingVolume = calcBoundingVolume(vertexPackage, modelMatrix); geoMap[geoName] = S3MContentFactory[layer.fileType]({ layer : layer, vertexPackage : vertexPackage, arrIndexPackage : arrIndexPackage, pickInfo : pickInfo, modelMatrix : modelMatrix, geoMatrix : geoMatrix, boundingVolume : geodeBoundingVolume, material : material, edgeGeometry : geoPackage.edgeGeometry, geoName : geoName }); } } if(Object.keys(geoMap).length < 1){ return ; } if(!Cesium.defined(pagelod.boundingVolume)) { let arr = []; for(let key in geoMap) { if(geoMap.hasOwnProperty(key)) { arr.push(geoMap[key].boundingVolume); } } pagelod.boundingVolume = { sphere : Cesium.BoundingSphere.fromBoundingSpheres(arr) }; } pagelod.geoMap = geoMap; } function parsePagelods(layer, content, materialTable) { let groupNode = content.groupNode; let pagelods = []; for(let i = 0, j = groupNode.pageLods.length;i < j; i++){ let pagelod = {}; let pagelodNode = groupNode.pageLods[i]; pagelod.rangeMode = pagelodNode.rangeMode; pagelod.rangeDataList = pagelodNode.childTile; pagelod.rangeList = pagelodNode.rangeList; if(pagelodNode.obb){ pagelod.boundingVolume = { box : { center : pagelodNode.obb.obbCenter, xExtent : pagelodNode.obb.xExtent, yExtent : pagelodNode.obb.yExtent, zExtent : pagelodNode.obb.zExtent } }; } else { let center = pagelodNode.boundingSphere.center; let radius = pagelodNode.boundingSphere.radius; if(pagelod.rangeDataList !== ''){ pagelod.boundingVolume = { sphere : { center : new Cesium.Cartesian3(center.x, center.y, center.z), radius : radius } }; } else { pagelod.isLeafTile = true; } } parseGeodes(layer, content, materialTable, pagelodNode, pagelod); if(Cesium.defined(pagelod.geoMap)){ pagelods.push(pagelod); } } return pagelods; } S3MContentParser.parse = function(layer, content, tile) { if(!Cesium.defined(content)) { return ; } let materialTable = parseMaterial(layer.context, content, tile); let pagelods = parsePagelods(layer, content, materialTable); return pagelods; }; const RangeMode = { Distance : 0, Pixel : 1, GeometryError : 2 }; var RangeMode$1 = Object.freeze(RangeMode); function S3MTile(layer, parent, boundingVolume, fileName, rangeData, rangeMode) { this.layer = layer; this.parent = parent; let path = fileName.replace(/\\/g, '/'); this.fileExtension = Cesium.getExtensionFromUri(fileName); this.relativePath = getUrl(path, layer); this.relativePath = this.relativePath.replace("data/path/data/path", 'data/path'); this.fileName = fileName; this.isLeafTile = rangeData === 0; this.isRootTile = false; this.boundingVolume = this.createBoundingVolume(boundingVolume, layer.modelMatrix); let baseResource = Cesium.Resource.createIfNeeded(layer._baseResource); if (Cesium.defined(parent)) { this.baseUri = parent.baseUri; } else { let resource = new Cesium.Resource(path); this.baseUri = resource.getBaseUri(); } this.contentResource = baseResource.getDerivedResource({ url: this.relativePath }); this.serverKey = Cesium.RequestScheduler.getServerKey(this.contentResource.getUrlComponent()); this.request = undefined; this.cacheNode = undefined; this.distanceToCamera = 0; this.centerZDepth = 0; this.pixel = 0; this.depth = parent ? parent.depth + 1 : 0; this.visibilityPlaneMask = 0; this.visible = false; this.children = []; this.renderEntities = []; this.lodRangeData = Cesium.defaultValue(rangeData, 16); this.lodRangeMode = Cesium.defaultValue(rangeMode, RangeMode$1.Pixel); this.contentState = this.isLeafTile ? ContentState$1.READY : ContentState$1.UNLOADED; this.touchedFrame = 0; this.requestedFrame = 0; this.processFrame = 0; this.selectedFrame = 0; this.updatedVisibilityFrame = 0; this.foveatedFactor = 0; this.priority = 0; this.priorityHolder = this; this.wasMinPriorityChild = false; this.shouldSelect = false; this.selected = false; this.finalResolution = true; this.refines = false; } Object.defineProperties(S3MTile.prototype, { renderable: { get: function () { let renderEntities = this.renderEntities; let len = renderEntities.length; if (len === 0) { return false; } for (let i = 0; i < len; i++) { if (!renderEntities[i].ready) { return false; } } return true; } } }); function createSphere(sphere, transform) { let scratchScale = new Cesium.Cartesian3(); let center = Cesium.Cartesian3.clone(sphere.center); let radius = sphere.radius; center = Cesium.Matrix4.multiplyByPoint(transform, center, center); let scale = Cesium.Matrix4.getScale(transform, scratchScale); let maxScale = Cesium.Cartesian3.maximumComponent(scale); radius *= maxScale; return new Cesium.TileBoundingSphere(center, radius); } function getUrl(fileName, layer) { fileName = fileName.replace(/\+/g, '%2B'); let url = layer._basePath; let isRealspace = layer._basePath.indexOf("realspace") > -1; if (!isRealspace) { return fileName; } let afterRealspace = url.replace(/(.*realspace)/, ""); let lastUrl = url.replace(/\/rest\/realspace/g, "").replace(afterRealspace, ""); return lastUrl + '/rest/realspace' + afterRealspace + 'data/path/' + fileName.replace(/^\.*/, "").replace(/^\//, "").replace(/\/$/, ""); } function createBoundingBox(box, transform) { const scratchMatrix = new Cesium.Matrix3(); let scratchScale = new Cesium.Cartesian3(); if (Cesium.defined(box.center)) { let center = new Cesium.Cartesian3(box.center.x, box.center.y, box.center.z); let vx = new Cesium.Cartesian4(box.xExtent.x, box.xExtent.y, box.xExtent.z, 0); let vy = new Cesium.Cartesian4(box.yExtent.x, box.yExtent.y, box.yExtent.z, 0); let vz = new Cesium.Cartesian4(box.zExtent.x, box.zExtent.y, box.zExtent.z, 0); let halfAxes = new Cesium.Matrix3(); Cesium.Matrix3.setColumn(halfAxes, 0, vx, halfAxes); Cesium.Matrix3.setColumn(halfAxes, 1, vy, halfAxes); Cesium.Matrix3.setColumn(halfAxes, 2, vz, halfAxes); center = Cesium.Matrix4.multiplyByPoint(transform, center, center); const rotationScale = Cesium.Matrix4.getMatrix3(transform, scratchMatrix); halfAxes = Cesium.Matrix3.multiply(rotationScale, halfAxes, halfAxes); return new Cesium.TileOrientedBoundingBox(center, halfAxes); } let min = new Cesium.Cartesian3(box.min.x, box.min.y, box.min.z); Cesium.Matrix4.multiplyByPoint(transform, min, min); let max = new Cesium.Cartesian3(box.max.x, box.max.y, box.max.z); Cesium.Matrix4.multiplyByPoint(transform, max, max); let sphere = Cesium.BoundingSphere.fromCornerPoints(min, max, new Cesium.BoundingSphere()); let center = sphere.center; let radius = sphere.radius; let scale = Cesium.Matrix4.getScale(transform, scratchScale); let maxScale = Cesium.Cartesian3.maximumComponent(scale); radius *= maxScale; return new Cesium.TileBoundingSphere(center, radius); } S3MTile.prototype.createBoundingVolume = function (parameter, transform) { if (Cesium.defined(parameter.sphere)) { return createSphere(parameter.sphere, transform); } else if (Cesium.defined(parameter.box)) { return createBoundingBox(parameter.box, transform); } return undefined; }; S3MTile.prototype.canTraverse = function () { if (this.children.length === 0 || this.isLeafTile) { return false; } if (!Cesium.defined(this.lodRangeData)) { return true; } return this.pixel > this.lodRangeData; }; function getBoundingVolume(tile, frameState) { return tile.boundingVolume; } S3MTile.prototype.getPixel = function (frameState) { const tileBoundingVolume = this.boundingVolume; let boundingVolume = tileBoundingVolume.boundingSphere; let radius = boundingVolume.radius; let center = boundingVolume.center; let distance = Cesium.Cartesian3.distance(frameState.camera.positionWC, center); let height = frameState.context.drawingBufferHeight; let theta = frameState.camera.frustum._fovy * 0.5; let screenYPix = height * 0.5; let lamat = screenYPix / Math.tan(theta); return lamat * radius / distance; }; S3MTile.prototype.getGeometryError = function (frameState) { const camera = frameState.camera; const height = this.layer.context.drawingBufferHeight; const geometricError = this.lodRangeData; const distance = this.boundingVolume.distanceToCamera(frameState); return (geometricError * height) / (distance * camera.frustum.sseDenominator); }; S3MTile.prototype.distanceToTile = function (frameState) { let boundingVolume = getBoundingVolume(this); return boundingVolume.distanceToCamera(frameState); }; S3MTile.prototype.distanceToTileCenter = function (frameState) { let scratchToTileCenter = new Cesium.Cartesian3(); const tileBoundingVolume = getBoundingVolume(this); const boundingVolume = tileBoundingVolume.boundingVolume; const toCenter = Cesium.Cartesian3.subtract(boundingVolume.center, frameState.camera.positionWC, scratchToTileCenter); return Cesium.Cartesian3.dot(frameState.camera.directionWC, toCenter); }; S3MTile.prototype.visibility = function (frameState, parentVisibilityPlaneMask) { let boundingVolume = getBoundingVolume(this); return frameState.cullingVolume.computeVisibilityWithPlaneMask(boundingVolume, parentVisibilityPlaneMask); }; function priorityDeferred(tile, frameState) { let scratchCartesian = new Cesium.Cartesian3(); let camera = frameState.camera; const tileBoundingVolume = tile.boundingVolume; let boundingVolume = tileBoundingVolume.boundingSphere; let radius = boundingVolume.radius; let scaledCameraDirection = Cesium.Cartesian3.multiplyByScalar(camera.directionWC, tile.centerZDepth, scratchCartesian); let closestPointOnLine = Cesium.Cartesian3.add(camera.positionWC, scaledCameraDirection, scratchCartesian); let toLine = Cesium.Cartesian3.subtract(closestPointOnLine, boundingVolume.center, scratchCartesian); let distanceToCenterLine = Cesium.Cartesian3.magnitude(toLine); let notTouchingSphere = distanceToCenterLine > radius; if (notTouchingSphere) { let toLineNormalized = Cesium.Cartesian3.normalize(toLine, scratchCartesian); let scaledToLine = Cesium.Cartesian3.multiplyByScalar(toLineNormalized, radius, scratchCartesian); let closestOnSphere = Cesium.Cartesian3.add(boundingVolume.center, scaledToLine, scratchCartesian); let toClosestOnSphere = Cesium.Cartesian3.subtract(closestOnSphere, camera.positionWC, scratchCartesian); let toClosestOnSphereNormalize = Cesium.Cartesian3.normalize(toClosestOnSphere, scratchCartesian); tile.foveatedFactor = 1.0 - Math.abs(Cesium.Cartesian3.dot(camera.directionWC, toClosestOnSphereNormalize)); } else { tile.foveatedFactor = 0.0; } } S3MTile.prototype.updateVisibility = function (frameState, layer) { let parent = this.parent; let parentVisibilityPlaneMask = Cesium.defined(parent) ? parent.visibilityPlaneMask : Cesium.CullingVolume.MASK_INDETERMINATE; this.distanceToCamera = this.distanceToTile(frameState); this.centerZDepth = this.distanceToTileCenter(frameState); this.pixel = this.getPixel(frameState); this.geometryError = this.getGeometryError(frameState); this.visibilityPlaneMask = this.visibility(frameState, parentVisibilityPlaneMask); this.visible = this.visibilityPlaneMask !== Cesium.CullingVolume.MASK_OUTSIDE && this.distanceToCamera >= layer.visibleDistanceMin && this.distanceToCamera <= layer.visibleDistanceMax; this.priorityDeferred = priorityDeferred(this, frameState); }; function createPriorityFunction(tile) { return function () { return tile.priority; }; } function getContentFailedFunction(tile) { return function (error) { tile.contentState = ContentState$1.FAILED; tile.contentReadyPromise && tile.contentReadyPromise.reject(error); }; } function createChildren(parent, datas) { let layer = parent.layer; let length = datas.length; let minRangeData = Number.MAX_VALUE; let maxRangeData = 0; let mode = RangeMode$1.Pixel; for (let i = 0; i < length; i++) { let data = datas[i]; let boundingVolume = data.boundingVolume; let fileName = data.rangeDataList; fileName = parent.baseUri + fileName; let rangeData = data.rangeList; let rangeMode = data.rangeMode; let renderEntitieMap = data.geoMap; if (rangeData !== 0) { let tile = new S3MTile(layer, parent, boundingVolume, fileName, rangeData, rangeMode); parent.children.push(tile); layer._cache.add(tile); } for (let geoName in renderEntitieMap) { if (renderEntitieMap.hasOwnProperty(geoName)) { parent.renderEntities.push(renderEntitieMap[geoName]); } } minRangeData = Math.min(minRangeData, rangeData); maxRangeData = Math.max(maxRangeData, rangeData); mode = rangeMode; } if (parent.isRootTile) { parent.lodRangeData = mode === RangeMode$1.Pixel ? minRangeData / 2 : maxRangeData * 2; parent.lodRangeMode = mode; } } function contentReadyFunction(layer, tile, arrayBuffer) { layer._cache.add(tile); S3ModelParser.s3tc = layer.context.s3tc; S3ModelParser.pvrtc = layer.context.pvrtc; S3ModelParser.etc1 = layer.context.etc1; let content = S3ModelParser.parseBuffer(arrayBuffer); if (!content) { tile.contentState = ContentState$1.FAILED; tile.contentReadyPromise.reject(); return; } let data = S3MContentParser.parse(layer, content, tile); createChildren(tile, data); tile.selectedFrame = 0; tile.contentState = ContentState$1.READY; tile.contentReadyPromise.resolve(content); } S3MTile.prototype.requestContent = function () { let that = this; let layer = this.layer; let resource = this.contentResource.clone(); let request = new Cesium.Request({ throttle: true, throttleByServer: true, type: Cesium.RequestType.TILES3D, priorityFunction: createPriorityFunction(this), serverKey: this.serverKey }); this.request = request; resource.request = request; let promise = resource.fetchArrayBuffer(); if (!Cesium.defined(promise)) { return false; } this.contentState = ContentState$1.LOADING; this.contentReadyPromise = Cesium.when.defer(); let contentFailedFunction = getContentFailedFunction(this); promise.then(function (arrayBuffer) { if (that.isDestroyed()) { contentFailedFunction(); return; } contentReadyFunction(layer, that, arrayBuffer); }).catch(function (error) { if (request.state === Cesium.RequestState.CANCELLED) { that.contentState = ContentState$1.UNLOADED; return; } contentFailedFunction(error); }); return true; }; function priorityNormalizeAndClamp(value, minimum, maximum) { return Math.max(Cesium.Math.normalize(value, minimum, maximum) - Cesium.Math.EPSILON7, 0.0); } function isolateDigits(normalizedValue, numberOfDigits, leftShift) { let scaled = normalizedValue * Math.pow(10, numberOfDigits); let integer = parseInt(scaled); return integer * Math.pow(10, leftShift); } S3MTile.prototype.updatePriority = function (layer, frameState) { let minimumPriority = layer._minimumPriority; let maximumPriority = layer._maximumPriority; let leftShift = 4; let digitsCount = 4; let normalizedFoveatedFactor = priorityNormalizeAndClamp(this.foveatedFactor, minimumPriority.foveatedFactor, maximumPriority.foveatedFactor); let foveatedDigits = isolateDigits(normalizedFoveatedFactor, digitsCount, leftShift); leftShift = 8; let normalizedPixel = priorityNormalizeAndClamp(this.pixel, minimumPriority.pixel, maximumPriority.pixel); let pixelDigits = isolateDigits(1.0 - normalizedPixel, digitsCount, leftShift); leftShift = 0; let distancePriority = priorityNormalizeAndClamp(this.distanceToCamera, minimumPriority.distance, maximumPriority.distance); let distanceDigit = isolateDigits(distancePriority, digitsCount, leftShift); this.priority = foveatedDigits + pixelDigits + distanceDigit; }; S3MTile.prototype.update = function (frameState, layer) { for (let i = 0, j = this.renderEntities.length; i < j; i++) { this.renderEntities[i].update(frameState, layer); } }; S3MTile.prototype.free = function () { this.contentState = ContentState$1.UNLOADED; this.request = undefined; this.cacheNode = undefined; this.priorityHolder = undefined; this.contentReadyPromise = undefined; this.priorityHolder = undefined; for (let i = 0, j = this.renderEntities.length; i < j; i++) { this.renderEntities[i].destroy(); } this.renderEntities.length = 0; this.children.length = 0; }; S3MTile.prototype.isDestroyed = function () { return false; }; S3MTile.prototype.destroy = function () { this.free(); return Cesium.destroyObject(this); }; function S3MLayerScheduler (){ this._stack = []; } function sortComparator(a, b) { if (b.distanceToCamera === 0 && a.distanceToCamera === 0) { return b.centerZDepth - a.centerZDepth; } return b.distanceToCamera - a.distanceToCamera; } function updateChildren(layer, tile, stack, frameState) { let i; let children = tile.children; let length = children.length; for (i = 0; i < length; ++i) { updateTile(frameState, layer, children[i]); } children.sort(sortComparator); let refines = true; let anyChildrenVisible = false; let minIndex = -1; let minimumPriority = Number.MAX_VALUE; for (i = 0; i < length; ++i) { let child = children[i]; if (child.foveatedFactor < minimumPriority) { minIndex = i; minimumPriority = child.foveatedFactor; } if (child.visible) { stack.push(child); anyChildrenVisible = true; } else { loadTile(layer, child, frameState); touchTile(layer, child, frameState); processTile(layer, child, frameState); } let childRefines = child.renderable; { refines = refines && childRefines; } } if (!anyChildrenVisible) { refines = false; } if (minIndex !== -1) { let minPriorityChild = children[minIndex]; minPriorityChild.wasMinPriorityChild = true; let priorityHolder = (tile.wasMinPriorityChild || tile.isRootTile) && minimumPriority <= tile.priorityHolder.foveatedFactor ? tile.priorityHolder : tile; priorityHolder.foveatedFactor = Math.min(minPriorityChild.foveatedFactor, priorityHolder.foveatedFactor); priorityHolder.distanceToCamera = Math.min(minPriorityChild.distanceToCamera, priorityHolder.distanceToCamera); for (i = 0; i < length; ++i) { let child = children[i]; child.priorityHolder = priorityHolder; } } return refines; } function selectTile(layer, tile, frameState) { if(tile.selectedFrame === frameState.frameNumber || !tile.renderable){ return ; } layer._selectedTiles.push(tile); tile.selectedFrame = frameState.frameNumber; } function loadTile(layer, tile, frameState) { if(tile.requestedFrame === frameState.frameNumber || tile.contentState !== ContentState$1.UNLOADED) { return ; } layer._requestTiles.push(tile); tile.requestedFrame = frameState.frameNumber; } function processTile(layer, tile, frameState) { if(tile.processFrame === frameState.frameNumber || tile.contentState !== ContentState$1.READY || tile.renderable) { return ; } tile.processFrame = frameState.frameNumber; layer._processTiles.push(tile); } function touchTile(layer, tile, frameState) { if (tile.touchedFrame === frameState.frameNumber) { return; } layer._cache.touch(tile); tile.touchedFrame = frameState.frameNumber; } function updateVisibility(layer, tile, frameState) { if (tile.updatedVisibilityFrame === frameState.frameNumber) { return; } tile.updatedVisibilityFrame = frameState.frameNumber; tile.updateVisibility(frameState, layer); } function updateTileVisibility(frameState, layer, tile) { updateVisibility(layer, tile, frameState); } function updateMinimumMaximumPriority(layer, tile) { layer._maximumPriority.distance = Math.max(tile.distanceToCamera, layer._maximumPriority.distance); layer._minimumPriority.distance = Math.min(tile.distanceToCamera, layer._minimumPriority.distance); layer._maximumPriority.depth = Math.max(tile.depth, layer._maximumPriority.depth); layer._minimumPriority.depth = Math.min(tile.depth, layer._minimumPriority.depth); layer._maximumPriority.foveatedFactor = Math.max(tile.foveatedFactor, layer._maximumPriority.foveatedFactor); layer._minimumPriority.foveatedFactor = Math.min(tile.foveatedFactor, layer._minimumPriority.foveatedFactor); layer._maximumPriority.pixel = Math.max(tile.pixel, layer._maximumPriority.pixel); layer._minimumPriority.pixel = Math.min(tile.pixel, layer._minimumPriority.pixel); } function updateTile(frameState, layer, tile) { updateTileVisibility(frameState, layer, tile); tile.wasMinPriorityChild = false; tile.priorityHolder = tile; updateMinimumMaximumPriority(layer, tile); tile.shouldSelect = false; tile.selected = false; } function canTraverse(layer, tile) { if (tile.children.length === 0) { return false; } if(tile.lodRangeMode === RangeMode$1.Pixel){ return tile.pixel / layer.lodRangeScale > tile.lodRangeData; } else if(tile.lodRangeMode === RangeMode$1.GeometryError) { return tile.geometryError > 16; } return tile.distanceToCamera * layer.lodRangeScale < tile.lodRangeData; } function traversal(layer, stack, frameState) { while(stack.length) { let tile = stack.pop(); let parent = tile.parent; let parentRefines = !Cesium.defined(parent) || parent.refines; let refines = false; if (canTraverse(layer, tile)) { refines = updateChildren(layer, tile, stack, frameState) && parentRefines; } let stoppedRefining = !refines && parentRefines; loadTile(layer, tile, frameState); processTile(layer, tile, frameState); if (stoppedRefining) { selectTile(layer, tile, frameState); } touchTile(layer, tile, frameState); tile.refines = refines; } } function selectRootTiles(layer, stack, frameState) { stack.length = 0; for(let i = 0,j = layer._rootTiles.length;i < j;i++){ let rootTile = layer._rootTiles[i]; updateTile(frameState, layer, rootTile); if(!rootTile.visible) { continue ; } stack.push(rootTile); } } function updatePriority(layer, frameState) { let requestTiles = layer._requestTiles; let length = requestTiles.length; for (let i = 0; i < length; ++i) { requestTiles[i].updatePriority(layer, frameState); } } S3MLayerScheduler.prototype.schedule = function(layer, frameState) { let stack = this._stack; selectRootTiles(layer, stack, frameState); traversal(layer, stack, frameState); updatePriority(layer, frameState); }; function S3MLayerCache() { this._list = new Cesium.DoublyLinkedList(); this._sentinel = this._list.add(); this._trimTiles = false; } S3MLayerCache.prototype.reset = function() { this._list.splice(this._list.tail, this._sentinel); }; S3MLayerCache.prototype.touch = function(tile) { let node = tile.cacheNode; if (Cesium.defined(node)) { this._list.splice(this._sentinel, node); } }; S3MLayerCache.prototype.add = function(tile) { if (!Cesium.defined(tile.cacheNode)) { tile.cacheNode = this._list.add(tile); } }; S3MLayerCache.prototype.unloadTile = function(layer, tile, unloadCallback) { let node = tile.cacheNode; if (!Cesium.defined(node)) { return; } this._list.remove(node); tile.cacheNode = undefined; unloadCallback(layer, tile); }; S3MLayerCache.prototype.unloadTiles = function(layer, unloadCallback) { let trimTiles = this._trimTiles; this._trimTiles = false; let list = this._list; let maximumMemoryUsageInBytes = layer.maximumMemoryUsage * 1024 * 1024; let sentinel = this._sentinel; let node = list.head; while (node && (node !== sentinel) && ((layer.totalMemoryUsageInBytes > maximumMemoryUsageInBytes) || trimTiles)) { let tile = node.item; node = node.next; this.unloadTile(layer, tile, unloadCallback); } }; S3MLayerCache.prototype.trim = function() { this._trimTiles = true; }; const OperationType = { RESET : 0, SetColor : 0x01, SELECTED : 0x02, HIDE : 0x04, OFFSET : 0x08, CLIP : 0x10, BLOOM : 0x20, ALL : 0xff }; var OperationType$1 = Object.freeze(OperationType); function Style3D(){ this._fillForeColor = new Cesium.Color(); this._lineColor = new Cesium.Color(); this._lineWidth = 1.0; this._bottomAltitude = 0; this._pointSize = 1.0; this._pointColor = new Cesium.Color(); } Object.defineProperties(Style3D.prototype, { fillForeColor : { get : function() { return this._fillForeColor; }, set : function(value) { Cesium.Check.typeOf.object('fillForeColor value', value); Cesium.Color.clone(value, this._fillForeColor); } }, bottomAltitude : { get : function() { return this._bottomAltitude; }, set : function(value) { Cesium.Check.typeOf.number('bottomAltitude value',value); if(this._bottomAltitude !== value) { this._bottomAltitude = value; this._dirty = true; } } }, altitudeMode : { get : function() { return this._altitudeMode; }, set : function(value) { Cesium.Check.typeOf.number('altitudeMode value',value); this._altitudeMode = value; } }, lineColor : { get : function() { return this._lineColor; }, set : function(value) { Cesium.Check.typeOf.object('line color',value); Cesium.Color.clone(value, this._lineColor); } }, lineWidth : { get : function() { return this._lineWidth; }, set : function(value) { Cesium.Check.typeOf.number('line width',value); this._lineWidth = value; } }, pointSize : { get : function() { return this._pointSize; }, set : function(value) { Cesium.Check.typeOf.number('point size',value); this._pointSize = value; } }, pointColor : { get : function() { return this._pointColor; }, set : function(value) { Cesium.Check.typeOf.object('point color',value); Cesium.Color.clone(value, this._pointColor); } } }); /** * * 创建s3m图层 * * @alias S3MTilesLayer * @param {Object} options 参数 * @param {String} [options.name] 模型名称 * @param {String} options.url 模型地址 * @param {Cesium.Scene} options.scene 地图场景对象 * @param {Number} [options.near=0] 最小可视距离 * @param {Number} [options.far=Number.MAX_VALUE] 最大可视距离 * @param {Number} [options.lodRangeScale=1] LOD层级切换距离缩放系数 * @param {Function} callback 回调函数 * @constructor * */ function S3MTilesLayer(options, callback) { options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT); Cesium.Check.defined('options.url', options.url); Cesium.Check.defined('options.context', options.scene); this.id = Cesium.createGuid(); this.name = options.name; this.scene = options.scene; this.context = this.scene._context; this.show = true; this._url = undefined; this._basePath = undefined; this._baseResource = undefined; this.modelMatrix = new Cesium.Matrix4(); this.invModelMatrix = new Cesium.Matrix4(); this._visibleDistanceMax = Cesium.defaultValue(options.far, Number.MAX_VALUE); this._visibleDistanceMin = Cesium.defaultValue(options.near, 0.0); this._lodRangeScale = Cesium.defaultValue(options.lodRangeScale, 1.0); this._selectedColor = new Cesium.Color(1.0, 0.0, 0.0, 1.0); this.fileType = undefined; this._position = undefined; this._rectangle = undefined; this._rootTiles = []; this._schuduler = new S3MLayerScheduler(); this._selections = []; this._objsOperationList = {}; this._requestTiles = []; this._processTiles = []; this._selectedTiles = []; this._cache = new S3MLayerCache(); this._maximumMemoryUsage = -1; this._totalMemoryUsageInBytes = 0; this._vertexCompressionType = undefined; this._style3D = new Style3D(); this._maximumPriority = { foveatedFactor: -Number.MAX_VALUE, depth: -Number.MAX_VALUE, distance: -Number.MAX_VALUE, pixel: -Number.MAX_VALUE }; this._minimumPriority = { foveatedFactor: Number.MAX_VALUE, depth: Number.MAX_VALUE, distance: Number.MAX_VALUE, pixel: Number.MAX_VALUE }; this._readyPromise = Cesium.when.defer(); this.loadConfig(options.url); this.scene.primitives.add(this); this.readyPromise.then(() => { callback && callback(this); }).otherwise(function (error) { console.log(error); }); } Object.defineProperties(S3MTilesLayer.prototype, { ready: { get: function () { return this._rootTiles.length > 0; } }, readyPromise: { get: function () { return this._readyPromise; } }, rectangle: { get: function () { return this._rectangle; } }, visibleDistanceMax: { get: function () { return this._visibleDistanceMax; }, set: function (value) { Cesium.Check.typeOf.number('max visible distance', value); this._visibleDistanceMax = value; } }, visibleDistanceMin: { get: function () { return this._visibleDistanceMin; }, set: function (value) { Cesium.Check.typeOf.number('min visible distance', value); this._visibleDistanceMin = value; } }, lodRangeScale: { get: function () { return this._lodRangeScale; }, set: function (value) { Cesium.Check.typeOf.number('set layer lod range scale', value); this._lodRangeScale = value; } }, totalMemoryUsageInBytes: { get: function () { return this._totalMemoryUsageInBytes; }, set: function (value) { this._totalMemoryUsageInBytes = value; } }, maximumMemoryUsage: { get: function () { return this._maximumMemoryUsage; }, set: function (value) { this._maximumMemoryUsage = value; } }, style3D: { get: function () { return this._style3D; }, set: function (value) { this._style3D = value; } } }); S3MTilesLayer.prototype.loadConfig = function (url, isXML) { let that = this; Cesium.when(url) .then(function (url) { let basePath; let resource = Cesium.Resource.createIfNeeded(url); basePath = resource.getBaseUri(true); that._url = resource.url; that._basePath = basePath; that._baseResource = resource; return isXML ? resource.fetchXML() : resource.fetchJson(); }) .then(function (config) { if (isXML) { config = xmlObj2json(config); } let extensions = config.extensions; if (extensions) { that.fileType = extensions["s3m:FileType"]; that._vertexCompressionType = extensions['s3m:VertexCompressionType']; } else { that.fileType = config.FileType; } let position = config.position || config.Position; let lon = position.x || position.X; let lat = position.y || position.Y; let height = position.z || position.Z; that._position = Cesium.Cartesian3.fromDegrees(lon, lat, height); that.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(that._position); that.invModelMatrix = Cesium.Matrix4.inverse(that.modelMatrix, that.invModelMatrix); if (config.heightRange) { that._minHeight = config.heightRange.min; that._maxHeight = config.heightRange.max; } else if (config.HeightRange) { that._minHeight = config.HeightRange.MinHeight; that._maxHeight = config.HeightRange.MaxHeight; } if (config.geoBounds) { that._rectangle = Cesium.Rectangle.fromDegrees(config.geoBounds.left, config.geoBounds.bottom, config.geoBounds.right, config.geoBounds.top); } else { that.viewPosition = Cesium.Cartesian3.fromDegrees(lon, lat, that._maxHeight); } if (config.wDescript) { let wDescript = config.wDescript.range; that._minWValue = wDescript.min; that._maxWValue = wDescript.max; } let tiles = config.tiles || config.rootTiles || (config.OSGFiles && config.OSGFiles.Files); for (let i = 0, len = tiles.length; i < len; i++) { let tileObj = tiles[i]; if (tileObj) { let fileName = tileObj.url || tileObj.FileName; let boundingVolume = { box: tileObj.boundingbox, }; if (tileObj.BoundingSphere) { boundingVolume.sphere = { radius: tileObj.BoundingSphere.Radius, center: new Cesium.Cartesian3(tileObj.BoundingSphere.CenterX, tileObj.BoundingSphere.CenterY, tileObj.BoundingSphere.CenterZ) }; } let tile = new S3MTile(that, undefined, boundingVolume, fileName); tile.isRootTile = true; that._cache.add(tile); that._rootTiles.push(tile); } } that._readyPromise.resolve(that); }).otherwise(function (error) { if (isXML) { that._readyPromise.reject(error); } else { that.loadConfig(url, true); } }); }; S3MTilesLayer.prototype._tranverseRenderEntity = function (options, callback) { let stack = []; for (let i = 0, j = this._rootTiles.length; i < j; i++) { let rootTile = this._rootTiles[i]; stack.push(rootTile); } while (stack.length) { let tile = stack.pop(); for (let i = 0, j = tile.renderEntities.length; i < j; i++) { const renderEntity = tile.renderEntities[i]; if (renderEntity.ready) { callback(renderEntity, options); } } for (let i = 0, j = tile.children.length; i < j; i++) { stack.push(tile.children[i]); } } }; function updateObjsOperationCallback(renderEntity, options) { renderEntity.updateObjsOperation(options.ids, options); } S3MTilesLayer.prototype._updateObjsOperation = function (ids) { this._tranverseRenderEntity({ ids: ids }, updateObjsOperationCallback); }; S3MTilesLayer.prototype._setObjsOperationType = function (ids, operationType) { Cesium.Check.defined('set Objs Operation ids', ids); Cesium.Check.defined('set Objs Operation operationType', operationType); if (!Array.isArray(ids)) { ids = [ids]; } let tmpArr = new Cesium.AssociativeArray(); let id; for (let i = 0, j = ids.length; i < j; i++) { id = ids[i]; if (!Cesium.defined(id)) { continue; } let operation = Cesium.defaultValue(this._objsOperationList[id], 0); if (operation === operationType) { continue; } operation = operation | operationType; this._objsOperationList[id] = operation; tmpArr.set(id, operation); } if (tmpArr.length > 0) { this._updateObjsOperation(tmpArr._hash); } }; S3MTilesLayer.prototype._removeObjsOperationType = function (ids, operationType) { Cesium.Check.defined('set Objs Operation ids', ids); if (!Array.isArray(ids)) { ids = [ids]; } let nonOperationType = OperationType$1.ALL ^ operationType; let tmpArr = new Cesium.AssociativeArray(); let id; for (let i = 0, j = ids.length; i < j; i++) { id = ids[i]; let operation = this._objsOperationList[id]; if (!Cesium.defined(operation)) { continue; } operation &= nonOperationType; if (operation === OperationType$1.RESET) { delete this._objsOperationList[id]; } else { this._objsOperationList[id] = operation; } tmpArr.set(id, operation); } if (tmpArr.length > 0) { this._updateObjsOperation(tmpArr._hash); } }; S3MTilesLayer.prototype.releaseSelection = function () { if (this._selections.length < 1) { return; } this._removeObjsOperationType(this._selections, OperationType$1.SELECTED); this._selections.length = 0; }; S3MTilesLayer.prototype.setSelection = function (ids) { Cesium.Check.defined('setSelection ids', ids); if (!Array.isArray(ids)) { ids = [ids]; } this.releaseSelection(); this._selections = this._selections.concat(ids); this._setObjsOperationType(ids, OperationType$1.SELECTED); }; function sortRequestByPriority(a, b) { return a.priority - b.priority; } function requestTiles(layer) { let requestTiles = layer._requestTiles; let length = requestTiles.length; requestTiles.sort(sortRequestByPriority); for (let i = 0; i < length; ++i) { let tile = requestTiles[i]; tile.requestContent(); } } function processTiles(layer, frameState) { let tiles = layer._processTiles; let length = tiles.length; for (let i = 0; i < length; ++i) { let tile = tiles[i]; tile.update(frameState, layer); } } function updateTiles(layer, frameState) { let selectedTiles = layer._selectedTiles; let length = selectedTiles.length; for (let i = 0; i < length; i++) { selectedTiles[i].update(frameState, layer); } } function unloadTile(layer, tile) { tile.free(); } function freeResource(layer) { layer._cache.unloadTiles(layer, unloadTile); } S3MTilesLayer.prototype.prePassesUpdate = function (frameState) { if (!this.ready) { return; } if (frameState.newFrame) { this._cache.reset(); this._requestTiles.length = 0; this._processTiles.length = 0; this._selectedTiles.length = 0; } }; S3MTilesLayer.prototype.postPassesUpdate = function (frameState) { if (!this.ready) { return; } freeResource(this); }; S3MTilesLayer.prototype.update = function (frameState) { if (!this.ready || !this.show) { return; } this._schuduler.schedule(this, frameState); requestTiles(this); processTiles(this, frameState); updateTiles(this, frameState); }; S3MTilesLayer.prototype.isDestroyed = function () { return false; }; /** * 删除 */ S3MTilesLayer.prototype.deleteObject = function () { this.scene.primitives.remove(this); }; /** * 销毁 */ S3MTilesLayer.prototype.destroy = function () { this._cache.reset(); freeResource(this); this._rootTiles.length = 0; this._requestTiles.length = 0; this._processTiles.length = 0; this._selectedTiles.length = 0; return Cesium.destroyObject(this); }; /** * 设置显示隐藏 * @param {boolean} [show] true|false */ S3MTilesLayer.prototype.setVisibility = function (show) { this.show = show; }; //This file is automatically rebuilt by the Cesium build process. var PolylineLinkSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ czm_material material = czm_getDefaultMaterial(materialInput);\n\ vec2 st = materialInput.st;\n\ if(plus && st.s < time && time - st.s <= 0.1){\n\ material.alpha = 1.0 - (time - st.s) / 0.1;\n\ if(material.alpha < 0.3){\n\ material.alpha = 0.3;\n\ material.diffuse = color.rgb;\n\ }else{\n\ material.diffuse = lightSpotColor.rgb;\n\ }\n\ }else if(inverse && st.s < (1.0 - time) && (1.0 - time) - st.s <= 0.1){\n\ material.alpha = ((1.0-time) - st.s) / 0.1;\n\ if(material.alpha < 0.3){\n\ material.alpha = 0.3;\n\ material.diffuse = color.rgb;\n\ }else{\n\ material.diffuse = lightSpotColor.rgb;\n\ }\n\ }else{\n\ material.alpha = 0.3;\n\ material.diffuse = color.rgb;\n\ }\n\ return material;\n\ }\n\ "; let polylineVolumeShapeData = new Map(); /** * 工具类 * * @alias Core * @author 金磊、张丹钊、张恒、薛鹏 * @constructor * */ function Core(Viewer) { this._viewer = Viewer; } /** * * 获取默认值。 * * @param {*} a * @param {*} b * @returns {*} 如果未定义,则返回第一个参数,否则返回第二个参数。 * * @example * param = sgworld.Core.defaultValue(param, 'default'); */ Core.prototype.defaultValue = function (a, b) { return defaultValue(a, b); }; /** * 随机id * @returns {String} 返回一个随机id * @example * id = sgworld.Core.createRandomId(); */ Core.prototype.createRandomId = function () { return (Math.random() * 10000000).toString(16).substr(0, 4) + '-' + (new Date()).getTime() + '-' + Math.random().toString().substr(2, 5); }; /** * 修改鼠标样式。 * * @param {DOM} container html DOM节点 * @param {Number} [cursorstyle=0] 鼠标类型(0为默认,1为使用cur图标) * @param {String} url cur图标路径。 * * @example * sgworld.Core.mouse(Viewer.container, 1, 'draw.cur'); */ Core.prototype.mouse = function (container, cursorstyle, url) { if (cursorstyle == 1) { container.style.cursor = "url(" + url + "),auto"; } else { container.style.cursor = "default"; } }; /** * 创建鼠标Tooltip提示框。 * * @param {*} [styleOrText] 提示框样式或文本内容 * @param {String} [styleOrText.origin='center'] 对齐方式(center/top/bottom) * @param {String} [styleOrText.color='black'] 提示框颜色(black/white/yellow) * @param {String} [styleOrText.id=undefined] 提示框唯一id(可选) * @param {Object} position 显示位置 * @param {Boolean} show 是否显示(如果为true,styleOrText必须为显示的文本内容) * @returns {Tooltip} Tooltip提示框。 * * @example * sgworld.Core.CreateTooltip('这里是提示信息', {x:500, y:500}, true); * 或 * tooltip = sgworld.Core.CreateTooltip(); * tooltip.showAt({x:500, y:500}, '这里是提示信息'); * * tooltip.show(false); //隐藏提示框 * tooltip.show(true); //显示提示框 */ Core.prototype.CreateTooltip = function (styleOrText = {}, position, show) { var style, _x, _y, _color, id; if (typeof styleOrText === 'object') { style = styleOrText; } if (style && style.origin) { style.origin === 'center' && (_x = 15, _y = -12); style.origin === 'top' && (_x = 15, _y = -44); style.origin === 'bottom' && (_x = 15, _y = 20); } else { _x = 15, _y = 20; } if (style && style.color) { style.color === 'white' && (_color = 'background: rgba(255, 255, 255, 0.8);color: black;'); style.color === 'black' && (_color = 'background: rgba(0, 0, 0, 0.5);color: white;'); style.color === 'yellow' && (_color = 'color: black;background-color: #ffcc33;border: 1px solid white;'); } else { _color = 'background: rgba(0, 0, 0, 0.5);color: white;'; } if (style && style.id) { id = "toolTip" + style.id; } else { id = "toolTip"; } var tooltip = (this._viewer ? this._viewer.container : document).querySelector('#' + id); if (!tooltip) { var elementbottom = document.createElement("div"); $(".cesium-viewer").append(elementbottom); var html = ''; $('.cesium-viewer').append(html); tooltip = document.getElementById(id); } if (show) { tooltip.innerHTML = styleOrText; tooltip.style.left = position.x + _x + "px"; tooltip.style.top = position.y + _y + "px"; tooltip.style.display = "block"; } else { tooltip.style.display = "none"; } return { tooltip: tooltip, style: style, showAt: function (position, text) { this.tooltip.innerHTML = text; if (this.style && this.style.origin) { this.style.origin === 'center' && (_x = 15, _y = -this.tooltip.offsetHeight / 2); this.style.origin === 'top' && (_x = 15, _y = -this.tooltip.offsetHeight - 20); this.style.origin === 'bottom' && (_x = 15, _y = 20); } else { _x = 15, _y = -this.tooltip.offsetHeight / 2; } this.tooltip.style.left = position.x + _x + "px"; this.tooltip.style.top = position.y + _y + "px"; this.tooltip.style.display = "block"; }, show: function (show) { if (show) { this.tooltip.style.display = "block"; } else { this.tooltip.style.display = "none"; } } }; }; /** * 获取wmts信息 * @param {Object} data 地址参数 * @param {String} data.url 服务地址 * @param {String} [data.layer] 图层名 * @param {String} [data.gisserverTMS=false] 是否gisserverTMS * @param {String} [data.srs="EPSG:4326"] 坐标系 * @param {Function} callback */ Core.prototype.getWMTSData = function (data, callback) { //获取行列号范围 WMTSGetCapabilities(data.url + "?service=WMTS&request=GetCapabilities").then((e) => { let xmlObj = e.xmlObj; let xml2json, layer, boundingSphere; let TileMatrixLimits = {}; if (data.gisserverTMS) { xml2json = xmlObj2json(xmlObj); layer = xml2json.Contents && xml2json.Contents.Layer; } else { let layers = xmlObj.getElementsByTagName("Layer"); for (let i = 0, identifier; i < layers.length; i++) { identifier = layers[i].getElementsByTagName("ows:Identifier"); if (identifier && identifier[0] && identifier[0].innerHTML === data.layer) { xmlObj = layers[i]; break; } } layer = xmlObj2json(xmlObj); } if (layer) { let TileMatrixSetLink = layer.TileMatrixSetLink; let WGS84BoundingBox = layer.WGS84BoundingBox; if (WGS84BoundingBox) { let LowerCorner = WGS84BoundingBox.LowerCorner.split(" "); let UpperCorner = WGS84BoundingBox.UpperCorner.split(" "); boundingSphere = Cesium.BoundingSphere.fromPoints([ Cesium.Cartesian3.fromDegrees(LowerCorner[0], LowerCorner[1]), Cesium.Cartesian3.fromDegrees(UpperCorner[0], UpperCorner[1]) ]); } let TileMatrixSet; if (data.gisserverTMS) { TileMatrixSet = TileMatrixSetLink; } else { let srs = data.srs || 'EPSG:4326'; TileMatrixSet = TileMatrixSetLink.filter(item => { return item.TileMatrixSet === srs; })[0]; } if (TileMatrixSet) { TileMatrixSet.TileMatrixSetLimits && TileMatrixSet.TileMatrixSetLimits.TileMatrixLimits.forEach(item => { let TileMatrix = item.TileMatrix; TileMatrix = TileMatrix.split(":"); let level = TileMatrix[TileMatrix.length - 1]; TileMatrixLimits[level] = { maxCol: item.MaxTileCol, minCol: item.MinTileCol, maxRow: item.MaxTileRow, minRow: item.MinTileRow, }; }); } } callback && callback({ boundingSphere, TileMatrixLimits }); }); }; /** * 获取点位到相机的距离 * @param {Viewer} Viewer 地图视图 * @param {Cartesian3} position 点位坐标 * @returns {Number} */ Core.prototype.getPointToCameraDistance = function (Viewer, position) { let distance; if (Viewer.scene.mode === 2) { let Cartographic = Viewer.camera.positionCartographic.clone(); distance = Cesium.Cartesian3.distance(position, Cesium.Cartesian3.fromRadians( Cartographic.longitude, Cartographic.latitude, Cartographic.height ) ); } else { distance = Cesium.Cartesian3.distance(position, Viewer.camera.position); } return distance; }; /** * 通过中心点经纬度、方位角和距离获取经纬度 * @param {Number} lon 经度 * @param {Number} lat 纬度 * @param {Number} distance 距离 * @param {Number} [heading=0] 方位角 * @returns {Array} * @example * degrees = sgworld.Core.getPositionFromHR(110, 30, 100, 30) */ Core.prototype.getPositionFromHR = function (lon, lat, distance, heading = 0) { var Ea = 6378137.0; // 赤道半径 var Eb = 6356725.0; // 极半径 var dx = distance * Math.sin(heading * Math.PI / 180.0); var dy = distance * Math.cos(heading * Math.PI / 180.0); var ec = Eb + (Ea - Eb) * (90.0 - lat) / 90.0; var ed = ec * Math.cos(lat * Math.PI / 180); var newLon = (dx / ed + lon * Math.PI / 180.0) * 180.0 / Math.PI; var newLat = (dy / ec + lat * Math.PI / 180.0) * 180.0 / Math.PI; return [newLon, newLat]; }; /** * 通过中心点经纬度、方位角、俯仰角和距离获取经纬度 * @param {Array} center 中心点 * @param {Number} distance 距离 * @param {Number} [heading=0] 方位角 * @param {Number} [pitch=0] 俯仰角 * @returns {Array} * @example * degrees = sgworld.Core.getPositionFromHPR([110, 30, 100], 100, 30, 10) */ Core.prototype.getPositionFromHPR = function (center, distance, heading = 0, pitch = 0) { let hDistance = Math.cos(Math.radians(pitch)) * distance; let vDistance = Math.sin(Math.radians(pitch)) * distance; let newP = this.getPositionFromHR(center[0], center[1], hDistance, heading); return { lon: newP[0], lat: newP[1], height: center[2] + vDistance } }; /** * 创建结果提示框 * * @param {Viewer} [Viewer] 地图视图 * @param {Object} [style] 样式 * @param {String} [style.id=undefined] 提示框唯一id(可选) * @param {String} [style.color='yellow'] 提示框颜色(black/white/yellow/blue) * @param {Number} [style.addX=0] 提示框X方向偏移量 * @param {Number} [style.addY=0] 提示框Y方向偏移量 * @param {Number} [style.near=undefined] 提示框最小可视距离 * @param {Number} [style.far=undefined] 提示框最大可视距离 * @param {Boolean} [style.closeBtn=false] 显示关闭按钮 * @param {Function} [style.close] 点击关闭按钮的回调函数 * * @returns {ResultTooltip} ResultTooltip提示框。 * * @example * tooltip = sgworld.Core.CreateResultTooltip(Viewer); * tooltip.showAt(Cesium.Cartesian3.fromDegrees(110, 30, 10), '这里是提示信息'); * * tooltip.show(false); //隐藏提示框 * tooltip.show(true); //显示提示框 */ Core.prototype.CreateResultTooltip = function (Viewer, style = {}) { var _x, _y, _color; let toolId = style.id ? 'resultToolTip' + style.id : 'resultToolTip'; var tooltip = document.getElementById(toolId); if (style.color) { style.color === 'white' && (_color = 'background: rgba(255, 255, 255, 0.8);color: black;'); style.color === 'black' && (_color = 'background: rgba(0, 0, 0, 0.5);color: white;'); style.color === 'blue' && (_color = 'background: rgba(48, 119, 221);color: white;'); style.color === 'yellow' && (_color = 'color: black;background-color: #ffcc33;border: 1px solid white;'); } else { _color = 'color: black;background-color: #ffcc33;border: 1px solid white;'; } if (!tooltip) { var html = ''; $(Viewer.container).append(html); tooltip = document.getElementById(toolId); } var addX = style.addX || 0; var addY = style.addY || 0; var position; var _this = this; if (style.closeBtn) { tooltip.className = 'resultToolTip resultToolTipClose'; tooltip.onclick = () => { tooltip.style.display = "none"; position = undefined; style.close && style.close(); }; } function updateHtmlPosition() { if (position) { if (style.far !== undefined || style.near !== undefined) { let distance = _this.getPointToCameraDistance(Viewer, position); if (distance > style.far) { tooltip.style.display = "none"; return; } else if (distance < style.near) { tooltip.style.display = "none"; return; } else { tooltip.style.display = "block"; } } var CanvasCoordinates = Viewer.scene.cartesianToCanvasCoordinates(position); if (!CanvasCoordinates) return; _x = -tooltip.offsetWidth / 2 + addX; _y = -tooltip.offsetHeight + addY; tooltip.style.left = CanvasCoordinates.x + _x + "px"; tooltip.style.top = CanvasCoordinates.y + _y + "px"; } } //监听视角改变 Viewer.clock.onTick.addEventListener(updateHtmlPosition); return { tooltip: tooltip, position: position, showAt: function (_position, text) { this.tooltip.innerHTML = text; this.tooltip.style.display = "block"; this.position = _position; position = _position; if (position) { var CanvasCoordinates = Viewer.scene.cartesianToCanvasCoordinates(position); if (!CanvasCoordinates) return; _x = -this.tooltip.offsetWidth / 2 + addX; _y = -this.tooltip.offsetHeight + addY; this.tooltip.style.left = CanvasCoordinates.x + _x + "px"; this.tooltip.style.top = CanvasCoordinates.y + _y + "px"; } }, show: function (show) { if (show) { this.tooltip.style.display = "block"; position = this.position; } else { this.tooltip.style.display = "none"; position = undefined; } }, destroy() { Viewer.clock.onTick.removeEventListener(updateHtmlPosition); tooltip.remove(); } }; }; /** * Echarts扩展 * * @param {Viewer} [Viewer] 地图视图 * @param {Object} [option] Echarts对应的参数。 * @param {Boolean} [isClear=false] 是否清除原先图层。 * * @returns {CombineEcharts} Echarts扩展工具 * * @example * echartsTool = sgworld.Core.CombineEcharts(Viewer, option, true); */ Core.prototype.CombineEcharts = function (Viewer, option, isClear) { if (!this._CombineEcharts) { this._CombineEcharts = new CombineEcharts(Viewer); } return this._CombineEcharts.setOption(option, isClear); }; /** * 获取随机的热力图数据 * * @param {Object} [bounds] 数据范围。 * @param {Number} [bounds.east] 东。 * @param {Number} [bounds.south] 南。 * @param {Number} [bounds.west] 西。 * @param {Number} [bounds.north] 北。 * @param {Object} [data] 热力值。 * @param {Number} [data.max] 最大值。 * @param {Number} [data.min] 最小值。 * @param {Number} [data.value] 固定值,如设置value,则所有点的热力值都为该值。 * @param {Number} [num=600] 随机点数。 * * @returns {Object} 热力图数据 * * @example * data = sgworld.Core.getHeatmapData({ * west: 70.0, * south: 10.0, * east: 140.0, * north: 50.0 * }, { * max:100, * min:0 * }); */ Core.prototype.getHeatmapData = function (bounds, data, num = 600) { let heatmapData = []; for (let i = 0; i < num; i++) { let x = Math.random() * (bounds.east - bounds.west) + bounds.west; let y = Math.random() * (bounds.north - bounds.south) + bounds.south; let value = data.value || Math.random() * (data.max - data.min) + data.min; heatmapData.push({ x: x, y: y, value: value }); } return heatmapData; }; /** * 射线求交 * * @param {Viewer} Viewer 地图视图 * @param {Cartesian3} start 起点 * @param {Cartesian3} end 终点 * @param {Array} objectsToExclude 排除的对象 */ Core.prototype.pickFromRay = function (Viewer, start, end, objectsToExclude = []) { if (start.equals(end)) { return undefined; } // 计算射线的方向,目标点left 视点right let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3()), new Cesium.Cartesian3()); // 建立射线 let ray = new Cesium.Ray(start, direction); let result = Viewer.scene.pickFromRay(ray, objectsToExclude); // 计算交互点,返回第一个 return result; }; /** * 打开本地文件获取路径 * @param {Object} option 参数 * @param {String} [option.accept] 文件类型 * @param {Boolean} [option.multiple=false] 多选 * @param {Function} option.callback 回调函数 */ Core.prototype.openLocalFile = function (option = {}) { let inputUpload = document.createElement('input'); inputUpload.accept = option.accept; inputUpload.type = 'file'; option.multiple && (inputUpload.multiple = 'multiple'); inputUpload.onchange = function () { if (typeof option.callback === 'function' && inputUpload.files.length) { if (option.multiple) { let fileURL = []; let file = []; for (let i = 0; i < inputUpload.files.length; i++) { fileURL.push(URL.createObjectURL(inputUpload.files[i])); file.push(inputUpload.files[i]); } option.callback(fileURL, file); } else { option.callback(URL.createObjectURL(inputUpload.files[0]), inputUpload.files[0]); } } }; inputUpload.click(); }; /** * 加载本地shp * @param {Function} callback 回调函数,function(entity){} * @param {String} [encoding="utf-8"] 编码方式 */ Core.prototype.openShapeFile = function (callback, encoding) { this.openLocalFile({ multiple: true, accept: '.shp,.dbf', callback: (fileURL, file) => { let shapeData = new Map(); file.forEach((item, index) => { let fileName = item.name.substring(0, item.name.length - 4); let data = shapeData.get(fileName); if (!data) { shapeData.set(fileName, { shp: undefined, dbf: undefined }); data = shapeData.get(fileName); } if (item.name.includes(".shp")) { data.shp = fileURL[index]; } else { data.dbf = fileURL[index]; } }); shapeData.forEach((item, fileName) => { if (item.shp) { this.loadShpFile({ shp: item.shp, dbf: item.dbf, encoding, fileName }, callback); } else { console.error("请选择" + fileName + '.shp文件'); } }); } }); }; /** * 加载shp数据 * @param {Object} option 参数 * @param {Function} callback 回调 */ Core.prototype.loadShpFile = function ({ fileName, shp, dbf, encoding }, callback) { if (!window.shapefile) { let SkipTool = new Skip(false); SkipTool.addJs(window.SmartEarthRootUrl + 'Workers/shapefile.js'); } return shapefile.open(shp, dbf, { encoding: encoding || "utf-8" }) .then(source => source.read() .then(function log(result) { if (result.done) return; // console.log(result.value); //result.value 为geojson文件 Cesium.GeoJsonDataSource.load(result.value, { clampToGround: true }).then(dataSource => { callback && fileName ? callback(fileName, dataSource.entities.values[0]) : callback(dataSource.entities.values[0]); }); return source.read().then(log); })) .catch(error => console.error(error.stack)); }; /** * 获取gif属性数据 * @param {String} url 路径 * @param {Number} [speed=6] 速率 */ Core.prototype.getGifImageProperty = function (url, speed = 6) { if (!url || url.indexOf('.gif') === -1) { return url; } if (!window.SuperGif) { let SkipTool = new Skip(false); SkipTool.addJs(window.SmartEarthRootUrl + 'Workers/libgif.js'); } let img = document.createElement('img'); img.src = url; img.setAttribute('rel:animated_src', url); // gif库需要img标签配置下面两个属性 img.setAttribute('rel:auto_play', '0'); document.body.appendChild(img); // 新建gif实例 let rub = new SuperGif({ gif: img }); let gif = []; new Promise((resolve) => { rub.load(() => { for (let i = 1; i <= rub.get_length(); i++) { rub.move_to(i); // 遍历gif实例的每一帧 gif.push(rub.get_canvas().toDataURL()); } resolve(gif); }); }); let imageIndex = 0; return new Cesium.CallbackProperty(function () { if (gif.length) { // 解析每一帧 if (imageIndex < speed * (gif.length - 1)) { imageIndex++; } else { imageIndex = 0; } return gif[Math.floor(imageIndex / speed) === gif.length - 1 ? 0 : Math.floor(imageIndex / speed)] } else { return url//因为loadGif是异步的,在解析完成之前先使用原图 } }, false); }; /** * 是否dom对象 * * @param {Object} obj 对象 */ Core.prototype.isDOM = function (obj) { if (typeof HTMLElement === 'object') { return obj instanceof HTMLElement; } else { return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string'; } }; /** * 获取json数据 * * @param {String} url json地址。 * @param {Function} callback 回调函数。 * * @example * sgworld.Core.getJSON('./abc.json', data => { * console.log(data) * }); */ Core.prototype.getJSON = function (url, callback) { const xhr = new XMLHttpRequest(); xhr.responseType = 'json'; xhr.open('get', url, true); xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { callback(xhr.response); } else { throw new Error(xhr.statusText); } }; xhr.send(); }; /** * WKT转三维笛卡尔坐标 * * @param {String} [WKT] WKT坐标串 * * @returns {Cartesian3[]} 三维笛卡尔坐标数组 * * @example * positions = sgworld.Core.getPositionFromWKT(WKT); */ Core.prototype.getPositionFromWKT = function (WKT) { let geometry = WKT + "!"; let geo; let position = []; if (geometry.indexOf("MULTIPOLYGON") > -1) { //去除首尾“MULTIPOLYGON(...)! ——> ((),(),()) , ((),(),()) , ((),(),())” geo = geometry.replace("MULTIPOLYGON(", ""); geo = geo.replace(")!", ""); //拆分多面 geo = geo.split(")),(("); geo.forEach((item, index) => { let _geo; if (geo.length === 1) { //如果只有1个,说明没有被分割 // 去掉首尾括号 ((),(),()) ——> (),(),() _geo = item.substring(1, item.length - 1); } else if (index === 0) { // 第一个,去第一个(, 补结尾加上) ((),(),( ——> (),(),() _geo = item.substring(1, item.length) + ")"; } else if (index === geo.length - 1) { // 最后一个, 补第一个(, 去 最后一个) ),(),()) ——> (),(),() _geo = "(" + item.substring(0, item.length - 1); } else { // 中间,补第一个(, 补最后一个) ),(),( ——> (),(),() _geo = "(" + item + ")"; } //_geo为(),(),() 环的集合 //拆分多环 _geo = _geo.split("),("); _geo.forEach((ring, _index) => { let ringGeo; if (_geo.length === 1) { //如果只有1个,说明没有被分割 // 去掉首尾括号 () ringGeo = ring.substring(1, ring.length - 1); } else if (_index === 0) { // 第一个,去第一个( ringGeo = ring.substring(1, ring.length); } else if (_index === _geo.length - 1) { // 最后一个, 去最后一个) ringGeo = ring.substring(0, ring.length - 1); } //ringGeo为点串 118.729063485 29.7893243870001,118.726590019 29.78666994 //拆分点 ringGeo = ringGeo.split(","); let _position = []; ringGeo.forEach((point) => { let degrees = point.split(" "); _position.push( Cesium.Cartesian3.fromDegrees(degrees[0], degrees[1]) ); }); position.push(_position); }); }); } else if (geometry.indexOf("POLYGON") > -1) { //去除首尾“POLYGON(...)! ——> (),(),()” geo = geometry.replace("POLYGON(", ""); geo = geo.replace(")!", ""); //拆分多环 geo = geo.split("),("); geo.forEach((ring, _index) => { let ringGeo; if (geo.length === 1) { //如果只有1个,说明没有被分割 // 去掉首尾括号 () ringGeo = ring.substring(1, ring.length - 1); } else if (_index === 0) { // 第一个,去第一个( ringGeo = ring.substring(1, ring.length); } else if (_index === geo.length - 1) { // 最后一个, 去最后一个) ringGeo = ring.substring(0, ring.length - 1); } //ringGeo为点串 118.729063485 29.7893243870001,118.726590019 29.78666994 //拆分点 ringGeo = ringGeo.split(","); let _position = []; ringGeo.forEach((point) => { let degrees = point.split(" "); _position.push( Cesium.Cartesian3.fromDegrees(degrees[0], degrees[1]) ); }); position.push(_position); }); } return position; }; /** * 矢量切片样式 * * @param {Object} [option] 样式 * * @returns {Object} 矢量切片样式 * */ Core.prototype.VectorSlice = function (option) { var port = 'EPSG:4490'; if (option.port) { port = option.port; } var defaultGeoOptions = { url: option.url, urlParams: { REQUEST: 'GetTile', SERVICE: 'WMTS', VERSION: '1.0.0', LAYER: option.layer, STYLE: '', TILEMATRIX: port + ':{z}', TILEMATRIXSET: port, FORMAT: 'application/json;type=geojson', TILECOL: '{x}', TILEROW: '{y}' }, upperLevelLimit: option.upperLevelLimit, lowerLevelLimit: option.lowerLevelLimit, rectangle: Cesium.Rectangle.fromDegrees(option.minx, option.miny, option.maxx, option.maxy) }; return defaultGeoOptions; }; /** * 三点计算角度 -1 && key.indexOf("]") > -1) { key = key.replace("[", "").replace("]", ""); } return properties && properties[key]; }; /** * 修改三维笛卡尔坐标高度 * * @param {Cartesian3} [position] 三维笛卡尔坐标 * @param {Number} [height] 修改后高度 * * @returns {Cartesian3} 三维笛卡尔坐标 * */ Core.prototype.setheight = function (position, height) { var Cartographic = Cesium.Cartographic.fromCartesian(position); return Cesium.Cartesian3.fromRadians(Cartographic.longitude, Cartographic.latitude, height); }; /** * 修改多个三维笛卡尔坐标高度 * * @param {Cartesian3[]} [positions] 三维笛卡尔坐标串 * @param {Number} [height] 修改后高度 * * @returns {Cartesian3[]} 三维笛卡尔坐标 * */ Core.prototype.setpolylineheight = function (position, height) { let path = []; position.forEach(function (item) { var Cartographic = Cesium.Cartographic.fromCartesian(item); path.push(Cesium.Cartesian3.fromRadians(Cartographic.longitude, Cartographic.latitude, height)); }); return path; }; //GeoJson数据对比 Core.prototype.StyleContrastGeoJson = function (obj1, Cesium) { var point = { color: Cesium.Color.WHITE, pixelSize: 1, outlineColor: Cesium.Color.BLACK, outlineWidth: 0, show: true, distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 999999999) }; var label = { id: 'my label', text: "", font: "30px sans-serif", fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.WHITE, outlineWidth: "10", scale: 1.0, distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 999999999) }; var billboard = { show: true, scale: 1.0, width: undefined, height: undefined, pixelOffset: undefined, color: Cesium.Color.WHITE, image: "", distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 999999999) }; var polyline = { positions: [], arcType: Cesium.ArcType.GEODESIC, clampToGround: true, width: 1.0, show: true, material: Cesium.Color.RED, height: 30, }; var polygon = { height: 0, heightReference: Cesium.HeightReference.NONE, show: true, fill: true, material: Cesium.Color.WHITE, outline: false, outlineColor: Cesium.Color.BLACK, outlineWidth: 1.0, stRotation: 0.0, granularity: Cesium.Math.RADIANS_PER_DEGREE, perPositionHeight: false, closeTop: true, closeBottom: true, shadows: Cesium.ShadowMode.ENABLED, clampToGround: true, }; if (this.isnull(obj1.near)) { obj1.near = 0; } if (this.isnull(obj1.far)) { obj1.far = 999999999; } var min = parseFloat(obj1.near); var max = parseFloat(obj1.far); delete obj1.near; delete obj1.far; // obj1.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(min, max); if (obj1.point != undefined) { obj1.point = this.extend(point, obj1.point, true); obj1.point.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(min, max); } if (obj1.label != undefined) { obj1.label = this.extend(label, obj1.label, true); obj1.label.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(min, max); } if (obj1.billboard != undefined) { obj1.billboard = this.extend(billboard, obj1.billboard, true); obj1.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(min, max); } if (obj1.polyline != undefined) { obj1.polyline = this.extend(polyline, obj1.polyline, true); obj1.polyline.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(min, max); } if (obj1.polygon != undefined) { obj1.polygon = this.extend(polygon, obj1.polygon, true); obj1.polygon.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(min, max); } return obj1; }; //点坐标解析 Core.prototype.getCatesian3FromPX = function (px, viewer, Cesium, entitys) { var pick = viewer.scene.pick(px); var cartesian; var drillPick = viewer.scene.drillPick(px); var truePick = null; if (entitys) { for (var i = 0; i < drillPick.length; i++) { if (drillPick[i].id._id != (entitys && entitys[0] && entitys[0].id) && drillPick[i].id._id != (entitys && entitys[1] && entitys[1].id)) { truePick = drillPick[i].id; break; } } } else { truePick = pick; } if (viewer.scene.pickPositionSupported && Cesium.defined(truePick)) { cartesian = viewer.scene.pickPosition(px); } else { var ray = viewer.camera.getPickRay(px); if (!ray) return; cartesian = viewer.scene.globe.pick(ray, viewer.scene); } return cartesian; }; //矢量数据样式对比 Core.prototype.StyleContrast = function (EntityTyple, obj1, Cesium) { var lable = { text: "", font: ' 30px sans-serif', style: Cesium.LabelStyle.FILL_AND_OUTLINE, fillColor: Cesium.Color.WHITE, // optional A Property specifying the fill Color. outlineColor: Cesium.Color.BLACK, // optional A Property specifying the outline Color. outlineWidth: 1.0, // optional A numeric Property specifying the outline width. show: true, // optional A boolean Property specifying the visibility of the label. showBackground: false, // optional A boolean Property specifying the visibility of the background behind the label. backgroundColor: new Cesium.Color(0.165, 0.165, 0.165, 0.8), //optional A Property specifying the background Color. backgroundPadding: new Cesium.Cartesian2(7, 5), //optional A Cartesian2 Property specifying the horizontal and vertical background padding in pixels. scale: 1.0, //optional A numeric Property specifying the scale to apply to the text. horizontalOrigin: Cesium.HorizontalOrigin.CENTER, //optional A Property specifying the HorizontalOrigin. verticalOrigin: Cesium.VerticalOrigin.CENTER, // optional A Property specifying the VerticalOrigin. eyeOffset: Cesium.Cartesian3.ZERO, // optional A Cartesian3 Property specifying the eye offset. pixelOffset: Cesium.Cartesian2.ZERO, // optional A Cartesian2 Property specifying the pixel offset. heightReference: Cesium.HeightReference.NONE, // optional A Property specifying what the height is relative to. scaleByDistance: undefined, distanceDisplayCondition: undefined }; var billboard = { show: true, position: Cesium.Cartesian3.ZERO, pixelOffset: Cesium.Cartesian2.ZERO, eyeOffset: Cesium.Cartesian3.ZERO, heightReference: Cesium.HeightReference.NONE, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, verticalOrigin: Cesium.VerticalOrigin.CENTER, scale: 1.0, image: '', imageSubRegion: undefined, color: Cesium.Color.WHITE, rotation: 0.0, alignedAxis: Cesium.Cartesian3.ZERO, width: undefined, height: undefined, scaleByDistance: undefined, translucencyByDistance: undefined, pixelOffsetScaleByDistance: undefined, sizeInMeters: false, distanceDisplayCondition: undefined }; var point = { show: true, pixelSize: 1, heightReference: Cesium.HeightReference.NONE, color: Cesium.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 1.0, scaleByDistance: undefined, translucencyByDistance: undefined, distanceDisplayCondition: undefined }; var polyline = { positions: [], width: 5, material: Cesium.Color.ALICEBLUE, arcType: Cesium.ArcType.GEODESIC }; var polygon = { polygonHierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray([-72.0, 40.0, -70.0, 35.0, -75.0, 30.0, -70.0, 30.0, -68.0, 40.0])), height: 0, extrudedHeight: 0, material: "rgba(245, 20, 20, 0.91)" }; if (this.isnull(obj1.near)) { obj1.near = 0; } if (this.isnull(obj1.far)) { obj1.far = 999999999; } var min = parseFloat(obj1.near); var max = parseFloat(obj1.far); delete obj1.near; delete obj1.far; obj1.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(min, max); if (EntityTyple == "lable") { obj1 = this.extend(lable, obj1, true); } else if (EntityTyple == "billboard") { obj1 = this.extend(billboard, obj1, true); } else if (EntityTyple == "point") { obj1 = this.extend(point, obj1, true); } else if (EntityTyple == "polyline") { obj1 = this.extend(polyline, obj1, true); } else if (EntityTyple == "polygon") { obj1 = this.extend(polygon, obj1, true); } return obj1; }; //创建矢量PolylineObject Core.prototype.createPolyline = function (entity, Type, id, Cesium) { var geometryInstance = null; if (Type == -1) { var geometry = new Cesium.PolylineGeometry(entity); geometryInstance = new Cesium.GeometryInstance({ id: id, geometry: geometry }); } else { var geometry = new Cesium.GroundPolylineGeometry(entity); geometryInstance = new Cesium.GeometryInstance({ geometry: geometry, id: id }); } return geometryInstance; }; //创建矢量PolygonObject Core.prototype.createPolygon = function (entity, Type, id, Cesium) { var geometryInstance = null; var color = entity.material; var extrudedPolygon = new Cesium.PolygonGeometry(entity); delete entity.material; //var geometry = Cesium.PolygonGeometry.createGeometry(extrudedPolygon); geometryInstance = new Cesium.GeometryInstance({ id: id, geometry: extrudedPolygon, attributes: { color: new Cesium.ColorGeometryInstanceAttribute.fromColor(color), } }); return geometryInstance; }; //坐标转化添加 Core.prototype.coordinate = function (newArr, arr) { for (var i = 0; i < arr.length; i++) { if (Array.isArray(arr[i])) { this.coordinate(newArr, arr[i]); } else { newArr.push(arr[i]); } } return newArr; }; //从矢量数据中解析数据 Core.prototype.Analysis = function (obj1, feature) { if (/^\[/.test(obj1) && /\]$/.test(obj1)) { var material = obj1.replace(/\[/, '').replace(/\]/, ''); if (feature.properties[material] != undefined) { obj1 = feature.properties[material]; } } return obj1; }; //数据数组去重 Core.prototype.unique = function (arr) { var newArr = []; for (var i = 0; i < arr.length; i++) { if (newArr.indexOf(arr[i]) === -1) { newArr.push(arr[i]); } } return newArr }; /** * 对象参数合并 * @param {Object} o 对象 * @param {Object} n 被合并的对象 * @param {Boolean} [override=false] 是否覆盖原属性值 * @param {Boolean} [mergeTheSame=false] 是否只合并相同属性 */ Core.prototype.extend = function (o, n, override = false, mergeTheSame = false) { for (var key in n) { if (mergeTheSame) { if (o.hasOwnProperty(key)) { o[key] = n[key]; } } else { if (!o.hasOwnProperty(key) || override) { o[key] = n[key]; } } } return o; }; /** * 坐标偏移 * @param {Cartesian3} position 坐标 * @param {Cartesian3} offset 偏移大小 * @param {HeadingPitchRoll} headingPitchRoll 旋转 * @returns {Cartesian3} */ Core.prototype.setPositionOffset = (position, offset, headingPitchRoll) => { // Matrix4 let frompoint_to_world_matrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, headingPitchRoll || new Cesium.HeadingPitchRoll()); // 向position为原点,正北为y,正东为x,地心朝上为z分别平移 // let offset = new Cesium.Cartesian3(10, 6, 2); let result = new Cesium.Cartesian3(0, 0, 0); // 转换矩阵左乘局部平移向量,结果是世界坐标下的平移终点向量 Cesium.Matrix4.multiplyByPoint(frompoint_to_world_matrix, offset, result); return result }; /** * 获取影像偏移的切片方案 * @param {String} [srs="GCJ02"] 坐标系 */ Core.prototype.getOffsetTilingScheme = function (srs = "GCJ02") { let TilingScheme, projection; if (srs === 'GCJ02') { TilingScheme = new Cesium.WebMercatorTilingScheme(); projection = new Cesium.WebMercatorProjection(); TilingScheme._projection.project = function (cartographic, result) { result = CoordTransform.WGS84ToGCJ02( Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude) ); result = projection.project( new Cesium.Cartographic( Cesium.Math.toRadians(result[0]), Cesium.Math.toRadians(result[1]) ) ); return new Cesium.Cartesian2(result.x, result.y); }; TilingScheme._projection.unproject = function (cartesian, result) { let cartographic = projection.unproject(cartesian); result = CoordTransform.GCJ02ToWGS84( Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude) ); return new Cesium.Cartographic( Cesium.Math.toRadians(result[0]), Cesium.Math.toRadians(result[1]) ); }; } return TilingScheme; }; /** * 跟踪对象 * @param {Viewer} Viewer 地图视图 * @param {Entity} entity 需要跟踪的对象 * @param {Object} [option] 参数 * @param {String} [option.type="tracked"] 跟踪类型【tracked | setView】 * @param {Cartesian3} [option.viewFrom] 视野,type为"tracked"时生效 * @param {Number} [option.heading=0] 初始方位角(度),type为"setView"时生效 * @param {Number} [option.pitch=-45] 初始俯仰角(度),type为"setView"时生效 * @param {Number} [option.distance=1000] 初始跟踪距离(米),type为"setView"时生效 * @param {Number} [option.minDistance=0] 最小跟踪距离(米),type为"setView"时生效 * @param {Object} [option.tooltip] 提示框 * @param {String} [option.tooltip.innerHTML=''] 提示框内容 * @param {Boolean} [option.tooltip.drag=false] 是否可拖动 * @param {Number} [option.tooltip.near=0] 提示框最小可视距离 * @param {Number} [option.tooltip.far=1000] 提示框最大小可视距离 * @param {Number} [option.tooltip.addX=0] 提示框X方向偏移量 * @param {Number} [option.tooltip.addY=0] 提示框Y方向偏移量 * @param {Number} [option.tooltip.far=1000] 提示框最大小可视距离 * @param {Function} [option.start] 开始回调 * @param {Function} [option.update] 更新回调 * @param {Function} [option.end] 结束回调 * * @example * var url = SmartEarthRootUrl + "Workers/Model/weixin.gltf"; var position = new Cesium.Cartesian3.fromDegrees(110, 32, 1000); let model = sgworld.Creator.addSimpleGraphic('model', { url: url, position: position, removeEdit: true // 屏蔽全局标绘编辑功能 }); sgworld.Core.trackedEntity(Viewer, model, { type: "setView", distance: 10000, tooltip: { drag: true, innerHTML: `

大湖名城,创新高地

`, far: 20000, addX: 50, addY: -60, } }) */ Core.prototype.trackedEntity = function (Viewer, entity, option = {}) { let _option = { type: 'tracked', heading: 0, pitch: -45, distance: 1000, minDistance: 0 }; Object.assign(_option, option); let tooltip, tooltipContainer, tooltipArrow; if (_option.tooltip) { let tooltipOption = { innerHTML: '', drag: false, near: 0, far: 1000, addX: 0, addY: 0, }; _option.tooltip = Object.assign(tooltipOption, _option.tooltip); let tooltipHTML = ``; $(Viewer.container).append(tooltipHTML); tooltip = document.getElementById("trackedTooltip" + entity.id); tooltipContainer = tooltip.firstElementChild; tooltipContainer.innerHTML = _option.tooltip.innerHTML; tooltipContainer.style.left = _option.tooltip.addX + 'px'; tooltipContainer.style.top = _option.tooltip.addY + 'px'; tooltipContainer.style.position = "relative"; if (_option.tooltip.drag) { // 引导线 tooltipArrow = document.createElement("div"); tooltipArrow.className = "trackedTooltip-arrow"; tooltip.appendChild(tooltipArrow); let width, _left, _bottom, transform; let getWithAndTransform = (x, y) => { let angle; width = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); _left = -(width - x) / 2 + "px"; _bottom = -y / 2 + "px"; if (!x) { // x为0 if (y > 0) { angle = 90; } else { angle = -90; } } else { angle = Cesium.Math.toDegrees(Math.atan(y / x)); if (x < 0) { _left = (width + x) / 2 - width + "px"; } } transform = `rotate(${angle}deg)`; }; getWithAndTransform(_option.tooltip.addX, _option.tooltip.addY); tooltipArrow.style.cssText = ` position: absolute; bottom: ${_bottom}; left: ${_left}; width: ${width}px; height: 0px; transform: ${transform}; border-top: 2px dashed #f00; `; tooltipContainer.style.pointerEvents = 'all'; tooltipContainer.addEventListener("mousedown", function (e) { //算出鼠标相对元素的位置 let x = e.pageX - tooltipContainer.offsetLeft; let y = e.pageY - tooltipContainer.offsetTop; let left, top; document.onmousemove = (e) => { left = e.pageX - x; top = e.pageY - y; //鼠标按下并移动的事件 //用鼠标的位置减去鼠标相对元素的位置,得到元素的位置 tooltipContainer.style.left = left + "px"; tooltipContainer.style.top = top + "px"; getWithAndTransform(left, top); tooltipArrow.style.width = `${width}px`; tooltipArrow.style.left = _left; tooltipArrow.style.bottom = _bottom; tooltipArrow.style.transform = transform; }; document.onmouseup = (e) => { document.onmousemove = null; }; }); } } this.endTrackedEntity && this.endTrackedEntity(); _option.start && typeof _option.start === 'function' && _option.start(); let handler = new Cesium.ScreenSpaceEventHandler(Viewer.scene.canvas); let setViewFun; if (_option.type === "setView") { setViewFun = () => { let time = Viewer.clock.currentTime.clone(); let position = entity.position.getValue(time); Viewer.scene.camera.setView({ destination: position, // 点的坐标 orientation: { heading: Cesium.Math.toRadians(_option.heading), pitch: Cesium.Math.toRadians(_option.pitch), } }); Viewer.scene.camera.moveBackward(_option.distance); if (_option.tooltip) { if (_option.distance <= _option.tooltip.far && _option.distance >= _option.tooltip.near) { tooltip.style.display = 'block'; } else { tooltip.style.display = 'none'; } let CanvasCoordinates = Viewer.scene.cartesianToCanvasCoordinates(position); if (!CanvasCoordinates) return; tooltip.style.left = CanvasCoordinates.x + "px"; tooltip.style.top = CanvasCoordinates.y - tooltip.offsetHeight + "px"; } _option.position = position; _option.update && typeof _option.update === 'function' && _option.update(); }; Viewer.scene.preRender.addEventListener(setViewFun); let startData, endPosition, _x, _y; handler.setInputAction(movement => { startData = { position: movement.position, heading: _option.heading, pitch: _option.pitch, }; }, Cesium.ScreenSpaceEventType.LEFT_DOWN); handler.setInputAction(movement => { startData = undefined; }, Cesium.ScreenSpaceEventType.LEFT_UP); handler.setInputAction(movement => { if (startData) { endPosition = movement.endPosition; _x = endPosition.x - startData.position.x; _y = endPosition.y - startData.position.y; _option.heading = startData.heading + _x / 8; _option.pitch = startData.pitch - _y / 6; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); handler.setInputAction(movement => { _option.distance -= movement * _option.distance / 1000; _option.distance < _option.minDistance && (_option.distance = _option.minDistance); }, Cesium.ScreenSpaceEventType.WHEEL); } else { _option.viewFrom && (entity.viewFrom = _option.viewFrom); Viewer.trackedEntity = entity; } handler.setInputAction(movement => { this.endTrackedEntity && this.endTrackedEntity(); }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); this.endTrackedEntity = () => { handler && handler.destroy(); Viewer.trackedEntity = undefined; setViewFun && Viewer.scene.preRender.removeEventListener(setViewFun); tooltip && tooltip.remove(); tooltip = undefined; setViewFun = undefined; handler = undefined; _option.end && typeof _option.end === 'function' && _option.end(); }; _option.destroy = this.endTrackedEntity; _option.updataTooltip = (innerHTML) => { tooltipContainer.innerHTML = _option.tooltip.innerHTML = innerHTML; }; return _option; }; Core.prototype.getPointFromWindowPoint = function (point, _viewer) { if (_viewer.scene.terrainProvider.constructor.name == "EllipsoidTerrainProvider") { return _viewer.camera.pickEllipsoid(point, _viewer.scene.globe.ellipsoid); } else { var ray = _viewer.scene.camera.getPickRay(point); return _viewer.scene.globe.pick(ray, _viewer.scene); } }; Core.prototype.isnull = function (param) { if (param == null || param == undefined || param === '') return true; else return false; }; Core.prototype.getuid = function () { // var idStr = Date.now().toString(36); // idStr += Math.random().toString(36).substr(3); // return idStr; // return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { // var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); // return v.toString(16); // }); return this.uuid(8, 16); }; //过滤数据 Core.prototype.extendgl = function (entity, optionItem, optionItems) { if (optionItem != undefined && optionItem != null) { if (typeof (optionItem) == 'string') { if (optionItem.charAt(0) == "[" && optionItem.charAt(optionItem.length - 1) == "]") { optionItem = optionItem.substr(0, optionItem.length - 1); optionItem = optionItem.substr(1); if (entity.properties[optionItem]._value != undefined) { optionItem = entity.properties[optionItem]._value; } else if (entity.properties[optionItem] != undefined) { optionItem = entity.properties[optionItem]; } } } return optionItem; } else { return optionItems; } }; /** * 自定义Geometry * @param {Object} option 参数 * @param {Array} option.position 顶点坐标 * @param {Array} option.st 纹理坐标 * @param {Array} option.indices 三角网连接索引 * @param {Boolean} option.grid 是否显示三角网 * @param {BoundingSphere} option.boundingSphere 边界球 * @returns {Geometry} */ Core.prototype.customGeometry = function (option) { if (option.scale) { for (let i = 0; i < option.position.length - 2; i += 3) { option.position[i] *= option.scale[0]; option.position[i + 1] *= option.scale[1]; option.position[i + 2] *= option.scale[2]; } } let geometry = new Cesium.Geometry({ attributes: { position: new Cesium.GeometryAttribute({ componentDatatype: Cesium.ComponentDatatype.DOUBLE, componentsPerAttribute: 3, values: option.position, }), st: new Cesium.GeometryAttribute({ componentDatatype: Cesium.ComponentDatatype.FLOAT, componentsPerAttribute: 2, values: option.st, }), }, //索引 indices: option.indices, //绘制类型 primitiveType: option.grid ? Cesium.PrimitiveType.LINES : Cesium.PrimitiveType.TRIANGLES, boundingSphere: option.boundingSphere, }); return geometry }; /** * 获取当前层级 */ Core.prototype.getLevel = function (Viewer) { let level = 0; let tilesToRender = Viewer.scene.globe._surface._tilesToRender; if (tilesToRender) { tilesToRender.forEach(tile => { if (tile.level > level) { level = tile.level; } }); } return level; }; /** * 获取当前视角范围 * @param {Viewer} Viewer 地图视图 */ Core.prototype.getViewRectangle = function (Viewer) { let rectangle = Viewer.camera.computeViewRectangle(); return this.toDegreesRectangle(rectangle); }; /** * 获取当前视角范围 * @param {Viewer} Viewer 地图视图 */ Core.prototype.toDegreesRectangle = function (rectangle) { let rec = new Cesium.Rectangle(); rec.west = Cesium.Math.toDegrees(rectangle.west); rec.north = Cesium.Math.toDegrees(rectangle.north); rec.east = Cesium.Math.toDegrees(rectangle.east); rec.south = Cesium.Math.toDegrees(rectangle.south); return rec; }; /** * 获取多边形质心 * @param {Array} positions 坐标串 */ Core.prototype.getCenterOfMass = function (positions) { let degreesArr = []; let height = 0; if (positions[0].x) { let degrees; positions.forEach(p => { degrees = this.toDegrees(p); degreesArr.push([degrees.lon, degrees.lat]); height += degrees.height; }); } else if (positions[0].lon) { positions.forEach(degrees => { degreesArr.push([degrees.lon, degrees.lat]); height += (degrees.height || 0); }); } else if (Array.isArray(positions[0])) { degreesArr = positions; positions.forEach(degrees => { height += (degrees[2] || 0); }); } let polygon = turf.polygon([degreesArr]); let center = turf.pointOnFeature(polygon); height /= positions.length; center.geometry.coordinates[2] = height; return center.geometry.coordinates; }; /** * 添加模型拾取高亮状态 * @param {Viewer} Viewer 地图视图 * @param {String} color 高亮颜色 */ Core.prototype.addPickStage = function (Viewer, color = 'rgba(255,0,0,0.6)') { let fragmentShaderSource = "uniform sampler2D colorTexture;\n" + "varying vec2 v_textureCoordinates;\n" + "uniform vec4 highlight;\n" + "void main() {\n" + " vec4 color = texture2D(colorTexture, v_textureCoordinates);\n" + " if (czm_selected()) {\n" + " vec3 highlighted = highlight.a * highlight.rgb + (1.0 - highlight.a) * color.rgb;\n" + " gl_FragColor = vec4(highlighted, 1.0);\n" + " } else { \n" + " gl_FragColor = color;\n" + " }\n" + "}\n"; let pickStage = Viewer.scene.postProcessStages.add( new Cesium.PostProcessStage({ fragmentShader: fragmentShaderSource, uniforms: { highlight: function () { return new Cesium.Color.fromCssColorString(color); } } }) ); pickStage.selected = []; return { select(feature) { if (!feature.color && feature.content) { feature = feature.content.tile; } else if (feature.id instanceof Cesium.Entity) { feature = feature.id; } pickStage.selected = [feature]; this.changeOtherHighlight(); }, changeOtherHighlight() { let feature = pickStage.selected[0]; if (feature) { if (feature instanceof Cesium.Cesium3DTile) { if (feature.defaultColor) { feature.color = feature.defaultColor; feature.defaultColor = null; } else { feature.defaultColor = feature.color && feature.color.clone(); feature.color = Cesium.Color.RED; } } else if (feature instanceof Cesium.Entity) ; else if (feature.primitive instanceof S3MTilesLayer) { if (feature.primitive._selections.length) { feature.primitive.releaseSelection(); } else { feature.primitive.setSelection(feature.id); } } } }, remove() { this.changeOtherHighlight(); pickStage.selected = []; }, destroy() { Viewer.scene.postProcessStages.remove(pickStage); } }; }; Core.prototype.addLoading = function (container, loadingImg) { let loading = document.createElement('div'); loading.id = 'cesiumLoading'; loading.style.cssText = 'width: 100%;height: 100%;display:none;pointer-events: none;position: absolute;top: 0;left: 0;-moz-box-sizing: border-box;box-sizing: border-box;background-color: unset;z-index: 99999;'; let img = document.createElement('img'); img.style.cssText = 'position: relative;width: 110px;height: 110px;margin: auto;top: 50%;left: 50%;margin-top: -55px;margin-left: -55px;'; img.src = loadingImg || window.SmartEarthRootUrl + configData$1.loading; loading.appendChild(img); container.appendChild(loading); return { isLoading(show) { if (show) { loading.style.display = 'block'; } else { loading.style.display = 'none'; } }, remove() { loading && loading.remove(); loading = null; } } }; /** * 获取uuid */ Core.prototype.uuid = function (len, radix) { var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); var uuid = [], i; var uuid = [], i; radix = radix || chars.length; if (len) { // Compact form for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]; } else { // rfc4122, version 4 form var r; // rfc4122 requires these characters uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; // Fill in random data. At i==19 set the high bits of clock sequence as // per rfc4122, sec. 4.1.5 for (i = 0; i < 36; i++) { if (!uuid[i]) { r = 0 | Math.random() * 16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } return uuid.join(''); }; //着色器 Core.prototype.Shaders = function (Shadersp) { var Shaders = ""; if (Shadersp == "VSHADER_SOURCE ") { Shaders = "attribute vec4 a_Position;" + "\nattribute vec2 a_TexCoord;" + "\nuniform mat4 u_MvpMatrix;" + "\nvarying vec2 v_TexCoord;" + "\n" + "void main()" + "{\ngl_Position = u_MvpMatrix * a_Position;\nv_TexCoord = a_TexCoord;\n}\n"; } else if (Shadersp == "TRIANGLE_FSHADER_SOURCE") { Shaders = "#ifdef GL_ES" + "\nprecision mediump float;" + "\n#endif" + "\nvarying vec4 v_Color;" + "\nvoid main()" + " {\ngl_FragColor = v_Color;\n'}\n"; } else if (Shadersp == "TRIANGLE_VSHADER_SOURCE") { Shaders = "attribute vec4 a_Position;" + "\nattribute vec4 a_Normal;" + "\nuniform mat4 u_MvpMatrix;" + "\nuniform mat4 u_NormalMatrix;" + "\nvarying vec4 v_Color;" + "\n" + "void main() {" + "\nvec3 lightDirection = vec3(0.0, 0.0, 1.0);\nvec4 color = vec4(1.0, 1.0, 0.0, 1.0);\ngl_Position = u_MvpMatrix * a_Position;\nvec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\nfloat nDotL = max(dot(normal, lightDirection), 0.0);\nv_Color = vec4(color.rgb * nDotL, color.a);\n}\n"; } else if (Shadersp == "vertexShaderSource") { Shaders = "attribute vec3 position3DHigh;" + "\r\n" + "attribute vec3 position3DLow;" + "\r\n" + "attribute vec3 normal;" + "\r\nattribute vec2 st;" + "\r\nattribute vec4 color;" + "\r\nattribute float batchId;" + "\r\nvarying vec3 v_positionEC;" + "\r\nvarying vec3 v_normalEC;" + "\r\nvarying vec2 v_st;" + "\r\nvarying vec4 v_color;" + "\r\n" + "void main()" + "\r\n{" + "\r\nvec4 p = czm_computePosition();" + "\r\nv_positionEC = (czm_modelViewRelativeToEye * p).xyz;" + "\r\nv_normalEC = czm_normal * normal;" + "\r\nv_st = st;" + "\r\nv_color = color;" + "\r\ngl_Position = czm_modelViewProjectionRelativeToEye * p;" + "\r\n}\r\n"; } else if (Shadersp == "fragmentShaderSource") { Shaders = "varying vec3 v_positionEC;" + "\r\nvarying vec3 v_normalEC;" + "\r\nvarying vec2 v_st;" + "\r\nvarying vec4 v_color;" + "\r\n" + "\r\nvec4 czm_phong(vec3 toEye, czm_material material)" + "\r\n{" + "\r\nfloat diffuse = czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 0.0, 1.0), material);" + "\r\nif (czm_sceneMode == czm_sceneMode3D) {" + "\r\n diffuse += czm_private_getLambertDiffuseOfMaterial(vec3(0.0, 1.0, 0.0), material);" + "\r\n}" + "\r\nfloat specular = czm_private_getSpecularOfMaterial(czm_sunDirectionEC, toEye, material) + czm_private_getSpecularOfMaterial(czm_moonDirectionEC, toEye, material);" + "\r\nvec3 materialDiffuse = material.diffuse * 0.5;" + "\r\nvec3 ambient = materialDiffuse;" + "\r\nvec3 color = ambient + material.emission;" + "\r\ncolor += materialDiffuse * diffuse;" + "\r\ncolor += material.specular * specular;" + "\r\nreturn vec4(color, material.alpha);" + "\r\n}" + "void main()" + "\r\n{\r\nvec3 positionToEyeEC = -v_positionEC;" + "\r\nvec3 normalEC = normalize(v_normalEC);" + "\r\n#ifdef FACE_FORWARD" + "\r\nnormalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);" + "\r\n#endif" + "\r\nvec4 color = czm_gammaCorrect(v_color);" + "\r\nczm_materialInput materialInput;" + "\r\nmaterialInput.normalEC = normalEC;" + "\r\nmaterialInput.positionToEyeEC = positionToEyeEC;\r\nmaterialInput.st = v_st;" + "\r\nczm_material material = czm_getDefaultMaterial(materialInput);" + "\r\nmaterial.diffuse = color.rgb;\r\nmaterial.alpha = color.a;" + "\r\n#ifdef FLAT\r\ngl_FragColor = vec4(material.diffuse + material.emission, material.alpha);" + "\r\n#else\r\ngl_FragColor = czm_phong(normalize(positionToEyeEC), material);\r\n#endif\r\n}\r\n"; } return Shaders; }; //判断是否是颜色 Core.prototype.isHtmlColor = function (htmlcolor) { var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/; return reg.test(htmlcolor); }; Core.prototype.isUrl = function (url) { if (this.isnull(url)) { return false; } var reg = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/; return reg.test(url); }; Core.prototype.dateTimespan = function () { var date = new Date(); return date.toTimeString(); }; //获取两点间距离起点某一距离的一个点 Core.prototype.getPointFromTwoPointCenter = function (positions, distance, height) { let allDistance = this.getSpaceDistancem(positions, Cesium); if (allDistance < distance) { return undefined; } let startPoint = positions[0]; let endPoint = positions[1]; let scartographic = Cesium.Cartographic.fromCartesian(startPoint); let slongitude = Cesium.Math.toDegrees(scartographic.longitude); let slatitude = Cesium.Math.toDegrees(scartographic.latitude); let sheight = scartographic.height; let ecartographic = Cesium.Cartographic.fromCartesian(endPoint); let elongitude = Cesium.Math.toDegrees(ecartographic.longitude); let elatitude = Cesium.Math.toDegrees(ecartographic.latitude); let eheight = ecartographic.height; let pointSum = parseFloat(allDistance / distance); //取样点个数 let addX = Cesium.Math.lerp(slongitude, elongitude, 1.0 / pointSum) - slongitude; let addY = Cesium.Math.lerp(slatitude, elatitude, 1.0 / pointSum) - slatitude; let addZ = Cesium.Math.lerp(sheight, eheight, 1.0 / pointSum) - sheight; return Cesium.Cartesian3.fromDegrees(slongitude + addX, slatitude + addY, height || sheight + addZ); }; //空间距离测量(千米) Core.prototype.getSpaceDistance = function (positions, Cesium) { var distance = 0; var dis = ""; for (var i = 0; i < positions.length - 1; i++) { var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]); var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]); /**根据经纬度计算出距离**/ var geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); var s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 s = (Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2))); distance = distance + s; } if (distance >= 1000) { dis = (distance / 1000).toFixed(2) + "千米"; } else { dis = (distance.toFixed(2)) + "米"; } //return distance.toFixed(2); return dis; }; //空间距离测量用米 Core.prototype.getSpaceDistancem = function (positions, Cesium) { var distance = 0; for (var i = 0; i < positions.length - 1; i++) { var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]); var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]); /**根据经纬度计算出距离**/ var geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); var s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 s = (Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2))); distance = distance + s; } return distance.toFixed(2); }; //水平距离测量 Core.prototype.getHorizontalDistance = function (positions, Cesium) { var distance = 0; for (var i = 0; i < positions.length - 1; i++) { var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]); var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]); /**根据经纬度计算出距离**/ var geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); var s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 //s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)); distance = distance + s; } if (distance >= 1000) { distance = (distance / 1000).toFixed(2) + "千米"; } else { distance = (distance.toFixed(2)) + "米"; } return distance; }; /** * 根据间隔获取多边形内的插值点 * @param {Array} degreesArr 面坐标 * @param {Number} [distance=50] 间隔(米) * @param {Boolean} [linePoint=true] 是否包含边界上的点 */ Core.prototype.getPointsInPolygon = function (degreesArr, distance = 50, linePoint = true) { if (degreesArr.length < 3) return; // 多边形闭合 degreesArr.push(degreesArr[0]); // 计算边界框 let line = Cesium_turf.lineString(degreesArr); let bbox = Cesium_turf.bbox(line); // 计算固定间隔的网格点 let grid = Cesium_turf.pointGrid(bbox, distance, { units: 'meters' }); // 多边形范围 let polygon = Cesium_turf.polygon([degreesArr]); // 点在多边形内 let PointInPolygon = Cesium_turf.pointsWithinPolygon(grid, polygon); if (linePoint) { // 根据间隔获取多边形边上的点 for (let i = 0; i < degreesArr.length - 1; i++) { let polygonLine = Cesium_turf.lineString([ degreesArr[i], degreesArr[i + 1] ]); let options = { units: 'meters' }; let length = Cesium_turf.length(polygonLine, options); let linePoint; for (let num = distance; true; num += distance) { if (num <= length) { linePoint = Cesium_turf.along(polygonLine, num, options); PointInPolygon.features.push(linePoint); } else { linePoint = Cesium_turf.along(polygonLine, length, options); PointInPolygon.features.push(linePoint); break; } } } } return PointInPolygon; }; /** * 根据点获取tin三角网 * @param {FeatureCollection} points 点集合 * @param {Object} [option] 参数 * @param {Boolean} [option.getArea=false] 是否计算面积 * @param {Feature} [option.polygon] 多边形范围 */ Core.prototype.tinFromPoints = function (points, option = {}) { let { polygon, getArea } = option; // 生成tin三角网 let tin = Cesium_turf.tin(points); let area = 0; if (tin && tin.features) { tin.features.forEach(feature => { let inPolygon = true; if (polygon) { // 计算面的质心 let center = Cesium_turf.centerOfMass(feature); // 质心是否在多边形内(即tin是否在面范围内) inPolygon = Cesium_turf.booleanPointInPolygon(center, polygon); } if (inPolygon) { let coordinates = feature.geometry.coordinates[0]; let points = [], positions = []; for (let i = 0; i < 3; i++) { points.push([coordinates[i][0], coordinates[i][1]]); positions.push(Cesium.Cartesian3.fromDegrees(coordinates[i][0], coordinates[i][1], coordinates[i][2])); } feature.positions = positions; if (getArea) { feature.area = this.getArea(points, positions, true); area += feature.area; } } }); } return { tin, area } }; /** * 计算空间面积(插值) * @param {Viewer} Viewer 地图视图 * @param {Array} degreesArr 经纬度数组 * @param {Object} [option] 参数 * @param {Number} [option.distance=50] 插值大小 * @param {Boolean} [option.isNum=false] 是否返回数字 * @param {Boolean} [option.onlyTerrain=false] 是否只测量高精度地形 * @returns {Promise|Object} */ Core.prototype.getSpaceArea = function (Viewer, degreesArr, option = {}) { let distance = this.defaultValue(option.distance, 50); let onlyTerrain = this.defaultValue(option.onlyTerrain, false); let isNum = this.defaultValue(option.isNum, false); // 点在多边形内 let PointInPolygon = this.getPointsInPolygon(degreesArr, distance, true); // 多边形范围 let polygon = Cesium_turf.polygon([degreesArr]); // 获取面积和三角网 let getAreaAndTin = () => { // 生成tin三角网 let { tin, area } = this.tinFromPoints(PointInPolygon, { getArea: true, polygon: polygon }); if (isNum) { return { area, tin }; } if (area < 1000000) { area = area.toFixed(2) + '平方米'; } else { area = (area / 1000000.0).toFixed(2) + '平方千米'; } return { area, tin }; }; if (onlyTerrain) { /** * * 获取高精度地形 * */ let polygonAllPoints = []; PointInPolygon.features.forEach(feature => { let coordinates = feature.geometry.coordinates; polygonAllPoints.push(Cesium.Cartographic.fromDegrees(coordinates[0], coordinates[1])); }); return this.getHeightsFromLonLat(Viewer, polygonAllPoints).then(polygonAllHeight => { PointInPolygon.features.forEach((feature, index) => { let coordinates = feature.geometry.coordinates; coordinates[2] = polygonAllHeight[index] || 0; }); return getAreaAndTin(); }) } else { /** * * 获取地形和模型,非高精度地形 * */ PointInPolygon.features.forEach(feature => { let coordinates = feature.geometry.coordinates; let position = new Cesium.Cartographic(Cesium.Math.toRadians(coordinates[0]), Cesium.Math.toRadians(coordinates[1])); let height = Viewer.scene.sampleHeight(position) || 0; coordinates[2] = height; }); return getAreaAndTin(); } }; //扫掠体截面样式-多边形 Core.prototype.starPositions = function (arms, rOuter, rInner) { var angle = Math.PI / arms; var pos = []; for (var i = 0; i < 2 * arms; i++) { var r = (i % 2) === 0 ? rOuter : rInner; var p = new Cesium.Cartesian2(Math.cos(i * angle) * r, Math.sin(i * angle) * r); pos.push(p); } return pos; }; //扫掠体截面样式-圆形 Core.prototype.computeCircle = function (radius) { let positions = polylineVolumeShapeData.get(radius); if (positions) { return positions; } else { positions = []; for (let i = 0; i < 360; i += 12) { let radians = Cesium.Math.toRadians(i); positions.push(new Cesium.Cartesian2(radius * Math.cos(radians), radius * Math.sin(radians))); } polylineVolumeShapeData.set(radius, positions); return positions; } }; //计算多边形面积 Core.prototype.getArea = function (points, positions, isnum) { if (points.length < 3) { return; } let pArr = Array.concat(points, [points[0]]); var res = 0; let polygon = Cesium_turf.polygon([pArr]); // 多边形拆分三角形 let triangles; if (pArr.length === 4) { triangles = [polygon]; } else { triangles = Cesium_turf.tesselate(polygon).features; } let coordinates, firstIndex, secondIndex, thirdIndex; triangles.forEach(feature => { coordinates = feature.geometry.coordinates[0]; firstIndex = pArr.findIndex(item => { return item.toString() === coordinates[0].toString() }); secondIndex = pArr.findIndex(item => { return item.toString() === coordinates[1].toString() }); thirdIndex = pArr.findIndex(item => { return item.toString() === coordinates[2].toString() }); let side1 = this.getdistance(positions[firstIndex], positions[secondIndex]); let side2 = this.getdistance(positions[secondIndex], positions[thirdIndex]); let side3 = this.getdistance(positions[firstIndex], positions[thirdIndex]); // 海伦公式(三边求三角形面积) let p = (side1 + side2 + side3) / 2; res += Math.sqrt(p * ((p - side1) * (p - side2) * (p - side3))); }); if (isnum) { return res; } if (res < 1000000) { res = res.toFixed(2) + '平方米'; } else { res = (res / 1000000.0).toFixed(2) + '平方千米'; } return res; }; //计算 Core.prototype.getdistance = function (point1, point2) { var point1cartographic = Cesium.Cartographic.fromCartesian(point1); var point2cartographic = Cesium.Cartographic.fromCartesian(point2); /**根据经纬度计算出距离**/ var geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); var s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)); return s; }; //角度计算 Core.prototype.Angle = function (p1, p2, p3) { var bearing21 = this.Bearing(p2, p1); var bearing23 = this.Bearing(p2, p3); var angle = bearing21 - bearing23; if (angle < 0) { angle += 360; } return angle; }; //方向计算 Core.prototype.Bearing = function (from, to) { var radiansPerDegree = Math.PI / 180.0; //角度转化为弧度(rad) var degreesPerRadian = 180.0 / Math.PI; //弧度转化为角度 var lat1 = from.lat * radiansPerDegree; var lon1 = from.lon * radiansPerDegree; var lat2 = to.lat * radiansPerDegree; var lon2 = to.lon * radiansPerDegree; var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)); if (angle < 0) { angle += Math.PI * 2.0; } angle = angle * degreesPerRadian; //角度 return angle; }; //获取高度 Core.prototype.getHeight = function (_positions, Cesium) { try { if (_positions.length > 1) { var cartographic = Cesium.Cartographic.fromCartesian(_positions[0]); var cartographic1 = Cesium.Cartographic.fromCartesian(_positions[1]); var height_temp = (cartographic1.height - cartographic.height) / 1000; //var height_temp = _positions[1].z - _positions[0].z; return height_temp.toFixed(2); } else { return 0; } } catch (ex) { console.log(ex); } }; //剖面分析 Core.prototype.getPmfx = function (_positions, pointSum1, cyjj, Cesium, viewer, methond) { //起止点相关信息 var pmx = { gcs: [], min: 99999, max: 0, juli: 0.0, cys: pointSum1 }; var julifr = this.getSpaceDistancem(_positions, Cesium); pmx.juli = julifr; if (cyjj == 0) ; else { pointSum1 = parseInt(julifr / cyjj); } pmx.cys = pointSum1; var startPoint = _positions[0]; var endPoint = _positions[_positions.length - 1]; var scartographic = Cesium.Cartographic.fromCartesian(startPoint); var slongitude = Cesium.Math.toDegrees(scartographic.longitude); var slatitude = Cesium.Math.toDegrees(scartographic.latitude); scartographic.height; var ecartographic = Cesium.Cartographic.fromCartesian(endPoint); var elongitude = Cesium.Math.toDegrees(ecartographic.longitude); var elatitude = Cesium.Math.toDegrees(ecartographic.latitude); ecartographic.height; var pointSum = pointSum1; //取样点个数 var addXTT = Cesium.Math.lerp(slongitude, elongitude, 1.0 / pointSum) - slongitude; var addYTT = Cesium.Math.lerp(slatitude, elatitude, 1.0 / pointSum) - slatitude; var positions = []; var heightArr = []; var Cartesian; positions.push(scartographic); for (var i = 0; i < pointSum; i++) { var longitude = slongitude + (i + 1) * addXTT; var latitude = slatitude + (i + 1) * addYTT; Cartesian = Cesium.Cartesian3.fromDegrees(longitude, latitude); positions.push(Cesium.Cartographic.fromCartesian(Cartesian)); } var _this = this; this.getHeightsFromLonLat(viewer, positions).then(data => { if (data) { heightArr = data; var changeDepthTest = false; if (viewer.scene.globe.depthTestAgainstTerrain !== true) { viewer.scene.globe.depthTestAgainstTerrain = true; changeDepthTest = true; } for (i = 0; i < heightArr.length; i++) { var modelHeight = _this.get3DTileOrPrimitivesHeights(positions[i], viewer); if (modelHeight !== undefined) { heightArr[i] = modelHeight; } var he = heightArr[i].toFixed(2); if (parseFloat(he) < parseFloat(pmx.min)) { pmx.min = parseFloat(he); } if (parseFloat(he) > parseFloat(pmx.max)) { pmx.max = parseFloat(he); } pmx.gcs.push(he); } if (changeDepthTest) { viewer.scene.globe.depthTestAgainstTerrain = false; } if (methond != "" && methond != null) { if (typeof methond == 'function') methond(pmx); } } }); }; //剖面分析 Core.prototype.getPmfxPro = function (_positions, pointSum1, cyjj, Cesium, viewer, methond) { let _this = this; //起止点相关信息 let pmx = { gcs: [], min: 99999, max: 0, juli: 0.0, cys: 0 }; let positions = []; let pointNum = []; //获取总间隔点数和距离 for (let i = 0; i < _positions.length - 1; i++) { let julifr = _this.getSpaceDistancem([_positions[i], _positions[i + 1]], Cesium); julifr = parseFloat(julifr); pmx.juli += julifr; if (cyjj == 0) ; else { pointSum1 = parseInt(julifr / cyjj); } pointNum.push(pointSum1); pmx.cys += pointSum1; } let startAnalyse = () => { pointNum.forEach((num, i) => { let startPoint = _positions[i]; let endPoint = _positions[i + 1]; //起点 let scartographic = Cesium.Cartographic.fromCartesian(startPoint); let slongitude = Cesium.Math.toDegrees(scartographic.longitude); let slatitude = Cesium.Math.toDegrees(scartographic.latitude); //终点 let ecartographic = Cesium.Cartographic.fromCartesian(endPoint); let elongitude = Cesium.Math.toDegrees(ecartographic.longitude); let elatitude = Cesium.Math.toDegrees(ecartographic.latitude); let pointSum = num; //取样点个数 let addXTT = Cesium.Math.lerp(slongitude, elongitude, 1.0 / pointSum) - slongitude; let addYTT = Cesium.Math.lerp(slatitude, elatitude, 1.0 / pointSum) - slatitude; let Cartesian; i === 0 && positions.push(scartographic); for (let j = 0; j < pointSum; j++) { let longitude = slongitude + (j + 1) * addXTT; let latitude = slatitude + (j + 1) * addYTT; Cartesian = Cesium.Cartesian3.fromDegrees(longitude, latitude); positions.push(Cesium.Cartographic.fromCartesian(Cartesian)); } }); positions.push(Cesium.Cartographic.fromCartesian(_positions[_positions.length - 1])); let heightArr = []; pmx.allPoint = positions; this.getHeightsFromLonLat(viewer, positions).then(data => { if (data) { heightArr = data; let changeDepthTest = viewer.scene.globe.depthTestAgainstTerrain; viewer.scene.globe.depthTestAgainstTerrain = true; for (let i = 0; i < heightArr.length; i++) { let modelHeight = _this.get3DTileOrPrimitivesHeights(positions[i], viewer); if (modelHeight !== undefined) { heightArr[i] = modelHeight; } let he = heightArr[i].toFixed(2); if (parseFloat(he) < parseFloat(pmx.min)) { pmx.min = parseFloat(he); } if (parseFloat(he) > parseFloat(pmx.max)) { pmx.max = parseFloat(he); } pmx.gcs.push(he); } viewer.scene.globe.depthTestAgainstTerrain = changeDepthTest; methond && typeof methond == 'function' && methond(pmx); } }); }; if (pmx.cys > 1000) { layuiLayer && layuiLayer.msg('当前采样点数过多,是否继续分析?', { time: 0, btn: ['继续', '取消'], btnAlign: 'c', yes: (index) => { layuiLayer.close(index); setTimeout(() => { startAnalyse(); }, 10); }, btn2: () => { methond && typeof methond == 'function' && methond(pmx); } }); } else { setTimeout(() => { startAnalyse(); }, 10); } }; //根据位置(Cartographic)获取3DTiles和Primitives高度 Core.prototype.get3DTileOrPrimitivesHeights = function (position, Viewer) { return Viewer.scene.sampleHeight(position); }; //根据经纬度获取地形高度(异步) Core.prototype.getHeightsFromLonLat = function (Viewer, positions) { var heights = []; if (Viewer.terrainProvider) { if (Viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider) { return new Promise(function (resolve, reject) { positions.forEach(p => { heights.push(0); }); resolve(heights); }); } else { //根据经纬度计算出地形高度。 let promise = Cesium.sampleTerrainMostDetailed(Viewer.terrainProvider, positions); return promise.then(updatedPositions => { updatedPositions.forEach(function (item) { heights.push(item.height); }); return heights; }, () => { positions.forEach(p => { heights.push(Viewer.scene.globe.getHeight(p)); }); return heights; }); } } else { return new Promise(function (resolve, reject) { positions.forEach(p => { heights.push(Viewer.scene.globe.getHeight(p)); }); resolve(heights); }); } }; Core.prototype.getColorRamp = function (selectedShading, colorArr, min, max) { var elevationRamp = [0.0, 0.05, 0.2, 0.35, 0.5, 0.65, 0.8, 0.95, 1.0]; var slopeRamp = []; var aspectRamp = [0.0, 0.0, 0.2, 0.4, 0.6, 0.8, 0.9, 1.0, 1.0]; var ramp = document.createElement('canvas'); ramp.width = 100; ramp.height = 1; var ctx = ramp.getContext('2d'); var values; if (selectedShading === 'elevation') { values = elevationRamp; } else if (selectedShading === 'slope') { values = slopeRamp; } else if (selectedShading === 'aspect') { values = aspectRamp; } if (!colorArr) { colorArr = ['#0b0b88', '#2747E0', '#D33B7D', '#D33038', '#FF9742', '#ffd700', '#bbff00']; } var grd = ctx.createLinearGradient(0, 0, 100, 0); if (selectedShading === 'slope') { if (min === undefined) { min = 0; } if (max === undefined) { min = 90; } if (min == 0) { slopeRamp.push(0.0); } else { slopeRamp.push(min / 90); grd.addColorStop(0.0, '#000000'); } var ave = (max - min) / 6; if (max == 90) { for (var i = 1; i <= 5; i++) { slopeRamp.push((min + i * ave) / 90); } slopeRamp.push(1.0); slopeRamp.forEach(function (item, index) { grd.addColorStop(item, colorArr[index]); }); } else { for (var i = 1; i <= 5; i++) { slopeRamp.push((min + i * ave) / 90); } slopeRamp.push(max / 90); slopeRamp.forEach(function (item, index) { grd.addColorStop(item, colorArr[index]); }); grd.addColorStop(1.0, '#000000'); } } else { grd.addColorStop(values[0], '#000000'); grd.addColorStop(values[1], colorArr[0]); grd.addColorStop(values[2], colorArr[1]); grd.addColorStop(values[3], colorArr[2]); grd.addColorStop(values[4], colorArr[3]); grd.addColorStop(values[5], colorArr[4]); grd.addColorStop(values[6], colorArr[5]); grd.addColorStop(values[7], colorArr[6]); grd.addColorStop(values[8], '#000000'); } ctx.fillStyle = grd; ctx.fillRect(0, 0, 100, 1); return ramp; }; //贴地面积测量 Core.prototype.Gauss_to_XY = function (L, B, middleL2, Cesium) { var aEarth = 6378137; var bEarth = 6356752.3142; var e2 = Math.sqrt(aEarth * aEarth - bEarth * bEarth) / bEarth; var t = 0, yita = 0; var t = 0, yita = 0; var nn = 0; var n = 0; var middleL = this.to_Radian(middleL2); B = this.to_Radian(B); L = this.to_Radian(L); var dL = L - middleL; var cosB = Math.cos(B); n = this.to_N(B); nn = n * Math.cos(B); t = Math.tan(B); yita = e2 * cosB; var pow_t2 = Math.pow(t, 2); var pow_t4 = Math.pow(t, 4); var pow_yita2 = Math.pow(yita, 2); var pow_yita4 = Math.pow(yita, 4); var pow_cosB3 = Math.pow(cosB, 3); var pow_cosB5 = Math.pow(cosB, 5); var tY = this.to_Sm(B) + Math.pow(dL, 2) / 2 * nn * cosB * t + Math.pow(dL, 4) / 24 * t * nn * pow_cosB3 * (5.0 - pow_t2 + 9.0 * pow_yita2 + 4 * pow_yita4) + Math.pow(dL, 6) / 720 * t * nn * pow_cosB5 * (61.0 - 58.0 * t * t + pow_t4 + 270 * pow_yita2 - 330 * t * t * pow_yita2); var tX = dL * n * cosB + Math.pow(dL, 3) / 6.0 * n * pow_cosB3 * (1 - t * t + yita * yita) + Math.pow(dL, 5) / 120.0 * n * pow_cosB5 * (5 - 18 * t * t + pow_t4 + 14.0 * pow_yita2 - 58.0 * pow_yita2 * pow_t2); return new Cesium.Cartesian2(tX, tY) }; Core.prototype.to_Radian = function (degree) { return degree * Math.PI / 180.0 }; Core.prototype.to_N = function (B) { var aEarth = 6378137; var bEarth = 6356752.3142; var e1 = Math.sqrt(aEarth * aEarth - bEarth * bEarth) / aEarth; var ans = (aEarth / Math.sqrt(1.00 - e1 * e1 * Math.sin(B) * Math.sin(B))); return ans }; Core.prototype.to_Sm = function (B) { var aEarth = 6378137; var bEarth = 6356752.3142; var e1 = Math.sqrt(aEarth * aEarth - bEarth * bEarth) / aEarth; var AA, BB, CC, DD, EE; AA = 1 + (e1 * e1) * 3 / 4 + Math.pow(e1, 4.0) * 45 / 64 + Math.pow(e1, 6) * 175 / 256 + Math.pow(e1, 8) * 11025 / 16384; BB = Math.pow(e1, 2) * 3 / 4 + Math.pow(e1, 4) * 15 / 16 + Math.pow(e1, 6) * 525 / 512 + Math.pow(e1, 8) * 2205 / 2048; CC = Math.pow(e1, 4) * 15 / 64 + Math.pow(e1, 6) * 105 / 256 + Math.pow(e1, 8) * 2205 / 4096; DD = Math.pow(e1, 6) * 35 / 512 + Math.pow(e1, 8) * 315 / 2048; EE = Math.pow(e1, 8) * 315 / 16384; return aEarth * (1 - e1 * e1) * (AA * B - BB / 2 * Math.sin(2 * B) + CC / 4 * Math.sin(4 * B) - DD / 6 * Math.sin(6 * B) + EE / 8 * Math.sin(8 * B)) }; /** * 计算空间两点之间的俯仰角 * @param {Object} p1 起始点 * @param {Object} p2 结束点 */ Core.prototype.ElevationAngle = function (p1, p2, Cesium) { //空间距离测量 function getSpaceDistance(positions, Cesium) { var distance = 0; for (var i = 0; i < positions.length - 1; i++) { var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]); var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]); /**根据经纬度计算出距离**/ var geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); var s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 s = (Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2))); distance = distance + s; } return distance; } //水平距离测量 function getHorizontalDistance(positions, Cesium) { var distance = 0; for (var i = 0; i < positions.length - 1; i++) { var point1cartographic = Cesium.Cartographic.fromCartesian(positions[i]); var point2cartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]); /**根据经纬度计算出距离**/ var geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); var s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 //s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)); distance = distance + s; } return distance; } //获取高度 function getHeight(_positions, Cesium) { try { if (_positions.length > 1) { var cartographic = Cesium.Cartographic.fromCartesian(_positions[0]); var cartographic1 = Cesium.Cartographic.fromCartesian(_positions[1]); var height_temp = (cartographic1.height - cartographic.height); //var height_temp = _positions[1].z - _positions[0].z; return height_temp; } else { return 0; } } catch (ex) { console.log(ex); } } var cartographic = Cesium.Cartographic.fromCartesian(p1); var cartographic1 = Cesium.Cartographic.fromCartesian(p2); cartographic.height - (cartographic.height - cartographic1.height); var p3 = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic1.longitude), Cesium.Math.toDegrees(cartographic1.latitude), cartographic.height); var c = parseFloat(getSpaceDistance([p1, p2], Cesium)); parseFloat(getHorizontalDistance([p1, p3], Cesium)); var b = parseFloat(getHeight([p3, p2], Cesium)); var sinb = b / c; var angle = Math.asin(sinb) * 180 / 3.14; return angle; }; /** * 两点方位角 * @param {number} lon1 起点经度 * @param {number} lat1 起点纬度 * @param {number} lon2 终点经度 * @param {number} lat2 终点纬度 */ Core.prototype.TwoPointAzimuth = function (lon1, lat1, lon2, lat2) { var result = 0.0; var getRad = function (d) { return d * Math.PI / 180.0; }; var ilat1 = Math.round(0.50 + lat1 * 360000.0); var ilat2 = Math.round(0.50 + lat2 * 360000.0); var ilon1 = Math.round(0.50 + lon1 * 360000.0); var ilon2 = Math.round(0.50 + lon2 * 360000.0); lat1 = getRad(lat1); lon1 = getRad(lon1); lat2 = getRad(lat2); lon2 = getRad(lon2); if ((ilat1 === ilat2) && (ilon1 === ilon2)) { return result; } else if (ilon1 === ilon2) { if (ilat1 > ilat2) result = 180.0; } else { var c = Math.acos(Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2) * Math.cos(lat1) * Math.cos((lon2 - lon1))); var A = Math.asin(Math.cos(lat2) * Math.sin((lon2 - lon1)) / Math.sin(c)); result = A * 180 / Math.PI; if ((ilat2 > ilat1) && (ilon2 > ilon1)) ; else if ((ilat2 < ilat1) && (ilon2 < ilon1)) { result = 180.0 - result; } else if ((ilat2 < ilat1) && (ilon2 > ilon1)) { result = 180.0 - result; } else if ((ilat2 > ilat1) && (ilon2 < ilon1)) { result += 360.0; } } return result; }; /** * 两点计算HeadingPitchRoll * @param {Viewer} Viewer 地图视图 * @param {Cartesian3} startPosition 起点 * @param {Cartesian3} endPosition 终点 */ Core.prototype.twoPointsHeadingPitchRoll = function (Viewer, startPosition, endPosition) { let Camera = new Cesium.Camera(Viewer.scene); Camera.position = startPosition; Camera.direction = Cesium.Cartesian3.subtract(endPosition, startPosition, new Cesium.Cartesian3()); //计算两个笛卡尔的组分差异。 Camera.up = Cesium.Cartesian3.normalize(startPosition, new Cesium.Cartesian3()); // 归一化 let radius = Cesium.Cartesian3.distance(startPosition, endPosition); let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(endPosition, startPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3()); Camera.direction = direction; //相机面向的方向 Camera.frustum.near = 0; Camera.frustum.far = radius; let { heading, pitch, roll } = Camera; Camera = null; return { heading, pitch, roll, radius } }; /** * 三点测量方位角 * @param {Object} p1 起始点 * @param {Object} p2 第二点 * @param {Object} p3 第三点 */ Core.prototype.ThreePointAzimuth = function (p1, p2, p3, Cesium) { var radiansPerDegree = Math.PI / 180.0; var degreesPerRadian = 180.0 / Math.PI; var cartographic1 = Cesium.Cartographic.fromCartesian(p1); var cartographic2 = Cesium.Cartographic.fromCartesian(p2); var cartographic3 = Cesium.Cartographic.fromCartesian(p3); p2 = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic2.longitude), Cesium.Math.toDegrees(cartographic2.latitude), cartographic1.height); p3 = Cesium.Cartesian3.fromDegrees(Cesium.Math.toDegrees(cartographic3.longitude), Cesium.Math.toDegrees(cartographic3.latitude), cartographic1.height); cartographic2 = Cesium.Cartographic.fromCartesian(p2); cartographic3 = Cesium.Cartographic.fromCartesian(p3); /*角度*/ function Angle(p1, p2, p3) { var bearing21 = Bearing(p2, p1); var bearing23 = Bearing(p2, p3); var angle = bearing21 - bearing23; if (angle < 0) { angle += 360; } return angle; } /*方向*/ function Bearing(from, to) { var lat1 = from.latitude * radiansPerDegree; var lon1 = from.longitude * radiansPerDegree; var lat2 = to.latitude * radiansPerDegree; var lon2 = to.longitude * radiansPerDegree; var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)); if (angle < 0) { angle += Math.PI * 2.0; } angle = angle * degreesPerRadian; return angle; } var angle = Angle(cartographic1, cartographic2, cartographic3); return angle; }; /** * 开启/还原深度检测 * @param {String} type 状态(open/close) * @param {Object} viewer 视图 */ Core.prototype.setDepthTest = function (type, viewer) { if (type === 'open' && this.defaultDepthTest === undefined) { this.defaultDepthTest = !!viewer.scene.globe.depthTestAgainstTerrain; viewer.scene.globe.depthTestAgainstTerrain = true; } else if (type === 'close' && this.defaultDepthTest !== undefined) { viewer.scene.globe.depthTestAgainstTerrain = !!this.defaultDepthTest; this.defaultDepthTest = undefined; } }; /** * 动态变化材质 * @param {String} type 状态(open/close) * @param {Object} viewer 视图 */ //var images = "../../img/arrow.png"; //var curCanvas = "a"; //var i = 0; Core.prototype.setImageMaterialProperty = function (image, Cesium, type, id) { this.id = id; var that = this; var canvas = document.createElement('canvas'); canvas.id = this.id + "-a"; canvas.width = 700; canvas.height = 100; var canvas1 = document.createElement('canvas'); canvas1.id = this.id + "-b"; canvas1.width = 700; canvas1.height = 100; document.body.appendChild(canvas); document.body.appendChild(canvas1); if (image) { that.images = image; } var ima = new Cesium.CallbackProperty(function (time, result) { var canvas = document.getElementById(that.id + "-" + that.curCanvas); var cwidth = 700; var cheight = 100; var ctx = canvas.getContext("2d"); var img = new Image(); img.src = that.images; ctx.clearRect(0, 0, cwidth, cheight); img.onload = function () { if (that.i <= cwidth) { ctx.drawImage(img, that.i, 0); ctx.drawImage(img, that.i + 100, 0); } else that.i = 0; that.i += 5; }; that.curCanvas = that.curCanvas === 'a' ? 'b' : 'a'; return canvas; }, false); if (type == 1) { ima = new Cesium.CallbackProperty(function (time, result) { var canvas = document.getElementById(that.id + "-" + that.curCanvas); var ctx = canvas.getContext("2d"); var grd = ctx.createLinearGradient(0, 100, 0, 0); grd.addColorStop(0, "red"); if (that.i > 1) { that.i = 1; } grd.addColorStop(that.i, "rgb(255,0,0,0.6)"); grd.addColorStop(1, "rgb(255,0,0,0.1)"); ctx.clearRect(0, 0, 700, 100); ctx.fillStyle = grd; ctx.fillRect(0, 0, 700, 100); if (that.i < 1) { that.i += 0.01; } else { that.i = 0; } that.curCanvas = that.curCanvas === 'a' ? 'b' : 'a'; return canvas; }, false); } return new Cesium.ImageMaterialProperty({ image: ima, transparent: true }) }; /** * 动态变化材质回调函数(水平移动图像) * @param {String} type 状态(open/close) * @param {Object} viewer 视图 */ Core.prototype.setDrawCanvasImage = function (time, result) { var canvas = document.getElementById("canvas-" + curCanvas); var cwidth = 700; var cheight = 100; var ctx = canvas.getContext("2d"); var img = new Image(); img.src = images; ctx.clearRect(0, 0, cwidth, cheight); img.onload = function () { if (i <= cwidth) { ctx.drawImage(img, i, 0); ctx.drawImage(img, i + 100, 0); } else i = 0; i += 5; }; curCanvas = curCanvas === 'a' ? 'b' : 'a'; return canvas; }; /** * 动态变化材质回调函数(上下移动颜色渐变) * @param {String} type 状态(open/close) * @param {Object} viewer 视图 */ Core.prototype.setDrawCanvasColorUpdown = function (time, result) { var canvas = document.getElementById("canvas-" + curCanvas); var ctx = canvas.getContext("2d"); var grd = ctx.createLinearGradient(0, 100, 0, 0); grd.addColorStop(0, "red"); if (i > 1) { i = 1; } grd.addColorStop(i, "rgb(255,0,0,0.6)"); grd.addColorStop(1, "rgb(255,0,0,0.1)"); ctx.clearRect(0, 0, 700, 100); ctx.fillStyle = grd; ctx.fillRect(0, 0, 700, 100); if (i < 1) { i += 0.01; } else { i = 0; } curCanvas = curCanvas === 'a' ? 'b' : 'a'; return canvas; }; /** * 三维笛卡尔坐标转经纬度 * @param {Cartesian3} cartesian 三维笛卡尔坐标 * @returns {Object} * * @example * degrees = sgworld.Core.toDegrees(position'); */ Core.prototype.toDegrees = function (cartesian) { let cartographic = Cesium.Cartographic.fromCartesian(cartesian); return { lon: Cesium.Math.toDegrees(cartographic.longitude), lat: Cesium.Math.toDegrees(cartographic.latitude), height: cartographic.height }; }; /** * 经纬度转三维笛卡尔坐标 * @param {Degrees} degrees 经纬度 * @returns {Object} * * @example * position = sgworld.Core.fromDegrees(degrees); */ Core.prototype.fromDegrees = function (degrees) { return Cesium.Cartesian3.fromDegrees( degrees.lon, degrees.lat, degrees.height ) }; //线段插值 Core.prototype.LineInterpolation = function (Viewer, option) { let positions, num; let getHeight = false; if (option.positions) { positions = option.positions; } else { positions = option; } num = option.num || 100; //采样点数 option.getHeight && (getHeight = true); //获取高度 let data = { positions: [], cartographic: [], lon_lat: [], height: [] }; for (let i = 0; i < positions.length - 1; i++) { let degrees1 = this.toDegrees(positions[i]); let degrees2 = this.toDegrees(positions[i + 1]); getPoint(degrees1.lon, degrees1.lat, degrees2.lon, degrees2.lat); } function getPoint(lon1, lat1, lon2, lat2) { // //获取面上的高程和经纬度 let addX = Cesium.Math.lerp(lon1, lon2, 1.0 / num) - lon1; let addY = Cesium.Math.lerp(lat1, lat2, 1.0 / num) - lat1; data.lon_lat.push(lon1, lat1); let height; if (getHeight) { height = getHeightFromLonLat(lon1, lat1); data.height.push(height); data.positions.push(Cesium.Cartesian3.fromDegrees(lon1, lat1, height)); for (let i = 0; i < num; i++) { let longitude = lon1 + (i + 1) * addX; let latitude = lat1 + (i + 1) * addY; data.lon_lat.push(longitude, latitude); height = getHeightFromLonLat(longitude, latitude); data.height.push(height); data.positions.push(Cesium.Cartesian3.fromDegrees(longitude, latitude, height)); } data.lon_lat.push(lon2, lat2); height = getHeightFromLonLat(lon2, lat2); data.height.push(height); data.positions.push(Cesium.Cartesian3.fromDegrees(lon2, lat2, height)); } else { data.positions.push(Cesium.Cartesian3.fromDegrees(lon1, lat1)); for (let i = 0; i < num; i++) { let longitude = lon1 + (i + 1) * addX; let latitude = lat1 + (i + 1) * addY; data.lon_lat.push(longitude, latitude); data.positions.push(Cesium.Cartesian3.fromDegrees(longitude, latitude)); } data.lon_lat.push(lon2, lat2); data.positions.push(Cesium.Cartesian3.fromDegrees(lon2, lat2)); } } //根据经纬度获取高度 function getHeightFromLonLat(lon, lat) { let Cartographic = Cesium.Cartographic.fromDegrees(lon, lat); let height = Viewer.scene.globe.getHeight(Cartographic); // let height2 = Viewer.scene.sampleHeight(Cartographic, option.objectsToExclude); // if (height2 !== undefined && height2 > height) { // height = height2; // } return height; } return data; }; /** * 创建CIMServer查询工具 * @param {String} url 服务地址 */ Core.prototype.CIMServerTool = function (url) { return new CIMServerTool(url); }; /** * 自动录屏*录制桌面 * * @alias Recorder * @constructor * * @param {String} [path='test.mp4'] 保存文件名。 * @param {Number} [videoBPS=5120000] 视频bps。 */ Core.prototype.Recorder = function (path, videoBPS) { if (this._Recorder) { this._Recorder.mediaOutputPath = this.defaultValue(path, 'test.mp4'); videoBPS && (this._Recorder.videoBPS = videoBPS); } else { this._Recorder = new Recorder(path, videoBPS); } return this._Recorder; }; /** * 添加链路纹理 */ Core.prototype.getLinkMaterial = function (color, lightSpotColor, time) { if (!Cesium.PolylineLinkMaterialProperty) { /* 链路纹理线 color 线颜色 pointColor 精灵点颜色 duration 持续时间 毫秒 */ function PolylineLinkMaterialProperty(color, lightSpotColor, duration) { this._definitionChanged = new Cesium.Event(); this._color = undefined; this._colorSubscription = undefined; this.color = color; this.lightSpotColor = lightSpotColor; this.duration = duration; this.old = undefined; this._time = (new Date()).getTime(); } Object.defineProperties(PolylineLinkMaterialProperty.prototype, { isConstant: { get: function () { return false; } }, definitionChanged: { get: function () { return this._definitionChanged; } }, color: Cesium.createPropertyDescriptor('color') }); PolylineLinkMaterialProperty.prototype.getType = function (time) { return 'PolylineLink'; }; PolylineLinkMaterialProperty.prototype.getValue = function (time, result) { if (!Cesium.defined(result)) { result = {}; } result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color); result.lightSpotColor = this.lightSpotColor; result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration; this.old === undefined && (this.old = result.time); if (this.old > 0.5 && result.time < 0.5) { result.plus = !result.plus; result.inverse = !result.inverse; } this.old = result.time; if (result.plus) { result.time = result.time * 1.1; } else { result.time = result.time * 1.2 - 0.1; } return result; }; PolylineLinkMaterialProperty.prototype.equals = function (other) { return this === other || (other instanceof PolylineLinkMaterialProperty && Cesium.Property.equals(this._color, other._color)) }; Cesium.PolylineLinkMaterialProperty = PolylineLinkMaterialProperty; Cesium.Material.PolylineLinkType = 'PolylineLink'; Cesium.Material.PolylineLinkSource = PolylineLinkSource; Cesium.Material._materialCache.addMaterial(Cesium.Material.PolylineLinkType, { fabric: { type: Cesium.Material.PolylineLinkType, uniforms: { color: new Cesium.Color(1.0, 0.0, 0.0, 0.5), lightSpotColor: new Cesium.Color(1.0, 1.0, 1.0, 0.5), time: 0, plus: true, inverse: false }, source: Cesium.Material.PolylineLinkSource }, translucent: function (material) { return true; } }); } return new Cesium.PolylineLinkMaterialProperty(Cesium.Color.fromCssColorString(this.defaultValue(color, "#0000ff")), Cesium.Color.fromCssColorString(this.defaultValue(lightSpotColor, "#ffffff")), this.defaultValue(time, 3000)); }; /** * 添加链路纹理 */ Core.prototype.getTrailLinkMaterial = function (color, LinkImage, time) { return new PolylineTrailLinkMaterial(color, LinkImage, time); }; /** * 添加卫星雷达扫描纹理 */ Core.prototype.getConeRadarMaterial = function (color) { if (!Cesium.ConeRadarMaterialProperty) { /* 雷达正射 color 颜色 duration 持续时间 毫秒 */ function ConeRadarMaterialProperty(color, duration) { this._definitionChanged = new Cesium.Event(); this._color = undefined; this._colorSubscription = undefined; this.color = color; this.duration = duration; this._time = (new Date()).getTime(); } Object.defineProperties(ConeRadarMaterialProperty.prototype, { isConstant: { get: function () { return false; } }, definitionChanged: { get: function () { return this._definitionChanged; } }, color: Cesium.createPropertyDescriptor('color') }); ConeRadarMaterialProperty.prototype.getType = function (time) { return 'ConeRadar'; }; ConeRadarMaterialProperty.prototype.getValue = function (time, result) { if (!Cesium.defined(result)) { result = {}; } result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color); result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration; return result; }; ConeRadarMaterialProperty.prototype.equals = function (other) { return this === other || (other instanceof ConeRadarMaterialProperty && Cesium.Property.equals(this._color, other._color)) }; Cesium.ConeRadarMaterialProperty = ConeRadarMaterialProperty; Cesium.Material.ConeRadarType = 'ConeRadar'; Cesium.Material.ConeRadarSource = "\n\ float ripple(float dist, float rippleIntensity, float rippleScale) {\n\ return rippleScale * ((sin(dist * rippleIntensity - czm_frameNumber/10.0)-0.9) / (dist * rippleIntensity));\n\ }\n\ czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ czm_material material = czm_getDefaultMaterial(materialInput);\n\ material.diffuse = color.rgb;\n\ vec2 st = materialInput.st;\n\ float dis = distance(st, vec2(0.5, 0.5));\n\ material.alpha = 0.0;\n\ float intensity = step(0.001,ripple(dis, 80.0, 15.0));\n\ if(intensity == 1.0)\n\ {\n\ material.alpha = 1.0;\n\ }\n\ return material;\n\ }"; Cesium.Material._materialCache.addMaterial(Cesium.Material.ConeRadarType, { fabric: { type: Cesium.Material.ConeRadarType, uniforms: { color: new Cesium.Color(1.0, 0.0, 0.0, 0.5), time: 0 }, source: Cesium.Material.ConeRadarSource }, translucent: function (material) { return true; } }); } return new Cesium.ConeRadarMaterialProperty(Cesium.Color.fromCssColorString(this.defaultValue(color, "#0000ff")), 3000); }; /** * 添加扩散圆扫描纹理(三环) */ Core.prototype.getMultiCircleScanMaterial = function (color, time) { if (!Cesium.CircleScanMultiMaterialProperty) { function CircleScanMultiMaterialProperty(color, duration) { this._definitionChanged = new Cesium.Event(); this._color = undefined; this._colorSubscription = undefined; this.color = color; this.u_radius1 = 0; this.u_radius2 = 0; this.u_radius3 = 0; this.duration = duration; this._time = (new Date()).getTime(); } Object.defineProperties(CircleScanMultiMaterialProperty.prototype, { isConstant: { get: function () { return false } }, definitionChanged: { get: function () { return this._definitionChanged } }, color: Cesium.createPropertyDescriptor('color') }); CircleScanMultiMaterialProperty.prototype.getType = function (time) { return 'CircleScanMulti'; }; CircleScanMultiMaterialProperty.prototype.getValue = function (time, result) { if (!Cesium.defined(result)) { result = {}; } result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color); result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration; if (result.time < 1 / 3 && this.u_radius2 === 0 && this.u_radius1 === 0) { this.u_radius3 = result.time; } else if (result.time >= 1 / 3 && result.time < 2 / 3 && this.u_radius1 === 0) { this.u_radius3 = result.time; this.u_radius2 = this.u_radius3 - 1 / 3; } else if (result.time >= 2 / 3) { this.u_radius3 = result.time; this.u_radius2 = this.u_radius3 - 1 / 3; this.u_radius1 = this.u_radius3 - 2 / 3; } else if (result.time < 1 / 3 && this.u_radius2 !== 0 && this.u_radius1 !== 0) { this.u_radius1 = result.time; this.u_radius2 = result.time + 1 / 3; this.u_radius3 = result.time + 2 / 3; } else if (result.time >= 1 / 3 && result.time < 2 / 3 && this.u_radius1 !== 0) { this.u_radius1 = result.time - 1 / 3; this.u_radius2 = result.time; this.u_radius3 = result.time + 1 / 3; } result.u_radius1 = this.u_radius1; result.u_radius2 = this.u_radius2; result.u_radius3 = this.u_radius3; return result; }; CircleScanMultiMaterialProperty.prototype.equals = function (other) { return this === other || (other instanceof CircleScanMultiMaterialProperty && Cesium.Property.equals(this._color, other._color)) }; Cesium.CircleScanMultiMaterialProperty = CircleScanMultiMaterialProperty; Cesium.Material.CircleScanMultiType = "CircleScanMulti"; // 自定义着色器 Cesium.Material.CircleScanMultiSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ czm_material material = czm_getDefaultMaterial(materialInput);\n\ material.diffuse = color.rgb;\n\ vec2 st = materialInput.st;\n\ float dis = distance(st, vec2(0.5, 0.5));\n\ dis = dis * 2.0;\n\ if(dis < u_radius1)\n\n\ {\n\ float f = dis / u_radius1;\n\ material.alpha = pow(f, 9.0);\n\ }else if(dis < u_radius2){\n\ float f = dis / u_radius2;\n\ material.alpha = pow(f, 9.0);\n\ }else if(dis < u_radius3){\n\ float f = dis / u_radius3;\n\ material.alpha = pow(f, 9.0);\n\ }else{\n\ material.alpha = 0.0;\n\ }\n\ return material;\n\ }"; Cesium.Material._materialCache.addMaterial(Cesium.Material.CircleScanMultiType, { fabric: { type: Cesium.Material.CircleScanMultiType, uniforms: { color: new Cesium.Color(1.0, 0.0, 0.0, 1), time: 0, u_radius1: 0, u_radius2: 0, u_radius3: 0 }, source: Cesium.Material.CircleScanMultiSource }, translucent: function (material) { return true; } }); } return new Cesium.CircleScanMultiMaterialProperty(Cesium.Color.fromCssColorString(this.defaultValue(color, "#ff0000")), this.defaultValue(time, 3000)); }; /** * 添加扇形扫描纹理 */ Core.prototype.getSectorScanMaterial = function (color, angle) { if (!Cesium.EllipsoidFadeMaterialProperty) { function EllipsoidFadeMaterialProperty(color, angle, duration) { this._definitionChanged = new Cesium.Event(); this._color = undefined; this._colorSubscription = undefined; this.color = color; this.duration = duration; this._angle = angle; this._time = (new Date()).getTime(); } Object.defineProperties(EllipsoidFadeMaterialProperty.prototype, { isConstant: { get: function () { return false } }, definitionChanged: { get: function () { return this._definitionChanged } }, color: Cesium.createPropertyDescriptor('color'), angle: Cesium.createPropertyDescriptor('angle'), }); EllipsoidFadeMaterialProperty.prototype.getType = function (time) { return 'EllipsoidFade'; }; EllipsoidFadeMaterialProperty.prototype.getValue = function (time, result) { if (!Cesium.defined(result)) { result = {}; } result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.ColorWHITE, result .color); result.angle = this._angle; return result; }; EllipsoidFadeMaterialProperty.prototype.equals = function (other) { return this === other || (other instanceof EllipsoidFadeMaterialProperty && Property.equals(this._color, other._color)) }; Cesium.EllipsoidFadeMaterialProperty = EllipsoidFadeMaterialProperty; Cesium.Material.EllipsoidFadeType = "EllipsoidFade"; // 自定义着色器 Cesium.Material.EllipsoidFadeSource = "float getAngle(in vec2 dv)\n" + "{\n" + " if(dv.y == 0.0 && dv.x > 0.0)\n" + " {\n" + " return 90.0;\n" + " }\n" + " if(dv.y == 0.0 && dv.x < 0.0)\n" + " {\n" + " return 270.0;\n" + " }\n" + " float rAngle = atan(dv.x/dv.y) * 180.0 / 3.1415926;\n" + " if(dv.x > 0.0)\n" + " {\n" + " if(dv.y < 0.0)\n" + " {\n" + " rAngle = 180.0 + rAngle;\n" + " }\n" + " }\n" + " if(dv.x <= 0.0)\n" + " {\n" + " if(dv.y < 0.0)\n" + " {\n" + " rAngle = 180.0 + rAngle;\n" + " }\n" + " if(dv.y > 0.0)\n" + " {\n" + " rAngle = 360.0 + rAngle;\n" + " }\n" + " }\n" + " return rAngle;\n" + "}\n" + "float ripple(float dist, float rippleIntensity, float rippleScale) {\n" + " return rippleScale * ((sin(dist * rippleIntensity - czm_frameNumber/10.0)-0.9) / (dist * rippleIntensity));\n" + "}\n" + "czm_material czm_getMaterial(czm_materialInput materialInput)\n" + "{\n" + " czm_material material = czm_getDefaultMaterial(materialInput);\n" + " material.diffuse = 1.5 * color.rgb;\n" + " vec2 st = materialInput.st;\n" + " float dis = distance(st, vec2(0.5, 0.5));\n" + " float nowAngle = getAngle(st.xy-vec2(0.5, 0.5));\n" + " if(nowAngle < angle)\n" + " {\n" + " material.alpha = 1.0 - dis/0.5;\n" + " float intensity =step(0.001,ripple(dis, 100.0, 15.0));\n" + " if(intensity == 1.0)\n" + " {\n" + " material.alpha = material.alpha/2.0;\n" + " }\n" + " }\n" + " else{\n" + " material.alpha = 0.0;\n" + " discard;\n" + " }\n" + " return material;\n" + "}"; Cesium.Material._materialCache.addMaterial(Cesium.Material.EllipsoidFadeType, { fabric: { type: Cesium.Material.EllipsoidFadeType, uniforms: { color: new Cesium.Color(1.0, 0.0, 0.0, 1), angle: 90 }, source: Cesium.Material.EllipsoidFadeSource }, translucent: function (material) { return true; } }); } return new Cesium.EllipsoidFadeMaterialProperty(Cesium.Color.fromCssColorString(this.defaultValue(color, "#ff0000")), this.defaultValue(angle, 45)) }; /** * 添加扩散圆扫描纹理 */ Core.prototype.getCircleScanMaterial = function (color, time) { if (!Cesium.CircleScanMaterialProperty) { function CircleScanMaterialProperty(color, duration) { this._definitionChanged = new Cesium.Event(); this._color = undefined; this._colorSubscription = undefined; this.color = color; this.duration = duration; this._time = (new Date()).getTime(); } Object.defineProperties(CircleScanMaterialProperty.prototype, { isConstant: { get: function () { return false } }, definitionChanged: { get: function () { return this._definitionChanged } }, color: Cesium.createPropertyDescriptor('color') }); CircleScanMaterialProperty.prototype.getType = function (time) { return 'CircleScan'; }; CircleScanMaterialProperty.prototype.getValue = function (time, result) { if (!Cesium.defined(result)) { result = {}; } result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color); result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration; return result; }; CircleScanMaterialProperty.prototype.equals = function (other) { return this === other || (other instanceof CircleScanMaterialProperty && Cesium.Property.equals(this._color, other._color)) }; Cesium.CircleScanMaterialProperty = CircleScanMaterialProperty; Cesium.Material.CircleScanType = "CircleScan"; // 自定义着色器 Cesium.Material.CircleScanSource = "czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ czm_material material = czm_getDefaultMaterial(materialInput);\n\ material.diffuse = color.rgb;\n\ vec2 st = materialInput.st;\n\ float dis = distance(st, vec2(0.5, 0.5));\n\ if(dis 360) { result.angle2 = result.angle2 - 360; } return result; }; RadarScanMaterialProperty.prototype.equals = function (other) { return this === other || (other instanceof RadarScanMaterialProperty && Cesium.Property.equals(this._color, other._color)) }; Cesium.RadarScanMaterialProperty = RadarScanMaterialProperty; Cesium.Material.RadarScanType = "RadarScan"; // 自定义着色器 Cesium.Material.RadarScanSource = "float getAngle(in vec2 dv)\n\ {\n\ if(dv.y == 0.0 && dv.x > 0.0)\n\ {\n\ return 90.0;\n\ }\n\ if(dv.y == 0.0 && dv.x < 0.0)\n\ {\n\ return 270.0;\n\ }\n\ float rAngle = atan(dv.x/dv.y) * 180.0 / 3.1415926;\n\ if(dv.x > 0.0)\n\ {\n\ if(dv.y < 0.0)\n\ {\n\ rAngle = 180.0 + rAngle;\n\ }\n\ }\n\ if(dv.x <= 0.0)\n\ {\n\ if(dv.y < 0.0)\n\ {\n\ rAngle = 180.0 + rAngle;\n\ }\n\ if(dv.y > 0.0)\n\ {\n\ rAngle = 360.0 + rAngle;\n\ }\n\ }\n\ return rAngle;\n\ }\n\ float ripple(float dist, float rippleIntensity, float rippleScale) {\n\ return rippleScale * ((sin(dist * rippleIntensity - czm_frameNumber/10.0)-0.9) / (dist * rippleIntensity));\n\ }\n\ czm_material czm_getMaterial(czm_materialInput materialInput)\n\ {\n\ czm_material material = czm_getDefaultMaterial(materialInput);\n\ material.diffuse = color.rgb;\n\ vec2 st = materialInput.st;\n\ float dis = distance(st, vec2(0.5, 0.5));\n\ float f = 0.0;\n\ float nowAngle = getAngle(st.xy-vec2(0.5, 0.5));\n\ if(nowAngle < angle2 && nowAngle > angle1)\n\ {\n\ f = (nowAngle - angle1) / 60.0;\n\ material.alpha = f;\n\ }else if(nowAngle < 360.0 && nowAngle > angle1 && angle2 < 60.0){\n\ f = (nowAngle - angle1) / 60.0;\n\ material.alpha = f;\n\ }else if(nowAngle < angle2 && nowAngle > 0.0 && angle2 < 60.0){\n\ f = (nowAngle + 360.0 - angle1) / 60.0;\n\ material.alpha = f;\n\ }else{\n\ material.alpha = 0.0;\n\ discard;\n\ }\n\ return material;\n\ }"; Cesium.Material._materialCache.addMaterial(Cesium.Material.RadarScanType, { fabric: { type: Cesium.Material.RadarScanType, uniforms: { color: new Cesium.Color(1.0, 0.0, 0.0, 1), time: 0, angle2: 0, angle1: 0 }, source: Cesium.Material.RadarScanSource }, translucent: function (material) { return true; } }); } return new Cesium.RadarScanMaterialProperty(Cesium.Color.fromCssColorString(this.defaultValue(color, "#ff0000")), this.defaultValue(time, 3000)); }; /** * 创建颜色阶梯过渡工具 * @param {String} url 服务地址 */ Core.prototype.gradientColor = function (startColor, endColor, step) { return new gradientColor(startColor, endColor, step); }; /** * ajax * @param {*} param */ Core.prototype.xhr = function (param) { // $method, $url, param, success, error var Request = new XMLHttpRequest(); var async = true; if (param.async == undefined) async = true; else if (param.async == null) async = true; else async = param.async; Request.open(param.type, param.url, async); if (param.headers) { for (const key in param.headers) { Request.setRequestHeader(key, param.headers[key]); } } Request.send(param.data || {}); Request.onreadystatechange = function () { if (this.readyState === 4 && this.status === 200) { //obj.innerHTML = Request.responseText; if (param.success && typeof param.success == 'function') param.success(param.isXml ? this.responseXML : JSON.parse(this.responseText)); } else if (this.status !== 200) { if (param.error && typeof param.error == 'function') param.error(Request); } if (param.complete && typeof param.complete == 'function') param.complete(); }; }; var _typeof$7 = 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; }; /** * 序列化参数对象 * * @param {Object} params 参数对象 * @returns {String} 序列化字符串 */ Core.prototype._serialize = function (params) { var queryArray = []; var encode = window.encodeURIComponent; for (var key in params) { var value = params[key]; if ((typeof value === 'undefined' ? 'undefined' : _typeof$7(value)) === 'object') { queryArray.push(encode(key) + '=' + encode(JSON.stringify(value))); } else { queryArray.push(encode(key) + '=' + encode(params[key])); } } return queryArray.join('&'); }; /** * xml转json */ Core.prototype.xml2json = function (xml, extended) { return xmlObj2json(xml); }; // 判断是否为手机浏览器 Core.prototype.getBrowser = function () { var ua = navigator.userAgent.toLowerCase(); var btypeInfo = (ua.match(/firefox|chrome|safari|opera/g) || "other")[0]; if ((ua.match(/msie|trident/g) || [])[0]) { btypeInfo = "msie"; } var pc = ""; var prefix = ""; var plat = ""; //如果没有触摸事件 判定为PC var isTocuh = ("ontouchstart" in window) || (ua.indexOf("touch") !== -1) || (ua.indexOf("mobile") !== -1); if (isTocuh) { if (ua.indexOf("ipad") !== -1) { pc = "pad"; } else if (ua.indexOf("mobile") !== -1) { pc = "mobile"; } else if (ua.indexOf("android") !== -1) { pc = "androidPad"; } else { pc = "pc"; } } else { pc = "pc"; } switch (btypeInfo) { case "chrome": case "safari": case "mobile": prefix = "webkit"; break; case "msie": prefix = "ms"; break; case "firefox": prefix = "Moz"; break; case "opera": prefix = "O"; break; default: prefix = "webkit"; break } plat = (ua.indexOf("android") > 0) ? "android" : navigator.platform.toLowerCase(); return { version: (ua.match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1], //版本 plat: plat, //系统 type: btypeInfo, //浏览器 pc: pc, prefix: prefix, //前缀 isMobile: (pc == "pc") ? false : true //是否是移动端 }; }; /** * * 这个方法用于创建颜色。 * * @alias Color * @author 金磊、张恒 * @constructor * */ function Color(viewer, cesium) { this._viewer = viewer; this._cesium = cesium; this._core = new Core(); } /** * 矢量切片颜色转化 * @returns {Promise.} 返回一个Cesium的颜色对象。 */ Color.prototype.VectorColorTransformation = function (obj, entity) { var Color = obj; //填充颜色设置 if (Color && Color.toString().charAt(0) == "[" && Color.toString().charAt(Color.length - 1) == "]") { var material = styleOption.fillColor.replace(/\[/, '').replace(/\]/, ''); Color = entity.properties[material]; } if (!this._core.isnull(Color)) { if (this._core.isHtmlColor(Color)) { Color = this.colorFromHtmlColor(Color); } else { if (/^rgb/.test(Color)) { Color = this.rgbaStringToRgbaObj(Color); } if (Color.r != undefined) { if (Color.r > 1) { Color.r = Color.r / 255; } if (Color.g > 1) { Color.g = Color.g / 255; } if (Color.b > 1) { Color.b = Color.b / 255; } if (Color.a > 1) { Color.a = Color.a / 255; } Color = this.createColor(Color.r, Color.g, Color.b, Color.a); } else if (Color.red != undefined) { if (Color.red > 1) { Color.red = Color.red / 255; } if (Color.green > 1) { Color.green = Color.green / 255; } if (Color.blue > 1) { Color.blue = Color.blue / 255; } if (Color.alpha > 1) { Color.alpha = Color.alpha / 255; } Color = this.createColor(Color.red, Color.green, Color.blue, Color.alpha); } } } return Color; }; /** * 这个方法用于创建颜色 *@param {number} [red] 红色组件。 * @param {number} [green] 绿色组件。 * @param {number} [blue] 蓝色组件。 * @param {number} [alphae] alphea组件。 * @returns {Promise.} 返回一个Cesium的颜色对象。 */ Color.prototype.createColorTransformation = function (obj) { var Color = obj; //填充颜色设置 if (!this._core.isnull(Color)) { if (Color.toString().charAt(0) == "[" && Color.toString().charAt(Color.length - 1) == "]") ; else { if (this._core.isHtmlColor(Color)) { Color = this.colorFromHtmlColor(Color); } else { if (/^rgb/.test(Color)) { Color = this.rgbaStringToRgbaObj(Color); } if (Color.r > 1) { Color.r = Color.r / 255; } if (Color.g > 1) { Color.g = Color.g / 255; } if (Color.b > 1) { Color.b = Color.b / 255; } if (Color.a > 1) { Color.a = Color.a / 255; } Color = this.createColor(Color.r, Color.g, Color.b, Color.a); } } } return Color; }; /** * 这个方法用于创建颜色 *@param {number} [red] 红色组件。 * @param {number} [green] 绿色组件。 * @param {number} [blue] 蓝色组件。 * @param {number} [alphae] alphea组件。 * @returns {Promise.} 返回一个Cesium的颜色对象。 */ Color.prototype.createColor = function (red, green, blue, alpha) { var Color = new this._cesium.Color(red, green, blue, alpha); return Color; }; /** * 16进制颜色转为RGB格式 *@param {String} [htmlcolor] 红色组件。 * @returns {Object} 返回一个Cesium的颜色对象。 */ Color.prototype.colorFromHtmlColor = function (htmlcolor) { if (typeof htmlcolor == 'object') { if (htmlcolor.color) { return htmlcolor.color; } return undefined; } ///#AFEEEE var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/; htmlcolor = htmlcolor.toLowerCase(); if (!reg.test(htmlcolor)) { console.log('不是有效的html颜色', htmlcolor); return; } if (htmlcolor.length == 4) { var sColorNew = "#"; for (var i = 1; i < 4; i += 1) { sColorNew += htmlcolor.slice(i, i + 1).concat(htmlcolor.slice(i, i + 1)); } htmlcolor = sColorNew; } //处理六位的颜色值 var sColorChange = []; for (var i = 1; i < 7; i += 2) { sColorChange.push(parseInt("0x" + htmlcolor.slice(i, i + 2))); } //处理八位颜色值加透明度 if (htmlcolor.length == 9) { var opity = parseInt(htmlcolor.substr(7, 2)) / 100; return this.createColor(sColorChange[0] / 255, sColorChange[1] / 255, sColorChange[2] / 255, opity); } return this.createColor(sColorChange[0] / 255, sColorChange[1] / 255, sColorChange[2] / 255, 1); }; /** * rgb 颜色转16进制 */ Color.prototype.toHtmlColor = function (color) { //color = color.toString().replace(/rgb|RGB|rgba|RGBA/,''); var rgb = color.split(','); var r = parseInt(rgb[0].split('(')[1]); var g = parseInt(rgb[1]); var b = parseInt(rgb[2].split(')')[0]); var hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); return hex; }; /** * 转为rgb颜色对象 */ Color.prototype.rgbaStringToRgbaObj = function (color) { if (/^rgb/.test(color)) { //rgba(28, 63, 169, 1) color = color.replace(/rgba\(/g, ""), color = color.replace(/rgb\(/g, ""); color = color.replace(/\)/g, ""); var colors = color.split(","); color = {}; if (colors.length == 3) { color.r = parseFloat(colors[0]); color.g = parseFloat(colors[1]); color.b = parseFloat(colors[2]); color.a = 1; } else if (colors.length == 4) { color.r = parseFloat(colors[0]); color.g = parseFloat(colors[1]); color.b = parseFloat(colors[2]); color.a = parseFloat(colors[3]); } } return color; }; /** * 仿照te修改 * * 这个方法用于创建颜色 *@param {number} [red] 红。 * @param {number} [green] 绿。 * @param {number} [blue] 蓝。 * @param {number} [alpha] 透明度。 * @returns {Promise.} 返回一个Cesium的颜色对象。 */ Color.prototype.CreateColor = function (red, green, blue, alpha) { var Color = new this._cesium.Color(red, green, blue, alpha); return Color; }; /** * * 创建等高线。 * * @alias ElevationContour * @constructor * @author 张丹钊 * */ function ElevationContour(viewer, cesium) { this._viewer = viewer; this._cesium = cesium; this._core = new Core(); } /** * 这个方法用于创建等高线 * */ ElevationContour.prototype.createElevationContour = function (hasContour, selectedShading, option) { var _this = this; var elevation = {}; _this.item = elevation; var minHeight = this._core.defaultValue(option.min, -414.0); var maxHeight = _this._core.defaultValue(option.max, 8844); _this.item.selectedShading = selectedShading; var hasContour = hasContour; var globe = _this._viewer.scene.globe; var material; if (hasContour) { if (selectedShading === 'elevation') { material = new _this._cesium.Material({ fabric: { type: 'ElevationColorContour', materials: { contourMaterial: { type: 'ElevationContour' }, elevationRampMaterial: { type: 'ElevationRamp' } }, components: { diffuse: 'contourMaterial.alpha == 0.0 ? elevationRampMaterial.diffuse : contourMaterial.diffuse', alpha: 'max(contourMaterial.alpha, elevationRampMaterial.alpha)' } }, translucent: false }); _this.item.shadingUniforms = material.materials.elevationRampMaterial.uniforms; _this.item.shadingUniforms.minimumHeight = minHeight; _this.item.shadingUniforms.maximumHeight = maxHeight; _this.item.contourUniforms = material.materials.contourMaterial.uniforms; } else if (selectedShading === 'slope') { material = new _this._cesium.Material({ fabric: { type: 'SlopeColorContour', materials: { contourMaterial: { type: 'ElevationContour' }, slopeRampMaterial: { type: 'SlopeRamp' } }, components: { diffuse: 'contourMaterial.alpha == 0.0 ? slopeRampMaterial.diffuse : contourMaterial.diffuse', alpha: 'max(contourMaterial.alpha, slopeRampMaterial.alpha)' } }, translucent: false }); _this.item.shadingUniforms = material.materials.slopeRampMaterial.uniforms; _this.item.contourUniforms = material.materials.contourMaterial.uniforms; } else if (selectedShading === 'aspect') { material = new _this._cesium.Material({ fabric: { type: 'AspectColorContour', materials: { contourMaterial: { type: 'ElevationContour' }, aspectRampMaterial: { type: 'AspectRamp' } }, components: { diffuse: 'contourMaterial.alpha == 0.0 ? aspectRampMaterial.diffuse : contourMaterial.diffuse', alpha: 'max(contourMaterial.alpha, aspectRampMaterial.alpha)' } }, translucent: false }); _this.item.shadingUniforms = material.materials.aspectRampMaterial.uniforms; _this.item.contourUniforms = material.materials.contourMaterial.uniforms; } else { material = _this._cesium.Material.fromType('ElevationContour'); _this.item.contourUniforms = material.uniforms; } _this.item.contourUniforms.width = _this._core.defaultValue(option.width, 2.0); _this.item.contourUniforms.spacing = _this._core.defaultValue(option.spacing, 150.0); _this.item.contourUniforms.color = _this._cesium.Color.fromCssColorString(_this._core.defaultValue(option.lineColor, '#ff0000')); } else if (selectedShading === 'elevation') { material = _this._cesium.Material.fromType('ElevationRamp'); _this.item.shadingUniforms = material.uniforms; _this.item.shadingUniforms.minimumHeight = minHeight; _this.item.shadingUniforms.maximumHeight = maxHeight; } else if (selectedShading === 'slope') { material = _this._cesium.Material.fromType('SlopeRamp'); _this.item.shadingUniforms = material.uniforms; } else if (selectedShading === 'aspect') { material = _this._cesium.Material.fromType('AspectRamp'); _this.item.shadingUniforms = material.uniforms; } if (selectedShading !== 'none') { if (option) { _this.item.shadingUniforms.image = _this._core.getColorRamp(selectedShading, option.colorArr, option.min, option.max); } else { _this.item.shadingUniforms.image = _this._core.getColorRamp(selectedShading); } } globe.material = undefined; _this._viewer.render(); globe.material = material; _this.item.material = globe.material; return this; }; /** * 这个方法用于创建坡度无线分析 * */ ElevationContour.prototype.executeMaterial = function (method) { var _this = this; var elevation = {}; _this.item = elevation; var minHeight = -414.0;// approximate dead sea elevation var maxHeight = 8777.0;// approximate everest elevation _this.item.selectedShading = method; _this.item.shadingUniforms = {}; var globe = this._viewer.scene.globe; var material; if (_this.item.selectedShading === 'elevation') { material = this._cesium.Material.fromType('ElevationRamp'); _this.item.shadingUniforms = material.uniforms; _this.item.shadingUniforms.minHeight = minHeight; _this.item.shadingUniforms.maxHeight = maxHeight; } else if (_this.item.selectedShading === 'slope') { material = this._cesium.Material.fromType('SlopeRamp'); _this.item.shadingUniforms = material.uniforms; } else if (_this.item.selectedShading === 'aspect') { material = this._cesium.Material.fromType('AspectRamp'); _this.item.shadingUniforms = material.uniforms; } if (_this.item.selectedShading !== 'none') { _this.item.shadingUniforms.image = this._core.getColorRamp(_this.item.selectedShading); } globe.material = material; _this.item.material = globe.material; return this; }; /** * 设置线的间距 * @param {Object} [elevation] elevation对象 * @returns {spacing} spacing设置间距。 * @returns {Object} 返回一个等高线或坡度对象。 */ ElevationContour.prototype.setSpacing = function (spacing) { try { //contourUniforms.spacing = parseFloat(newValue); this.item.contourUniforms.spacing = parseFloat(spacing); } catch (ex) { console.log(ex); } return this; }; /** * 设置等高线坡度颜色 * @param {Object} [elevation] elevation对象 * @returns {htmlColor} htmlColor颜色。 * @returns {Object} 返回一个Label对象。 */ ElevationContour.prototype.setMaterialColor = function (htmlColor) { try { this.item.contourUniforms.color = new Color(this._viewer, this._cesium).colorFromHtmlColor(htmlColor); //this.item.contourUniforms.color = this._cesium.Color.GOLD.clone() } catch (ex) { console.log(ex); } return this; }; /** * 设置线的宽度 * @param {Object} [elevation] elevation对象 * @param {double} [width] 线宽 * @returns {Object} 返回一个等高线或坡度对象。 */ ElevationContour.prototype.setWidth = function (width) { try { //contourUniforms.spacing = parseFloat(newValue); this.item.contourUniforms.width = parseFloat(width); } catch (ex) { console.log(ex); } return this; }; /** * 这个方法用于创建坡度有线分析 * */ ElevationContour.prototype.executeContourMaterial = function (method) { var _this = this; var elevation = {}; _this.item = elevation; var minHeight = -414.0;// approximate dead sea elevation var maxHeight = 8777.0;// approximate everest elevation _this.item.selectedShading = method; var globe = _this._viewer.scene.globe; var material; if (_this.item.selectedShading === 'elevation') { material = new this._cesium.Material({ fabric: { type: 'ElevationColorContour', materials: { contourMaterial: { type: 'ElevationContour' }, elevationRampMaterial: { type: 'ElevationRamp' } }, components: { diffuse: 'contourMaterial.alpha == 0.0 ? elevationRampMaterial.diffuse : contourMaterial.diffuse', alpha: 'max(contourMaterial.alpha, elevationRampMaterial.alpha)' } }, translucent: false }); _this.item.shadingUniforms = material.materials.elevationRampMaterial.uniforms; _this.item.shadingUniforms.minHeight = minHeight; _this.item.shadingUniforms.maxHeight = maxHeight; _this.item.contourUniforms = material.materials.contourMaterial.uniforms; } else if (_this.item.selectedShading === 'slope') { material = getSlopeContourMaterial(); _this.item.shadingUniforms = material.materials.slopeRampMaterial.uniforms; _this.item.contourUniforms = material.materials.contourMaterial.uniforms; } else if (_this.item.selectedShading === 'aspect') { material = getAspectContourMaterial(); _this.item.shadingUniforms = material.materials.aspectRampMaterial.uniforms; _this.item.contourUniforms = material.materials.contourMaterial.uniforms; } else { material = this._cesium.Material.fromType('ElevationContour'); _this.item.contourUniforms = material.uniforms; } if (_this.item.selectedShading !== 'none') { _this.item.shadingUniforms.image = this._core.getColorRamp(_this.item.selectedShading); } _this.item.contourUniforms.width = 2.0; _this.item.contourUniforms.spacing = 150.0; _this.item.contourUniforms.color = this._cesium.Color.fromRandom({ alpha: 1.0 }, this._cesium.Color.RED.clone()); globe.material = material; _this.item.material = globe.material; return this; }; Object.defineProperties(ElevationContour.prototype, { /** * 获取或设置矩形 */ elevation: { get: function () { return this.item; }, set: function (item) { this.item = item; } } }); /** * ModelEdit * * @alias ModelEdit * @author 张丹钊 * @constructor * * @param {Viewer} viewer 地图视图。 * * @example * modelEdit = new SmartEarth.ModelEdit(Viewer); * modelEdit.start(model) */ function ModelEdit(viewer) { this._viewer = viewer; this.editType = 'Entity'; this._core = new Core(); this.tooltip = this._core.CreateTooltip({ id: 'ModelEdit' }); } /** * 开始编辑 * @param {Entity} model 模型 * @param {Object} [option] 参数 * @param {Boolean} [option.rotateX=true] X轴旋转 * @param {Boolean} [option.rotateY=true] Y轴旋转 * @param {Boolean} [option.rotateZ=true] Z轴旋转 * @param {Number} [option.minimumPixelSize=0] 最小显示尺寸 * @param {Function} [option.callback] 编辑回调函数 function(type){ } * @returns {ModelEdit} */ ModelEdit.prototype.start = function (model, option = {}) { this.end(); if (!model) return let position, radius; if (model.item && model.item instanceof Cesium.Cesium3DTileset) { this.editType = 'SE3DTiles'; // 所编辑模型的边界半径和中心 radius = model.boundingSphereRadius; position = Cesium.Cartesian3.fromDegrees(model.modelEditData.lon, model.modelEditData.lat, model.modelEditData.height); } else { this.editType = 'Entity'; let modelIndex = this._viewer.scene.primitives._primitives.findIndex(primitive => { return primitive.id && primitive.id.id === model.id }); if (modelIndex < 0) return let model_primitive = this._viewer.scene.primitives.get(modelIndex); let boundingSphere = model_primitive.boundingSphere; // 所编辑模型的边界半径和中心 radius = boundingSphere.radius; position = model.position.getValue(); !model.heading && (model.heading = 0); !model.pitch && (model.pitch = 0); !model.roll && (model.roll = 0); } this.model = model; // 编辑坐标轴的边界半径 let axisRadius = 3.63; // 编辑坐标轴的比例 let axisScale = 2 * radius / axisRadius; let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position); this.axis = this._viewer.scene.primitives.add(Cesium.Model.fromGltf({ id: 'modeEditAxis', modelMatrix: modelMatrix, url: window.SmartEarthRootUrl + configData$1.modelAxis, scale: axisScale, minimumPixelSize: option.minimumPixelSize })); this.axis.readyPromise.then(() => { option.rotateX === false && (this.axis._nodeCommands[1].show = false); option.rotateY === false && (this.axis._nodeCommands[0].show = false); option.rotateZ === false && (this.axis._nodeCommands[5].show = false); }); this.initEvent(option); return this }; /* * 初始化模型编辑响应事件 */ ModelEdit.prototype.initEvent = function (option) { this.editHandler && this.editHandler.destroy(); this.editHandler = new Cesium.ScreenSpaceEventHandler(this._viewer.scene.canvas); let editType, startP; this.editHandler.setInputAction(event => { if (editType) { startP = event.position; if (this.editType === 'Entity') { this.originPosition = this.model.position.getValue(); this.originHeading = this.model.heading || 0; this.originPitch = this.model.pitch || 0; this.originRoll = this.model.roll || 0; } else { this.originPosition = Cesium.Cartesian3.fromDegrees( this.model.modelEditData.lon, this.model.modelEditData.lat, this.model.modelEditData.height ); this.originHeading = this.model.modelEditData.heading || 0; this.originPitch = this.model.modelEditData.ritch || 0; this.originRoll = this.model.modelEditData.roll || 0; } this.startPosition = this._viewer.scene.pickPosition(startP); this.defaultEvent(false); this.setMouseStyle('edit'); } else { startP = undefined; } }, Cesium.ScreenSpaceEventType.LEFT_DOWN); this.editHandler.setInputAction(event => { startP = undefined; this.defaultEvent(true); this.setMouseStyle('default'); }, Cesium.ScreenSpaceEventType.LEFT_UP); this.editHandler.setInputAction(event => { if (startP) { this.mouseTooltip(editType, event); this.edit(editType, startP, event.endPosition); option.callback && option.callback(editType); return } let pick = this._viewer.scene.pick(event.endPosition); if (pick && pick.id === 'modeEditAxis') { let name = pick.mesh ? pick.mesh.name : pick.detail.node._name; if (name === 'XArrow_1') { editType = 'y'; } else if (name === 'YArrow_1') { editType = 'x'; } else if (name === 'ZArrow_1') { editType = 'z'; } else if (name === 'ZAxis_1') { editType = 'heading'; } else if (name === 'XAxis_1') { editType = 'pitch'; } else if (name === 'YAxis_1') { editType = 'roll'; } else { editType = undefined; } } else { editType = undefined; } this.mouseTooltip(editType, event); }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); }; /* * 默认鼠标事件 */ ModelEdit.prototype.defaultEvent = function (isOpen) { let scene = this._viewer.scene; scene.screenSpaceCameraController.enableRotate = isOpen; scene.screenSpaceCameraController.enableTranslate = isOpen; scene.screenSpaceCameraController.enableZoom = isOpen; scene.screenSpaceCameraController.enableTilt = isOpen; scene.screenSpaceCameraController.enableLook = isOpen; }; /* * 设置鼠标样式 */ ModelEdit.prototype.setMouseStyle = function (type) { if (type === 'edit') { this.defaultMouseStyle = this._viewer.container.style.cursor; this._viewer.container.style.cursor = "crosshair"; } else if (type === 'default') { this._viewer.container.style.cursor = this.defaultMouseStyle || "default"; } }; /* * 编辑模型 */ ModelEdit.prototype.edit = function (editType, start, end) { if (editType) { let centerPosition = this.originPosition; let startPosition = this.startPosition; let endPosition = this._viewer.scene.pickPosition(end); let centerDegrees = this._core.toDegrees(centerPosition); let startDegrees = this._core.toDegrees(startPosition); let endDegrees = this._core.toDegrees(endPosition); let c_winPosition = this._viewer.scene.cartesianToCanvasCoordinates(centerPosition); end.x - start.x; let _y = end.y - start.y; if (editType === 'x') { let originLon = startDegrees.lon - endDegrees.lon; //移动后经度变化 centerDegrees.lon -= originLon; this.setPosition(centerDegrees); } else if (editType === 'y') { let originLat = startDegrees.lat - endDegrees.lat; //移动后纬度变化 centerDegrees.lat -= originLat; this.setPosition(centerDegrees); } else if (editType === 'z') { let originHeight = startDegrees.height - centerDegrees.height; //移动后高度变化 let _height = _y * Math.abs(originHeight / (start.y - c_winPosition.y)); centerDegrees.height -= _height; this.setPosition(centerDegrees); } else if (editType === 'heading') { let heading = this.originHeading; let angle = this._core.arge(c_winPosition, start, end, '+-', true); heading -= angle; this.setRotate('heading', heading); } else if (editType === 'pitch') { let originLon = startDegrees.lon - centerDegrees.lon; //移动后经度变化 let _lon = originLon / (start.x - c_winPosition.x); let pitch = this.originPitch; let angle = this._core.arge(c_winPosition, start, end, '+-', true); if (_lon > 0) { pitch += angle; } else { pitch -= angle; } this.setRotate('pitch', pitch); } else if (editType === 'roll') { let originLat = startDegrees.lat - centerDegrees.lat; //移动后纬度变化 let _lat = originLat / (start.x - c_winPosition.x); let roll = this.originRoll; let angle = this._core.arge(c_winPosition, start, end, '+-', true); if (_lat < 0) { roll -= angle; } else { roll += angle; } this.setRotate('roll', roll); } } }; /* * 设置模型位置 */ ModelEdit.prototype.setPosition = function (centerDegrees) { let newPosition = Cesium.Cartesian3.fromDegrees(centerDegrees.lon, centerDegrees.lat, centerDegrees.height); if (this.editType === 'Entity') { this.model.position = newPosition; if (window.SmartEarthPopupData && window.SmartEarthPopupData.window) { SmartEarthPopupData.window.document.querySelector('.model input[name="height"]') && (SmartEarthPopupData.window.document.querySelector('.model input[name="height"]').value = centerDegrees.height.toFixed(2)); } } else { this.model.setEditData(centerDegrees); } this.axis.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(newPosition); }; /** * 设置模型旋转角 * @param {String} type 旋转类型【heading | pitch | roll】 * @param {Number} value 旋转角 */ ModelEdit.prototype.setRotate = function (type, value) { if (this.model) { if (this.editType === 'Entity') { let heading = this.model.heading; let pitch = this.model.pitch; let roll = this.model.roll; if (type === 'heading') { this.model.heading = heading = value; } else if (type === 'pitch') { this.model.pitch = pitch = value; } else if (type === 'roll') { this.model.roll = roll = value; } this.model.orientation = Cesium.Transforms.headingPitchRollQuaternion( this.model.position.getValue(), new Cesium.HeadingPitchRoll( Cesium.Math.toRadians(heading), Cesium.Math.toRadians(pitch), Cesium.Math.toRadians(roll) ) ); if (window.SmartEarthPopupData && window.SmartEarthPopupData.window) { SmartEarthPopupData.window.document.querySelector(`.model input[name="${type}"]`) && (SmartEarthPopupData.window.document.querySelector(`.model input[name="${type}"]`).value = value); } } else { switch (type) { case "heading": this.model.setEditData({ heading: -value }); break; case "pitch": this.model.setEditData({ pitch: value }); break; case "roll": this.model.setEditData({ roll: value }); break; } } } }; /* * 鼠标提示 */ ModelEdit.prototype.mouseTooltip = function (editType, event) { if (editType) { let position = event.endPosition || event.position; if (editType === 'x') { this.tooltip.showAt(position, "X方向平移"); } else if (editType === 'y') { this.tooltip.showAt(position, "Y方向平移"); } else if (editType === 'z') { this.tooltip.showAt(position, "Z方向平移"); } else if (editType === 'heading') { this.tooltip.showAt(position, "绕Z轴旋转"); } else if (editType === 'pitch') { this.tooltip.showAt(position, "绕Y轴旋转"); } else if (editType === 'roll') { this.tooltip.showAt(position, "绕X轴旋转"); } else { this.tooltip.show(false); } } else { this.tooltip.show(false); } }; /** * 结束编辑 * */ ModelEdit.prototype.end = function () { this.axis && this._viewer.scene.primitives.remove(this.axis); this.axis = undefined; this.editHandler && this.editHandler.destroy(); this.editHandler = undefined; this.model && (this.model.ModelEdit = undefined); this.model = undefined; this.tooltip && this.tooltip.show(false); }; /* Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined$1; /* Used as the semantic version number. */ var VERSION$1 = '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 = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; /* Used to map HTML entities to characters. */ var htmlUnescapes = { '&': '&', '<': '<', '>': '>', '"': '"', ''': "'" }; /* 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 global == 'object' && global && global.Object === Object && global; /* 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 = typeof exports == 'object' && exports && !exports.nodeType && exports; /* Detect free variable `module`. */ var freeModule = freeExports && typeof module == '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 * 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 * 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. * @param {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. * @param {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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 '

' + func(text) + '

'; * }); * * p('fred, barney, & pebbles'); * // => '

fred, barney, & pebbles

' */ 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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(''); * // => 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 _ * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 _ * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 _ * String * @param {string} [string=''] The string to escape. * @returns {string} Returns the escaped string. * @example * * _.escape('fred, barney, & pebbles'); * // => 'fred, barney, & 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 _ * 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('<%- value %>'); * compiled({ 'value': '