diff --git a/game/NoSleep.js b/game/NoSleep.js index eee50a69d..7195991a7 100644 --- a/game/NoSleep.js +++ b/game/NoSleep.js @@ -1,192 +1,192 @@ -/*! NoSleep.js v0.9.0 - git.io/vfn01 - Rich Tibbett - MIT license */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["NoSleep"] = factory(); - else - root["NoSleep"] = factory(); -})(typeof self !== 'undefined' ? self : this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 0); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -var _require = __webpack_require__(1), - webm = _require.webm, - mp4 = _require.mp4; - -// Detect iOS browsers < version 10 - - -var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream; - -var NoSleep = function () { - function NoSleep() { - var _this = this; - - _classCallCheck(this, NoSleep); - - if (oldIOS) { - this.noSleepTimer = null; - } else { - // Set up no sleep video element - this.noSleepVideo = document.createElement('video'); - - this.noSleepVideo.setAttribute('muted', ''); - this.noSleepVideo.setAttribute('title', 'No Sleep'); - this.noSleepVideo.setAttribute('playsinline', ''); - - this._addSourceToVideo(this.noSleepVideo, 'webm', webm); - this._addSourceToVideo(this.noSleepVideo, 'mp4', mp4); - - this.noSleepVideo.addEventListener('loadedmetadata', function () { - if (_this.noSleepVideo.duration <= 1) { - // webm source - _this.noSleepVideo.setAttribute('loop', ''); - } else { - // mp4 source - _this.noSleepVideo.addEventListener('timeupdate', function () { - if (_this.noSleepVideo.currentTime > 0.5) { - _this.noSleepVideo.currentTime = Math.random(); - } - }); - } - }); - } - } - - _createClass(NoSleep, [{ - key: '_addSourceToVideo', - value: function _addSourceToVideo(element, type, dataURI) { - var source = document.createElement('source'); - source.src = dataURI; - source.type = 'video/' + type; - element.appendChild(source); - } - }, { - key: 'enable', - value: function enable() { - if (oldIOS) { - this.disable(); - console.warn('\n NoSleep enabled for older iOS devices. This can interrupt\n active or long-running network requests from completing successfully.\n See https://github.com/richtr/NoSleep.js/issues/15 for more details.\n '); - this.noSleepTimer = window.setInterval(function () { - if (!document.hidden) { - window.location.href = window.location.href.split('#')[0]; - window.setTimeout(window.stop, 0); - } - }, 15000); - } else { - this.noSleepVideo.play(); - } - } - }, { - key: 'disable', - value: function disable() { - if (oldIOS) { - if (this.noSleepTimer) { - console.warn('\n NoSleep now disabled for older iOS devices.\n '); - window.clearInterval(this.noSleepTimer); - this.noSleepTimer = null; - } - } else { - this.noSleepVideo.pause(); - } - } - }]); - - return NoSleep; -}(); - -; - -module.exports = NoSleep; - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = { - webm: 'data:video/webm;base64,GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA=', - mp4: 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=' -}; - -/***/ }) -/******/ ]); -}); \ No newline at end of file +/*! NoSleep.js v0.9.0 - git.io/vfn01 - Rich Tibbett - MIT license */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["NoSleep"] = factory(); + else + root["NoSleep"] = factory(); +})(typeof self !== 'undefined' ? self : this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var _require = __webpack_require__(1), + webm = _require.webm, + mp4 = _require.mp4; + +// Detect iOS browsers < version 10 + + +var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream; + +var NoSleep = function () { + function NoSleep() { + var _this = this; + + _classCallCheck(this, NoSleep); + + if (oldIOS) { + this.noSleepTimer = null; + } else { + // Set up no sleep video element + this.noSleepVideo = document.createElement('video'); + + this.noSleepVideo.setAttribute('muted', ''); + this.noSleepVideo.setAttribute('title', 'No Sleep'); + this.noSleepVideo.setAttribute('playsinline', ''); + + this._addSourceToVideo(this.noSleepVideo, 'webm', webm); + this._addSourceToVideo(this.noSleepVideo, 'mp4', mp4); + + this.noSleepVideo.addEventListener('loadedmetadata', function () { + if (_this.noSleepVideo.duration <= 1) { + // webm source + _this.noSleepVideo.setAttribute('loop', ''); + } else { + // mp4 source + _this.noSleepVideo.addEventListener('timeupdate', function () { + if (_this.noSleepVideo.currentTime > 0.5) { + _this.noSleepVideo.currentTime = Math.random(); + } + }); + } + }); + } + } + + _createClass(NoSleep, [{ + key: '_addSourceToVideo', + value: function _addSourceToVideo(element, type, dataURI) { + var source = document.createElement('source'); + source.src = dataURI; + source.type = 'video/' + type; + element.appendChild(source); + } + }, { + key: 'enable', + value: function enable() { + if (oldIOS) { + this.disable(); + console.warn('\n NoSleep enabled for older iOS devices. This can interrupt\n active or long-running network requests from completing successfully.\n See https://github.com/richtr/NoSleep.js/issues/15 for more details.\n '); + this.noSleepTimer = window.setInterval(function () { + if (!document.hidden) { + window.location.href = window.location.href.split('#')[0]; + window.setTimeout(window.stop, 0); + } + }, 15000); + } else { + this.noSleepVideo.play(); + } + } + }, { + key: 'disable', + value: function disable() { + if (oldIOS) { + if (this.noSleepTimer) { + console.warn('\n NoSleep now disabled for older iOS devices.\n '); + window.clearInterval(this.noSleepTimer); + this.noSleepTimer = null; + } + } else { + this.noSleepVideo.pause(); + } + } + }]); + + return NoSleep; +}(); + +; + +module.exports = NoSleep; + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = { + webm: 'data:video/webm;base64,GkXfo0AgQoaBAUL3gQFC8oEEQvOBCEKCQAR3ZWJtQoeBAkKFgQIYU4BnQI0VSalmQCgq17FAAw9CQE2AQAZ3aGFtbXlXQUAGd2hhbW15RIlACECPQAAAAAAAFlSua0AxrkAu14EBY8WBAZyBACK1nEADdW5khkAFVl9WUDglhohAA1ZQOIOBAeBABrCBCLqBCB9DtnVAIueBAKNAHIEAAIAwAQCdASoIAAgAAUAmJaQAA3AA/vz0AAA=', + mp4: 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=' +}; + +/***/ }) +/******/ ]); +}); diff --git a/game/asset.js b/game/asset.js index 80a424b5c..9bc6968a2 100644 --- a/game/asset.js +++ b/game/asset.js @@ -1,9610 +1,9610 @@ -window.noname_asset_list=[ - 'v1.10.10', - /*audio start*/ - 'audio/background/aozhan_chaoming.mp3', - 'audio/background/aozhan_online.mp3', - 'audio/background/aozhan_rewrite.mp3', - 'audio/background/music_danji.mp3', - 'audio/background/music_default.mp3', - 'audio/background/music_diaochan.mp3', - 'audio/background/music_jifeng.mp3', - 'audio/background/music_jilve.mp3', - 'audio/background/music_phliosophy.mp3', - 'audio/background/music_shezhan.mp3', - /*cardaudio start*/ - 'audio/card/default.mp3', - - 'audio/card/female/caomu.mp3', - 'audio/card/female/chiling.mp3', - 'audio/card/female/diaohulishan.mp3', - 'audio/card/female/fulei.mp3', - 'audio/card/female/huoshaolianying.mp3', - 'audio/card/female/jinchan.mp3', - 'audio/card/female/lianjunshengyan.mp3', - 'audio/card/female/lulitongxin.mp3', - 'audio/card/female/qijia.mp3', - 'audio/card/female/shengdong.mp3', - 'audio/card/female/shuiyanqijun.mp3', - 'audio/card/female/xietianzi.mp3', - 'audio/card/female/zengbin.mp3', - 'audio/card/female/chuqibuyi.mp3', - 'audio/card/female/dongzhuxianji.mp3', - 'audio/card/female/sha_ice.mp3', - 'audio/card/female/suijiyingbian.mp3', - 'audio/card/female/zhujinqiyuan.mp3', - 'audio/card/female/binglinchengxiax.mp3', - 'audio/card/female/chenghuodajie.mp3', - 'audio/card/female/dz_mantianguohai.mp3', - 'audio/card/female/guaguliaodu.mp3', - 'audio/card/female/gz_guguoanbang.mp3', - 'audio/card/female/gz_haolingtianxia.mp3', - 'audio/card/female/gz_kefuzhongyuan.mp3', - 'audio/card/female/gz_wenheluanwu.mp3', - 'audio/card/female/kaihua.mp3', - 'audio/card/female/qizhengxiangsheng.mp3', - 'audio/card/female/sha_stab.mp3', - 'audio/card/female/tiaojiyanmei.mp3', - 'audio/card/female/tuixinzhifu.mp3', - - 'audio/card/female/bagua.mp3', - 'audio/card/female/baiyin.mp3', - 'audio/card/female/chitu.mp3', - 'audio/card/female/cixiong.mp3', - 'audio/card/female/dawan.mp3', - 'audio/card/female/dilu.mp3', - 'audio/card/female/fangtian.mp3', - 'audio/card/female/guanshi.mp3', - 'audio/card/female/guding.mp3', - 'audio/card/female/hanbing.mp3', - 'audio/card/female/hualiu.mp3', - 'audio/card/female/jueying.mp3', - 'audio/card/female/muniu.mp3', - 'audio/card/female/qilin.mp3', - 'audio/card/female/qinggang.mp3', - 'audio/card/female/qinglong.mp3', - 'audio/card/female/renwang.mp3', - 'audio/card/female/sanjian.mp3', - 'audio/card/female/tengjia.mp3', - 'audio/card/female/wuliu.mp3', - 'audio/card/female/zhangba.mp3', - 'audio/card/female/zhuahuang.mp3', - 'audio/card/female/zhuge.mp3', - 'audio/card/female/zhuque.mp3', - 'audio/card/female/zixin.mp3', - - 'audio/card/female/bingliang.mp3', - 'audio/card/female/guohe.mp3', - 'audio/card/female/huogong.mp3', - 'audio/card/female/jiedao.mp3', - 'audio/card/female/jiu.mp3', - 'audio/card/female/juedou.mp3', - 'audio/card/female/lebu.mp3', - 'audio/card/female/nanman.mp3', - 'audio/card/female/sha.mp3', - 'audio/card/female/sha_fire.mp3', - 'audio/card/female/sha_thunder.mp3', - 'audio/card/female/shan.mp3', - 'audio/card/female/shandian.mp3', - 'audio/card/female/shunshou.mp3', - 'audio/card/female/taoyuan.mp3', - 'audio/card/female/tiesuo.mp3', - 'audio/card/female/wanjian.mp3', - 'audio/card/female/wugu.mp3', - 'audio/card/female/wuxie.mp3', - 'audio/card/female/wuzhong.mp3', - 'audio/card/female/yiyi.mp3', - 'audio/card/female/yuanjiao.mp3', - 'audio/card/female/zhibi.mp3', - - 'audio/card/male/caomu.mp3', - 'audio/card/male/chiling.mp3', - 'audio/card/male/diaohulishan.mp3', - 'audio/card/male/fulei.mp3', - 'audio/card/male/huoshaolianying.mp3', - 'audio/card/male/jinchan.mp3', - 'audio/card/male/lianjunshengyan.mp3', - 'audio/card/male/lulitongxin.mp3', - 'audio/card/male/qijia.mp3', - 'audio/card/male/shengdong.mp3', - 'audio/card/male/shuiyanqijun.mp3', - 'audio/card/male/xietianzi.mp3', - 'audio/card/male/zengbin.mp3', - 'audio/card/male/chuqibuyi.mp3', - 'audio/card/male/dongzhuxianji.mp3', - 'audio/card/male/sha_ice.mp3', - 'audio/card/male/suijiyingbian.mp3', - 'audio/card/male/zhujinqiyuan.mp3', - 'audio/card/male/binglinchengxiax.mp3', - 'audio/card/male/chenghuodajie.mp3', - 'audio/card/male/dz_mantianguohai.mp3', - 'audio/card/male/guaguliaodu.mp3', - 'audio/card/male/gz_guguoanbang.mp3', - 'audio/card/male/gz_haolingtianxia.mp3', - 'audio/card/male/gz_kefuzhongyuan.mp3', - 'audio/card/male/gz_wenheluanwu.mp3', - 'audio/card/male/kaihua.mp3', - 'audio/card/male/qizhengxiangsheng.mp3', - 'audio/card/male/sha_stab.mp3', - 'audio/card/male/tiaojiyanmei.mp3', - 'audio/card/male/tuixinzhifu.mp3', - - 'audio/card/male/bagua.mp3', - 'audio/card/male/baiyin.mp3', - 'audio/card/male/chitu.mp3', - 'audio/card/male/cixiong.mp3', - 'audio/card/male/dawan.mp3', - 'audio/card/male/dilu.mp3', - 'audio/card/male/fangtian.mp3', - 'audio/card/male/guanshi.mp3', - 'audio/card/male/guding.mp3', - 'audio/card/male/hanbing.mp3', - 'audio/card/male/hualiu.mp3', - 'audio/card/male/jueying.mp3', - 'audio/card/male/muniu.mp3', - 'audio/card/male/qilin.mp3', - 'audio/card/male/qinggang.mp3', - 'audio/card/male/qinglong.mp3', - 'audio/card/male/renwang.mp3', - 'audio/card/male/sanjian.mp3', - 'audio/card/male/tengjia.mp3', - 'audio/card/male/wuliu.mp3', - 'audio/card/male/zhangba.mp3', - 'audio/card/male/zhuahuang.mp3', - 'audio/card/male/zhuge.mp3', - 'audio/card/male/zhuque.mp3', - 'audio/card/male/zixin.mp3', - - 'audio/card/male/bingliang.mp3', - 'audio/card/male/guohe.mp3', - 'audio/card/male/huogong.mp3', - 'audio/card/male/jiedao.mp3', - 'audio/card/male/jiu.mp3', - 'audio/card/male/juedou.mp3', - 'audio/card/male/lebu.mp3', - 'audio/card/male/nanman.mp3', - 'audio/card/male/sha.mp3', - 'audio/card/male/sha_fire.mp3', - 'audio/card/male/sha_thunder.mp3', - 'audio/card/male/shan.mp3', - 'audio/card/male/shandian.mp3', - 'audio/card/male/shunshou.mp3', - 'audio/card/male/taoyuan.mp3', - 'audio/card/male/tiesuo.mp3', - 'audio/card/male/wanjian.mp3', - 'audio/card/male/wugu.mp3', - 'audio/card/male/wuxie.mp3', - 'audio/card/male/wuzhong.mp3', - 'audio/card/male/yiyi.mp3', - 'audio/card/male/yuanjiao.mp3', - 'audio/card/male/zhibi.mp3', - /*cardaudio end*/ - - /*dieaudio begin*/ - 'audio/die/ahuinan.mp3', - 'audio/die/bailingyun.mp3', - 'audio/die/baosanniang.mp3', - 'audio/die/beimihu.mp3', - 'audio/die/bianfuren.mp3', - 'audio/die/bianxi.mp3', - 'audio/die/boss_lvbu1.mp3', - 'audio/die/boss_lvbu2.mp3', - 'audio/die/boss_lvbu3.mp3', - 'audio/die/boss_wuguanwang.mp3', - 'audio/die/boss_zhaoyun.mp3', - 'audio/die/bulianshi.mp3', - 'audio/die/buzhi.mp3', - 'audio/die/caesar.mp3', - 'audio/die/caifuren.mp3', - 'audio/die/caimaozhangyun.mp3', - 'audio/die/caiwenji.mp3', - 'audio/die/caiyong.mp3', - 'audio/die/caizhaoji.mp3', - 'audio/die/caizhenji.mp3', - 'audio/die/caoang.mp3', - 'audio/die/caoanmin.mp3', - 'audio/die/caocao.mp3', - 'audio/die/caochong.mp3', - 'audio/die/caochun.mp3', - 'audio/die/caohong.mp3', - 'audio/die/caohua.mp3', - 'audio/die/caojie.mp3', - 'audio/die/caojinyu.mp3', - 'audio/die/caomao.mp3', - 'audio/die/caopi.mp3', - 'audio/die/caoren.mp3', - 'audio/die/caorui.mp3', - 'audio/die/caoshuang.mp3', - 'audio/die/caosong.mp3', - 'audio/die/caoxi.mp3', - 'audio/die/caoxian.mp3', - 'audio/die/caoxiancaohua.mp3', - 'audio/die/caoxing.mp3', - 'audio/die/caoxiu.mp3', - 'audio/die/caoyi.mp3', - 'audio/die/caoying.mp3', - 'audio/die/caoyu.mp3', - 'audio/die/caozhang.mp3', - 'audio/die/caozhen.mp3', - 'audio/die/caozhi.mp3', - 'audio/die/cenhun.mp3', - 'audio/die/cheliji.mp3', - 'audio/die/chendao.mp3', - 'audio/die/chendeng.mp3', - 'audio/die/chendong.mp3', - 'audio/die/chengbing.mp3', - 'audio/die/chengjichengcui.mp3', - 'audio/die/chengong.mp3', - 'audio/die/chengpu.mp3', - 'audio/die/chengui.mp3', - 'audio/die/chengyu.mp3', - 'audio/die/chenjiao.mp3', - 'audio/die/chenlin.mp3', - 'audio/die/chenqun.mp3', - 'audio/die/chenshi.mp3', - 'audio/die/chentai.mp3', - 'audio/die/chenwudongxi.mp3', - 'audio/die/chunyuqiong.mp3', - 'audio/die/clan_hanrong.mp3', - 'audio/die/clan_hanshao.mp3', - 'audio/die/clan_wanghun.mp3', - 'audio/die/clan_wangling.mp3', - 'audio/die/clan_wanglun.mp3', - 'audio/die/clan_wangyun.mp3', - 'audio/die/clan_wuban.mp3', - 'audio/die/clan_wukuang.mp3', - 'audio/die/clan_wuxian.mp3', - 'audio/die/clan_xuncai.mp3', - 'audio/die/clan_xuncan.mp3', - 'audio/die/clan_xunchen.mp3', - 'audio/die/clan_xunshu.mp3', - 'audio/die/clan_xunyou.mp3', - 'audio/die/clan_zhonghui.mp3', - 'audio/die/clan_zhongyan.mp3', - 'audio/die/clan_zhongyu.mp3', - 'audio/die/cuimao.mp3', - 'audio/die/cuiyan.mp3', - 'audio/die/daqiao.mp3', - 'audio/die/daxiaoqiao.mp3', - 'audio/die/db_wenyang.mp3', - 'audio/die/dc_bulianshi.mp3', - 'audio/die/dc_caiyang.mp3', - 'audio/die/dc_caoshuang.mp3', - 'audio/die/dc_caozhi.mp3', - 'audio/die/dc_chenqun.mp3', - 'audio/die/dc_dengzhi.mp3', - 'audio/die/dc_dongzhao.mp3', - 'audio/die/dc_duyu.mp3', - 'audio/die/dc_gaolan.mp3', - 'audio/die/dc_gongsunzan.mp3', - 'audio/die/dc_huangchengyan.mp3', - 'audio/die/dc_huanghao.mp3', - 'audio/die/dc_huangquan.mp3', - 'audio/die/dc_huangzu.mp3', - 'audio/die/dc_huban.mp3', - 'audio/die/dc_hujinding.mp3', - 'audio/die/dc_huojun.mp3', - 'audio/die/dc_jiachong.mp3', - 'audio/die/dc_jiben.mp3', - 'audio/die/dc_jiling.mp3', - 'audio/die/dc_liru.mp3', - 'audio/die/dc_liuba.mp3', - 'audio/die/dc_liuli.mp3', - 'audio/die/dc_liuye.mp3', - 'audio/die/dc_liuyu.mp3', - 'audio/die/dc_luotong.mp3', - 'audio/die/dc_lvkuanglvxiang.mp3', - 'audio/die/dc_mengda.mp3', - 'audio/die/dc_ruiji.mp3', - 'audio/die/dc_sb_lusu.mp3', - 'audio/die/dc_sb_simayi.mp3', - 'audio/die/dc_sb_simayi_shadow.mp3', - 'audio/die/dc_sb_zhouyu.mp3', - 'audio/die/dc_sp_jiaxu.mp3', - 'audio/die/dc_sunchen.mp3', - 'audio/die/dc_sunhanhua.mp3', - 'audio/die/dc_sunru.mp3', - 'audio/die/dc_sunziliufang.mp3', - 'audio/die/dc_tengfanglan.mp3', - 'audio/die/dc_wangchang.mp3', - 'audio/die/dc_wangjun.mp3', - 'audio/die/dc_wangyun.mp3', - 'audio/die/dc_wuban.mp3', - 'audio/die/dc_xujing.mp3', - 'audio/die/dc_xushu.mp3', - 'audio/die/dc_yangbiao.mp3', - 'audio/die/dc_yanghu.mp3', - 'audio/die/dc_yuejiu.mp3', - 'audio/die/dc_zhangmancheng.mp3', - 'audio/die/dc_zhaotongzhaoguang.mp3', - 'audio/die/dc_zhaoyǎn.mp3', - 'audio/die/dc_zhaoyun.mp3', - 'audio/die/dc_zhouxuān.mp3', - 'audio/die/dc_zhuling.mp3', - 'audio/die/dengai.mp3', - 'audio/die/dengshizai.mp3', - 'audio/die/dengzhi.mp3', - 'audio/die/dengzhong.mp3', - 'audio/die/dianwei.mp3', - 'audio/die/diaochan.mp3', - 'audio/die/dingfeng.mp3', - 'audio/die/dingshangwan.mp3', - 'audio/die/dingyuan.mp3', - 'audio/die/dongbai.mp3', - 'audio/die/dongcheng.mp3', - 'audio/die/dongguiren.mp3', - 'audio/die/dongtuna.mp3', - 'audio/die/dongwan.mp3', - 'audio/die/dongxie.mp3', - 'audio/die/dongyun.mp3', - 'audio/die/dongzhao.mp3', - 'audio/die/dongzhuo.mp3', - 'audio/die/duanjiong.mp3', - 'audio/die/duanqiaoxiao.mp3', - 'audio/die/duanwei.mp3', - 'audio/die/dufuren.mp3', - 'audio/die/duji.mp3', - 'audio/die/dukui.mp3', - 'audio/die/duosidawang.mp3', - 'audio/die/duxi.mp3', - 'audio/die/duyu.mp3', - 'audio/die/erqiao.mp3', - 'audio/die/erzhang.mp3', - 'audio/die/fanchou.mp3', - 'audio/die/fanjiangzhangda.mp3', - 'audio/die/fanyufeng.mp3', - 'audio/die/fazheng.mp3', - 'audio/die/feiyi.mp3', - 'audio/die/fengfang.mp3', - 'audio/die/fengfangnv.mp3', - 'audio/die/fengxi.mp3', - 'audio/die/fuhuanghou.mp3', - 'audio/die/furong.mp3', - 'audio/die/furongfuqian.mp3', - 'audio/die/fuwan.mp3', - 'audio/die/ganfuren.mp3', - 'audio/die/ganfurenmifuren.mp3', - 'audio/die/ganning.mp3', - 'audio/die/gaogan.mp3', - 'audio/die/gaolan.mp3', - 'audio/die/gaoshun.mp3', - 'audio/die/gaoxiang.mp3', - 'audio/die/gexuan.mp3', - 'audio/die/gongsundu.mp3', - 'audio/die/gongsunkang.mp3', - 'audio/die/gongsunyuan.mp3', - 'audio/die/gongsunzan.mp3', - 'audio/die/guanhai.mp3', - 'audio/die/guanlu.mp3', - 'audio/die/guanning.mp3', - 'audio/die/guānning.mp3', - 'audio/die/guanping.mp3', - 'audio/die/guanqiujian.mp3', - 'audio/die/guanxingzhangbao.mp3', - 'audio/die/guanyinping.mp3', - 'audio/die/guanyu.mp3', - 'audio/die/guanzhang.mp3', - 'audio/die/guohuai.mp3', - 'audio/die/guohuanghou.mp3', - 'audio/die/guojia.mp3', - 'audio/die/guosi.mp3', - 'audio/die/guotu.mp3', - 'audio/die/guotufengji.mp3', - 'audio/die/guozhao.mp3', - 'audio/die/guyong.mp3', - 'audio/die/guzhielai.mp3', - 'audio/die/gz_dc_yanghu.mp3', - 'audio/die/gz_dengzhi.mp3', - 'audio/die/gz_gongsunyuan.mp3', - 'audio/die/gz_huangzu.mp3', - 'audio/die/gz_jun_caocao.mp3', - 'audio/die/gz_jun_liubei.mp3', - 'audio/die/gz_jun_sunquan.mp3', - 'audio/die/gz_jun_zhangjiao.mp3', - 'audio/die/gz_liuba.mp3', - 'audio/die/gz_liuqi.mp3', - 'audio/die/gz_lukang.mp3', - 'audio/die/gz_luxun.mp3', - 'audio/die/gz_miheng.mp3', - 'audio/die/gz_panjun.mp3', - 'audio/die/gz_pengyang.mp3', - 'audio/die/gz_re_xushu.mp3', - 'audio/die/gz_shixie.mp3', - 'audio/die/gz_simazhao.mp3', - 'audio/die/gz_sunchen.mp3', - 'audio/die/gz_tangzi.mp3', - 'audio/die/gz_wenqin.mp3', - 'audio/die/gz_wujing.mp3', - 'audio/die/gz_xf_sufei.mp3', - 'audio/die/gz_xiahouba.mp3', - 'audio/die/gz_xuyou.mp3', - 'audio/die/gz_yanbaihu.mp3', - 'audio/die/gz_zhanglu.mp3', - 'audio/die/gz_zhonghui.mp3', - 'audio/die/gz_zhugeke.mp3', - 'audio/die/gz_zhuling.mp3', - 'audio/die/hanba.mp3', - 'audio/die/handang.mp3', - 'audio/die/hanfu.mp3', - 'audio/die/hanhaoshihuan.mp3', - 'audio/die/hanlong.mp3', - 'audio/die/hanmeng.mp3', - 'audio/die/hansui.mp3', - 'audio/die/haomeng.mp3', - 'audio/die/haopu.mp3', - 'audio/die/haozhao.mp3', - 'audio/die/hejin.mp3', - 'audio/die/heqi.mp3', - 'audio/die/hetaihou.mp3', - 'audio/die/heyan.mp3', - 'audio/die/huaman.mp3', - 'audio/die/huanfan.mp3', - 'audio/die/huangchengyan.mp3', - 'audio/die/huangfusong.mp3', - 'audio/die/huanggai.mp3', - 'audio/die/huanghao.mp3', - 'audio/die/huangquan.mp3', - 'audio/die/huangyueying.mp3', - 'audio/die/huangzhong.mp3', - 'audio/die/huangzu.mp3', - 'audio/die/huatuo.mp3', - 'audio/die/huaxin.mp3', - 'audio/die/huaxiong.mp3', - 'audio/die/hucheer.mp3', - 'audio/die/hujinding.mp3', - 'audio/die/huojun.mp3', - 'audio/die/huzhao.mp3', - 'audio/die/jiachong.mp3', - 'audio/die/jiakui.mp3', - 'audio/die/jiangboyue.mp3', - 'audio/die/jiangfei.mp3', - 'audio/die/jianggan.mp3', - 'audio/die/jiangqin.mp3', - 'audio/die/jiangwanfeiyi.mp3', - 'audio/die/jiangwei.mp3', - 'audio/die/jianyong.mp3', - 'audio/die/jiawenhe.mp3', - 'audio/die/jiaxu.mp3', - 'audio/die/jikang.mp3', - 'audio/die/jiling.mp3', - 'audio/die/jin_guohuai.mp3', - 'audio/die/jin_jiachong.mp3', - 'audio/die/jin_simashi.mp3', - 'audio/die/jin_simayi.mp3', - 'audio/die/jin_simazhao.mp3', - 'audio/die/jin_wangyuanji.mp3', - 'audio/die/jin_xiahouhui.mp3', - 'audio/die/jin_yanghu.mp3', - 'audio/die/jin_yanghuiyu.mp3', - 'audio/die/jin_zhangchunhua.mp3', - 'audio/die/jin_zhouchu.mp3', - 'audio/die/jinxuandi.mp3', - 'audio/die/jsp_caoren.mp3', - 'audio/die/jsp_guanyu.mp3', - 'audio/die/jsp_huangyueying.mp3', - 'audio/die/junk_guanyu.mp3', - 'audio/die/kanze.mp3', - 'audio/die/kebineng.mp3', - 'audio/die/key_abyusa.mp3', - 'audio/die/key_hinata.mp3', - 'audio/die/key_hisako.mp3', - 'audio/die/key_noda.mp3', - 'audio/die/key_saya.mp3', - 'audio/die/key_shiina.mp3', - 'audio/die/key_shiki.mp3', - 'audio/die/key_shiorimiyuki.mp3', - 'audio/die/key_yui.mp3', - 'audio/die/key_yuri.mp3', - 'audio/die/kongrong.mp3', - 'audio/die/kuailiangkuaiyue.mp3', - 'audio/die/kuaiqi.mp3', - 'audio/die/laimin.mp3', - 'audio/die/laiyinger.mp3', - 'audio/die/leibo.mp3', - 'audio/die/leitong.mp3', - 'audio/die/liangxing.mp3', - 'audio/die/liaohua.mp3', - 'audio/die/libai.mp3', - 'audio/die/licaiwei.mp3', - 'audio/die/lidian.mp3', - 'audio/die/lifeng.mp3', - 'audio/die/lijue.mp3', - 'audio/die/lingcao.mp3', - 'audio/die/lingju.mp3', - 'audio/die/lingtong.mp3', - 'audio/die/liqueguosi.mp3', - 'audio/die/liru.mp3', - 'audio/die/lisu.mp3', - 'audio/die/litong.mp3', - 'audio/die/liuba.mp3', - 'audio/die/liubei.mp3', - 'audio/die/liubian.mp3', - 'audio/die/liubiao.mp3', - 'audio/die/liuchen.mp3', - 'audio/die/liucheng.mp3', - 'audio/die/liuchongluojun.mp3', - 'audio/die/liufeng.mp3', - 'audio/die/liuhong.mp3', - 'audio/die/liuhui.mp3', - 'audio/die/liupi.mp3', - 'audio/die/liuqi.mp3', - 'audio/die/liushan.mp3', - 'audio/die/liuxie.mp3', - 'audio/die/liuyan.mp3', - 'audio/die/liuyao.mp3', - 'audio/die/liuye.mp3', - 'audio/die/liuyong.mp3', - 'audio/die/liuyu.mp3', - 'audio/die/liuzan.mp3', - 'audio/die/liuzhang.mp3', - 'audio/die/liwan.mp3', - 'audio/die/liyan.mp3', - 'audio/die/liyi.mp3', - 'audio/die/liyixiejing.mp3', - 'audio/die/longwang.mp3', - 'audio/die/luboyan.mp3', - 'audio/die/luji.mp3', - 'audio/die/lukai.mp3', - 'audio/die/lukang.mp3', - 'audio/die/luotong.mp3', - 'audio/die/luoxian.mp3', - 'audio/die/lushi.mp3', - 'audio/die/lusu.mp3', - 'audio/die/luxun.mp3', - 'audio/die/luyi.mp3', - 'audio/die/luyusheng.mp3', - 'audio/die/luzhi.mp3', - 'audio/die/lvboshe.mp3', - 'audio/die/lvbu.mp3', - 'audio/die/lvdai.mp3', - 'audio/die/lvfan.mp3', - 'audio/die/lvkai.mp3', - 'audio/die/lvkuanglvxiang.mp3', - 'audio/die/lvlingqi.mp3', - 'audio/die/lvmeng.mp3', - 'audio/die/lvqian.mp3', - 'audio/die/machao.mp3', - 'audio/die/macheng.mp3', - 'audio/die/madai.mp3', - 'audio/die/majun.mp3', - 'audio/die/maliang.mp3', - 'audio/die/malingli.mp3', - 'audio/die/mamidi.mp3', - 'audio/die/manchong.mp3', - 'audio/die/mangyachang.mp3', - 'audio/die/mateng.mp3', - 'audio/die/maxiumatie.mp3', - 'audio/die/mayuanyi.mp3', - 'audio/die/mayunlu.mp3', - 'audio/die/mazhong.mp3', - 'audio/die/mb_chengui.mp3', - 'audio/die/mb_huban.mp3', - 'audio/die/mb_xianglang.mp3', - 'audio/die/mengda.mp3', - 'audio/die/menghuo.mp3', - 'audio/die/mengjie.mp3', - 'audio/die/mengyou.mp3', - 'audio/die/mifangfushiren.mp3', - 'audio/die/mifuren.mp3', - 'audio/die/miheng.mp3', - 'audio/die/mizhu.mp3', - 'audio/die/mp_liuling.mp3', - 'audio/die/muludawang.mp3', - 'audio/die/mushun.mp3', - 'audio/die/nanhualaoxian.mp3', - 'audio/die/nashime.mp3', - 'audio/die/neo_xuchu.mp3', - 'audio/die/neo_zhouyu.mp3', - 'audio/die/new_caoren.mp3', - 'audio/die/nezha.mp3', - 'audio/die/niufu.mp3', - 'audio/die/niujin.mp3', - 'audio/die/ns_zanghong.mp3', - 'audio/die/ol_caiwenji.mp3', - 'audio/die/ol_chendeng.mp3', - 'audio/die/ol_dengai.mp3', - 'audio/die/ol_dengzhi.mp3', - 'audio/die/ol_dianwei.mp3', - 'audio/die/ol_dingshangwan.mp3', - 'audio/die/ol_dingyuan.mp3', - 'audio/die/ol_dongzhao.mp3', - 'audio/die/ol_dongzhuo.mp3', - 'audio/die/ol_feiyi.mp3', - 'audio/die/ol_furong.mp3', - 'audio/die/ol_huangzhong.mp3', - 'audio/die/ol_huaxin.mp3', - 'audio/die/ol_huban.mp3', - 'audio/die/ol_hujinding.mp3', - 'audio/die/ol_jiangwei.mp3', - 'audio/die/ol_lisu.mp3', - 'audio/die/ol_liuba.mp3', - 'audio/die/ol_liushan.mp3', - 'audio/die/ol_lusu.mp3', - 'audio/die/ol_masu.mp3', - 'audio/die/ol_mengda.mp3', - 'audio/die/ol_pangde.mp3', - 'audio/die/ol_pangtong.mp3', - 'audio/die/ol_puyuan.mp3', - 'audio/die/ol_qianzhao.mp3', - 'audio/die/ol_sb_guanyu.mp3', - 'audio/die/ol_sb_jiangwei.mp3', - 'audio/die/ol_sb_taishici.mp3', - 'audio/die/ol_sb_yuanshao.mp3', - 'audio/die/ol_sb_yuanshao_shadow.mp3', - 'audio/die/ol_sp_zhugeliang.mp3', - 'audio/die/ol_sunjian.mp3', - 'audio/die/ol_wangrong.mp3', - 'audio/die/ol_weiyan.mp3', - 'audio/die/ol_wenqin.mp3', - 'audio/die/ol_xiahouyuan.mp3', - 'audio/die/ol_xiaoqiao.mp3', - 'audio/die/ol_xuhuang.mp3', - 'audio/die/ol_xunyu.mp3', - 'audio/die/ol_yangyi.mp3', - 'audio/die/ol_yanwen.mp3', - 'audio/die/ol_yuanshao.mp3', - 'audio/die/ol_yujin.mp3', - 'audio/die/ol_zhangyì.mp3', - 'audio/die/ol_zhangzhang.mp3', - 'audio/die/ol_zhouqun.mp3', - 'audio/die/ol_zhujun.mp3', - 'audio/die/ol_zhuling.mp3', - 'audio/die/ol_zhurong.mp3', - 'audio/die/old_guanzhang.mp3', - 'audio/die/old_madai.mp3', - 'audio/die/old_quancong.mp3', - 'audio/die/old_wangyi.mp3', - 'audio/die/old_zhuhuan.mp3', - 'audio/die/panfeng.mp3', - 'audio/die/pangde.mp3', - 'audio/die/pangdegong.mp3', - 'audio/die/panghui.mp3', - 'audio/die/panglingming.mp3', - 'audio/die/pangshanmin.mp3', - 'audio/die/pangtong.mp3', - 'audio/die/panjun.mp3', - 'audio/die/panshu.mp3', - 'audio/die/panzhangmazhong.mp3', - 'audio/die/peixiu.mp3', - 'audio/die/peiyuanshao.mp3', - 'audio/die/puyuan.mp3', - 'audio/die/qianzhao.mp3', - 'audio/die/qiaogong.mp3', - 'audio/die/qiaorui.mp3', - 'audio/die/qiaozhou.mp3', - 'audio/die/qinghegongzhu.mp3', - 'audio/die/qinlang.mp3', - 'audio/die/qinmi.mp3', - 'audio/die/qinyilu.mp3', - 'audio/die/qiuliju.mp3', - 'audio/die/quancong.mp3', - 'audio/die/quanhuijie.mp3', - 'audio/die/quhuang.mp3', - 'audio/die/quyi.mp3', - 'audio/die/re_bulianshi.mp3', - 'audio/die/re_caifuren.mp3', - 'audio/die/re_caiwenji.mp3', - 'audio/die/re_caiyong.mp3', - 'audio/die/re_caocao.mp3', - 'audio/die/re_caochong.mp3', - 'audio/die/re_caopi.mp3', - 'audio/die/re_caoxiu.mp3', - 'audio/die/re_caozhang.mp3', - 'audio/die/re_caozhen.mp3', - 'audio/die/re_caozhi.mp3', - 'audio/die/re_chendeng.mp3', - 'audio/die/re_chengong.mp3', - 'audio/die/re_chengpu.mp3', - 'audio/die/re_chenqun.mp3', - 'audio/die/re_chunyuqiong.mp3', - 'audio/die/re_daqiao.mp3', - 'audio/die/re_dengai.mp3', - 'audio/die/re_dianwei.mp3', - 'audio/die/re_diaochan.mp3', - 'audio/die/re_dongbai.mp3', - 'audio/die/re_dongcheng.mp3', - 'audio/die/re_dongzhuo.mp3', - 'audio/die/re_duji.mp3', - 'audio/die/re_fazheng.mp3', - 'audio/die/re_fengfangnv.mp3', - 'audio/die/re_fuhuanghou.mp3', - 'audio/die/re_ganning.mp3', - 'audio/die/re_gaoshun.mp3', - 'audio/die/re_gongsunyuan.mp3', - 'audio/die/re_gongsunzan.mp3', - 'audio/die/re_guanping.mp3', - 'audio/die/re_guanyu.mp3', - 'audio/die/re_guanzhang.mp3', - 'audio/die/re_guohuai.mp3', - 'audio/die/re_guohuanghou.mp3', - 'audio/die/re_guojia.mp3', - 'audio/die/re_guotufengji.mp3', - 'audio/die/re_guyong.mp3', - 'audio/die/re_handang.mp3', - 'audio/die/re_hanhaoshihuan.mp3', - 'audio/die/re_huanggai.mp3', - 'audio/die/re_huangyueying.mp3', - 'audio/die/re_huangzhong.mp3', - 'audio/die/re_huatuo.mp3', - 'audio/die/re_huaxiong.mp3', - 'audio/die/re_hucheer.mp3', - 'audio/die/re_jiangwei.mp3', - 'audio/die/re_jianyong.mp3', - 'audio/die/re_jiaxu.mp3', - 'audio/die/re_jsp_huangyueying.mp3', - 'audio/die/re_jsp_pangtong.mp3', - 'audio/die/re_jushou.mp3', - 'audio/die/re_liaohua.mp3', - 'audio/die/re_lingtong.mp3', - 'audio/die/re_liru.mp3', - 'audio/die/re_liubei.mp3', - 'audio/die/re_liubiao.mp3', - 'audio/die/re_liuchen.mp3', - 'audio/die/re_liufeng.mp3', - 'audio/die/re_liushan.mp3', - 'audio/die/re_liuzan.mp3', - 'audio/die/re_lusu.mp3', - 'audio/die/re_luxun.mp3', - 'audio/die/re_lvbu.mp3', - 'audio/die/re_lvmeng.mp3', - 'audio/die/re_machao.mp3', - 'audio/die/re_madai.mp3', - 'audio/die/re_manchong.mp3', - 'audio/die/re_masu.mp3', - 'audio/die/re_mazhong.mp3', - 'audio/die/re_menghuo.mp3', - 'audio/die/re_miheng.mp3', - 'audio/die/re_nanhualaoxian.mp3', - 'audio/die/re_panfeng.mp3', - 'audio/die/re_pangde.mp3', - 'audio/die/re_pangdegong.mp3', - 'audio/die/re_pangtong.mp3', - 'audio/die/re_panshu.mp3', - 'audio/die/re_panzhangmazhong.mp3', - 'audio/die/re_quancong.mp3', - 'audio/die/re_simayi.mp3', - 'audio/die/re_sp_taishici.mp3', - 'audio/die/re_sp_zhugeliang.mp3', - 'audio/die/re_sunben.mp3', - 'audio/die/re_sunce.mp3', - 'audio/die/re_sundeng.mp3', - 'audio/die/re_sunjian.mp3', - 'audio/die/re_sunluban.mp3', - 'audio/die/re_sunquan.mp3', - 'audio/die/re_sunshangxiang.mp3', - 'audio/die/re_sunxiu.mp3', - 'audio/die/re_sunyi.mp3', - 'audio/die/re_taishici.mp3', - 'audio/die/re_taoqian.mp3', - 'audio/die/re_wangyi.mp3', - 'audio/die/re_weiyan.mp3', - 'audio/die/re_wenpin.mp3', - 'audio/die/re_wuguotai.mp3', - 'audio/die/re_wuyi.mp3', - 'audio/die/re_xiahoudun.mp3', - 'audio/die/re_xiahoushi.mp3', - 'audio/die/re_xiahouyuan.mp3', - 'audio/die/re_xiaoqiao.mp3', - 'audio/die/re_xuhuang.mp3', - 'audio/die/re_xunchen.mp3', - 'audio/die/re_xunyou.mp3', - 'audio/die/re_xunyu.mp3', - 'audio/die/re_xusheng.mp3', - 'audio/die/re_xushu.mp3', - 'audio/die/re_xuzhu.mp3', - 'audio/die/re_yanwen.mp3', - 'audio/die/re_yuanshu.mp3', - 'audio/die/re_yufan.mp3', - 'audio/die/re_yuji.mp3', - 'audio/die/re_zhangchunhua.mp3', - 'audio/die/re_zhangfei.mp3', - 'audio/die/re_zhanghe.mp3', - 'audio/die/re_zhangjiao.mp3', - 'audio/die/re_zhangliang.mp3', - 'audio/die/re_zhangliao.mp3', - 'audio/die/re_zhangsong.mp3', - 'audio/die/re_zhangyi.mp3', - 'audio/die/re_zhangzhang.mp3', - 'audio/die/re_zhaoyun.mp3', - 'audio/die/re_zhenji.mp3', - 'audio/die/re_zhonghui.mp3', - 'audio/die/re_zhongyao.mp3', - 'audio/die/re_zhoucang.mp3', - 'audio/die/re_zhouyu.mp3', - 'audio/die/re_zhugeliang.mp3', - 'audio/die/re_zhuhuan.mp3', - 'audio/die/re_zhuran.mp3', - 'audio/die/re_zhurong.mp3', - 'audio/die/re_zhuzhi.mp3', - 'audio/die/re_zoushi.mp3', - 'audio/die/re_zuoci.mp3', - 'audio/die/ruanhui.mp3', - 'audio/die/ruanji.mp3', - 'audio/die/ruanyu.mp3', - 'audio/die/ruiji.mp3', - 'audio/die/sb_caocao.mp3', - 'audio/die/sb_caopi.mp3', - 'audio/die/sb_caoren.mp3', - 'audio/die/sb_chengong.mp3', - 'audio/die/sb_daqiao.mp3', - 'audio/die/sb_diaochan.mp3', - 'audio/die/sb_fazheng.mp3', - 'audio/die/sb_ganning.mp3', - 'audio/die/sb_guanyu.mp3', - 'audio/die/sb_huanggai.mp3', - 'audio/die/sb_huangyueying.mp3', - 'audio/die/sb_huangzhong.mp3', - 'audio/die/sb_huaxiong.mp3', - 'audio/die/sb_jiangwei.mp3', - 'audio/die/sb_liubei.mp3', - 'audio/die/sb_liubiao.mp3', - 'audio/die/sb_lvmeng.mp3', - 'audio/die/sb_machao.mp3', - 'audio/die/sb_menghuo.mp3', - 'audio/die/sb_pangtong.mp3', - 'audio/die/sb_sp_zhugeliang.mp3', - 'audio/die/sb_sunce.mp3', - 'audio/die/sb_sunquan.mp3', - 'audio/die/sb_sunshangxiang.mp3', - 'audio/die/sb_xiahoushi.mp3', - 'audio/die/sb_xiaoqiao.mp3', - 'audio/die/sb_xuhuang.mp3', - 'audio/die/sb_xunyu.mp3', - 'audio/die/sb_yl_luzhi.mp3', - 'audio/die/sb_yuanshao.mp3', - 'audio/die/sb_yujin.mp3', - 'audio/die/sb_zhangfei.mp3', - 'audio/die/sb_zhanghe.mp3', - 'audio/die/sb_zhangjiao.mp3', - 'audio/die/sb_zhaoyun.mp3', - 'audio/die/sb_zhenji.mp3', - 'audio/die/sb_zhouyu.mp3', - 'audio/die/sb_zhugeliang.mp3', - 'audio/die/sb_zhurong.mp3', - 'audio/die/shamoke.mp3', - 'audio/die/shen_caocao.mp3', - 'audio/die/shen_caopi.mp3', - 'audio/die/shen_dengai.mp3', - 'audio/die/shen_dianwei.mp3', - 'audio/die/shen_diaochan.mp3', - 'audio/die/shen_ganning.mp3', - 'audio/die/shen_guanyu.mp3', - 'audio/die/shen_guojia.mp3', - 'audio/die/shen_huatuo.mp3', - 'audio/die/shen_jiangwei.mp3', - 'audio/die/shen_liubei.mp3', - 'audio/die/shen_lusu.mp3', - 'audio/die/shen_luxun.mp3', - 'audio/die/shen_lvbu.mp3', - 'audio/die/shen_lvbu1.mp3', - 'audio/die/shen_lvbu2.mp3', - 'audio/die/shen_lvmeng.mp3', - 'audio/die/shen_machao.mp3', - 'audio/die/shen_simayi.mp3', - 'audio/die/shen_sunce.mp3', - 'audio/die/shen_sunquan.mp3', - 'audio/die/shen_taishici.mp3', - 'audio/die/shen_xunyu.mp3', - 'audio/die/shen_xuzhu.mp3', - 'audio/die/shen_zhangfei.mp3', - 'audio/die/shen_zhangjiao.mp3', - 'audio/die/shen_zhangliao.mp3', - 'audio/die/shen_zhaoyun.mp3', - 'audio/die/shen_zhenji.mp3', - 'audio/die/shen_zhouyu.mp3', - 'audio/die/shen_zhugeliang.mp3', - 'audio/die/shenpei.mp3', - 'audio/die/shibao.mp3', - 'audio/die/shichangshi.mp3', - 'audio/die/shichangshiRest.mp3', - 'audio/die/shixie.mp3', - 'audio/die/shiyi.mp3', - 'audio/die/simafu.mp3', - 'audio/die/simahui.mp3', - 'audio/die/simalang.mp3', - 'audio/die/simashi.mp3', - 'audio/die/simayi.mp3', - 'audio/die/simazhao.mp3', - 'audio/die/simazhou.mp3', - 'audio/die/sp_bianfuren.mp3', - 'audio/die/sp_caiwenji.mp3', - 'audio/die/sp_caohong.mp3', - 'audio/die/sp_caoren.mp3', - 'audio/die/sp_caosong.mp3', - 'audio/die/sp_chendong.mp3', - 'audio/die/sp_chenzhen.mp3', - 'audio/die/sp_cuiyan.mp3', - 'audio/die/sp_dongzhuo.mp3', - 'audio/die/sp_duyu.mp3', - 'audio/die/sp_gaolan.mp3', - 'audio/die/sp_guanyu.mp3', - 'audio/die/sp_huaman.mp3', - 'audio/die/sp_huangfusong.mp3', - 'audio/die/sp_huaxin.mp3', - 'audio/die/sp_jianggan.mp3', - 'audio/die/sp_jiangqing.mp3', - 'audio/die/sp_jiangwan.mp3', - 'audio/die/sp_jiangwei.mp3', - 'audio/die/sp_jiaxu.mp3', - 'audio/die/sp_key_kanade.mp3', - 'audio/die/sp_kongrong.mp3', - 'audio/die/sp_lvfan.mp3', - 'audio/die/sp_machao.mp3', - 'audio/die/sp_maojie.mp3', - 'audio/die/sp_menghuo.mp3', - 'audio/die/sp_mifangfushiren.mp3', - 'audio/die/sp_mifuren.mp3', - 'audio/die/sp_ol_zhanghe.mp3', - 'audio/die/sp_pangde.mp3', - 'audio/die/sp_pangtong.mp3', - 'audio/die/sp_pengyang.mp3', - 'audio/die/sp_shenpei.mp3', - 'audio/die/sp_sufei.mp3', - 'audio/die/sp_sunshangxiang.mp3', - 'audio/die/sp_sunshao.mp3', - 'audio/die/sp_taishici.mp3', - 'audio/die/sp_wangcan.mp3', - 'audio/die/sp_wangshuang.mp3', - 'audio/die/sp_wenpin.mp3', - 'audio/die/sp_xiahoudun.mp3', - 'audio/die/sp_xinpi.mp3', - 'audio/die/sp_xujing.mp3', - 'audio/die/sp_xunchen.mp3', - 'audio/die/sp_xusheng.mp3', - 'audio/die/sp_xuyou.mp3', - 'audio/die/sp_yanghu.mp3', - 'audio/die/sp_yangwan.mp3', - 'audio/die/sp_yuji.mp3', - 'audio/die/sp_zhangchangpu.mp3', - 'audio/die/sp_zhanghe.mp3', - 'audio/die/sp_zhangliao.mp3', - 'audio/die/sp_zhangwen.mp3', - 'audio/die/sp_zhugeliang.mp3', - 'audio/die/sp_zhujun.mp3', - 'audio/die/sp_zongyu.mp3', - 'audio/die/st_xushu.mp3', - 'audio/die/st_yuanshu.mp3', - 'audio/die/star_caoren.mp3', - 'audio/die/star_dongzhuo.mp3', - 'audio/die/star_yuanshao.mp3', - 'audio/die/star_yuanshu.mp3', - 'audio/die/sufei.mp3', - 'audio/die/sunce.mp3', - 'audio/die/sundeng.mp3', - 'audio/die/sunhanhua.mp3', - 'audio/die/sunhao.mp3', - 'audio/die/sunhong.mp3', - 'audio/die/sunhuan.mp3', - 'audio/die/sunjian.mp3', - 'audio/die/sunlang.mp3', - 'audio/die/sunliang.mp3', - 'audio/die/sunlingluan.mp3', - 'audio/die/sunluban.mp3', - 'audio/die/sunluyu.mp3', - 'audio/die/sunqian.mp3', - 'audio/die/sunquan.mp3', - 'audio/die/sunru.mp3', - 'audio/die/sunshangxiang.mp3', - 'audio/die/sunshao.mp3', - 'audio/die/sunwukong.mp3', - 'audio/die/sunxiu.mp3', - 'audio/die/sunyi.mp3', - 'audio/die/sunyu.mp3', - 'audio/die/sunziliufang.mp3', - 'audio/die/tadun.mp3', - 'audio/die/taishici.mp3', - 'audio/die/tangji.mp3', - 'audio/die/tangzi.mp3', - 'audio/die/taoqian.mp3', - 'audio/die/taoshen.mp3', - 'audio/die/tengfanglan.mp3', - 'audio/die/tenggongzhu.mp3', - 'audio/die/tengyin.mp3', - 'audio/die/tianchou.mp3', - 'audio/die/tianfeng.mp3', - 'audio/die/tianshangyi.mp3', - 'audio/die/tianyu.mp3', - 'audio/die/tongyuan.mp3', - 'audio/die/tw_baoxin.mp3', - 'audio/die/tw_beimihu.mp3', - 'audio/die/tw_bingyuan.mp3', - 'audio/die/tw_caocao.mp3', - 'audio/die/tw_caozhao.mp3', - 'audio/die/tw_chenzhen.mp3', - 'audio/die/tw_dongzhao.mp3', - 'audio/die/tw_fengxí.mp3', - 'audio/die/tw_gexuan.mp3', - 'audio/die/tw_gongsunfan.mp3', - 'audio/die/tw_haomeng.mp3', - 'audio/die/tw_huchuquan.mp3', - 'audio/die/tw_huojun.mp3', - 'audio/die/tw_jiangji.mp3', - 'audio/die/tw_jiangwei.mp3', - 'audio/die/tw_jianshuo.mp3', - 'audio/die/tw_liubei.mp3', - 'audio/die/tw_liufuren.mp3', - 'audio/die/tw_liuhong.mp3', - 'audio/die/tw_liwei.mp3', - 'audio/die/tw_mateng.mp3', - 'audio/die/tw_niufudongxie.mp3', - 'audio/die/tw_puyangxing.mp3', - 'audio/die/tw_qiaorui.mp3', - 'audio/die/tw_shen_guanyu.mp3', - 'audio/die/tw_shen_lvmeng.mp3', - 'audio/die/tw_tianyu.mp3', - 'audio/die/tw_wangcan.mp3', - 'audio/die/tw_wangchang.mp3', - 'audio/die/tw_weixu.mp3', - 'audio/die/tw_xiahouen.mp3', - 'audio/die/tw_xiahoushang.mp3', - 'audio/die/tw_yangang.mp3', - 'audio/die/tw_yanxiang.mp3', - 'audio/die/tw_yufuluo.mp3', - 'audio/die/tw_yujin.mp3', - 'audio/die/tw_zhanghong.mp3', - 'audio/die/tw_zhangji.mp3', - 'audio/die/tw_zhangnan.mp3', - 'audio/die/tw_zhangning.mp3', - 'audio/die/tw_zhangzhao.mp3', - 'audio/die/vtb_xiaojiu.mp3', - 'audio/die/vtb_xiaole.mp3', - 'audio/die/vtb_xiaosha.mp3', - 'audio/die/vtb_xiaoshan.mp3', - 'audio/die/vtb_xiaotao.mp3', - 'audio/die/wangcan.mp3', - 'audio/die/wangfuzhaolei.mp3', - 'audio/die/wangguan.mp3', - 'audio/die/wangji.mp3', - 'audio/die/wangjun.mp3', - 'audio/die/wanglang.mp3', - 'audio/die/wanglie.mp3', - 'audio/die/wangling.mp3', - 'audio/die/wangping.mp3', - 'audio/die/wangrong.mp3', - 'audio/die/wangshuang.mp3', - 'audio/die/wangtao.mp3', - 'audio/die/wangwei.mp3', - 'audio/die/wangxiang.mp3', - 'audio/die/wangyan.mp3', - 'audio/die/wangyi.mp3', - 'audio/die/wangyuanji.mp3', - 'audio/die/wangyue.mp3', - 'audio/die/wangyun.mp3', - 'audio/die/wanniangongzhu.mp3', - 'audio/die/weiguan.mp3', - 'audio/die/weiwenzhugezhi.mp3', - 'audio/die/weiyan.mp3', - 'audio/die/weizi.mp3', - 'audio/die/wenpin.mp3', - 'audio/die/wenyang.mp3', - 'audio/die/wis_huaxiong.mp3', - 'audio/die/wis_jiangwan.mp3', - 'audio/die/wis_jiangwei.mp3', - 'audio/die/wis_shuijing.mp3', - 'audio/die/wis_sunce.mp3', - 'audio/die/wis_tianfeng.mp3', - 'audio/die/wis_xuyou.mp3', - 'audio/die/wis_zhangzhao.mp3', - 'audio/die/wolongfengchu.mp3', - 'audio/die/wu_luxun.mp3', - 'audio/die/wu_zhugeliang.mp3', - 'audio/die/wu_zhutiexiong.mp3', - 'audio/die/wuanguo.mp3', - 'audio/die/wuban.mp3', - 'audio/die/wufan.mp3', - 'audio/die/wuguotai.mp3', - 'audio/die/wujing.mp3', - 'audio/die/wulan.mp3', - 'audio/die/wutugu.mp3', - 'audio/die/wuxian.mp3', - 'audio/die/wuyan.mp3', - 'audio/die/wuyi.mp3', - 'audio/die/xf_yiji.mp3', - 'audio/die/xia_dianwei.mp3', - 'audio/die/xia_liubei.mp3', - 'audio/die/xia_liyàn.mp3', - 'audio/die/xia_lusu.mp3', - 'audio/die/xia_tongyuan.mp3', - 'audio/die/xia_wangyue.mp3', - 'audio/die/xia_xiahoudun.mp3', - 'audio/die/xia_xiahousone.mp3', - 'audio/die/xia_xiahouzie.mp3', - 'audio/die/xia_xushu.mp3', - 'audio/die/xia_zhangwei.mp3', - 'audio/die/xia_zhaoe.mp3', - 'audio/die/xiahouba.mp3', - 'audio/die/xiahoudun.mp3', - 'audio/die/xiahoujie.mp3', - 'audio/die/xiahoujuan.mp3', - 'audio/die/xiahoulingnv.mp3', - 'audio/die/xiahoumao.mp3', - 'audio/die/xiahoushi.mp3', - 'audio/die/xiahouxuan.mp3', - 'audio/die/xiahouyuan.mp3', - 'audio/die/xiangchong.mp3', - 'audio/die/xianglang.mp3', - 'audio/die/xiangrang.mp3', - 'audio/die/xiaoqiao.mp3', - 'audio/die/xiaoyuehankehan.mp3', - 'audio/die/xielingyu.mp3', - 'audio/die/xin_caifuren.mp3', - 'audio/die/xin_caoxiu.mp3', - 'audio/die/xin_caozhang.mp3', - 'audio/die/xin_caozhen.mp3', - 'audio/die/xin_chengpu.mp3', - 'audio/die/xin_fazheng.mp3', - 'audio/die/xin_fuhuanghou.mp3', - 'audio/die/xin_gaoshun.mp3', - 'audio/die/xin_gongsunzan.mp3', - 'audio/die/xin_guohuai.mp3', - 'audio/die/xin_guozhao.mp3', - 'audio/die/xin_guyong.mp3', - 'audio/die/xin_handang.mp3', - 'audio/die/xin_hansui.mp3', - 'audio/die/xin_jianyong.mp3', - 'audio/die/xin_jushou.mp3', - 'audio/die/xin_liaohua.mp3', - 'audio/die/xin_lingtong.mp3', - 'audio/die/xin_liubiao.mp3', - 'audio/die/xin_mamidi.mp3', - 'audio/die/xin_panzhangmazhong.mp3', - 'audio/die/xin_quancong.mp3', - 'audio/die/xin_sunluban.mp3', - 'audio/die/xin_sunxiu.mp3', - 'audio/die/xin_wuguotai.mp3', - 'audio/die/xin_wuyi.mp3', - 'audio/die/xin_xusheng.mp3', - 'audio/die/xin_xushu.mp3', - 'audio/die/xin_yuanshao.mp3', - 'audio/die/xin_yufan.mp3', - 'audio/die/xin_yuji.mp3', - 'audio/die/xin_zhangyi.mp3', - 'audio/die/xin_zhonghui.mp3', - 'audio/die/xin_zhuhuan.mp3', - 'audio/die/xin_zhuran.mp3', - 'audio/die/xin_zhuzhi.mp3', - 'audio/die/xinchang.mp3', - 'audio/die/xinfu_yuji.mp3', - 'audio/die/xingdaorong.mp3', - 'audio/die/xinpi.mp3', - 'audio/die/xinping.mp3', - 'audio/die/xinxianying.mp3', - 'audio/die/xinzhongyong.mp3', - 'audio/die/xizheng.mp3', - 'audio/die/xizhicai.mp3', - 'audio/die/xuangongzhu.mp3', - 'audio/die/xuelingyun.mp3', - 'audio/die/xuezong.mp3', - 'audio/die/xugong.mp3', - 'audio/die/xuhuang.mp3', - 'audio/die/xujing.mp3', - 'audio/die/xunchen.mp3', - 'audio/die/xunyou.mp3', - 'audio/die/xunyu.mp3', - 'audio/die/xurong.mp3', - 'audio/die/xushao.mp3', - 'audio/die/xusheng.mp3', - 'audio/die/xushi.mp3', - 'audio/die/xushu.mp3', - 'audio/die/xuyou.mp3', - 'audio/die/xuzhu.mp3', - 'audio/die/yanbaihu.mp3', - 'audio/die/yanfuren.mp3', - 'audio/die/yangbiao.mp3', - 'audio/die/yangfu.mp3', - 'audio/die/yanghong.mp3', - 'audio/die/yanghuiyu.mp3', - 'audio/die/yangwan.mp3', - 'audio/die/yangxiu.mp3', - 'audio/die/yangyan.mp3', - 'audio/die/yangyi.mp3', - 'audio/die/yangzhi.mp3', - 'audio/die/yanjun.mp3', - 'audio/die/yanpu.mp3', - 'audio/die/yanrou.mp3', - 'audio/die/yanwen.mp3', - 'audio/die/yanyan.mp3', - 'audio/die/yinfuren.mp3', - 'audio/die/yitianjian.mp3', - 'audio/die/yj_ganning.mp3', - 'audio/die/yj_huangzhong.mp3', - 'audio/die/yj_jushou.mp3', - 'audio/die/yj_qiaozhou.mp3', - 'audio/die/yj_sufei.mp3', - 'audio/die/yj_weiyan.mp3', - 'audio/die/yj_xuhuang.mp3', - 'audio/die/yj_zhanghe.mp3', - 'audio/die/yj_zhangliao.mp3', - 'audio/die/yj_zhoubuyi.mp3', - 'audio/die/yl_luzhi.mp3', - 'audio/die/yl_yuanshu.mp3', - 'audio/die/yuanhuan.mp3', - 'audio/die/yuanji.mp3', - 'audio/die/yuanshao.mp3', - 'audio/die/yuanshu.mp3', - 'audio/die/yuantanyuanshang.mp3', - 'audio/die/yuantanyuanxiyuanshang.mp3', - 'audio/die/yue_caiwenji.mp3', - 'audio/die/yue_daqiao.mp3', - 'audio/die/yue_xiaoqiao.mp3', - 'audio/die/yue_zhoufei.mp3', - 'audio/die/yuechen.mp3', - 'audio/die/yuejin.mp3', - 'audio/die/yuejiu.mp3', - 'audio/die/yufan.mp3', - 'audio/die/yuji.mp3', - 'audio/die/yujin.mp3', - 'audio/die/yujin_yujin.mp3', - 'audio/die/zangba.mp3', - 'audio/die/zerong.mp3', - 'audio/die/zhangbao.mp3', - 'audio/die/zhangchangpu.mp3', - 'audio/die/zhangchu.mp3', - 'audio/die/zhangchunhua.mp3', - 'audio/die/zhangfei.mp3', - 'audio/die/zhangfen.mp3', - 'audio/die/zhanggong.mp3', - 'audio/die/zhanggongqi.mp3', - 'audio/die/zhanghe.mp3', - 'audio/die/zhangheng.mp3', - 'audio/die/zhanghu.mp3', - 'audio/die/zhanghua.mp3', - 'audio/die/zhanghuyuechen.mp3', - 'audio/die/zhangji.mp3', - 'audio/die/zhangjiao.mp3', - 'audio/die/zhangjinyun.mp3', - 'audio/die/zhangjunyi.mp3', - 'audio/die/zhangkai.mp3', - 'audio/die/zhangliao.mp3', - 'audio/die/zhangling.mp3', - 'audio/die/zhanglu.mp3', - 'audio/die/zhangmancheng.mp3', - 'audio/die/zhangmiao.mp3', - 'audio/die/zhangning.mp3', - 'audio/die/zhangqiying.mp3', - 'audio/die/zhangrang.mp3', - 'audio/die/zhangren.mp3', - 'audio/die/zhangshiping.mp3', - 'audio/die/zhangsong.mp3', - 'audio/die/zhangwen.mp3', - 'audio/die/zhangxingcai.mp3', - 'audio/die/zhangxiu.mp3', - 'audio/die/zhangxuan.mp3', - 'audio/die/zhangxun.mp3', - 'audio/die/zhangyan.mp3', - 'audio/die/zhangyao.mp3', - 'audio/die/zhangyi.mp3', - 'audio/die/zhangyì.mp3', - 'audio/die/zhangzhang.mp3', - 'audio/die/zhangzhi.mp3', - 'audio/die/zhangzhongjing.mp3', - 'audio/die/zhaoang.mp3', - 'audio/die/zhaotongzhaoguang.mp3', - 'audio/die/zhaoxiang.mp3', - 'audio/die/zhaoyan.mp3', - 'audio/die/zhaoyǎn.mp3', - 'audio/die/zhaoyun.mp3', - 'audio/die/zhaozhi.mp3', - 'audio/die/zhaozhong.mp3', - 'audio/die/zhenghun.mp3', - 'audio/die/zhengxuan.mp3', - 'audio/die/zhenji.mp3', - 'audio/die/zhiling.mp3', - 'audio/die/zhonghui.mp3', - 'audio/die/zhongshiji.mp3', - 'audio/die/zhongyan.mp3', - 'audio/die/zhongyao.mp3', - 'audio/die/zhoubuyi.mp3', - 'audio/die/zhoucang.mp3', - 'audio/die/zhouchu.mp3', - 'audio/die/zhoufang.mp3', - 'audio/die/zhoufei.mp3', - 'audio/die/zhouqun.mp3', - 'audio/die/zhoushan.mp3', - 'audio/die/zhoutai.mp3', - 'audio/die/zhouyi.mp3', - 'audio/die/zhouyu.mp3', - 'audio/die/zhugedan.mp3', - 'audio/die/zhugeguo.mp3', - 'audio/die/zhugejin.mp3', - 'audio/die/zhugeke.mp3', - 'audio/die/zhugeliang.mp3', - 'audio/die/zhugemengxue.mp3', - 'audio/die/zhugeruoxue.mp3', - 'audio/die/zhugeshang.mp3', - 'audio/die/zhugezhan.mp3', - 'audio/die/zhuhuan.mp3', - 'audio/die/zhujianping.mp3', - 'audio/die/zhujun.mp3', - 'audio/die/zhuling.mp3', - 'audio/die/zhuran.mp3', - 'audio/die/zhurong.mp3', - 'audio/die/zhutiexiong.mp3', - 'audio/die/zhuzhi.mp3', - 'audio/die/zongyu.mp3', - 'audio/die/zoushi.mp3', - 'audio/die/zumao.mp3', - 'audio/die/zuoci.mp3', - 'audio/die/zuofen.mp3', - /*effect audio end*/ - - /*skill audio begin*/ - 'audio/skill/abyusa_dunying1.mp3', - 'audio/skill/abyusa_dunying2.mp3', - 'audio/skill/abyusa_jueqing1.mp3', - 'audio/skill/abyusa_jueqing2.mp3', - 'audio/skill/aichen1.mp3', - 'audio/skill/aichen2.mp3', - 'audio/skill/anguo1.mp3', - 'audio/skill/anguo2.mp3', - 'audio/skill/anjian1.mp3', - 'audio/skill/anjian2.mp3', - 'audio/skill/anxian1.mp3', - 'audio/skill/anxian2.mp3', - 'audio/skill/anxu1.mp3', - 'audio/skill/anxu2.mp3', - 'audio/skill/anyong1.mp3', - 'audio/skill/anyong2.mp3', - 'audio/skill/aocai_gz_zhugeke1.mp3', - 'audio/skill/aocai_gz_zhugeke2.mp3', - 'audio/skill/aocai1.mp3', - 'audio/skill/aocai2.mp3', - 'audio/skill/bagua_skill.mp3', - 'audio/skill/baijia_tw_beimihu1.mp3', - 'audio/skill/baijia_tw_beimihu2.mp3', - 'audio/skill/baijia1.mp3', - 'audio/skill/baijia2.mp3', - 'audio/skill/baiyi1.mp3', - 'audio/skill/baiyi2.mp3', - 'audio/skill/baiyin_skill.mp3', - 'audio/skill/baoling1.mp3', - 'audio/skill/baoling2.mp3', - 'audio/skill/baonu1.mp3', - 'audio/skill/baonu2.mp3', - 'audio/skill/baonue2_re_dongzhuo1.mp3', - 'audio/skill/baonue2_re_dongzhuo2.mp3', - 'audio/skill/baonue21.mp3', - 'audio/skill/baonue22.mp3', - 'audio/skill/baoqie1.mp3', - 'audio/skill/baoqie2.mp3', - 'audio/skill/baoshu1.mp3', - 'audio/skill/baoshu2.mp3', - 'audio/skill/bazhan1.mp3', - 'audio/skill/bazhan2.mp3', - 'audio/skill/bazhen_ol_pangtong1.mp3', - 'audio/skill/bazhen_ol_pangtong2.mp3', - 'audio/skill/bazhen_ol_sp_zhugeliang1.mp3', - 'audio/skill/bazhen_ol_sp_zhugeliang2.mp3', - 'audio/skill/bazhen_re_sp_zhugeliang1.mp3', - 'audio/skill/bazhen_re_sp_zhugeliang2.mp3', - 'audio/skill/bazhen1.mp3', - 'audio/skill/bazhen2.mp3', - 'audio/skill/beige_ol_caiwenji1.mp3', - 'audio/skill/beige_ol_caiwenji2.mp3', - 'audio/skill/beige_re_caiwenji1.mp3', - 'audio/skill/beige_re_caiwenji2.mp3', - 'audio/skill/beige1.mp3', - 'audio/skill/beige2.mp3', - 'audio/skill/beini1.mp3', - 'audio/skill/beini2.mp3', - 'audio/skill/beishui1.mp3', - 'audio/skill/beishui2.mp3', - 'audio/skill/beizhan1.mp3', - 'audio/skill/beizhan2.mp3', - 'audio/skill/beizhu1.mp3', - 'audio/skill/beizhu2.mp3', - 'audio/skill/beizhu3.mp3', - 'audio/skill/benghuai_ol_dongzhuo1.mp3', - 'audio/skill/benghuai_ol_dongzhuo2.mp3', - 'audio/skill/benghuai_re_dongzhuo1.mp3', - 'audio/skill/benghuai_re_dongzhuo2.mp3', - 'audio/skill/benghuai_zhugedan1.mp3', - 'audio/skill/benghuai_zhugedan2.mp3', - 'audio/skill/benghuai1.mp3', - 'audio/skill/benghuai2.mp3', - 'audio/skill/benxi1.mp3', - 'audio/skill/benxi2.mp3', - 'audio/skill/benyu1.mp3', - 'audio/skill/benyu2.mp3', - 'audio/skill/biaozhao1.mp3', - 'audio/skill/biaozhao2.mp3', - 'audio/skill/biejun1.mp3', - 'audio/skill/biejun2.mp3', - 'audio/skill/bifa1.mp3', - 'audio/skill/bifa2.mp3', - 'audio/skill/bihuo1.mp3', - 'audio/skill/bihuo2.mp3', - 'audio/skill/biluan1.mp3', - 'audio/skill/biluan2.mp3', - 'audio/skill/binghuo1.mp3', - 'audio/skill/binghuo2.mp3', - 'audio/skill/bingjie1.mp3', - 'audio/skill/bingjie2.mp3', - 'audio/skill/binglun1.mp3', - 'audio/skill/binglun2.mp3', - 'audio/skill/bingqing1.mp3', - 'audio/skill/bingqing2.mp3', - 'audio/skill/bingxin1.mp3', - 'audio/skill/bingxin2.mp3', - 'audio/skill/bingyi_xin_guyong1.mp3', - 'audio/skill/bingyi_xin_guyong2.mp3', - 'audio/skill/bingyi1.mp3', - 'audio/skill/bingyi2.mp3', - 'audio/skill/bingzheng1.mp3', - 'audio/skill/bingzheng2.mp3', - 'audio/skill/bixiong1.mp3', - 'audio/skill/bixiong2.mp3', - 'audio/skill/biyue1.mp3', - 'audio/skill/biyue2.mp3', - 'audio/skill/bizheng1.mp3', - 'audio/skill/bizheng2.mp3', - 'audio/skill/bizhuan1.mp3', - 'audio/skill/bizhuan2.mp3', - 'audio/skill/bmcanshi_tw_beimihu1.mp3', - 'audio/skill/bmcanshi_tw_beimihu2.mp3', - 'audio/skill/bmcanshi1.mp3', - 'audio/skill/bmcanshi2.mp3', - 'audio/skill/bolan1.mp3', - 'audio/skill/bolan2.mp3', - 'audio/skill/boming1.mp3', - 'audio/skill/boming2.mp3', - 'audio/skill/boss_baolin.mp3', - 'audio/skill/boss_baonu1.mp3', - 'audio/skill/boss_baonu2.mp3', - 'audio/skill/boss_biantianx1.mp3', - 'audio/skill/boss_biantianx2.mp3', - 'audio/skill/boss_bufo.mp3', - 'audio/skill/boss_chiying1.mp3', - 'audio/skill/boss_chiying2.mp3', - 'audio/skill/boss_chuanyun.mp3', - 'audio/skill/boss_dayuan.mp3', - 'audio/skill/boss_diting.mp3', - 'audio/skill/boss_fanshi.mp3', - 'audio/skill/boss_fengxing.mp3', - 'audio/skill/boss_gongshenjg1.mp3', - 'audio/skill/boss_gongshenjg2.mp3', - 'audio/skill/boss_guihan1.mp3', - 'audio/skill/boss_guihan2.mp3', - 'audio/skill/boss_honglian1.mp3', - 'audio/skill/boss_honglian2.mp3', - 'audio/skill/boss_hujia1.mp3', - 'audio/skill/boss_hujia2.mp3', - 'audio/skill/boss_huodi1.mp3', - 'audio/skill/boss_huodi2.mp3', - 'audio/skill/boss_jingmiao1.mp3', - 'audio/skill/boss_jingmiao2.mp3', - 'audio/skill/boss_jizhen1.mp3', - 'audio/skill/boss_jizhen2.mp3', - 'audio/skill/boss_jizhi1.mp3', - 'audio/skill/boss_jizhi2.mp3', - 'audio/skill/boss_jueji1.mp3', - 'audio/skill/boss_jueji2.mp3', - 'audio/skill/boss_leiji1.mp3', - 'audio/skill/boss_leiji2.mp3', - 'audio/skill/boss_leili1.mp3', - 'audio/skill/boss_leili2.mp3', - 'audio/skill/boss_lingfeng1.mp3', - 'audio/skill/boss_lingfeng2.mp3', - 'audio/skill/boss_qiangzheng1.mp3', - 'audio/skill/boss_qiangzheng2.mp3', - 'audio/skill/boss_qiwu.mp3', - 'audio/skill/boss_shengshou.mp3', - 'audio/skill/boss_shiyou.mp3', - 'audio/skill/boss_skonghun.mp3', - 'audio/skill/boss_tianyu.mp3', - 'audio/skill/boss_tianyujg.mp3', - 'audio/skill/boss_wanghun.mp3', - 'audio/skill/boss_wangshi.mp3', - 'audio/skill/boss_wuliang.mp3', - 'audio/skill/boss_wuxin1.mp3', - 'audio/skill/boss_wuxin2.mp3', - 'audio/skill/boss_xianyin1.mp3', - 'audio/skill/boss_xianyin2.mp3', - 'audio/skill/boss_xuanlei.mp3', - 'audio/skill/boss_yuhuojg.mp3', - 'audio/skill/boss_zhinang1.mp3', - 'audio/skill/boss_zhinang2.mp3', - 'audio/skill/botu1.mp3', - 'audio/skill/botu2.mp3', - 'audio/skill/boyan1.mp3', - 'audio/skill/boyan2.mp3', - 'audio/skill/buchen1.mp3', - 'audio/skill/buchen2.mp3', - 'audio/skill/buqi1.mp3', - 'audio/skill/buqi2.mp3', - 'audio/skill/buqu1.mp3', - 'audio/skill/buqu2.mp3', - 'audio/skill/bushi1.mp3', - 'audio/skill/bushi2.mp3', - 'audio/skill/busuan1.mp3', - 'audio/skill/busuan2.mp3', - 'audio/skill/buxu1.mp3', - 'audio/skill/buxu2.mp3', - 'audio/skill/buyi_re_wuguotai1.mp3', - 'audio/skill/buyi_re_wuguotai2.mp3', - 'audio/skill/buyi1.mp3', - 'audio/skill/buyi2.mp3', - 'audio/skill/caishi1.mp3', - 'audio/skill/caishi2.mp3', - 'audio/skill/caiwang1.mp3', - 'audio/skill/caiwang2.mp3', - 'audio/skill/caiyi1.mp3', - 'audio/skill/caiyi2.mp3', - 'audio/skill/caiyuan1.mp3', - 'audio/skill/caiyuan2.mp3', - 'audio/skill/caizhaoji_hujia.mp3', - 'audio/skill/cangchu1.mp3', - 'audio/skill/cangchu2.mp3', - 'audio/skill/cangji.mp3', - 'audio/skill/cangzhuo1.mp3', - 'audio/skill/cangzhuo2.mp3', - 'audio/skill/canmou1.mp3', - 'audio/skill/canmou2.mp3', - 'audio/skill/canshi1.mp3', - 'audio/skill/canshi2.mp3', - 'audio/skill/caozhao1.mp3', - 'audio/skill/caozhao2.mp3', - 'audio/skill/changbiao1.mp3', - 'audio/skill/changbiao2.mp3', - 'audio/skill/chanhui1.mp3', - 'audio/skill/chanhui2.mp3', - 'audio/skill/channi1.mp3', - 'audio/skill/channi2.mp3', - 'audio/skill/chanyuan1.mp3', - 'audio/skill/chanyuan2.mp3', - 'audio/skill/chaofeng1.mp3', - 'audio/skill/chaofeng2.mp3', - 'audio/skill/chenggong1.mp3', - 'audio/skill/chenggong2.mp3', - 'audio/skill/chengshang1.mp3', - 'audio/skill/chengshang2.mp3', - 'audio/skill/chengwu1.mp3', - 'audio/skill/chengwu2.mp3', - 'audio/skill/chengxiang1.mp3', - 'audio/skill/chengxiang2.mp3', - 'audio/skill/chengye1.mp3', - 'audio/skill/chengye2.mp3', - 'audio/skill/chengye3.mp3', - 'audio/skill/chengzhang1.mp3', - 'audio/skill/chengzhang2.mp3', - 'audio/skill/chengzhao1.mp3', - 'audio/skill/chengzhao2.mp3', - 'audio/skill/chenjian1.mp3', - 'audio/skill/chenjian2.mp3', - 'audio/skill/chenjie1.mp3', - 'audio/skill/chenjie2.mp3', - 'audio/skill/chenqing1.mp3', - 'audio/skill/chenqing2.mp3', - 'audio/skill/chexuan1.mp3', - 'audio/skill/chexuan2.mp3', - 'audio/skill/chijie.mp3', - 'audio/skill/chizhong1.mp3', - 'audio/skill/chizhong2.mp3', - 'audio/skill/chongxin1.mp3', - 'audio/skill/chongxin2.mp3', - 'audio/skill/chongxu1.mp3', - 'audio/skill/chongxu2.mp3', - 'audio/skill/chongzhen1.mp3', - 'audio/skill/chongzhen2.mp3', - 'audio/skill/chouce1.mp3', - 'audio/skill/chouce2.mp3', - 'audio/skill/choufa1.mp3', - 'audio/skill/choufa2.mp3', - 'audio/skill/chouhai1.mp3', - 'audio/skill/chouhai2.mp3', - 'audio/skill/choujue1.mp3', - 'audio/skill/choujue2.mp3', - 'audio/skill/chouliang.mp3', - 'audio/skill/choulve1.mp3', - 'audio/skill/choulve2.mp3', - 'audio/skill/choutao1.mp3', - 'audio/skill/choutao2.mp3', - 'audio/skill/chuaili1.mp3', - 'audio/skill/chuaili2.mp3', - 'audio/skill/chuanshu1.mp3', - 'audio/skill/chuanshu2.mp3', - 'audio/skill/chuanxin1.mp3', - 'audio/skill/chuanxin2.mp3', - 'audio/skill/chuanyun.mp3', - 'audio/skill/chuhai1.mp3', - 'audio/skill/chuhai2.mp3', - 'audio/skill/chuhai3.mp3', - 'audio/skill/chuiti1.mp3', - 'audio/skill/chuiti2.mp3', - 'audio/skill/chulao1.mp3', - 'audio/skill/chulao2.mp3', - 'audio/skill/chunlao_xin_chengpu1.mp3', - 'audio/skill/chunlao_xin_chengpu2.mp3', - 'audio/skill/chunlao1.mp3', - 'audio/skill/chunlao2.mp3', - 'audio/skill/chuyuan1.mp3', - 'audio/skill/chuyuan2.mp3', - 'audio/skill/cibei1.mp3', - 'audio/skill/cibei2.mp3', - 'audio/skill/cihuang1.mp3', - 'audio/skill/cihuang2.mp3', - 'audio/skill/ciwei1.mp3', - 'audio/skill/ciwei2.mp3', - 'audio/skill/cixiao1.mp3', - 'audio/skill/cixiao2.mp3', - 'audio/skill/cixiong_skill.mp3', - 'audio/skill/clanbaichu1.mp3', - 'audio/skill/clanbaichu2.mp3', - 'audio/skill/clanbalong1.mp3', - 'audio/skill/clanbalong2.mp3', - 'audio/skill/clanbaozu_clan_zhonghui1.mp3', - 'audio/skill/clanbaozu_clan_zhonghui2.mp3', - 'audio/skill/clanbaozu_clan_zhongyan1.mp3', - 'audio/skill/clanbaozu_clan_zhongyan2.mp3', - 'audio/skill/clanbaozu_clan_zhongyu1.mp3', - 'audio/skill/clanbaozu_clan_zhongyu2.mp3', - 'audio/skill/clanbeishi1.mp3', - 'audio/skill/clanbeishi2.mp3', - 'audio/skill/clanbolong1.mp3', - 'audio/skill/clanbolong2.mp3', - 'audio/skill/clanchenya1.mp3', - 'audio/skill/clanchenya2.mp3', - 'audio/skill/clandaojie_clan_xuncai1.mp3', - 'audio/skill/clandaojie_clan_xuncai2.mp3', - 'audio/skill/clandaojie_clan_xuncan1.mp3', - 'audio/skill/clandaojie_clan_xuncan2.mp3', - 'audio/skill/clandaojie_clan_xunchen1.mp3', - 'audio/skill/clandaojie_clan_xunchen2.mp3', - 'audio/skill/clandaojie_clan_xunshu1.mp3', - 'audio/skill/clandaojie_clan_xunshu2.mp3', - 'audio/skill/clandaojie_clan_xunyou1.mp3', - 'audio/skill/clandaojie_clan_xunyou2.mp3', - 'audio/skill/clandianzhan1.mp3', - 'audio/skill/clandianzhan2.mp3', - 'audio/skill/clanfangzhen1.mp3', - 'audio/skill/clanfangzhen2.mp3', - 'audio/skill/clanfenchai1.mp3', - 'audio/skill/clanfenchai2.mp3', - 'audio/skill/clanfuxun1.mp3', - 'audio/skill/clanfuxun2.mp3', - 'audio/skill/clanguangu1.mp3', - 'audio/skill/clanguangu2.mp3', - 'audio/skill/clanguixiang1.mp3', - 'audio/skill/clanguixiang2.mp3', - 'audio/skill/clanhuanghan1.mp3', - 'audio/skill/clanhuanghan2.mp3', - 'audio/skill/clanhuanjia1.mp3', - 'audio/skill/clanhuanjia2.mp3', - 'audio/skill/clanhuanyin1.mp3', - 'audio/skill/clanhuanyin2.mp3', - 'audio/skill/clanjianyuan1.mp3', - 'audio/skill/clanjianyuan2.mp3', - 'audio/skill/clanjiejian1.mp3', - 'audio/skill/clanjiejian2.mp3', - 'audio/skill/clanjiexuan1.mp3', - 'audio/skill/clanjiexuan2.mp3', - 'audio/skill/clanlianhe1.mp3', - 'audio/skill/clanlianhe2.mp3', - 'audio/skill/clanlianzhu1.mp3', - 'audio/skill/clanlianzhu2.mp3', - 'audio/skill/clanlieshi1.mp3', - 'audio/skill/clanlieshi2.mp3', - 'audio/skill/clanliuju1.mp3', - 'audio/skill/clanliuju2.mp3', - 'audio/skill/clanmingjie1.mp3', - 'audio/skill/clanmingjie2.mp3', - 'audio/skill/clanmuyin_clan_wuban1.mp3', - 'audio/skill/clanmuyin_clan_wuban2.mp3', - 'audio/skill/clanmuyin_clan_wukuang1.mp3', - 'audio/skill/clanmuyin_clan_wukuang2.mp3', - 'audio/skill/clanmuyin_clan_wuxian1.mp3', - 'audio/skill/clanmuyin_clan_wuxian2.mp3', - 'audio/skill/clanqiuxin1.mp3', - 'audio/skill/clanqiuxin2.mp3', - 'audio/skill/clansankuang1.mp3', - 'audio/skill/clansankuang2.mp3', - 'audio/skill/clanshangshen1.mp3', - 'audio/skill/clanshangshen2.mp3', - 'audio/skill/clanshenjun1.mp3', - 'audio/skill/clanshenjun2.mp3', - 'audio/skill/clanxiaoyong1.mp3', - 'audio/skill/clanxiaoyong2.mp3', - 'audio/skill/clanxieshu1.mp3', - 'audio/skill/clanxieshu2.mp3', - 'audio/skill/clanxumin_clan_hanrong1.mp3', - 'audio/skill/clanxumin_clan_hanrong2.mp3', - 'audio/skill/clanxumin_clan_hanshao1.mp3', - 'audio/skill/clanxumin_clan_hanshao2.mp3', - 'audio/skill/clanyirong1.mp3', - 'audio/skill/clanyirong2.mp3', - 'audio/skill/clanyunshen1.mp3', - 'audio/skill/clanyunshen2.mp3', - 'audio/skill/clanyuzhi1.mp3', - 'audio/skill/clanyuzhi2.mp3', - 'audio/skill/clanzhanding1.mp3', - 'audio/skill/clanzhanding2.mp3', - 'audio/skill/clanzhongliu_clan_wanghun1.mp3', - 'audio/skill/clanzhongliu_clan_wanghun2.mp3', - 'audio/skill/clanzhongliu_clan_wangling1.mp3', - 'audio/skill/clanzhongliu_clan_wangling2.mp3', - 'audio/skill/clanzhongliu_clan_wanglun1.mp3', - 'audio/skill/clanzhongliu_clan_wanglun2.mp3', - 'audio/skill/clanzhongliu_clan_wangyun1.mp3', - 'audio/skill/clanzhongliu_clan_wangyun2.mp3', - 'audio/skill/congjian1.mp3', - 'audio/skill/congjian2.mp3', - 'audio/skill/cslilu1.mp3', - 'audio/skill/cslilu2.mp3', - 'audio/skill/csyizheng1.mp3', - 'audio/skill/csyizheng2.mp3', - 'audio/skill/cuguo1.mp3', - 'audio/skill/cuguo2.mp3', - 'audio/skill/cuijian1.mp3', - 'audio/skill/cuijian2.mp3', - 'audio/skill/cuijin1.mp3', - 'audio/skill/cuijin2.mp3', - 'audio/skill/cuijue1.mp3', - 'audio/skill/cuijue2.mp3', - 'audio/skill/cunsi1.mp3', - 'audio/skill/cunsi2.mp3', - 'audio/skill/cuorui1.mp3', - 'audio/skill/cuorui2.mp3', - 'audio/skill/cxliushi1.mp3', - 'audio/skill/cxliushi2.mp3', - 'audio/skill/dahe.mp3', - 'audio/skill/daiyan1.mp3', - 'audio/skill/daiyan2.mp3', - 'audio/skill/daming1.mp3', - 'audio/skill/daming2.mp3', - 'audio/skill/dangmo1.mp3', - 'audio/skill/dangmo2.mp3', - 'audio/skill/dangxian_guansuo1.mp3', - 'audio/skill/dangxian_guansuo2.mp3', - 'audio/skill/dangxian_re_liaohua1.mp3', - 'audio/skill/dangxian_re_liaohua2.mp3', - 'audio/skill/dangxian_xin_liaohua1.mp3', - 'audio/skill/dangxian_xin_liaohua2.mp3', - 'audio/skill/dangxian1.mp3', - 'audio/skill/dangxian2.mp3', - 'audio/skill/dangzai1.mp3', - 'audio/skill/dangzai2.mp3', - 'audio/skill/danji1.mp3', - 'audio/skill/danji2.mp3', - 'audio/skill/danlao1.mp3', - 'audio/skill/danlao2.mp3', - 'audio/skill/danshou1.mp3', - 'audio/skill/danshou2.mp3', - 'audio/skill/danxin1.mp3', - 'audio/skill/danxin2.mp3', - 'audio/skill/daoji1.mp3', - 'audio/skill/daoji2.mp3', - 'audio/skill/daoshu1.mp3', - 'audio/skill/daoshu2.mp3', - 'audio/skill/dawu1.mp3', - 'audio/skill/dawu2.mp3', - 'audio/skill/dbchongjian1.mp3', - 'audio/skill/dbchongjian2.mp3', - 'audio/skill/dbchoujue1.mp3', - 'audio/skill/dbchoujue2.mp3', - 'audio/skill/dbquedi1.mp3', - 'audio/skill/dbquedi2.mp3', - 'audio/skill/dbzhuifeng1.mp3', - 'audio/skill/dbzhuifeng2.mp3', - 'audio/skill/dcaichen1.mp3', - 'audio/skill/dcaichen2.mp3', - 'audio/skill/dcaishou1.mp3', - 'audio/skill/dcaishou2.mp3', - 'audio/skill/dcanliao1.mp3', - 'audio/skill/dcanliao2.mp3', - 'audio/skill/dcanxu1.mp3', - 'audio/skill/dcanxu2.mp3', - 'audio/skill/dcanzhi1.mp3', - 'audio/skill/dcanzhi2.mp3', - 'audio/skill/dcbeifen1.mp3', - 'audio/skill/dcbeifen2.mp3', - 'audio/skill/dcbeini1.mp3', - 'audio/skill/dcbeini2.mp3', - 'audio/skill/dcbenshi1.mp3', - 'audio/skill/dcbenshi2.mp3', - 'audio/skill/dcbianzhuang1.mp3', - 'audio/skill/dcbianzhuang2.mp3', - 'audio/skill/dcbihuo1.mp3', - 'audio/skill/dcbihuo2.mp3', - 'audio/skill/dcbingji1.mp3', - 'audio/skill/dcbingji2.mp3', - 'audio/skill/dccaisi1.mp3', - 'audio/skill/dccaisi2.mp3', - 'audio/skill/dccaixia1.mp3', - 'audio/skill/dccaixia2.mp3', - 'audio/skill/dccaizhuang1.mp3', - 'audio/skill/dccaizhuang2.mp3', - 'audio/skill/dccansi1.mp3', - 'audio/skill/dccansi2.mp3', - 'audio/skill/dcchaixie1.mp3', - 'audio/skill/dcchaixie2.mp3', - 'audio/skill/dcchangqu1.mp3', - 'audio/skill/dcchangqu2.mp3', - 'audio/skill/dcchanjuan1.mp3', - 'audio/skill/dcchanjuan2.mp3', - 'audio/skill/dcchenyong1.mp3', - 'audio/skill/dcchenyong2.mp3', - 'audio/skill/dcchiying1.mp3', - 'audio/skill/dcchiying2.mp3', - 'audio/skill/dcchongwang1.mp3', - 'audio/skill/dcchongwang2.mp3', - 'audio/skill/dcchongxu1.mp3', - 'audio/skill/dcchongxu2.mp3', - 'audio/skill/dcchongyi1.mp3', - 'audio/skill/dcchongyi2.mp3', - 'audio/skill/dccibei1.mp3', - 'audio/skill/dccibei2.mp3', - 'audio/skill/dccongshi1.mp3', - 'audio/skill/dccongshi2.mp3', - 'audio/skill/dcctjiuxian1.mp3', - 'audio/skill/dcctjiuxian2.mp3', - 'audio/skill/dccuichuan1.mp3', - 'audio/skill/dccuichuan2.mp3', - 'audio/skill/dccuijin1.mp3', - 'audio/skill/dccuijin2.mp3', - 'audio/skill/dccuixin1.mp3', - 'audio/skill/dccuixin2.mp3', - 'audio/skill/dccunwei1.mp3', - 'audio/skill/dccunwei2.mp3', - 'audio/skill/dcdanyi1.mp3', - 'audio/skill/dcdanyi2.mp3', - 'audio/skill/dcdanying1.mp3', - 'audio/skill/dcdanying2.mp3', - 'audio/skill/dcdehua1.mp3', - 'audio/skill/dcdehua2.mp3', - 'audio/skill/dcdeshao1.mp3', - 'audio/skill/dcdeshao2.mp3', - 'audio/skill/dcdeshi1.mp3', - 'audio/skill/dcdeshi2.mp3', - 'audio/skill/dcdingji1.mp3', - 'audio/skill/dcdingji2.mp3', - 'audio/skill/dcditing1.mp3', - 'audio/skill/dcditing2.mp3', - 'audio/skill/dcdouzhen1.mp3', - 'audio/skill/dcdouzhen2.mp3', - 'audio/skill/dcdyqingshi1.mp3', - 'audio/skill/dcdyqingshi2.mp3', - 'audio/skill/dcenyu1.mp3', - 'audio/skill/dcenyu2.mp3', - 'audio/skill/dcfangdu1.mp3', - 'audio/skill/dcfangdu2.mp3', - 'audio/skill/dcfanshi1.mp3', - 'audio/skill/dcfanshi2.mp3', - 'audio/skill/dcfanyin1.mp3', - 'audio/skill/dcfanyin2.mp3', - 'audio/skill/dcfaqi1.mp3', - 'audio/skill/dcfaqi2.mp3', - 'audio/skill/dcfencheng1.mp3', - 'audio/skill/dcfencheng2.mp3', - 'audio/skill/dcfengyan1.mp3', - 'audio/skill/dcfengyan2.mp3', - 'audio/skill/dcfengying1.mp3', - 'audio/skill/dcfengying2.mp3', - 'audio/skill/dcfozong1.mp3', - 'audio/skill/dcfozong2.mp3', - 'audio/skill/dcfudao1.mp3', - 'audio/skill/dcfudao2.mp3', - 'audio/skill/dcfudou1.mp3', - 'audio/skill/dcfudou2.mp3', - 'audio/skill/dcfuli1.mp3', - 'audio/skill/dcfuli2.mp3', - 'audio/skill/dcfumou1.mp3', - 'audio/skill/dcfumou2.mp3', - 'audio/skill/dcfuning1.mp3', - 'audio/skill/dcfuning2.mp3', - 'audio/skill/dcfuxue1.mp3', - 'audio/skill/dcfuxue2.mp3', - 'audio/skill/dcgeyuan1.mp3', - 'audio/skill/dcgeyuan2.mp3', - 'audio/skill/dcgonghu1.mp3', - 'audio/skill/dcgonghu2.mp3', - 'audio/skill/dcguangshi1.mp3', - 'audio/skill/dcguangshi2.mp3', - 'audio/skill/dcgue1.mp3', - 'audio/skill/dcgue2.mp3', - 'audio/skill/dcgusuan1.mp3', - 'audio/skill/dcgusuan2.mp3', - 'audio/skill/dchanying1.mp3', - 'audio/skill/dchanying2.mp3', - 'audio/skill/dchaochong1.mp3', - 'audio/skill/dchaochong2.mp3', - 'audio/skill/dchuace1.mp3', - 'audio/skill/dchuace2.mp3', - 'audio/skill/dchuagui1.mp3', - 'audio/skill/dchuagui2.mp3', - 'audio/skill/dchuahuo1.mp3', - 'audio/skill/dchuahuo2.mp3', - 'audio/skill/dchuayi1.mp3', - 'audio/skill/dchuayi2.mp3', - 'audio/skill/dchuiling1.mp3', - 'audio/skill/dchuiling2.mp3', - 'audio/skill/dchuishu1.mp3', - 'audio/skill/dchuishu2.mp3', - 'audio/skill/dchuizhi1.mp3', - 'audio/skill/dchuizhi2.mp3', - 'audio/skill/dchumei1.mp3', - 'audio/skill/dchumei2.mp3', - 'audio/skill/dcjianguo1.mp3', - 'audio/skill/dcjianguo2.mp3', - 'audio/skill/dcjianji1.mp3', - 'audio/skill/dcjianji2.mp3', - 'audio/skill/dcjianying1.mp3', - 'audio/skill/dcjianying2.mp3', - 'audio/skill/dcjianzheng1.mp3', - 'audio/skill/dcjianzheng2.mp3', - 'audio/skill/dcjianzhuan1.mp3', - 'audio/skill/dcjianzhuan2.mp3', - 'audio/skill/dcjiaofeng1.mp3', - 'audio/skill/dcjiaofeng2.mp3', - 'audio/skill/dcjiaoxia1.mp3', - 'audio/skill/dcjiaoxia2.mp3', - 'audio/skill/dcjichun1.mp3', - 'audio/skill/dcjichun2.mp3', - 'audio/skill/dcjieling1.mp3', - 'audio/skill/dcjieling2.mp3', - 'audio/skill/dcjieshu1.mp3', - 'audio/skill/dcjieshu2.mp3', - 'audio/skill/dcjiexing1.mp3', - 'audio/skill/dcjiexing2.mp3', - 'audio/skill/dcjiezhen1.mp3', - 'audio/skill/dcjiezhen2.mp3', - 'audio/skill/dcjijiao1.mp3', - 'audio/skill/dcjijiao2.mp3', - 'audio/skill/dcjincui1.mp3', - 'audio/skill/dcjincui2.mp3', - 'audio/skill/dcjinggong1.mp3', - 'audio/skill/dcjinggong2.mp3', - 'audio/skill/dcjingzao1.mp3', - 'audio/skill/dcjingzao2.mp3', - 'audio/skill/dcjini1.mp3', - 'audio/skill/dcjini2.mp3', - 'audio/skill/dcjinjian1.mp3', - 'audio/skill/dcjinjian2.mp3', - 'audio/skill/dcjinjie1.mp3', - 'audio/skill/dcjinjie2.mp3', - 'audio/skill/dcjinjin1.mp3', - 'audio/skill/dcjinjin2.mp3', - 'audio/skill/dcjiudun1.mp3', - 'audio/skill/dcjiudun2.mp3', - 'audio/skill/dcjiushi1.mp3', - 'audio/skill/dcjiushi2.mp3', - 'audio/skill/dcjizhong1.mp3', - 'audio/skill/dcjizhong2.mp3', - 'audio/skill/dcjue1.mp3', - 'audio/skill/dcjue2.mp3', - 'audio/skill/dcjuejing1.mp3', - 'audio/skill/dcjuejing2.mp3', - 'audio/skill/dcjuying1.mp3', - 'audio/skill/dcjuying2.mp3', - 'audio/skill/dckaiji1.mp3', - 'audio/skill/dckaiji2.mp3', - 'audio/skill/dckanji1.mp3', - 'audio/skill/dckanji2.mp3', - 'audio/skill/dclbjiuxian1.mp3', - 'audio/skill/dclbjiuxian2.mp3', - 'audio/skill/dcliangxiu1.mp3', - 'audio/skill/dcliangxiu2.mp3', - 'audio/skill/dclianzhi1.mp3', - 'audio/skill/dclianzhi2.mp3', - 'audio/skill/dclibang1.mp3', - 'audio/skill/dclibang2.mp3', - 'audio/skill/dcliehou1.mp3', - 'audio/skill/dcliehou2.mp3', - 'audio/skill/dcligong1.mp3', - 'audio/skill/dcligong2.mp3', - 'audio/skill/dclingfang1.mp3', - 'audio/skill/dclingfang2.mp3', - 'audio/skill/dclinghui1.mp3', - 'audio/skill/dclinghui2.mp3', - 'audio/skill/dclingkong1.mp3', - 'audio/skill/dclingkong2.mp3', - 'audio/skill/dclingxi1.mp3', - 'audio/skill/dclingxi2.mp3', - 'audio/skill/dclingyin1.mp3', - 'audio/skill/dclingyin2.mp3', - 'audio/skill/dclingyue1.mp3', - 'audio/skill/dclingyue2.mp3', - 'audio/skill/dcliuzhuan1.mp3', - 'audio/skill/dcliuzhuan2.mp3', - 'audio/skill/dcliying1.mp3', - 'audio/skill/dcliying2.mp3', - 'audio/skill/dclonggong1.mp3', - 'audio/skill/dclonggong2.mp3', - 'audio/skill/dclonghun1.mp3', - 'audio/skill/dclonghun2.mp3', - 'audio/skill/dclongsong1.mp3', - 'audio/skill/dclongsong2.mp3', - 'audio/skill/dcluochong1.mp3', - 'audio/skill/dcluochong2.mp3', - 'audio/skill/dclvecheng1.mp3', - 'audio/skill/dclvecheng2.mp3', - 'audio/skill/dcmanzhi1.mp3', - 'audio/skill/dcmanzhi2.mp3', - 'audio/skill/dcmengjie1.mp3', - 'audio/skill/dcmengjie2.mp3', - 'audio/skill/dcmieji1.mp3', - 'audio/skill/dcmieji2.mp3', - 'audio/skill/dcmingfa1.mp3', - 'audio/skill/dcmingfa2.mp3', - 'audio/skill/dcminze1.mp3', - 'audio/skill/dcminze2.mp3', - 'audio/skill/dcmiyi1.mp3', - 'audio/skill/dcmiyi2.mp3', - 'audio/skill/dcmiyun1.mp3', - 'audio/skill/dcmiyun2.mp3', - 'audio/skill/dcmoyu1.mp3', - 'audio/skill/dcmoyu2.mp3', - 'audio/skill/dcneifa1.mp3', - 'audio/skill/dcneifa2.mp3', - 'audio/skill/dcniji1.mp3', - 'audio/skill/dcniji2.mp3', - 'audio/skill/dcnuanhui1.mp3', - 'audio/skill/dcnuanhui2.mp3', - 'audio/skill/dcnuchen1.mp3', - 'audio/skill/dcnuchen2.mp3', - 'audio/skill/dcnutao1.mp3', - 'audio/skill/dcnutao2.mp3', - 'audio/skill/dcnutao3.mp3', - 'audio/skill/dcnutao4.mp3', - 'audio/skill/dcpandi1.mp3', - 'audio/skill/dcpandi2.mp3', - 'audio/skill/dcpeiqi1.mp3', - 'audio/skill/dcpeiqi2.mp3', - 'audio/skill/dcpijing1.mp3', - 'audio/skill/dcpijing2.mp3', - 'audio/skill/dcpingxi1.mp3', - 'audio/skill/dcpingxi2.mp3', - 'audio/skill/dcpitian1.mp3', - 'audio/skill/dcpitian2.mp3', - 'audio/skill/dcporui1.mp3', - 'audio/skill/dcporui2.mp3', - 'audio/skill/dcposuo1.mp3', - 'audio/skill/dcposuo2.mp3', - 'audio/skill/dcpoyuan1.mp3', - 'audio/skill/dcpoyuan2.mp3', - 'audio/skill/dcqiangzhi1.mp3', - 'audio/skill/dcqiangzhi2.mp3', - 'audio/skill/dcqianzheng1.mp3', - 'audio/skill/dcqianzheng2.mp3', - 'audio/skill/dcqiaomeng1.mp3', - 'audio/skill/dcqiaomeng2.mp3', - 'audio/skill/dcqijing1.mp3', - 'audio/skill/dcqijing2.mp3', - 'audio/skill/dcqinghuang1.mp3', - 'audio/skill/dcqinghuang2.mp3', - 'audio/skill/dcqingren1.mp3', - 'audio/skill/dcqingren2.mp3', - 'audio/skill/dcqingshi1.mp3', - 'audio/skill/dcqingshi2.mp3', - 'audio/skill/dcqingyan1.mp3', - 'audio/skill/dcqingyan2.mp3', - 'audio/skill/dcqinqing1.mp3', - 'audio/skill/dcqinqing2.mp3', - 'audio/skill/dcqinshen1.mp3', - 'audio/skill/dcqinshen2.mp3', - 'audio/skill/dcqiongying1.mp3', - 'audio/skill/dcqiongying2.mp3', - 'audio/skill/dcqiqin_yue_daqiao1.mp3', - 'audio/skill/dcqiqin_yue_daqiao2.mp3', - 'audio/skill/dcqiqin1.mp3', - 'audio/skill/dcqiqin2.mp3', - 'audio/skill/dcquanjian1.mp3', - 'audio/skill/dcquanjian2.mp3', - 'audio/skill/dcquanshou1.mp3', - 'audio/skill/dcquanshou2.mp3', - 'audio/skill/dcrihui1.mp3', - 'audio/skill/dcrihui2.mp3', - 'audio/skill/dcruizhan1.mp3', - 'audio/skill/dcruizhan2.mp3', - 'audio/skill/dcruxian1.mp3', - 'audio/skill/dcruxian2.mp3', - 'audio/skill/dcruyi1.mp3', - 'audio/skill/dcruyi2.mp3', - 'audio/skill/dcsantou1.mp3', - 'audio/skill/dcsantou2.mp3', - 'audio/skill/dcsaowei1.mp3', - 'audio/skill/dcsaowei2.mp3', - 'audio/skill/dcsbmengmou1.mp3', - 'audio/skill/dcsbmengmou2.mp3', - 'audio/skill/dcsbmingshi1.mp3', - 'audio/skill/dcsbmingshi2.mp3', - 'audio/skill/dcsbpingliao_dc_sb_simayi_shadow1.mp3', - 'audio/skill/dcsbpingliao_dc_sb_simayi_shadow2.mp3', - 'audio/skill/dcsbpingliao1.mp3', - 'audio/skill/dcsbpingliao2.mp3', - 'audio/skill/dcsbquanmou_dc_sb_simayi_shadow1.mp3', - 'audio/skill/dcsbquanmou_dc_sb_simayi_shadow2.mp3', - 'audio/skill/dcsbquanmou1.mp3', - 'audio/skill/dcsbquanmou2.mp3', - 'audio/skill/dcsbronghuo1.mp3', - 'audio/skill/dcsbronghuo2.mp3', - 'audio/skill/dcsbyingmou1.mp3', - 'audio/skill/dcsbyingmou2.mp3', - 'audio/skill/dcshangyu1.mp3', - 'audio/skill/dcshangyu2.mp3', - 'audio/skill/dcshengdu1.mp3', - 'audio/skill/dcshengdu2.mp3', - 'audio/skill/dcshexue1.mp3', - 'audio/skill/dcshexue2.mp3', - 'audio/skill/dcshibei1.mp3', - 'audio/skill/dcshibei2.mp3', - 'audio/skill/dcshiji1.mp3', - 'audio/skill/dcshiji2.mp3', - 'audio/skill/dcshilie1.mp3', - 'audio/skill/dcshilie2.mp3', - 'audio/skill/dcshixian1.mp3', - 'audio/skill/dcshixian2.mp3', - 'audio/skill/dcshizhao1.mp3', - 'audio/skill/dcshizhao2.mp3', - 'audio/skill/dcshizong1.mp3', - 'audio/skill/dcshizong2.mp3', - 'audio/skill/dcshoutan1.mp3', - 'audio/skill/dcshoutan2.mp3', - 'audio/skill/dcshouze.mp3', - 'audio/skill/dcshuaijie1.mp3', - 'audio/skill/dcshuaijie2.mp3', - 'audio/skill/dcshuangjia1.mp3', - 'audio/skill/dcshuangjia2.mp3', - 'audio/skill/dcshuangren1.mp3', - 'audio/skill/dcshuangren2.mp3', - 'audio/skill/dcshuhe1.mp3', - 'audio/skill/dcshuhe2.mp3', - 'audio/skill/dcsigong1.mp3', - 'audio/skill/dcsigong2.mp3', - 'audio/skill/dcsilun1.mp3', - 'audio/skill/dcsilun2.mp3', - 'audio/skill/dcsilve1.mp3', - 'audio/skill/dcsilve2.mp3', - 'audio/skill/dcsitian1.mp3', - 'audio/skill/dcsitian2.mp3', - 'audio/skill/dcsuifu1.mp3', - 'audio/skill/dcsuifu2.mp3', - 'audio/skill/dcsushou1.mp3', - 'audio/skill/dcsushou2.mp3', - 'audio/skill/dctaji1.mp3', - 'audio/skill/dctaji2.mp3', - 'audio/skill/dctianji1.mp3', - 'audio/skill/dctianji2.mp3', - 'audio/skill/dctingxian1.mp3', - 'audio/skill/dctingxian2.mp3', - 'audio/skill/dctongguan1.mp3', - 'audio/skill/dctongguan2.mp3', - 'audio/skill/dctongliao1.mp3', - 'audio/skill/dctongliao2.mp3', - 'audio/skill/dctongliao3.mp3', - 'audio/skill/dctongye1.mp3', - 'audio/skill/dctongye2.mp3', - 'audio/skill/dctujue1.mp3', - 'audio/skill/dctujue2.mp3', - 'audio/skill/dctuoyu1.mp3', - 'audio/skill/dctuoyu2.mp3', - 'audio/skill/dcwanglu1.mp3', - 'audio/skill/dcwanglu2.mp3', - 'audio/skill/dcwangyuan1.mp3', - 'audio/skill/dcwangyuan2.mp3', - 'audio/skill/dcweidang1.mp3', - 'audio/skill/dcweidang2.mp3', - 'audio/skill/dcweiwan1.mp3', - 'audio/skill/dcweiwan2.mp3', - 'audio/skill/dcwencan1.mp3', - 'audio/skill/dcwencan2.mp3', - 'audio/skill/dcwudao1.mp3', - 'audio/skill/dcwudao2.mp3', - 'audio/skill/dcwudao3.mp3', - 'audio/skill/dcwujie1.mp3', - 'audio/skill/dcwujie2.mp3', - 'audio/skill/dcwumei1.mp3', - 'audio/skill/dcwumei2.mp3', - 'audio/skill/dcwuyuan1.mp3', - 'audio/skill/dcwuyuan2.mp3', - 'audio/skill/dcxiace1.mp3', - 'audio/skill/dcxiace2.mp3', - 'audio/skill/dcxialei1.mp3', - 'audio/skill/dcxialei2.mp3', - 'audio/skill/dcxiangmian1.mp3', - 'audio/skill/dcxiangmian2.mp3', - 'audio/skill/dcxiangshu1.mp3', - 'audio/skill/dcxiangshu2.mp3', - 'audio/skill/dcxianjin1.mp3', - 'audio/skill/dcxianjin2.mp3', - 'audio/skill/dcxianshu1.mp3', - 'audio/skill/dcxianshu2.mp3', - 'audio/skill/dcxianzhu1.mp3', - 'audio/skill/dcxianzhu2.mp3', - 'audio/skill/dcxiaojuan1.mp3', - 'audio/skill/dcxiaojuan2.mp3', - 'audio/skill/dcxiaoren1.mp3', - 'audio/skill/dcxiaoren2.mp3', - 'audio/skill/dcxiaoxi1.mp3', - 'audio/skill/dcxiaoxi2.mp3', - 'audio/skill/dcxiaoyin1.mp3', - 'audio/skill/dcxiaoyin2.mp3', - 'audio/skill/dcxieshou1.mp3', - 'audio/skill/dcxieshou2.mp3', - 'audio/skill/dcxinyou1.mp3', - 'audio/skill/dcxinyou2.mp3', - 'audio/skill/dcxiongmu1.mp3', - 'audio/skill/dcxiongmu2.mp3', - 'audio/skill/dcxiuwen1.mp3', - 'audio/skill/dcxiuwen2.mp3', - 'audio/skill/dcxuewei1.mp3', - 'audio/skill/dcxuewei2.mp3', - 'audio/skill/dcxunbie1.mp3', - 'audio/skill/dcxunbie2.mp3', - 'audio/skill/dcxunji1.mp3', - 'audio/skill/dcxunji2.mp3', - 'audio/skill/dcxunjie1.mp3', - 'audio/skill/dcxunjie2.mp3', - 'audio/skill/dcyaoyi1.mp3', - 'audio/skill/dcyaoyi2.mp3', - 'audio/skill/dcyicong1.mp3', - 'audio/skill/dcyicong2.mp3', - 'audio/skill/dcyijia1.mp3', - 'audio/skill/dcyijia2.mp3', - 'audio/skill/dcyingtu1.mp3', - 'audio/skill/dcyingtu2.mp3', - 'audio/skill/dcyingyu1.mp3', - 'audio/skill/dcyingyu2.mp3', - 'audio/skill/dcyinjun1.mp3', - 'audio/skill/dcyinjun2.mp3', - 'audio/skill/dcyinlu1.mp3', - 'audio/skill/dcyinlu2.mp3', - 'audio/skill/dcyinshi1.mp3', - 'audio/skill/dcyinshi2.mp3', - 'audio/skill/dcyishu1.mp3', - 'audio/skill/dcyishu2.mp3', - 'audio/skill/dcyiyong1.mp3', - 'audio/skill/dcyiyong2.mp3', - 'audio/skill/dcyongbi1.mp3', - 'audio/skill/dcyongbi2.mp3', - 'audio/skill/dcyouqi1.mp3', - 'audio/skill/dcyouqi2.mp3', - 'audio/skill/dcyouzhan1.mp3', - 'audio/skill/dcyouzhan2.mp3', - 'audio/skill/dcyuandi1.mp3', - 'audio/skill/dcyuandi2.mp3', - 'audio/skill/dcyuanmo1.mp3', - 'audio/skill/dcyuanmo2.mp3', - 'audio/skill/dcyuguan1.mp3', - 'audio/skill/dcyuguan2.mp3', - 'audio/skill/dcyuxin1.mp3', - 'audio/skill/dcyuxin2.mp3', - 'audio/skill/dczecai1.mp3', - 'audio/skill/dczecai2.mp3', - 'audio/skill/dczhangcai1.mp3', - 'audio/skill/dczhangcai2.mp3', - 'audio/skill/dczhanmeng1.mp3', - 'audio/skill/dczhanmeng2.mp3', - 'audio/skill/dczhanyi1.mp3', - 'audio/skill/dczhanyi2.mp3', - 'audio/skill/dczhaohan1.mp3', - 'audio/skill/dczhaohan2.mp3', - 'audio/skill/dczhaowen1.mp3', - 'audio/skill/dczhaowen2.mp3', - 'audio/skill/dczhengxu1.mp3', - 'audio/skill/dczhengxu2.mp3', - 'audio/skill/dczhenze1.mp3', - 'audio/skill/dczhenze2.mp3', - 'audio/skill/dczhifou1.mp3', - 'audio/skill/dczhifou2.mp3', - 'audio/skill/dczhizhe1.mp3', - 'audio/skill/dczhizhe2.mp3', - 'audio/skill/dczhongji1.mp3', - 'audio/skill/dczhongji2.mp3', - 'audio/skill/dczhongjie1.mp3', - 'audio/skill/dczhongjie2.mp3', - 'audio/skill/dczhouli2.mp3', - 'audio/skill/dczhubi1.mp3', - 'audio/skill/dczhubi2.mp3', - 'audio/skill/dczhuiyi1.mp3', - 'audio/skill/dczhuiyi2.mp3', - 'audio/skill/dczhuoli1.mp3', - 'audio/skill/dczigu1.mp3', - 'audio/skill/dczigu2.mp3', - 'audio/skill/dczimu1.mp3', - 'audio/skill/dczixi1.mp3', - 'audio/skill/dczixi2.mp3', - 'audio/skill/dczuojian1.mp3', - 'audio/skill/dczuojian2.mp3', - 'audio/skill/dczuowei1.mp3', - 'audio/skill/dczuowei2.mp3', - 'audio/skill/debao1.mp3', - 'audio/skill/debao2.mp3', - 'audio/skill/decadejingce1.mp3', - 'audio/skill/decadejingce2.mp3', - 'audio/skill/decadejinjiu1.mp3', - 'audio/skill/decadejinjiu2.mp3', - 'audio/skill/decadepojun1.mp3', - 'audio/skill/decadepojun2.mp3', - 'audio/skill/decadexianzhen1.mp3', - 'audio/skill/decadexianzhen2.mp3', - 'audio/skill/decadezhenjun1.mp3', - 'audio/skill/decadezhenjun2.mp3', - 'audio/skill/decadezishou1.mp3', - 'audio/skill/decadezishou2.mp3', - 'audio/skill/decadezongshi1.mp3', - 'audio/skill/decadezongshi2.mp3', - 'audio/skill/dengji1.mp3', - 'audio/skill/dengji2.mp3', - 'audio/skill/dengzhi.mp3', - 'audio/skill/dezhang1.mp3', - 'audio/skill/dezhang2.mp3', - 'audio/skill/diancai1.mp3', - 'audio/skill/diancai2.mp3', - 'audio/skill/diaodu1.mp3', - 'audio/skill/diaodu2.mp3', - 'audio/skill/diaoling1.mp3', - 'audio/skill/diaoling2.mp3', - 'audio/skill/diezhang1.mp3', - 'audio/skill/diezhang2.mp3', - 'audio/skill/difa1.mp3', - 'audio/skill/difa2.mp3', - 'audio/skill/dili_chigang1.mp3', - 'audio/skill/dili_chigang2.mp3', - 'audio/skill/dili_jiaohui1.mp3', - 'audio/skill/dili_jiaohui2.mp3', - 'audio/skill/dili_qionglan1.mp3', - 'audio/skill/dili_qionglan2.mp3', - 'audio/skill/dili_quandao1.mp3', - 'audio/skill/dili_quandao2.mp3', - 'audio/skill/dili_shengzhi1.mp3', - 'audio/skill/dili_shengzhi2.mp3', - 'audio/skill/dili_yuanlv1.mp3', - 'audio/skill/dili_yuanlv2.mp3', - 'audio/skill/dili1.mp3', - 'audio/skill/dili2.mp3', - 'audio/skill/dimeng1.mp3', - 'audio/skill/dimeng2.mp3', - 'audio/skill/dingfa1.mp3', - 'audio/skill/dingfa2.mp3', - 'audio/skill/dinghan1.mp3', - 'audio/skill/dinghan2.mp3', - 'audio/skill/dingpan1.mp3', - 'audio/skill/dingpan2.mp3', - 'audio/skill/dingpin1.mp3', - 'audio/skill/dingpin2.mp3', - 'audio/skill/dingzhou1.mp3', - 'audio/skill/dingzhou2.mp3', - 'audio/skill/disordersidi1.mp3', - 'audio/skill/disordersidi2.mp3', - 'audio/skill/donggui1.mp3', - 'audio/skill/donggui2.mp3', - 'audio/skill/drlt_congjian1.mp3', - 'audio/skill/drlt_congjian2.mp3', - 'audio/skill/drlt_duorui1.mp3', - 'audio/skill/drlt_duorui2.mp3', - 'audio/skill/drlt_hongju1.mp3', - 'audio/skill/drlt_hongju2.mp3', - 'audio/skill/drlt_huairou1.mp3', - 'audio/skill/drlt_huairou2.mp3', - 'audio/skill/drlt_jieying1.mp3', - 'audio/skill/drlt_jieying2.mp3', - 'audio/skill/drlt_jueyan1.mp3', - 'audio/skill/drlt_jueyan2.mp3', - 'audio/skill/drlt_poshi1.mp3', - 'audio/skill/drlt_poshi2.mp3', - 'audio/skill/drlt_poxi1.mp3', - 'audio/skill/drlt_poxi2.mp3', - 'audio/skill/drlt_qianjie1.mp3', - 'audio/skill/drlt_qianjie2.mp3', - 'audio/skill/drlt_qingce1.mp3', - 'audio/skill/drlt_qingce2.mp3', - 'audio/skill/drlt_wanglie1.mp3', - 'audio/skill/drlt_wanglie2.mp3', - 'audio/skill/drlt_weidi1.mp3', - 'audio/skill/drlt_weidi2.mp3', - 'audio/skill/drlt_xiongluan1.mp3', - 'audio/skill/drlt_xiongluan2.mp3', - 'audio/skill/drlt_yongsi1.mp3', - 'audio/skill/drlt_yongsi2.mp3', - 'audio/skill/drlt_zhenggu1.mp3', - 'audio/skill/drlt_zhenggu2.mp3', - 'audio/skill/drlt_zhenrong1.mp3', - 'audio/skill/drlt_zhenrong2.mp3', - 'audio/skill/drlt_zhiti1.mp3', - 'audio/skill/drlt_zhiti2.mp3', - 'audio/skill/duanbi1.mp3', - 'audio/skill/duanbi2.mp3', - 'audio/skill/duanbing_heqi1.mp3', - 'audio/skill/duanbing_heqi2.mp3', - 'audio/skill/duanbing1.mp3', - 'audio/skill/duanbing2.mp3', - 'audio/skill/duanchang_ol_caiwenji1.mp3', - 'audio/skill/duanchang_ol_caiwenji2.mp3', - 'audio/skill/duanchang_re_caiwenji1.mp3', - 'audio/skill/duanchang_re_caiwenji2.mp3', - 'audio/skill/duanchang1.mp3', - 'audio/skill/duanchang2.mp3', - 'audio/skill/duanliang1_re_xuhuang1.mp3', - 'audio/skill/duanliang1_re_xuhuang2.mp3', - 'audio/skill/duanliang11.mp3', - 'audio/skill/duanliang12.mp3', - 'audio/skill/duansuo1.mp3', - 'audio/skill/duansuo2.mp3', - 'audio/skill/duanwan1.mp3', - 'audio/skill/duanwan2.mp3', - 'audio/skill/duanxie1.mp3', - 'audio/skill/duanxie2.mp3', - 'audio/skill/dujin1.mp3', - 'audio/skill/dujin2.mp3', - 'audio/skill/duliang1.mp3', - 'audio/skill/duliang2.mp3', - 'audio/skill/dulie1.mp3', - 'audio/skill/dulie2.mp3', - 'audio/skill/dunshi1.mp3', - 'audio/skill/dunshi2.mp3', - 'audio/skill/dunxi1.mp3', - 'audio/skill/dunxi2.mp3', - 'audio/skill/duodao1.mp3', - 'audio/skill/duodao2.mp3', - 'audio/skill/duoduan1.mp3', - 'audio/skill/duoduan2.mp3', - 'audio/skill/duoji1.mp3', - 'audio/skill/duoji2.mp3', - 'audio/skill/duoshi1.mp3', - 'audio/skill/duoshi2.mp3', - 'audio/skill/dushi1.mp3', - 'audio/skill/dushi2.mp3', - 'audio/skill/duwang1.mp3', - 'audio/skill/duwang2.mp3', - 'audio/skill/duwu1.mp3', - 'audio/skill/duwu2.mp3', - 'audio/skill/dzgengzhan1.mp3', - 'audio/skill/dzgengzhan2.mp3', - 'audio/skill/dzkanpo1.mp3', - 'audio/skill/dzkanpo2.mp3', - 'audio/skill/ejian1.mp3', - 'audio/skill/ejian2.mp3', - 'audio/skill/enyuan1.mp3', - 'audio/skill/enyuan2.mp3', - 'audio/skill/equan1.mp3', - 'audio/skill/equan2.mp3', - 'audio/skill/faen1.mp3', - 'audio/skill/faen2.mp3', - 'audio/skill/fanghun1.mp3', - 'audio/skill/fanghun2.mp3', - 'audio/skill/fangquan1.mp3', - 'audio/skill/fangquan2.mp3', - 'audio/skill/fangtian_skill.mp3', - 'audio/skill/fangzhu1.mp3', - 'audio/skill/fangzhu2.mp3', - 'audio/skill/fanjian1.mp3', - 'audio/skill/fanjian2.mp3', - 'audio/skill/fankui1.mp3', - 'audio/skill/fankui2.mp3', - 'audio/skill/fanxiang1.mp3', - 'audio/skill/fanxiang2.mp3', - 'audio/skill/fencheng1.mp3', - 'audio/skill/fencheng2.mp3', - 'audio/skill/fengji1.mp3', - 'audio/skill/fengji2.mp3', - 'audio/skill/fengjie1.mp3', - 'audio/skill/fengjie2.mp3', - 'audio/skill/fengliang1.mp3', - 'audio/skill/fengliang2.mp3', - 'audio/skill/fenglve1.mp3', - 'audio/skill/fenglve2.mp3', - 'audio/skill/fengpo1.mp3', - 'audio/skill/fengpo2.mp3', - 'audio/skill/fengwu1.mp3', - 'audio/skill/fengwu2.mp3', - 'audio/skill/fengxiang1.mp3', - 'audio/skill/fengxiang2.mp3', - 'audio/skill/fengyang1.mp3', - 'audio/skill/fengyang2.mp3', - 'audio/skill/fengying1.mp3', - 'audio/skill/fengying2.mp3', - 'audio/skill/fenji1.mp3', - 'audio/skill/fenji2.mp3', - 'audio/skill/fenli_xin_zhuhuan1.mp3', - 'audio/skill/fenli_xin_zhuhuan2.mp3', - 'audio/skill/fenli1.mp3', - 'audio/skill/fenli2.mp3', - 'audio/skill/fenming1.mp3', - 'audio/skill/fenming2.mp3', - 'audio/skill/fenrui1.mp3', - 'audio/skill/fenrui2.mp3', - 'audio/skill/fensi1.mp3', - 'audio/skill/fensi2.mp3', - 'audio/skill/fentian1.mp3', - 'audio/skill/fentian2.mp3', - 'audio/skill/fenwei_heqi1.mp3', - 'audio/skill/fenwei_heqi2.mp3', - 'audio/skill/fenwei1.mp3', - 'audio/skill/fenwei2.mp3', - 'audio/skill/fenxin1.mp3', - 'audio/skill/fenxin2.mp3', - 'audio/skill/fenxun1.mp3', - 'audio/skill/fenxun2.mp3', - 'audio/skill/fenyin1.mp3', - 'audio/skill/fenyin2.mp3', - 'audio/skill/fenyong1.mp3', - 'audio/skill/fenyong2.mp3', - 'audio/skill/fenyue1.mp3', - 'audio/skill/fenyue2.mp3', - 'audio/skill/fubi1.mp3', - 'audio/skill/fubi2.mp3', - 'audio/skill/fuhan1.mp3', - 'audio/skill/fuhan2.mp3', - 'audio/skill/fuhun_re_guanzhang1.mp3', - 'audio/skill/fuhun_re_guanzhang2.mp3', - 'audio/skill/fuhun1.mp3', - 'audio/skill/fuhun2.mp3', - 'audio/skill/fuli1.mp3', - 'audio/skill/fuli2.mp3', - 'audio/skill/fulin1.mp3', - 'audio/skill/fulin2.mp3', - 'audio/skill/fuman1.mp3', - 'audio/skill/fuman2.mp3', - 'audio/skill/fumian1.mp3', - 'audio/skill/fumian2.mp3', - 'audio/skill/funan1.mp3', - 'audio/skill/funan2.mp3', - 'audio/skill/fuping1.mp3', - 'audio/skill/fuping2.mp3', - 'audio/skill/fuqi1.mp3', - 'audio/skill/fuqi2.mp3', - 'audio/skill/fuyuan1.mp3', - 'audio/skill/fuyuan2.mp3', - 'audio/skill/fuzhong1.mp3', - 'audio/skill/fuzhong2.mp3', - 'audio/skill/fuzhu1.mp3', - 'audio/skill/fuzhu2.mp3', - 'audio/skill/fyjianyu1.mp3', - 'audio/skill/fyjianyu2.mp3', - 'audio/skill/fz_liegong.mp3', - 'audio/skill/fz_new_longdan.mp3', - 'audio/skill/fz_new_paoxiao.mp3', - 'audio/skill/fz_new_tieji.mp3', - 'audio/skill/fz_wusheng.mp3', - 'audio/skill/fz_xinkuanggu.mp3', - 'audio/skill/ganglie1.mp3', - 'audio/skill/ganglie2.mp3', - 'audio/skill/gangzhi1.mp3', - 'audio/skill/gangzhi2.mp3', - 'audio/skill/ganlu1.mp3', - 'audio/skill/ganlu2.mp3', - 'audio/skill/gaoling1.mp3', - 'audio/skill/gaoling2.mp3', - 'audio/skill/gaoyuan1.mp3', - 'audio/skill/gaoyuan2.mp3', - 'audio/skill/gebo1.mp3', - 'audio/skill/gebo2.mp3', - 'audio/skill/gnjinfan1.mp3', - 'audio/skill/gnjinfan2.mp3', - 'audio/skill/gnsheque1.mp3', - 'audio/skill/gnsheque2.mp3', - 'audio/skill/gongao1.mp3', - 'audio/skill/gongao2.mp3', - 'audio/skill/gonghuan1.mp3', - 'audio/skill/gonghuan2.mp3', - 'audio/skill/gongji1.mp3', - 'audio/skill/gongji2.mp3', - 'audio/skill/gongjian1.mp3', - 'audio/skill/gongjian2.mp3', - 'audio/skill/gongsun1.mp3', - 'audio/skill/gongsun2.mp3', - 'audio/skill/gongxin_gexuan1.mp3', - 'audio/skill/gongxin_re_lvmeng1.mp3', - 'audio/skill/gongxin_re_lvmeng2.mp3', - 'audio/skill/gongxin1.mp3', - 'audio/skill/gongxin2.mp3', - 'audio/skill/gongxiu1.mp3', - 'audio/skill/gongxiu2.mp3', - 'audio/skill/guanshi_skill.mp3', - 'audio/skill/guanxing_gexuan1.mp3', - 'audio/skill/guanxing_jiangwei1.mp3', - 'audio/skill/guanxing_jiangwei2.mp3', - 'audio/skill/guanxing_ol_jiangwei1.mp3', - 'audio/skill/guanxing_ol_jiangwei2.mp3', - 'audio/skill/guanxing_re_jiangwei1.mp3', - 'audio/skill/guanxing_re_jiangwei2.mp3', - 'audio/skill/guanxing_re_zhugeliang1.mp3', - 'audio/skill/guanxing_re_zhugeliang2.mp3', - 'audio/skill/guanxing1.mp3', - 'audio/skill/guanxing2.mp3', - 'audio/skill/guanxu1.mp3', - 'audio/skill/guanxu2.mp3', - 'audio/skill/guanzong1.mp3', - 'audio/skill/guanzong2.mp3', - 'audio/skill/guding_skill.mp3', - 'audio/skill/guhuo_guess1.mp3', - 'audio/skill/guhuo_guess2.mp3', - 'audio/skill/guhuo1.mp3', - 'audio/skill/guhuo2.mp3', - 'audio/skill/guicai1.mp3', - 'audio/skill/guicai2.mp3', - 'audio/skill/guidao_sp_zhangjiao1.mp3', - 'audio/skill/guidao_sp_zhangjiao2.mp3', - 'audio/skill/guidao1.mp3', - 'audio/skill/guidao2.mp3', - 'audio/skill/guili1.mp3', - 'audio/skill/guili2.mp3', - 'audio/skill/guiming1.mp3', - 'audio/skill/guiming2.mp3', - 'audio/skill/guimou1.mp3', - 'audio/skill/guimou2.mp3', - 'audio/skill/guixin1.mp3', - 'audio/skill/guixin2.mp3', - 'audio/skill/guixiu1.mp3', - 'audio/skill/guixiu2.mp3', - 'audio/skill/guizao1.mp3', - 'audio/skill/guizao2.mp3', - 'audio/skill/guizhen1.mp3', - 'audio/skill/guizhen2.mp3', - 'audio/skill/guju_tw_beimihu1.mp3', - 'audio/skill/guju_tw_beimihu2.mp3', - 'audio/skill/guju1.mp3', - 'audio/skill/guju2.mp3', - 'audio/skill/guose1.mp3', - 'audio/skill/guose2.mp3', - 'audio/skill/guowu1.mp3', - 'audio/skill/guowu2.mp3', - 'audio/skill/gushe1.mp3', - 'audio/skill/gushe2.mp3', - 'audio/skill/guying1.mp3', - 'audio/skill/guying2.mp3', - 'audio/skill/guzheng_re_zhangzhang1.mp3', - 'audio/skill/guzheng_re_zhangzhang2.mp3', - 'audio/skill/guzheng1.mp3', - 'audio/skill/guzheng2.mp3', - 'audio/skill/gxlianhua1.mp3', - 'audio/skill/gxlianhua2.mp3', - 'audio/skill/gz_jun_liubei.mp3', - 'audio/skill/gz_jun_sunquan.mp3', - 'audio/skill/gzbaolie1.mp3', - 'audio/skill/gzbaolie2.mp3', - 'audio/skill/gzbiluan1.mp3', - 'audio/skill/gzbiluan2.mp3', - 'audio/skill/gzbuqu1.mp3', - 'audio/skill/gzbuqu2.mp3', - 'audio/skill/gzbushi1.mp3', - 'audio/skill/gzbushi2.mp3', - 'audio/skill/gzchenglve1.mp3', - 'audio/skill/gzchenglve2.mp3', - 'audio/skill/gzcongcha1.mp3', - 'audio/skill/gzcongcha2.mp3', - 'audio/skill/gzduannian1.mp3', - 'audio/skill/gzduannian2.mp3', - 'audio/skill/gzduwu1.mp3', - 'audio/skill/gzduwu2.mp3', - 'audio/skill/gzfangyuan1.mp3', - 'audio/skill/gzfangyuan2.mp3', - 'audio/skill/gzfankui1.mp3', - 'audio/skill/gzfankui2.mp3', - 'audio/skill/gzfudi1.mp3', - 'audio/skill/gzfudi2.mp3', - 'audio/skill/gzhuaiyi1.mp3', - 'audio/skill/gzhuaiyi2.mp3', - 'audio/skill/gzjiancai1.mp3', - 'audio/skill/gzjiancai2.mp3', - 'audio/skill/gzjianliang1.mp3', - 'audio/skill/gzjianliang2.mp3', - 'audio/skill/gzjieyue1.mp3', - 'audio/skill/gzjieyue2.mp3', - 'audio/skill/gzjili1.mp3', - 'audio/skill/gzjili2.mp3', - 'audio/skill/gzjinfa1.mp3', - 'audio/skill/gzjinfa2.mp3', - 'audio/skill/gzjixi.mp3', - 'audio/skill/gzjixi1.mp3', - 'audio/skill/gzjuejue1.mp3', - 'audio/skill/gzjuejue2.mp3', - 'audio/skill/gzkuangcai1.mp3', - 'audio/skill/gzkuangcai2.mp3', - 'audio/skill/gzlianpian1.mp3', - 'audio/skill/gzlianpian2.mp3', - 'audio/skill/gzlianyou1.mp3', - 'audio/skill/gzlianyou2.mp3', - 'audio/skill/gzlixia1.mp3', - 'audio/skill/gzlixia2.mp3', - 'audio/skill/gzmidao1.mp3', - 'audio/skill/gzmidao2.mp3', - 'audio/skill/gzpaiyi1.mp3', - 'audio/skill/gzpaiyi2.mp3', - 'audio/skill/gzquanji1.mp3', - 'audio/skill/gzquanji2.mp3', - 'audio/skill/gzshejian1.mp3', - 'audio/skill/gzshejian2.mp3', - 'audio/skill/gzshicai1.mp3', - 'audio/skill/gzshicai2.mp3', - 'audio/skill/gzshilu1.mp3', - 'audio/skill/gzshilu2.mp3', - 'audio/skill/gzsuzhi1.mp3', - 'audio/skill/gzsuzhi2.mp3', - 'audio/skill/gztunjiang1.mp3', - 'audio/skill/gztunjiang2.mp3', - 'audio/skill/gzweimeng1.mp3', - 'audio/skill/gzweimeng2.mp3', - 'audio/skill/gzwenji1.mp3', - 'audio/skill/gzwenji2.mp3', - 'audio/skill/gzxingzhao_xunxun1.mp3', - 'audio/skill/gzxingzhao_xunxun2.mp3', - 'audio/skill/gzxingzhao1.mp3', - 'audio/skill/gzxingzhao2.mp3', - 'audio/skill/gzxiongnve1.mp3', - 'audio/skill/gzxiongnve2.mp3', - 'audio/skill/gzxishe1.mp3', - 'audio/skill/gzxishe2.mp3', - 'audio/skill/gzyinghun_re_sunyi1.mp3', - 'audio/skill/gzyjili1.mp3', - 'audio/skill/gzyjili2.mp3', - 'audio/skill/gzzhaoxin1.mp3', - 'audio/skill/gzzhaoxin2.mp3', - 'audio/skill/gzzhidao1.mp3', - 'audio/skill/gzzhidao2.mp3', - 'audio/skill/gzzisui1.mp3', - 'audio/skill/gzzisui2.mp3', - 'audio/skill/gzzongyu1.mp3', - 'audio/skill/gzzongyu2.mp3', - 'audio/skill/hanbing_skill.mp3', - 'audio/skill/hannan1.mp3', - 'audio/skill/hannan2.mp3', - 'audio/skill/hanyong1.mp3', - 'audio/skill/hanyong2.mp3', - 'audio/skill/hanzhan1.mp3', - 'audio/skill/hanzhan2.mp3', - 'audio/skill/haoshi1.mp3', - 'audio/skill/haoshi2.mp3', - 'audio/skill/heji1.mp3', - 'audio/skill/heji2.mp3', - 'audio/skill/hengjiang1.mp3', - 'audio/skill/hengjiang2.mp3', - 'audio/skill/hengwu1.mp3', - 'audio/skill/hengwu2.mp3', - 'audio/skill/hengzheng1.mp3', - 'audio/skill/hengzheng2.mp3', - 'audio/skill/heqia1.mp3', - 'audio/skill/heqia2.mp3', - 'audio/skill/hezhong1.mp3', - 'audio/skill/hezhong2.mp3', - 'audio/skill/hfjieying1.mp3', - 'audio/skill/hfjieying2.mp3', - 'audio/skill/hinata_ehou1.mp3', - 'audio/skill/hinata_ehou2.mp3', - 'audio/skill/hinata_qiulve1.mp3', - 'audio/skill/hinata_qiulve2.mp3', - 'audio/skill/hisako_yinbao1.mp3', - 'audio/skill/hisako_yinbao2.mp3', - 'audio/skill/hmxili1.mp3', - 'audio/skill/hmxili2.mp3', - 'audio/skill/hongde1.mp3', - 'audio/skill/hongde2.mp3', - 'audio/skill/hongfa_hp.mp3', - 'audio/skill/hongfa1.mp3', - 'audio/skill/hongfa2.mp3', - 'audio/skill/hongyan.mp3', - 'audio/skill/hongyi1.mp3', - 'audio/skill/hongyi2.mp3', - 'audio/skill/hongyuan1.mp3', - 'audio/skill/hongyuan2.mp3', - 'audio/skill/houfeng1.mp3', - 'audio/skill/houfeng2.mp3', - 'audio/skill/houfeng3.mp3', - 'audio/skill/huaibi1.mp3', - 'audio/skill/huaibi2.mp3', - 'audio/skill/huaiyi1.mp3', - 'audio/skill/huaiyi2.mp3', - 'audio/skill/huaiyuan1.mp3', - 'audio/skill/huaiyuan2.mp3', - 'audio/skill/huamu1.mp3', - 'audio/skill/huamu2.mp3', - 'audio/skill/huamu3.mp3', - 'audio/skill/huamu4.mp3', - 'audio/skill/huamu5.mp3', - 'audio/skill/huamu6.mp3', - 'audio/skill/huangjintianbingfu1.mp3', - 'audio/skill/huangjintianbingfu2.mp3', - 'audio/skill/huangkong1.mp3', - 'audio/skill/huangkong2.mp3', - 'audio/skill/huangtian2_re_zhangjiao1.mp3', - 'audio/skill/huangtian2_re_zhangjiao2.mp3', - 'audio/skill/huangtian2_zhangjiao1.mp3', - 'audio/skill/huangtian2_zhangjiao2.mp3', - 'audio/skill/huangtian21.mp3', - 'audio/skill/huangtian22.mp3', - 'audio/skill/huanhua1.mp3', - 'audio/skill/huanhua2.mp3', - 'audio/skill/huanshi1.mp3', - 'audio/skill/huanshi2.mp3', - 'audio/skill/huantu1.mp3', - 'audio/skill/huantu2.mp3', - 'audio/skill/huaping.mp3', - 'audio/skill/huaping1.mp3', - 'audio/skill/huaping2.mp3', - 'audio/skill/huashen21.mp3', - 'audio/skill/huashen22.mp3', - 'audio/skill/huguan_wangyue1.mp3', - 'audio/skill/huguan_wangyue2.mp3', - 'audio/skill/huguan1.mp3', - 'audio/skill/huguan2.mp3', - 'audio/skill/huibian1.mp3', - 'audio/skill/huibian2.mp3', - 'audio/skill/huilei1.mp3', - 'audio/skill/huilei2.mp3', - 'audio/skill/huimin1.mp3', - 'audio/skill/huimin2.mp3', - 'audio/skill/huirong1.mp3', - 'audio/skill/huirong2.mp3', - 'audio/skill/huisheng_dc_huanghao1.mp3', - 'audio/skill/huisheng_dc_huanghao2.mp3', - 'audio/skill/huisheng1.mp3', - 'audio/skill/huisheng2.mp3', - 'audio/skill/huishi1.mp3', - 'audio/skill/huishi2.mp3', - 'audio/skill/huituo1.mp3', - 'audio/skill/huituo2.mp3', - 'audio/skill/hujia_re_caocao1.mp3', - 'audio/skill/hujia_re_caocao2.mp3', - 'audio/skill/hujia1.mp3', - 'audio/skill/hujia2.mp3', - 'audio/skill/hunzi1.mp3', - 'audio/skill/hunzi2.mp3', - 'audio/skill/huoji1.mp3', - 'audio/skill/huoji2.mp3', - 'audio/skill/huomo_huzhao1.mp3', - 'audio/skill/huomo_huzhao2.mp3', - 'audio/skill/huomo_re_zhongyao1.mp3', - 'audio/skill/huomo_re_zhongyao2.mp3', - 'audio/skill/huomo1.mp3', - 'audio/skill/huomo2.mp3', - 'audio/skill/huoshaowuchao.mp3', - 'audio/skill/huoshou1_re_menghuo1.mp3', - 'audio/skill/huoshou1_re_menghuo2.mp3', - 'audio/skill/huoshou11.mp3', - 'audio/skill/huoshou12.mp3', - 'audio/skill/huoshui1.mp3', - 'audio/skill/huoshui2.mp3', - 'audio/skill/huoxin1.mp3', - 'audio/skill/huoxin2.mp3', - 'audio/skill/huwei1.mp3', - 'audio/skill/huwei2.mp3', - 'audio/skill/huxiao1.mp3', - 'audio/skill/huxiao2.mp3', - 'audio/skill/huyuan1.mp3', - 'audio/skill/huyuan2.mp3', - 'audio/skill/hxrenshi1.mp3', - 'audio/skill/hxrenshi2.mp3', - 'audio/skill/jiahe_put1.mp3', - 'audio/skill/jiahe_put2.mp3', - 'audio/skill/jiahe1.mp3', - 'audio/skill/jiahe2.mp3', - 'audio/skill/jianan1.mp3', - 'audio/skill/jianan2.mp3', - 'audio/skill/jianchu_re_pangde1.mp3', - 'audio/skill/jianchu_re_pangde2.mp3', - 'audio/skill/jianchu1.mp3', - 'audio/skill/jianchu2.mp3', - 'audio/skill/jiang_re_sunben1.mp3', - 'audio/skill/jiang_re_sunben2.mp3', - 'audio/skill/jiang_re_sunce1.mp3', - 'audio/skill/jiang_re_sunce2.mp3', - 'audio/skill/jiang_sp_lvmeng1.mp3', - 'audio/skill/jiang_sp_lvmeng2.mp3', - 'audio/skill/jiang1.mp3', - 'audio/skill/jiang2.mp3', - 'audio/skill/jiangchi1.mp3', - 'audio/skill/jiangchi2.mp3', - 'audio/skill/jianglue1.mp3', - 'audio/skill/jianglue2.mp3', - 'audio/skill/jiangxi1.mp3', - 'audio/skill/jiangxi2.mp3', - 'audio/skill/jianhui1.mp3', - 'audio/skill/jianhui2.mp3', - 'audio/skill/jianliang1.mp3', - 'audio/skill/jianliang2.mp3', - 'audio/skill/jianshoudaiyuan.mp3', - 'audio/skill/jianshu1.mp3', - 'audio/skill/jianshu2.mp3', - 'audio/skill/jianxiong1.mp3', - 'audio/skill/jianxiong2.mp3', - 'audio/skill/jianyan1.mp3', - 'audio/skill/jianyan2.mp3', - 'audio/skill/jianying1.mp3', - 'audio/skill/jianying2.mp3', - 'audio/skill/jianzhan1.mp3', - 'audio/skill/jianzhan2.mp3', - 'audio/skill/jianzheng1.mp3', - 'audio/skill/jianzheng2.mp3', - 'audio/skill/jiaojin1.mp3', - 'audio/skill/jiaojin2.mp3', - 'audio/skill/jiaoxia1.mp3', - 'audio/skill/jiaoxia2.mp3', - 'audio/skill/jiaoying1.mp3', - 'audio/skill/jiaoying2.mp3', - 'audio/skill/jiaozhao1.mp3', - 'audio/skill/jiaozhao2.mp3', - 'audio/skill/jiaozi1.mp3', - 'audio/skill/jiaozi2.mp3', - 'audio/skill/jibing1.mp3', - 'audio/skill/jibing2.mp3', - 'audio/skill/jici1.mp3', - 'audio/skill/jici2.mp3', - 'audio/skill/jidian1.mp3', - 'audio/skill/jidian2.mp3', - 'audio/skill/jiebing1.mp3', - 'audio/skill/jiebing2.mp3', - 'audio/skill/jiefan_re_handang1.mp3', - 'audio/skill/jiefan_re_handang2.mp3', - 'audio/skill/jiefan1.mp3', - 'audio/skill/jiefan2.mp3', - 'audio/skill/jieliang1.mp3', - 'audio/skill/jieliang2.mp3', - 'audio/skill/jielie1.mp3', - 'audio/skill/jielie2.mp3', - 'audio/skill/jieming1.mp3', - 'audio/skill/jieming2.mp3', - 'audio/skill/jiewei1.mp3', - 'audio/skill/jiewei2.mp3', - 'audio/skill/jiexun1.mp3', - 'audio/skill/jiexun2.mp3', - 'audio/skill/jieyin1.mp3', - 'audio/skill/jieyin2.mp3', - 'audio/skill/jieyuan_less.mp3', - 'audio/skill/jieyuan_more.mp3', - 'audio/skill/jieyue_shan.mp3', - 'audio/skill/jieyue_wuxie.mp3', - 'audio/skill/jieyue1.mp3', - 'audio/skill/jieyue2.mp3', - 'audio/skill/jiezhong1.mp3', - 'audio/skill/jiezhong2.mp3', - 'audio/skill/jiezi1.mp3', - 'audio/skill/jiezi2.mp3', - 'audio/skill/jigong1.mp3', - 'audio/skill/jigong2.mp3', - 'audio/skill/jihun1.mp3', - 'audio/skill/jihun2.mp3', - 'audio/skill/jijiang1_liushan1.mp3', - 'audio/skill/jijiang1_liushan2.mp3', - 'audio/skill/jijiang1_ol_liushan1.mp3', - 'audio/skill/jijiang1_ol_liushan2.mp3', - 'audio/skill/jijiang1_re_liubei1.mp3', - 'audio/skill/jijiang1_re_liubei2.mp3', - 'audio/skill/jijiang1_re_liushan1.mp3', - 'audio/skill/jijiang1_re_liushan2.mp3', - 'audio/skill/jijiang11.mp3', - 'audio/skill/jijiang12.mp3', - 'audio/skill/jijiang2_liushan1.mp3', - 'audio/skill/jijiang2_liushan2.mp3', - 'audio/skill/jijiang21.mp3', - 'audio/skill/jijiang22.mp3', - 'audio/skill/jijing1.mp3', - 'audio/skill/jijing2.mp3', - 'audio/skill/jijiu_re_huatuo1.mp3', - 'audio/skill/jijiu_re_huatuo2.mp3', - 'audio/skill/jijiu1.mp3', - 'audio/skill/jijiu2.mp3', - 'audio/skill/jilei1.mp3', - 'audio/skill/jilei2.mp3', - 'audio/skill/jili1.mp3', - 'audio/skill/jili2.mp3', - 'audio/skill/jilue_fangzhu.mp3', - 'audio/skill/jilue_fangzhu1.mp3', - 'audio/skill/jilue_guicai.mp3', - 'audio/skill/jilue_guicai1.mp3', - 'audio/skill/jilue_jizhi.mp3', - 'audio/skill/jilue_jizhi1.mp3', - 'audio/skill/jilue_wansha.mp3', - 'audio/skill/jilue_zhiheng.mp3', - 'audio/skill/jilue_zhiheng1.mp3', - 'audio/skill/jimeng1.mp3', - 'audio/skill/jimeng2.mp3', - 'audio/skill/jingce1.mp3', - 'audio/skill/jingce2.mp3', - 'audio/skill/jinghe1.mp3', - 'audio/skill/jinghe2.mp3', - 'audio/skill/jinglan1.mp3', - 'audio/skill/jinglan2.mp3', - 'audio/skill/jinglve1.mp3', - 'audio/skill/jinglve2.mp3', - 'audio/skill/jingong1.mp3', - 'audio/skill/jingong2.mp3', - 'audio/skill/jingzhong1.mp3', - 'audio/skill/jingzhong2.mp3', - 'audio/skill/jinhui1.mp3', - 'audio/skill/jinhui2.mp3', - 'audio/skill/jinjian1.mp3', - 'audio/skill/jinjian2.mp3', - 'audio/skill/jinjiu1.mp3', - 'audio/skill/jinjiu2.mp3', - 'audio/skill/jinqu1.mp3', - 'audio/skill/jinqu2.mp3', - 'audio/skill/jintao1.mp3', - 'audio/skill/jintao2.mp3', - 'audio/skill/jinzhi1.mp3', - 'audio/skill/jinzhi2.mp3', - 'audio/skill/jiqiao1.mp3', - 'audio/skill/jiqiao2.mp3', - 'audio/skill/jishe1.mp3', - 'audio/skill/jishe2.mp3', - 'audio/skill/jishi1.mp3', - 'audio/skill/jishi2.mp3', - 'audio/skill/jisi1.mp3', - 'audio/skill/jisi2.mp3', - 'audio/skill/jiuchi_re_dongzhuo1.mp3', - 'audio/skill/jiuchi_re_dongzhuo2.mp3', - 'audio/skill/jiuchi1.mp3', - 'audio/skill/jiuchi2.mp3', - 'audio/skill/jiufa1.mp3', - 'audio/skill/jiufa2.mp3', - 'audio/skill/jiushi11.mp3', - 'audio/skill/jiushi12.mp3', - 'audio/skill/jiushi21.mp3', - 'audio/skill/jiushi22.mp3', - 'audio/skill/jiushi31.mp3', - 'audio/skill/jiushi32.mp3', - 'audio/skill/jiuwei.mp3', - 'audio/skill/jiuyuan1.mp3', - 'audio/skill/jiuyuan2.mp3', - 'audio/skill/jiwu1.mp3', - 'audio/skill/jiwu2.mp3', - 'audio/skill/jixi_gz_dengai1.mp3', - 'audio/skill/jixi_gz_dengai2.mp3', - 'audio/skill/jixi_ol_dengai1.mp3', - 'audio/skill/jixi_ol_dengai2.mp3', - 'audio/skill/jixi_re_dengai1.mp3', - 'audio/skill/jixi_re_dengai2.mp3', - 'audio/skill/jixi1.mp3', - 'audio/skill/jixi2.mp3', - 'audio/skill/jixian1.mp3', - 'audio/skill/jixian2.mp3', - 'audio/skill/jiyu1.mp3', - 'audio/skill/jiyu2.mp3', - 'audio/skill/jizhao1.mp3', - 'audio/skill/jizhao2.mp3', - 'audio/skill/jizhi_jianyong1.mp3', - 'audio/skill/jizhi_jianyong2.mp3', - 'audio/skill/jizhi1.mp3', - 'audio/skill/jizhi2.mp3', - 'audio/skill/jspdanqi1.mp3', - 'audio/skill/jspdanqi2.mp3', - 'audio/skill/juanjia1.mp3', - 'audio/skill/juanjia2.mp3', - 'audio/skill/jubao1.mp3', - 'audio/skill/jubao2.mp3', - 'audio/skill/juece_dc_liru1.mp3', - 'audio/skill/juece_dc_liru2.mp3', - 'audio/skill/juece1.mp3', - 'audio/skill/juece2.mp3', - 'audio/skill/juedi1.mp3', - 'audio/skill/juedi2.mp3', - 'audio/skill/juejing.mp3', - 'audio/skill/jueman1.mp3', - 'audio/skill/jueman2.mp3', - 'audio/skill/jueqing1.mp3', - 'audio/skill/jueqing2.mp3', - 'audio/skill/juesheng1.mp3', - 'audio/skill/juesheng2.mp3', - 'audio/skill/juesi1.mp3', - 'audio/skill/juesi2.mp3', - 'audio/skill/juetao1.mp3', - 'audio/skill/juetao2.mp3', - 'audio/skill/juexiang_he1.mp3', - 'audio/skill/juexiang_ji1.mp3', - 'audio/skill/juexiang_lie1.mp3', - 'audio/skill/juexiang_rou1.mp3', - 'audio/skill/juexiang1.mp3', - 'audio/skill/juexiang2.mp3', - 'audio/skill/jueyong1.mp3', - 'audio/skill/jueyong2.mp3', - 'audio/skill/juezhi1.mp3', - 'audio/skill/juezhi2.mp3', - 'audio/skill/jugu1.mp3', - 'audio/skill/jugu2.mp3', - 'audio/skill/juguan1.mp3', - 'audio/skill/juguan2.mp3', - 'audio/skill/jujian1.mp3', - 'audio/skill/jujian2.mp3', - 'audio/skill/junbing1.mp3', - 'audio/skill/junbing2.mp3', - 'audio/skill/junxing1.mp3', - 'audio/skill/junxing2.mp3', - 'audio/skill/jushou.mp3', - 'audio/skill/jushou1.mp3', - 'audio/skill/jushou2.mp3', - 'audio/skill/juxiang1_ol_zhurong1.mp3', - 'audio/skill/juxiang1_ol_zhurong2.mp3', - 'audio/skill/juxiang1_re_zhurong1.mp3', - 'audio/skill/juxiang1_re_zhurong2.mp3', - 'audio/skill/juxiang11.mp3', - 'audio/skill/juxiang12.mp3', - 'audio/skill/juyi1.mp3', - 'audio/skill/juyi2.mp3', - 'audio/skill/jyishi1.mp3', - 'audio/skill/jyishi2.mp3', - 'audio/skill/jyzongshi_re_jianyong1.mp3', - 'audio/skill/jyzongshi_re_jianyong2.mp3', - 'audio/skill/jyzongshi1.mp3', - 'audio/skill/jyzongshi2.mp3', - 'audio/skill/kaikang1.mp3', - 'audio/skill/kaikang2.mp3', - 'audio/skill/kanade_benzhan1.mp3', - 'audio/skill/kanade_benzhan2.mp3', - 'audio/skill/kanade_benzhan3.mp3', - 'audio/skill/kanade_mapo1.mp3', - 'audio/skill/kanade_mapo2.mp3', - 'audio/skill/kangge1.mp3', - 'audio/skill/kangge2.mp3', - 'audio/skill/kanpo1.mp3', - 'audio/skill/kanpo2.mp3', - 'audio/skill/keji_re_lvmeng1.mp3', - 'audio/skill/keji_re_lvmeng2.mp3', - 'audio/skill/keji1.mp3', - 'audio/skill/keji2.mp3', - 'audio/skill/keshou1.mp3', - 'audio/skill/keshou2.mp3', - 'audio/skill/kongcheng_re_zhugeliang1.mp3', - 'audio/skill/kongcheng_re_zhugeliang2.mp3', - 'audio/skill/kongcheng11.mp3', - 'audio/skill/kongcheng12.mp3', - 'audio/skill/kongsheng1.mp3', - 'audio/skill/kongsheng2.mp3', - 'audio/skill/koulve1.mp3', - 'audio/skill/koulve2.mp3', - 'audio/skill/kousheng1.mp3', - 'audio/skill/kousheng2.mp3', - 'audio/skill/kuangbi1.mp3', - 'audio/skill/kuangbi2.mp3', - 'audio/skill/kuangcai1.mp3', - 'audio/skill/kuangcai2.mp3', - 'audio/skill/kuangfeng1.mp3', - 'audio/skill/kuangfeng2.mp3', - 'audio/skill/kuangfu1.mp3', - 'audio/skill/kuangfu2.mp3', - 'audio/skill/kuanggu_ol_weiyan1.mp3', - 'audio/skill/kuanggu_ol_weiyan2.mp3', - 'audio/skill/kuanggu_re_weiyan1.mp3', - 'audio/skill/kuanggu_re_weiyan2.mp3', - 'audio/skill/kuanggu1.mp3', - 'audio/skill/kuanggu2.mp3', - 'audio/skill/kuanshi1.mp3', - 'audio/skill/kuanshi2.mp3', - 'audio/skill/kuiji1.mp3', - 'audio/skill/kuiji2.mp3', - 'audio/skill/kuimang1.mp3', - 'audio/skill/kuimang2.mp3', - 'audio/skill/kuiwei1.mp3', - 'audio/skill/kuiwei2.mp3', - 'audio/skill/kunfen1.mp3', - 'audio/skill/kunfen2.mp3', - 'audio/skill/kurou1.mp3', - 'audio/skill/kurou2.mp3', - 'audio/skill/kuwu.mp3', - 'audio/skill/laishou1.mp3', - 'audio/skill/laishou2.mp3', - 'audio/skill/laishou3.mp3', - 'audio/skill/langmie1.mp3', - 'audio/skill/langmie2.mp3', - 'audio/skill/lanjiang1.mp3', - 'audio/skill/lanjiang2.mp3', - 'audio/skill/leiji1.mp3', - 'audio/skill/leiji2.mp3', - 'audio/skill/liandui1.mp3', - 'audio/skill/liandui2.mp3', - 'audio/skill/liangcaokuifa.mp3', - 'audio/skill/liangfan1.mp3', - 'audio/skill/liangfan2.mp3', - 'audio/skill/liangjue1.mp3', - 'audio/skill/liangjue2.mp3', - 'audio/skill/liangjunxiangchi.mp3', - 'audio/skill/liangyin1.mp3', - 'audio/skill/liangyin2.mp3', - 'audio/skill/liangying1.mp3', - 'audio/skill/liangyuan1.mp3', - 'audio/skill/liangyuan2.mp3', - 'audio/skill/liangzhu1.mp3', - 'audio/skill/liangzhu2.mp3', - 'audio/skill/lianhuan1.mp3', - 'audio/skill/lianhuan2.mp3', - 'audio/skill/lianhuo1.mp3', - 'audio/skill/lianhuo2.mp3', - 'audio/skill/lianji.mp3', - 'audio/skill/lianpo.mp3', - 'audio/skill/lianpo1.mp3', - 'audio/skill/lianpo2.mp3', - 'audio/skill/lianying1.mp3', - 'audio/skill/lianying2.mp3', - 'audio/skill/lianzhou1.mp3', - 'audio/skill/lianzhou2.mp3', - 'audio/skill/lianzhu1.mp3', - 'audio/skill/lianzhu2.mp3', - 'audio/skill/lianzi1.mp3', - 'audio/skill/lianzi2.mp3', - 'audio/skill/liaoyi1.mp3', - 'audio/skill/liaoyi2.mp3', - 'audio/skill/liechi1.mp3', - 'audio/skill/liechi2.mp3', - 'audio/skill/liedan1.mp3', - 'audio/skill/liedan2.mp3', - 'audio/skill/liegong_ol_huangzhong1.mp3', - 'audio/skill/liegong_ol_huangzhong2.mp3', - 'audio/skill/liegong_re_huangzhong1.mp3', - 'audio/skill/liegong_re_huangzhong2.mp3', - 'audio/skill/liegong1.mp3', - 'audio/skill/liegong2.mp3', - 'audio/skill/liehou1.mp3', - 'audio/skill/liehou2.mp3', - 'audio/skill/liejie1.mp3', - 'audio/skill/liejie2.mp3', - 'audio/skill/lieren_ol_zhurong1.mp3', - 'audio/skill/lieren_ol_zhurong2.mp3', - 'audio/skill/lieren1.mp3', - 'audio/skill/lieren2.mp3', - 'audio/skill/liewei1.mp3', - 'audio/skill/liewei2.mp3', - 'audio/skill/lieyi1.mp3', - 'audio/skill/lieyi2.mp3', - 'audio/skill/liezhi1.mp3', - 'audio/skill/liezhi2.mp3', - 'audio/skill/lihun1.mp3', - 'audio/skill/lihun2.mp3', - 'audio/skill/lihuo_re_chengpu1.mp3', - 'audio/skill/lihuo_re_chengpu2.mp3', - 'audio/skill/lihuo1.mp3', - 'audio/skill/lihuo2.mp3', - 'audio/skill/liji1.mp3', - 'audio/skill/liji2.mp3', - 'audio/skill/lijian_re_diaochan1.mp3', - 'audio/skill/lijian_re_diaochan2.mp3', - 'audio/skill/lijian1.mp3', - 'audio/skill/lijian2.mp3', - 'audio/skill/lingbo1.mp3', - 'audio/skill/lingbo2.mp3', - 'audio/skill/lingce1.mp3', - 'audio/skill/lingce2.mp3', - 'audio/skill/linglong1.mp3', - 'audio/skill/linglong2.mp3', - 'audio/skill/lingren_jianxiong1.mp3', - 'audio/skill/lingren_xingshang1.mp3', - 'audio/skill/lirang1.mp3', - 'audio/skill/lirang2.mp3', - 'audio/skill/lisi1.mp3', - 'audio/skill/lisi2.mp3', - 'audio/skill/liubing1.mp3', - 'audio/skill/liubing2.mp3', - 'audio/skill/liuli_daxiaoqiao1.mp3', - 'audio/skill/liuli_daxiaoqiao2.mp3', - 'audio/skill/liuli_re_daqiao1.mp3', - 'audio/skill/liuli_re_daqiao2.mp3', - 'audio/skill/liuli1.mp3', - 'audio/skill/liuli2.mp3', - 'audio/skill/liunian1.mp3', - 'audio/skill/liunian2.mp3', - 'audio/skill/lixia1.mp3', - 'audio/skill/lixia2.mp3', - 'audio/skill/liyu1.mp3', - 'audio/skill/liyu2.mp3', - 'audio/skill/lizhan1.mp3', - 'audio/skill/lizhan2.mp3', - 'audio/skill/lkbushi1.mp3', - 'audio/skill/lkbushi2.mp3', - 'audio/skill/lkzhongzhuang1.mp3', - 'audio/skill/lkzhongzhuang2.mp3', - 'audio/skill/llqshenwei1.mp3', - 'audio/skill/llqshenwei2.mp3', - 'audio/skill/longdan_sha_re_zhaoyun1.mp3', - 'audio/skill/longdan_sha_re_zhaoyun2.mp3', - 'audio/skill/longdan_sha1.mp3', - 'audio/skill/longdan_sha2.mp3', - 'audio/skill/longdan_tongyuan.mp3', - 'audio/skill/longhun1.mp3', - 'audio/skill/longhun2.mp3', - 'audio/skill/longhun3.mp3', - 'audio/skill/longhun4.mp3', - 'audio/skill/longyin1.mp3', - 'audio/skill/longyin2.mp3', - 'audio/skill/longyuan1.mp3', - 'audio/skill/longyuan2.mp3', - 'audio/skill/lskuizhu1.mp3', - 'audio/skill/lskuizhu2.mp3', - 'audio/skill/lslixun1.mp3', - 'audio/skill/lslixun2.mp3', - 'audio/skill/luanchou1.mp3', - 'audio/skill/luanchou2.mp3', - 'audio/skill/luanfeng1.mp3', - 'audio/skill/luanfeng2.mp3', - 'audio/skill/luanji1.mp3', - 'audio/skill/luanji2.mp3', - 'audio/skill/luanqun1.mp3', - 'audio/skill/luanqun2.mp3', - 'audio/skill/luanwu_re_jiaxu1.mp3', - 'audio/skill/luanwu_re_jiaxu2.mp3', - 'audio/skill/luanwu1.mp3', - 'audio/skill/luanwu2.mp3', - 'audio/skill/luanzhan1.mp3', - 'audio/skill/luanzhan2.mp3', - 'audio/skill/lulve1.mp3', - 'audio/skill/lulve2.mp3', - 'audio/skill/luochong1.mp3', - 'audio/skill/luochong2.mp3', - 'audio/skill/luoshen1.mp3', - 'audio/skill/luoshen2.mp3', - 'audio/skill/luoyi1.mp3', - 'audio/skill/luoyi2.mp3', - 'audio/skill/luoying_discard1.mp3', - 'audio/skill/luoying_discard2.mp3', - 'audio/skill/luoying_judge1.mp3', - 'audio/skill/luoying_judge2.mp3', - 'audio/skill/luoying1.mp3', - 'audio/skill/luoying2.mp3', - 'audio/skill/lvli1.mp3', - 'audio/skill/lvli2.mp3', - 'audio/skill/lxzhuixi1.mp3', - 'audio/skill/lxzhuixi2.mp3', - 'audio/skill/maihuo1.mp3', - 'audio/skill/maihuo2.mp3', - 'audio/skill/manji1.mp3', - 'audio/skill/manji2.mp3', - 'audio/skill/manjuan.mp3', - 'audio/skill/mansi1.mp3', - 'audio/skill/mansi2.mp3', - 'audio/skill/manyi_mengyou1.mp3', - 'audio/skill/manyi_mengyou2.mp3', - 'audio/skill/manyi1.mp3', - 'audio/skill/manyi2.mp3', - 'audio/skill/mazui.mp3', - 'audio/skill/mbaosi1.mp3', - 'audio/skill/mbaosi2.mp3', - 'audio/skill/mbdaoshu1.mp3', - 'audio/skill/mbdaoshu2.mp3', - 'audio/skill/mbdaoshu3.mp3', - 'audio/skill/mbguli1.mp3', - 'audio/skill/mbguli2.mp3', - 'audio/skill/mbhuiyao1.mp3', - 'audio/skill/mbhuiyao2.mp3', - 'audio/skill/mbquesong1.mp3', - 'audio/skill/mbquesong2.mp3', - 'audio/skill/mbshihe1.mp3', - 'audio/skill/mbshihe2.mp3', - 'audio/skill/mbyilie1.mp3', - 'audio/skill/mbyilie2.mp3', - 'audio/skill/mbyilie3.mp3', - 'audio/skill/mbzhenfu1.mp3', - 'audio/skill/mbzhenfu2.mp3', - 'audio/skill/meibu1.mp3', - 'audio/skill/meibu2.mp3', - 'audio/skill/meihun1.mp3', - 'audio/skill/meihun2.mp3', - 'audio/skill/mengjin1.mp3', - 'audio/skill/mengjin2.mp3', - 'audio/skill/mengqing1.mp3', - 'audio/skill/mengqing2.mp3', - 'audio/skill/mffengshi_sp_mifangfushiren1.mp3', - 'audio/skill/mffengshi_sp_mifangfushiren2.mp3', - 'audio/skill/mffengshi1.mp3', - 'audio/skill/mffengshi2.mp3', - 'audio/skill/miaojian1.mp3', - 'audio/skill/miaojian2.mp3', - 'audio/skill/miaoxian1.mp3', - 'audio/skill/miaoxian2.mp3', - 'audio/skill/mibei1.mp3', - 'audio/skill/mibei2.mp3', - 'audio/skill/midao1.mp3', - 'audio/skill/midao2.mp3', - 'audio/skill/midu1.mp3', - 'audio/skill/midu2.mp3', - 'audio/skill/mieji1.mp3', - 'audio/skill/mieji2.mp3', - 'audio/skill/miji_re_wangyi1.mp3', - 'audio/skill/miji_re_wangyi2.mp3', - 'audio/skill/miji1.mp3', - 'audio/skill/miji2.mp3', - 'audio/skill/mingce1.mp3', - 'audio/skill/mingce2.mp3', - 'audio/skill/mingcha1.mp3', - 'audio/skill/mingcha2.mp3', - 'audio/skill/mingfa1.mp3', - 'audio/skill/mingfa2.mp3', - 'audio/skill/mingjian1.mp3', - 'audio/skill/mingjian2.mp3', - 'audio/skill/mingjie1.mp3', - 'audio/skill/mingluan1.mp3', - 'audio/skill/mingluan2.mp3', - 'audio/skill/mingshi1.mp3', - 'audio/skill/mingshi2.mp3', - 'audio/skill/mingzhe1.mp3', - 'audio/skill/mingzhe2.mp3', - 'audio/skill/minsi1.mp3', - 'audio/skill/minsi2.mp3', - 'audio/skill/mizhao1.mp3', - 'audio/skill/mizhao2.mp3', - 'audio/skill/mjchenshi1.mp3', - 'audio/skill/mjchenshi2.mp3', - 'audio/skill/mjdingyi1.mp3', - 'audio/skill/mjdingyi2.mp3', - 'audio/skill/mjmouzhi1.mp3', - 'audio/skill/mjmouzhi2.mp3', - 'audio/skill/mjweipo1.mp3', - 'audio/skill/mjweipo2.mp3', - 'audio/skill/mobiledanshou1.mp3', - 'audio/skill/mobiledanshou2.mp3', - 'audio/skill/mobilejingce1.mp3', - 'audio/skill/mobilejingce2.mp3', - 'audio/skill/mobilexingxue1.mp3', - 'audio/skill/mobilexingxue2.mp3', - 'audio/skill/mobileyanzhu1.mp3', - 'audio/skill/mobileyanzhu2.mp3', - 'audio/skill/mobilezhongyong1.mp3', - 'audio/skill/mobilezhongyong2.mp3', - 'audio/skill/monkey.mp3', - 'audio/skill/moucheng1.mp3', - 'audio/skill/moucheng2.mp3', - 'audio/skill/moucuan1.mp3', - 'audio/skill/moucuan2.mp3', - 'audio/skill/moukui1.mp3', - 'audio/skill/moukui2.mp3', - 'audio/skill/mouli1.mp3', - 'audio/skill/mouli2.mp3', - 'audio/skill/mouni1.mp3', - 'audio/skill/mouni2.mp3', - 'audio/skill/mouzhi1.mp3', - 'audio/skill/mouzhi2.mp3', - 'audio/skill/mouzhu1.mp3', - 'audio/skill/mouzhu2.mp3', - 'audio/skill/mozhi1.mp3', - 'audio/skill/mozhi2.mp3', - 'audio/skill/mpbishi1.mp3', - 'audio/skill/mpbishi2.mp3', - 'audio/skill/mpjiusong1.mp3', - 'audio/skill/mpjiusong2.mp3', - 'audio/skill/mpmaotao1.mp3', - 'audio/skill/mpmaotao2.mp3', - 'audio/skill/mubing1.mp3', - 'audio/skill/mubing2.mp3', - 'audio/skill/mumu1.mp3', - 'audio/skill/mumu2.mp3', - 'audio/skill/muzhen1.mp3', - 'audio/skill/muzhen2.mp3', - 'audio/skill/naman1.mp3', - 'audio/skill/naman2.mp3', - 'audio/skill/naxiang1.mp3', - 'audio/skill/naxiang2.mp3', - 'audio/skill/naxue1.mp3', - 'audio/skill/naxue2.mp3', - 'audio/skill/neifa1.mp3', - 'audio/skill/neifa2.mp3', - 'audio/skill/new_jiangchi1.mp3', - 'audio/skill/new_jiangchi2.mp3', - 'audio/skill/new_reqingnang1.mp3', - 'audio/skill/new_reqingnang2.mp3', - 'audio/skill/new_reyaowu_sb_huaxiong1.mp3', - 'audio/skill/new_reyaowu_sb_huaxiong2.mp3', - 'audio/skill/new_reyaowu1.mp3', - 'audio/skill/new_reyaowu2.mp3', - 'audio/skill/niepan_re_pangtong1.mp3', - 'audio/skill/niepan_re_pangtong2.mp3', - 'audio/skill/niepan1.mp3', - 'audio/skill/niepan2.mp3', - 'audio/skill/nifu1.mp3', - 'audio/skill/nifu2.mp3', - 'audio/skill/niluan1.mp3', - 'audio/skill/niluan2.mp3', - 'audio/skill/noda_fengcheng1.mp3', - 'audio/skill/noda_fengcheng2.mp3', - 'audio/skill/noda_xunxin1.mp3', - 'audio/skill/noda_xunxin2.mp3', - 'audio/skill/ns_nsshimeng1.mp3', - 'audio/skill/ns_nsshimeng2.mp3', - 'audio/skill/nzry_binglve1.mp3', - 'audio/skill/nzry_binglve2.mp3', - 'audio/skill/nzry_chenglve1.mp3', - 'audio/skill/nzry_chenglve2.mp3', - 'audio/skill/nzry_cuike1.mp3', - 'audio/skill/nzry_cuike2.mp3', - 'audio/skill/nzry_cunmu1.mp3', - 'audio/skill/nzry_cunmu2.mp3', - 'audio/skill/nzry_dinghuo1.mp3', - 'audio/skill/nzry_dinghuo2.mp3', - 'audio/skill/nzry_feijun1.mp3', - 'audio/skill/nzry_feijun2.mp3', - 'audio/skill/nzry_huaiju1.mp3', - 'audio/skill/nzry_huaiju2.mp3', - 'audio/skill/nzry_jianxiang1.mp3', - 'audio/skill/nzry_jianxiang2.mp3', - 'audio/skill/nzry_jieying1.mp3', - 'audio/skill/nzry_jieying2.mp3', - 'audio/skill/nzry_junlve1.mp3', - 'audio/skill/nzry_junlve2.mp3', - 'audio/skill/nzry_juzhan_11.mp3', - 'audio/skill/nzry_juzhan_12.mp3', - 'audio/skill/nzry_kuizhu1.mp3', - 'audio/skill/nzry_kuizhu2.mp3', - 'audio/skill/nzry_lijun11.mp3', - 'audio/skill/nzry_lijun12.mp3', - 'audio/skill/nzry_longnu1.mp3', - 'audio/skill/nzry_longnu2.mp3', - 'audio/skill/nzry_mingren_1_sb_yl_luzhi1.mp3', - 'audio/skill/nzry_mingren_1_sb_yl_luzhi2.mp3', - 'audio/skill/nzry_mingren_11.mp3', - 'audio/skill/nzry_mingren_12.mp3', - 'audio/skill/nzry_shenshi_11.mp3', - 'audio/skill/nzry_shenshi_12.mp3', - 'audio/skill/nzry_shicai_21.mp3', - 'audio/skill/nzry_shicai_22.mp3', - 'audio/skill/nzry_yili1.mp3', - 'audio/skill/nzry_yili2.mp3', - 'audio/skill/nzry_zhenglun1.mp3', - 'audio/skill/nzry_zhenglun2.mp3', - 'audio/skill/nzry_zhenliang_11.mp3', - 'audio/skill/nzry_zhenliang_12.mp3', - 'audio/skill/nzry_zhizheng1.mp3', - 'audio/skill/nzry_zhizheng2.mp3', - 'audio/skill/ocongjian_tongyuan.mp3', - 'audio/skill/ol_shenfen1.mp3', - 'audio/skill/ol_shenfen2.mp3', - 'audio/skill/ol_shichou1.mp3', - 'audio/skill/ol_shichou2.mp3', - 'audio/skill/ol_wuqian1.mp3', - 'audio/skill/ol_wuqian2.mp3', - 'audio/skill/olbaonue1.mp3', - 'audio/skill/olbaonue2.mp3', - 'audio/skill/olbeige1.mp3', - 'audio/skill/olbeige2.mp3', - 'audio/skill/olbihun1.mp3', - 'audio/skill/olbihun2.mp3', - 'audio/skill/olbixin1.mp3', - 'audio/skill/olbixin2.mp3', - 'audio/skill/olchanshuang1.mp3', - 'audio/skill/olchanshuang2.mp3', - 'audio/skill/olchenglie1.mp3', - 'audio/skill/olchenglie2.mp3', - 'audio/skill/olchenshuo1.mp3', - 'audio/skill/olchenshuo2.mp3', - 'audio/skill/olchongshen1.mp3', - 'audio/skill/olchongshen2.mp3', - 'audio/skill/olchuanwu1.mp3', - 'audio/skill/olchuanwu2.mp3', - 'audio/skill/olchuming1.mp3', - 'audio/skill/olchuming2.mp3', - 'audio/skill/olcuipo1.mp3', - 'audio/skill/olcuipo2.mp3', - 'audio/skill/old_fuhun1.mp3', - 'audio/skill/old_fuhun2.mp3', - 'audio/skill/old_guhuo1.mp3', - 'audio/skill/old_guhuo2.mp3', - 'audio/skill/oldaili1.mp3', - 'audio/skill/oldaili2.mp3', - 'audio/skill/oldianjun1.mp3', - 'audio/skill/oldianjun2.mp3', - 'audio/skill/oldimeng1.mp3', - 'audio/skill/oldimeng2.mp3', - 'audio/skill/oldingcuo1.mp3', - 'audio/skill/oldingcuo2.mp3', - 'audio/skill/oldmiji1.mp3', - 'audio/skill/oldmiji2.mp3', - 'audio/skill/oldongdao1.mp3', - 'audio/skill/oldongdao2.mp3', - 'audio/skill/oldqianxi1.mp3', - 'audio/skill/oldqianxi2.mp3', - 'audio/skill/olduanliang1.mp3', - 'audio/skill/olduanliang2.mp3', - 'audio/skill/oldzhenlie1.mp3', - 'audio/skill/oldzhenlie2.mp3', - 'audio/skill/olfangquan_shen_caopi1.mp3', - 'audio/skill/olfangquan_shen_caopi2.mp3', - 'audio/skill/olfangquan1.mp3', - 'audio/skill/olfangquan2.mp3', - 'audio/skill/olfeibai1.mp3', - 'audio/skill/olfeibai2.mp3', - 'audio/skill/olfengji1.mp3', - 'audio/skill/olfengji2.mp3', - 'audio/skill/olfengyan1.mp3', - 'audio/skill/olfengyan2.mp3', - 'audio/skill/olfengzi1.mp3', - 'audio/skill/olfengzi2.mp3', - 'audio/skill/olfudao1.mp3', - 'audio/skill/olfudao2.mp3', - 'audio/skill/olfushi1.mp3', - 'audio/skill/olfushi2.mp3', - 'audio/skill/olfusong1.mp3', - 'audio/skill/olfusong2.mp3', - 'audio/skill/olgangshu1.mp3', - 'audio/skill/olgangshu2.mp3', - 'audio/skill/olgongjie1.mp3', - 'audio/skill/olgongjie2.mp3', - 'audio/skill/olgoude1.mp3', - 'audio/skill/olgoude2.mp3', - 'audio/skill/olguangao1.mp3', - 'audio/skill/olguangao2.mp3', - 'audio/skill/olguzheng1.mp3', - 'audio/skill/olguzheng2.mp3', - 'audio/skill/olhaoshi1.mp3', - 'audio/skill/olhaoshi2.mp3', - 'audio/skill/olhongji1.mp3', - 'audio/skill/olhongji2.mp3', - 'audio/skill/olhuanfu1.mp3', - 'audio/skill/olhuanfu2.mp3', - 'audio/skill/olhuiqi1.mp3', - 'audio/skill/olhuiqi2.mp3', - 'audio/skill/olhuiyun1.mp3', - 'audio/skill/olhuiyun2.mp3', - 'audio/skill/olhunzi_re_sunyi1.mp3', - 'audio/skill/olhunzi_re_sunyi2.mp3', - 'audio/skill/olhunzi1.mp3', - 'audio/skill/olhunzi2.mp3', - 'audio/skill/oljianhe1.mp3', - 'audio/skill/oljianhe2.mp3', - 'audio/skill/oljianman1.mp3', - 'audio/skill/oljianman2.mp3', - 'audio/skill/oljianxuan1.mp3', - 'audio/skill/oljianxuan2.mp3', - 'audio/skill/oljieming1.mp3', - 'audio/skill/oljieming2.mp3', - 'audio/skill/oljiezi1.mp3', - 'audio/skill/oljiezi2.mp3', - 'audio/skill/oljiuchi1.mp3', - 'audio/skill/oljiuchi2.mp3', - 'audio/skill/oljizhan1.mp3', - 'audio/skill/oljizhan2.mp3', - 'audio/skill/oljuanxia1.mp3', - 'audio/skill/oljuanxia2.mp3', - 'audio/skill/olkangrui1.mp3', - 'audio/skill/olkangrui2.mp3', - 'audio/skill/olkenshang1.mp3', - 'audio/skill/olkenshang2.mp3', - 'audio/skill/olkuansai1.mp3', - 'audio/skill/olkuansai2.mp3', - 'audio/skill/ollangdao1.mp3', - 'audio/skill/ollangdao2.mp3', - 'audio/skill/olleijie1.mp3', - 'audio/skill/olleijie2.mp3', - 'audio/skill/olluanji_shen_caopi1.mp3', - 'audio/skill/olluanji_shen_caopi2.mp3', - 'audio/skill/olluanji1.mp3', - 'audio/skill/olluanji2.mp3', - 'audio/skill/olmiuyan1.mp3', - 'audio/skill/olmiuyan2.mp3', - 'audio/skill/olniepan1.mp3', - 'audio/skill/olniepan2.mp3', - 'audio/skill/olningwu1.mp3', - 'audio/skill/olningwu2.mp3', - 'audio/skill/olnishou1.mp3', - 'audio/skill/olnishou2.mp3', - 'audio/skill/olqiejian1.mp3', - 'audio/skill/olqiejian2.mp3', - 'audio/skill/olqingyi1.mp3', - 'audio/skill/olqingyi2.mp3', - 'audio/skill/olqingyuan1.mp3', - 'audio/skill/olqingyuan2.mp3', - 'audio/skill/olqisi1.mp3', - 'audio/skill/olqisi2.mp3', - 'audio/skill/olqushi1.mp3', - 'audio/skill/olqushi2.mp3', - 'audio/skill/olruoyu1.mp3', - 'audio/skill/olruoyu2.mp3', - 'audio/skill/olsaogu1.mp3', - 'audio/skill/olsaogu2.mp3', - 'audio/skill/olsbdouchan1.mp3', - 'audio/skill/olsbdouchan2.mp3', - 'audio/skill/olsbdulie1.mp3', - 'audio/skill/olsbdulie2.mp3', - 'audio/skill/olsbduoshou1.mp3', - 'audio/skill/olsbduoshou2.mp3', - 'audio/skill/olsbfumeng1.mp3', - 'audio/skill/olsbfumeng2.mp3', - 'audio/skill/olsbguidao1.mp3', - 'audio/skill/olsbguidao2.mp3', - 'audio/skill/olsbhetao_ol_sb_yuanshao_shadow1.mp3', - 'audio/skill/olsbhetao_ol_sb_yuanshao_shadow2.mp3', - 'audio/skill/olsbhetao_ol_sb_yuanshao_shadow3.mp3', - 'audio/skill/olsbhetao1.mp3', - 'audio/skill/olsbhetao2.mp3', - 'audio/skill/olsbhetao3.mp3', - 'audio/skill/olsbranji1.mp3', - 'audio/skill/olsbranji2.mp3', - 'audio/skill/olsbshenli_ol_sb_yuanshao_shadow1.mp3', - 'audio/skill/olsbshenli_ol_sb_yuanshao_shadow2.mp3', - 'audio/skill/olsbshenli_ol_sb_yuanshao_shadow3.mp3', - 'audio/skill/olsbshenli1.mp3', - 'audio/skill/olsbshenli2.mp3', - 'audio/skill/olsbshenli3.mp3', - 'audio/skill/olsbshishou_ol_sb_yuanshao_shadow1.mp3', - 'audio/skill/olsbshishou_ol_sb_yuanshao_shadow2.mp3', - 'audio/skill/olsbshishou_ol_sb_yuanshao_shadow3.mp3', - 'audio/skill/olsbshishou1.mp3', - 'audio/skill/olsbshishou2.mp3', - 'audio/skill/olsbshishou3.mp3', - 'audio/skill/olsbweilin1.mp3', - 'audio/skill/olsbweilin2.mp3', - 'audio/skill/olsbyufeng_ol_sb_yuanshao_shadow1.mp3', - 'audio/skill/olsbyufeng1.mp3', - 'audio/skill/olsbyufeng2.mp3', - 'audio/skill/olsbzhuri1.mp3', - 'audio/skill/olsbzhuri2.mp3', - 'audio/skill/olshandao1.mp3', - 'audio/skill/olshandao2.mp3', - 'audio/skill/olshengong1.mp3', - 'audio/skill/olshengong2.mp3', - 'audio/skill/olshilu1.mp3', - 'audio/skill/olshilu2.mp3', - 'audio/skill/olshuangxiong1.mp3', - 'audio/skill/olshuangxiong2.mp3', - 'audio/skill/olsuji1.mp3', - 'audio/skill/olsuji2.mp3', - 'audio/skill/olsujian1.mp3', - 'audio/skill/olsujian2.mp3', - 'audio/skill/oltianhou_club.mp3', - 'audio/skill/oltianhou_diamond.mp3', - 'audio/skill/oltianhou_heart.mp3', - 'audio/skill/oltianhou_spade.mp3', - 'audio/skill/oltianhou1.mp3', - 'audio/skill/oltianhou2.mp3', - 'audio/skill/oltongduo1.mp3', - 'audio/skill/oltongduo2.mp3', - 'audio/skill/oltousui1.mp3', - 'audio/skill/oltousui2.mp3', - 'audio/skill/oltuntian1.mp3', - 'audio/skill/oltuntian2.mp3', - 'audio/skill/olweifu1.mp3', - 'audio/skill/olweifu2.mp3', - 'audio/skill/olweijie1.mp3', - 'audio/skill/olweijie2.mp3', - 'audio/skill/olxianbi1.mp3', - 'audio/skill/olxianbi2.mp3', - 'audio/skill/olxiangxv1.mp3', - 'audio/skill/olxiangxv2.mp3', - 'audio/skill/olxiangzuo1.mp3', - 'audio/skill/olxiangzuo2.mp3', - 'audio/skill/olxianlve1.mp3', - 'audio/skill/olxianlve2.mp3', - 'audio/skill/olxiaosi1.mp3', - 'audio/skill/olxiaosi2.mp3', - 'audio/skill/olxibing1.mp3', - 'audio/skill/olxibing2.mp3', - 'audio/skill/olxieju1.mp3', - 'audio/skill/olxieju2.mp3', - 'audio/skill/olximo1.mp3', - 'audio/skill/olximo2.mp3', - 'audio/skill/olximo3.mp3', - 'audio/skill/olxinggu1.mp3', - 'audio/skill/olxinggu2.mp3', - 'audio/skill/olxiuhao1.mp3', - 'audio/skill/olxiuhao2.mp3', - 'audio/skill/olxueyi1.mp3', - 'audio/skill/olxueyi2.mp3', - 'audio/skill/olzaowang1.mp3', - 'audio/skill/olzaowang2.mp3', - 'audio/skill/olzaoxian1.mp3', - 'audio/skill/olzaoxian2.mp3', - 'audio/skill/olzenrun1.mp3', - 'audio/skill/olzenrun2.mp3', - 'audio/skill/olzeyue1.mp3', - 'audio/skill/olzeyue2.mp3', - 'audio/skill/olzhanjin1.mp3', - 'audio/skill/olzhanjin2.mp3', - 'audio/skill/olzhenying1.mp3', - 'audio/skill/olzhenying2.mp3', - 'audio/skill/olzhiba1.mp3', - 'audio/skill/olzhiba2.mp3', - 'audio/skill/olzhiji1.mp3', - 'audio/skill/olzhiji2.mp3', - 'audio/skill/olzhijian1.mp3', - 'audio/skill/olzhijian2.mp3', - 'audio/skill/olzhubi1.mp3', - 'audio/skill/olzhubi2.mp3', - 'audio/skill/olzhuyan1.mp3', - 'audio/skill/olzhuyan2.mp3', - 'audio/skill/paiyi_re_zhonghui1.mp3', - 'audio/skill/paiyi_re_zhonghui2.mp3', - 'audio/skill/paiyi1.mp3', - 'audio/skill/paiyi2.mp3', - 'audio/skill/paoxiao_guanzhang1.mp3', - 'audio/skill/paoxiao_guanzhang2.mp3', - 'audio/skill/paoxiao_re_guanzhang1.mp3', - 'audio/skill/paoxiao_re_guanzhang2.mp3', - 'audio/skill/paoxiao_re_zhangfei1.mp3', - 'audio/skill/paoxiao_re_zhangfei2.mp3', - 'audio/skill/paoxiao_xiahouba1.mp3', - 'audio/skill/paoxiao_xiahouba2.mp3', - 'audio/skill/paoxiao1.mp3', - 'audio/skill/paoxiao2.mp3', - 'audio/skill/pcaudio_fengchu_card.mp3', - 'audio/skill/pcaudio_shuijing_card.mp3', - 'audio/skill/pcaudio_wolong_card.mp3', - 'audio/skill/pcaudio_xuanjian_card.mp3', - 'audio/skill/pianchong1.mp3', - 'audio/skill/pianchong2.mp3', - 'audio/skill/pianyi1.mp3', - 'audio/skill/pianyi2.mp3', - 'audio/skill/piaoling1.mp3', - 'audio/skill/piaoling2.mp3', - 'audio/skill/piaoping1.mp3', - 'audio/skill/piaoping2.mp3', - 'audio/skill/pindi1.mp3', - 'audio/skill/pindi2.mp3', - 'audio/skill/pinghe1.mp3', - 'audio/skill/pinghe2.mp3', - 'audio/skill/pingjian1.mp3', - 'audio/skill/pingjian2.mp3', - 'audio/skill/pingkou1.mp3', - 'audio/skill/pingkou2.mp3', - 'audio/skill/pingxiang1.mp3', - 'audio/skill/pingxiang2.mp3', - 'audio/skill/pojun1.mp3', - 'audio/skill/pojun2.mp3', - 'audio/skill/polu1.mp3', - 'audio/skill/polu2.mp3', - 'audio/skill/poxiang1.mp3', - 'audio/skill/poxiang2.mp3', - 'audio/skill/pozhu1.mp3', - 'audio/skill/pozhu2.mp3', - 'audio/skill/pytianjiang1.mp3', - 'audio/skill/pytianjiang2.mp3', - 'audio/skill/pyzhuren1.mp3', - 'audio/skill/pyzhuren2.mp3', - 'audio/skill/qhzhangji1.mp3', - 'audio/skill/qhzhangji2.mp3', - 'audio/skill/qiangwu1.mp3', - 'audio/skill/qiangwu2.mp3', - 'audio/skill/qiangxi_boss_lvbu31.mp3', - 'audio/skill/qiangxi_boss_lvbu32.mp3', - 'audio/skill/qiangxi_ol_dianwei1.mp3', - 'audio/skill/qiangxi_ol_dianwei2.mp3', - 'audio/skill/qiangxi1.mp3', - 'audio/skill/qiangxi2.mp3', - 'audio/skill/qiangzhi_re_zhangsong1.mp3', - 'audio/skill/qiangzhi_re_zhangsong2.mp3', - 'audio/skill/qiangzhi1.mp3', - 'audio/skill/qiangzhi2.mp3', - 'audio/skill/qianhuan1.mp3', - 'audio/skill/qianhuan2.mp3', - 'audio/skill/qianlong1.mp3', - 'audio/skill/qianlong2.mp3', - 'audio/skill/qianmeng1.mp3', - 'audio/skill/qianmeng2.mp3', - 'audio/skill/qianxi1.mp3', - 'audio/skill/qianxi2.mp3', - 'audio/skill/qianxin1.mp3', - 'audio/skill/qianxin2.mp3', - 'audio/skill/qianxun1.mp3', - 'audio/skill/qianxun2.mp3', - 'audio/skill/qianya1.mp3', - 'audio/skill/qianya2.mp3', - 'audio/skill/qiaobian1.mp3', - 'audio/skill/qiaobian2.mp3', - 'audio/skill/qiaoli1.mp3', - 'audio/skill/qiaoli2.mp3', - 'audio/skill/qiaomeng1.mp3', - 'audio/skill/qiaomeng2.mp3', - 'audio/skill/qiaoshi1.mp3', - 'audio/skill/qiaoshi2.mp3', - 'audio/skill/qiaoshui1.mp3', - 'audio/skill/qiaoshui2.mp3', - 'audio/skill/qiaoyan1.mp3', - 'audio/skill/qiaoyan2.mp3', - 'audio/skill/qibaodao2.mp3', - 'audio/skill/qibie1.mp3', - 'audio/skill/qibie2.mp3', - 'audio/skill/qice_clan_xunyou1.mp3', - 'audio/skill/qice_clan_xunyou2.mp3', - 'audio/skill/qice1.mp3', - 'audio/skill/qice2.mp3', - 'audio/skill/qieting1.mp3', - 'audio/skill/qieting2.mp3', - 'audio/skill/qiexie1.mp3', - 'audio/skill/qiexie2.mp3', - 'audio/skill/qigong1.mp3', - 'audio/skill/qigong2.mp3', - 'audio/skill/qilin_skill.mp3', - 'audio/skill/qiluan21.mp3', - 'audio/skill/qiluan22.mp3', - 'audio/skill/qimei1.mp3', - 'audio/skill/qimei2.mp3', - 'audio/skill/qimou1.mp3', - 'audio/skill/qimou2.mp3', - 'audio/skill/qinbao1.mp3', - 'audio/skill/qinbao2.mp3', - 'audio/skill/qingbei1.mp3', - 'audio/skill/qingbei2.mp3', - 'audio/skill/qingcheng1.mp3', - 'audio/skill/qingcheng2.mp3', - 'audio/skill/qinggang_skill.mp3', - 'audio/skill/qingguo_sb_zhenji1.mp3', - 'audio/skill/qingguo_sb_zhenji2.mp3', - 'audio/skill/qingguo1.mp3', - 'audio/skill/qingguo2.mp3', - 'audio/skill/qingjian1.mp3', - 'audio/skill/qingjian2.mp3', - 'audio/skill/qingjiao1.mp3', - 'audio/skill/qingjiao2.mp3', - 'audio/skill/qingjue1.mp3', - 'audio/skill/qingjue2.mp3', - 'audio/skill/qingleng1.mp3', - 'audio/skill/qingleng2.mp3', - 'audio/skill/qingliang1.mp3', - 'audio/skill/qingliang2.mp3', - 'audio/skill/qinglong_skill.mp3', - 'audio/skill/qingman1.mp3', - 'audio/skill/qingman2.mp3', - 'audio/skill/qingnang1.mp3', - 'audio/skill/qingnang2.mp3', - 'audio/skill/qingtan1.mp3', - 'audio/skill/qingtan2.mp3', - 'audio/skill/qinguo_lose1.mp3', - 'audio/skill/qinguo_lose2.mp3', - 'audio/skill/qinguo_use1.mp3', - 'audio/skill/qinguo_use2.mp3', - 'audio/skill/qingxi1.mp3', - 'audio/skill/qingxi2.mp3', - 'audio/skill/qingxian1.mp3', - 'audio/skill/qingxian2.mp3', - 'audio/skill/qingyi1.mp3', - 'audio/skill/qingyi2.mp3', - 'audio/skill/qingyin1.mp3', - 'audio/skill/qingyin2.mp3', - 'audio/skill/qingyu1.mp3', - 'audio/skill/qingyu2.mp3', - 'audio/skill/qingyu3.mp3', - 'audio/skill/qingzhong1.mp3', - 'audio/skill/qingzhong2.mp3', - 'audio/skill/qinqing1.mp3', - 'audio/skill/qinqing2.mp3', - 'audio/skill/qinwang11.mp3', - 'audio/skill/qinwang12.mp3', - 'audio/skill/qinwang21.mp3', - 'audio/skill/qinwang22.mp3', - 'audio/skill/qinxue1.mp3', - 'audio/skill/qinxue2.mp3', - 'audio/skill/qinyin1.mp3', - 'audio/skill/qinyin2.mp3', - 'audio/skill/qinzheng1.mp3', - 'audio/skill/qinzheng2.mp3', - 'audio/skill/qiongshou1.mp3', - 'audio/skill/qiongshou2.mp3', - 'audio/skill/qirang1.mp3', - 'audio/skill/qirang2.mp3', - 'audio/skill/qiuan1.mp3', - 'audio/skill/qiuan2.mp3', - 'audio/skill/qiuyuan1.mp3', - 'audio/skill/qiuyuan2.mp3', - 'audio/skill/qiwu.mp3', - 'audio/skill/qixi_re_ganning1.mp3', - 'audio/skill/qixi_re_ganning2.mp3', - 'audio/skill/qixi_re_heqi1.mp3', - 'audio/skill/qixi_re_heqi2.mp3', - 'audio/skill/qixi1.mp3', - 'audio/skill/qixi2.mp3', - 'audio/skill/qixing1.mp3', - 'audio/skill/qixing2.mp3', - 'audio/skill/qizhi1.mp3', - 'audio/skill/qizhi2.mp3', - 'audio/skill/qljsuiren1.mp3', - 'audio/skill/qljsuiren2.mp3', - 'audio/skill/quanbian1.mp3', - 'audio/skill/quanbian2.mp3', - 'audio/skill/quanfeng1.mp3', - 'audio/skill/quanfeng2.mp3', - 'audio/skill/quanji1.mp3', - 'audio/skill/quanji2.mp3', - 'audio/skill/quanjin1.mp3', - 'audio/skill/quanjin2.mp3', - 'audio/skill/quanjiu1.mp3', - 'audio/skill/quanjiu2.mp3', - 'audio/skill/quhu_ol_xunyu1.mp3', - 'audio/skill/quhu_ol_xunyu2.mp3', - 'audio/skill/quhu_re_xunyu1.mp3', - 'audio/skill/quhu_re_xunyu2.mp3', - 'audio/skill/quhu1.mp3', - 'audio/skill/quhu2.mp3', - 'audio/skill/quji1.mp3', - 'audio/skill/quji2.mp3', - 'audio/skill/quxi1.mp3', - 'audio/skill/quxi2.mp3', - 'audio/skill/rangjie1.mp3', - 'audio/skill/rangjie2.mp3', - 'audio/skill/ranshang1.mp3', - 'audio/skill/ranshang2.mp3', - 'audio/skill/ranshang21.mp3', - 'audio/skill/ranshang22.mp3', - 'audio/skill/reandong1.mp3', - 'audio/skill/reandong2.mp3', - 'audio/skill/reanguo1.mp3', - 'audio/skill/reanguo2.mp3', - 'audio/skill/reanjian1.mp3', - 'audio/skill/reanjian2.mp3', - 'audio/skill/reanxu1.mp3', - 'audio/skill/reanxu2.mp3', - 'audio/skill/rebaobian1.mp3', - 'audio/skill/rebaobian2.mp3', - 'audio/skill/rebingyi1.mp3', - 'audio/skill/rebingyi2.mp3', - 'audio/skill/rebiyue1.mp3', - 'audio/skill/rebiyue2.mp3', - 'audio/skill/rebizhuan1.mp3', - 'audio/skill/rebizhuan2.mp3', - 'audio/skill/recangchu1.mp3', - 'audio/skill/recangchu2.mp3', - 'audio/skill/rechanhui1.mp3', - 'audio/skill/rechanhui2.mp3', - 'audio/skill/rechanyuan1.mp3', - 'audio/skill/rechanyuan2.mp3', - 'audio/skill/rechengxiang1.mp3', - 'audio/skill/rechengxiang2.mp3', - 'audio/skill/rechunlao1.mp3', - 'audio/skill/rechunlao2.mp3', - 'audio/skill/redanxin1.mp3', - 'audio/skill/redanxin2.mp3', - 'audio/skill/redaoji1.mp3', - 'audio/skill/redaoji2.mp3', - 'audio/skill/redingpin1.mp3', - 'audio/skill/redingpin2.mp3', - 'audio/skill/reduodao1.mp3', - 'audio/skill/reduodao2.mp3', - 'audio/skill/reenyuan1.mp3', - 'audio/skill/reenyuan2.mp3', - 'audio/skill/refaen_dc_chenqun1.mp3', - 'audio/skill/refaen_dc_chenqun2.mp3', - 'audio/skill/refaen1.mp3', - 'audio/skill/refaen2.mp3', - 'audio/skill/refangquan1.mp3', - 'audio/skill/refangquan2.mp3', - 'audio/skill/refangzhu1.mp3', - 'audio/skill/refangzhu2.mp3', - 'audio/skill/refanjian1.mp3', - 'audio/skill/refanjian2.mp3', - 'audio/skill/refankui1.mp3', - 'audio/skill/refankui2.mp3', - 'audio/skill/refenglve1.mp3', - 'audio/skill/refenglve2.mp3', - 'audio/skill/refenli1.mp3', - 'audio/skill/refenli2.mp3', - 'audio/skill/refenyin_wufan1.mp3', - 'audio/skill/refenyin_wufan2.mp3', - 'audio/skill/refenyin1.mp3', - 'audio/skill/refenyin2.mp3', - 'audio/skill/refuli1.mp3', - 'audio/skill/refuli2.mp3', - 'audio/skill/refuman1.mp3', - 'audio/skill/refuman2.mp3', - 'audio/skill/refuyuan1.mp3', - 'audio/skill/refuyuan2.mp3', - 'audio/skill/reganglie1.mp3', - 'audio/skill/reganglie2.mp3', - 'audio/skill/reganlu1.mp3', - 'audio/skill/reganlu2.mp3', - 'audio/skill/regongji1.mp3', - 'audio/skill/regongji2.mp3', - 'audio/skill/reguhuo1.mp3', - 'audio/skill/reguhuo2.mp3', - 'audio/skill/reguicai1.mp3', - 'audio/skill/reguicai2.mp3', - 'audio/skill/reguose1.mp3', - 'audio/skill/reguose2.mp3', - 'audio/skill/rehongyan1.mp3', - 'audio/skill/rehongyan2.mp3', - 'audio/skill/rehuaiyi1.mp3', - 'audio/skill/rehuaiyi2.mp3', - 'audio/skill/rehuashen1.mp3', - 'audio/skill/rehuashen2.mp3', - 'audio/skill/rehunzi1.mp3', - 'audio/skill/rehunzi2.mp3', - 'audio/skill/rehuoji_ol_pangtong1.mp3', - 'audio/skill/rehuoji_ol_pangtong2.mp3', - 'audio/skill/rehuoji_ol_sp_zhugeliang1.mp3', - 'audio/skill/rehuoji_ol_sp_zhugeliang2.mp3', - 'audio/skill/rehuoji1.mp3', - 'audio/skill/rehuoji2.mp3', - 'audio/skill/rehuoshui1.mp3', - 'audio/skill/rehuoshui2.mp3', - 'audio/skill/rejianchu1.mp3', - 'audio/skill/rejianchu2.mp3', - 'audio/skill/rejiangchi1.mp3', - 'audio/skill/rejiangchi2.mp3', - 'audio/skill/rejianxiong_shen_caopi1.mp3', - 'audio/skill/rejianxiong_shen_caopi2.mp3', - 'audio/skill/rejianxiong1.mp3', - 'audio/skill/rejianxiong2.mp3', - 'audio/skill/rejianyan1.mp3', - 'audio/skill/rejianyan2.mp3', - 'audio/skill/rejiaojin1.mp3', - 'audio/skill/rejiaojin2.mp3', - 'audio/skill/rejiaozhao1.mp3', - 'audio/skill/rejiaozhao2.mp3', - 'audio/skill/rejieming1.mp3', - 'audio/skill/rejieming2.mp3', - 'audio/skill/rejieyin1.mp3', - 'audio/skill/rejieyin2.mp3', - 'audio/skill/rejieyue1.mp3', - 'audio/skill/rejieyue2.mp3', - 'audio/skill/rejigong1.mp3', - 'audio/skill/rejigong2.mp3', - 'audio/skill/rejinjiu1.mp3', - 'audio/skill/rejinjiu2.mp3', - 'audio/skill/rejiqiao1.mp3', - 'audio/skill/rejiqiao2.mp3', - 'audio/skill/rejiushi1.mp3', - 'audio/skill/rejiushi2.mp3', - 'audio/skill/rejiuyuan1.mp3', - 'audio/skill/rejiuyuan2.mp3', - 'audio/skill/rejixu1.mp3', - 'audio/skill/rejixu2.mp3', - 'audio/skill/rejizhi_lukang1.mp3', - 'audio/skill/rejizhi_lukang2.mp3', - 'audio/skill/rejizhi1.mp3', - 'audio/skill/rejizhi2.mp3', - 'audio/skill/rejuece1.mp3', - 'audio/skill/rejuece2.mp3', - 'audio/skill/rejueqing1.mp3', - 'audio/skill/rejueqing2.mp3', - 'audio/skill/rejunxing1.mp3', - 'audio/skill/rejunxing2.mp3', - 'audio/skill/rekanpo_ol_pangtong1.mp3', - 'audio/skill/rekanpo_ol_pangtong2.mp3', - 'audio/skill/rekanpo_ol_sp_zhugeliang1.mp3', - 'audio/skill/rekanpo_ol_sp_zhugeliang2.mp3', - 'audio/skill/rekanpo1.mp3', - 'audio/skill/rekanpo2.mp3', - 'audio/skill/rekuangbi1.mp3', - 'audio/skill/rekuangbi2.mp3', - 'audio/skill/rekuangcai1.mp3', - 'audio/skill/rekuangcai2.mp3', - 'audio/skill/rekurou1.mp3', - 'audio/skill/rekurou2.mp3', - 'audio/skill/releiji1.mp3', - 'audio/skill/releiji2.mp3', - 'audio/skill/reliangying1.mp3', - 'audio/skill/reliangying2.mp3', - 'audio/skill/relianying1.mp3', - 'audio/skill/relianying2.mp3', - 'audio/skill/relieren1.mp3', - 'audio/skill/relieren2.mp3', - 'audio/skill/relihuo1.mp3', - 'audio/skill/relihuo2.mp3', - 'audio/skill/relinglong1.mp3', - 'audio/skill/relinglong2.mp3', - 'audio/skill/relonghun1.mp3', - 'audio/skill/relonghun2.mp3', - 'audio/skill/relongyin1.mp3', - 'audio/skill/relongyin2.mp3', - 'audio/skill/reluanji1.mp3', - 'audio/skill/reluanji2.mp3', - 'audio/skill/reluoshen1.mp3', - 'audio/skill/reluoshen2.mp3', - 'audio/skill/reluoyi1.mp3', - 'audio/skill/reluoyi2.mp3', - 'audio/skill/reluoying_dc_caozhi1.mp3', - 'audio/skill/reluoying_dc_caozhi2.mp3', - 'audio/skill/reluoying1.mp3', - 'audio/skill/reluoying2.mp3', - 'audio/skill/remieji1.mp3', - 'audio/skill/remieji2.mp3', - 'audio/skill/remingce1.mp3', - 'audio/skill/remingce2.mp3', - 'audio/skill/rende1.mp3', - 'audio/skill/rende2.mp3', - 'audio/skill/renjie.mp3', - 'audio/skill/renjie2.mp3', - 'audio/skill/renjie21.mp3', - 'audio/skill/renjie22.mp3', - 'audio/skill/renshe1.mp3', - 'audio/skill/renshe2.mp3', - 'audio/skill/renshi1.mp3', - 'audio/skill/renshi2.mp3', - 'audio/skill/renwang_skill.mp3', - 'audio/skill/renxin_re_caochong1.mp3', - 'audio/skill/renxin_re_caochong2.mp3', - 'audio/skill/renxin1.mp3', - 'audio/skill/renxin2.mp3', - 'audio/skill/renzheng1.mp3', - 'audio/skill/renzheng2.mp3', - 'audio/skill/repaoxiao1.mp3', - 'audio/skill/repaoxiao2.mp3', - 'audio/skill/repindi1.mp3', - 'audio/skill/repindi2.mp3', - 'audio/skill/repingkou1.mp3', - 'audio/skill/repingkou2.mp3', - 'audio/skill/repojun1.mp3', - 'audio/skill/repojun2.mp3', - 'audio/skill/repolu1.mp3', - 'audio/skill/reqiangxi1.mp3', - 'audio/skill/reqiangxi2.mp3', - 'audio/skill/reqianxi1.mp3', - 'audio/skill/reqianxi2.mp3', - 'audio/skill/reqianxun1.mp3', - 'audio/skill/reqianxun2.mp3', - 'audio/skill/reqiaobian1.mp3', - 'audio/skill/reqiaobian2.mp3', - 'audio/skill/reqiaoshi1.mp3', - 'audio/skill/reqiaoshi2.mp3', - 'audio/skill/reqiaoshui1.mp3', - 'audio/skill/reqiaoshui2.mp3', - 'audio/skill/reqice1.mp3', - 'audio/skill/reqice2.mp3', - 'audio/skill/reqieting1.mp3', - 'audio/skill/reqieting2.mp3', - 'audio/skill/reqimou1.mp3', - 'audio/skill/reqimou2.mp3', - 'audio/skill/reqingcheng1.mp3', - 'audio/skill/reqingcheng2.mp3', - 'audio/skill/reqingguo1.mp3', - 'audio/skill/reqingguo2.mp3', - 'audio/skill/reqingxi1.mp3', - 'audio/skill/reqingxi2.mp3', - 'audio/skill/reqinwang1.mp3', - 'audio/skill/reqinwang2.mp3', - 'audio/skill/reqiuyuan1.mp3', - 'audio/skill/reqiuyuan2.mp3', - 'audio/skill/requanji1.mp3', - 'audio/skill/requanji2.mp3', - 'audio/skill/rerende_gz_jun_liubei1.mp3', - 'audio/skill/rerende_gz_jun_liubei2.mp3', - 'audio/skill/rerende_shen_caopi1.mp3', - 'audio/skill/rerende_shen_caopi2.mp3', - 'audio/skill/rerende1.mp3', - 'audio/skill/rerende2.mp3', - 'audio/skill/resanyao1.mp3', - 'audio/skill/resanyao2.mp3', - 'audio/skill/reshangshi1.mp3', - 'audio/skill/reshangshi2.mp3', - 'audio/skill/reshejian1.mp3', - 'audio/skill/reshejian2.mp3', - 'audio/skill/reshenduan1.mp3', - 'audio/skill/reshenduan2.mp3', - 'audio/skill/reshenxing1.mp3', - 'audio/skill/reshenxing2.mp3', - 'audio/skill/reshishou1.mp3', - 'audio/skill/reshishou2.mp3', - 'audio/skill/residi1.mp3', - 'audio/skill/residi2.mp3', - 'audio/skill/retieji_boss_lvbu31.mp3', - 'audio/skill/retieji_boss_lvbu32.mp3', - 'audio/skill/retieji1.mp3', - 'audio/skill/retieji2.mp3', - 'audio/skill/retishen1.mp3', - 'audio/skill/retishen2.mp3', - 'audio/skill/retongbo1.mp3', - 'audio/skill/retongbo2.mp3', - 'audio/skill/retuntian1.mp3', - 'audio/skill/retuntian2.mp3', - 'audio/skill/retuxi1.mp3', - 'audio/skill/retuxi2.mp3', - 'audio/skill/rewangzu1.mp3', - 'audio/skill/rewangzu2.mp3', - 'audio/skill/reweimu1.mp3', - 'audio/skill/reweimu2.mp3', - 'audio/skill/rewurong1.mp3', - 'audio/skill/rewurong2.mp3', - 'audio/skill/rexiantu1.mp3', - 'audio/skill/rexiantu2.mp3', - 'audio/skill/rexianzhen1.mp3', - 'audio/skill/rexianzhen2.mp3', - 'audio/skill/rexianzhou1.mp3', - 'audio/skill/rexianzhou2.mp3', - 'audio/skill/rexingshang1.mp3', - 'audio/skill/rexingshang2.mp3', - 'audio/skill/rexingsheng1.mp3', - 'audio/skill/rexingsheng2.mp3', - 'audio/skill/rexingxue1.mp3', - 'audio/skill/rexingxue2.mp3', - 'audio/skill/rexinsheng1.mp3', - 'audio/skill/rexinsheng2.mp3', - 'audio/skill/rexuanhuo1.mp3', - 'audio/skill/rexuanhuo2.mp3', - 'audio/skill/reyajiao1.mp3', - 'audio/skill/reyajiao2.mp3', - 'audio/skill/reyanyu1.mp3', - 'audio/skill/reyanyu2.mp3', - 'audio/skill/reyanzhu1.mp3', - 'audio/skill/reyanzhu2.mp3', - 'audio/skill/reyicong_dc_gongsunzan.mp3', - 'audio/skill/reyicong_dc_gongsunzan1.mp3', - 'audio/skill/reyicong1.mp3', - 'audio/skill/reyicong2.mp3', - 'audio/skill/reyiji1.mp3', - 'audio/skill/reyiji2.mp3', - 'audio/skill/reyingshi1.mp3', - 'audio/skill/reyingshi2.mp3', - 'audio/skill/reyingshui1.mp3', - 'audio/skill/reyingshui2.mp3', - 'audio/skill/reyingzi_gexuan1.mp3', - 'audio/skill/reyingzi_heqi1.mp3', - 'audio/skill/reyingzi_heqi2.mp3', - 'audio/skill/reyingzi_re_heqi1.mp3', - 'audio/skill/reyingzi_re_heqi2.mp3', - 'audio/skill/reyingzi_re_sunben1.mp3', - 'audio/skill/reyingzi_re_sunben2.mp3', - 'audio/skill/reyingzi_re_sunce1.mp3', - 'audio/skill/reyingzi_re_sunce2.mp3', - 'audio/skill/reyingzi_re_sunyi1.mp3', - 'audio/skill/reyingzi_sunce1.mp3', - 'audio/skill/reyingzi_sunce2.mp3', - 'audio/skill/reyingzi1.mp3', - 'audio/skill/reyingzi2.mp3', - 'audio/skill/reyonglve1.mp3', - 'audio/skill/reyonglve2.mp3', - 'audio/skill/rezaiqi1.mp3', - 'audio/skill/rezaiqi2.mp3', - 'audio/skill/rezhanjue1.mp3', - 'audio/skill/rezhanjue2.mp3', - 'audio/skill/rezhiheng_shen_caopi1.mp3', - 'audio/skill/rezhiheng_shen_caopi2.mp3', - 'audio/skill/rezhiheng1.mp3', - 'audio/skill/rezhiheng2.mp3', - 'audio/skill/rezhijian1.mp3', - 'audio/skill/rezhijian2.mp3', - 'audio/skill/rezhiyu1.mp3', - 'audio/skill/rezhiyu2.mp3', - 'audio/skill/rezhongyong1.mp3', - 'audio/skill/rezhongyong2.mp3', - 'audio/skill/rezhuhai1.mp3', - 'audio/skill/rezhuhai2.mp3', - 'audio/skill/rezhuikong1.mp3', - 'audio/skill/rezhuikong2.mp3', - 'audio/skill/rezongshi1.mp3', - 'audio/skill/rezongshi2.mp3', - 'audio/skill/rezongxuan1.mp3', - 'audio/skill/rezongxuan2.mp3', - 'audio/skill/rongbei1.mp3', - 'audio/skill/rongbei2.mp3', - 'audio/skill/roulin_ol_dongzhuo1.mp3', - 'audio/skill/roulin_ol_dongzhuo2.mp3', - 'audio/skill/roulin_re_dongzhuo1.mp3', - 'audio/skill/roulin_re_dongzhuo2.mp3', - 'audio/skill/roulin1.mp3', - 'audio/skill/roulin2.mp3', - 'audio/skill/ruilve1.mp3', - 'audio/skill/ruilve2.mp3', - 'audio/skill/ruoyu_re_liushan1.mp3', - 'audio/skill/ruoyu_re_liushan2.mp3', - 'audio/skill/ruoyu1.mp3', - 'audio/skill/ruoyu2.mp3', - 'audio/skill/rw_bagua_skill.mp3', - 'audio/skill/rw_baiyin_skill.mp3', - 'audio/skill/rw_renwang_skill.mp3', - 'audio/skill/rw_tengjia1.mp3', - 'audio/skill/rw_tengjia2.mp3', - 'audio/skill/rw_zhuge_skill.mp3', - 'audio/skill/sanchen1.mp3', - 'audio/skill/sanchen2.mp3', - 'audio/skill/sangu1.mp3', - 'audio/skill/sangu2.mp3', - 'audio/skill/sanjian_skill.mp3', - 'audio/skill/sanku1.mp3', - 'audio/skill/sanku2.mp3', - 'audio/skill/sanshou1.mp3', - 'audio/skill/sanshou2.mp3', - 'audio/skill/sanyao1.mp3', - 'audio/skill/sanyao2.mp3', - 'audio/skill/saodi1.mp3', - 'audio/skill/saodi2.mp3', - 'audio/skill/saya_powei1.mp3', - 'audio/skill/saya_powei2.mp3', - 'audio/skill/saya_shouji1.mp3', - 'audio/skill/saya_shouji2.mp3', - 'audio/skill/sbaiyin.mp3', - 'audio/skill/sbaiyin1.mp3', - 'audio/skill/sbaiyin2.mp3', - 'audio/skill/sbanguo1.mp3', - 'audio/skill/sbanguo2.mp3', - 'audio/skill/sbanguo3.mp3', - 'audio/skill/sbbenxi1.mp3', - 'audio/skill/sbbenxi2.mp3', - 'audio/skill/sbbenxi3.mp3', - 'audio/skill/sbbiyue1.mp3', - 'audio/skill/sbbiyue2.mp3', - 'audio/skill/sbduanliang_false.mp3', - 'audio/skill/sbduanliang_true1.mp3', - 'audio/skill/sbduanliang_true2.mp3', - 'audio/skill/sbduanliang1.mp3', - 'audio/skill/sbdujiang1.mp3', - 'audio/skill/sbdujiang2.mp3', - 'audio/skill/sbduojing1.mp3', - 'audio/skill/sbduojing2.mp3', - 'audio/skill/sbenyuan1.mp3', - 'audio/skill/sbenyuan2.mp3', - 'audio/skill/sbfangzhu1.mp3', - 'audio/skill/sbfangzhu2.mp3', - 'audio/skill/sbfanjian1.mp3', - 'audio/skill/sbfanjian2.mp3', - 'audio/skill/sbfenwei1.mp3', - 'audio/skill/sbfenwei2.mp3', - 'audio/skill/sbguanxing1.mp3', - 'audio/skill/sbguanxing2.mp3', - 'audio/skill/sbguidao1.mp3', - 'audio/skill/sbguidao2.mp3', - 'audio/skill/sbguose1.mp3', - 'audio/skill/sbguose2.mp3', - 'audio/skill/sbhuangtian1.mp3', - 'audio/skill/sbhuangtian2.mp3', - 'audio/skill/sbhujia1.mp3', - 'audio/skill/sbhujia2.mp3', - 'audio/skill/sbhunzi1.mp3', - 'audio/skill/sbhunzi2.mp3', - 'audio/skill/sbhuoji1.mp3', - 'audio/skill/sbhuoji2.mp3', - 'audio/skill/sbhuoji3.mp3', - 'audio/skill/sbhuoshou1.mp3', - 'audio/skill/sbhuoshou2.mp3', - 'audio/skill/sbjiang1.mp3', - 'audio/skill/sbjiang2.mp3', - 'audio/skill/sbjianxiong1.mp3', - 'audio/skill/sbjianxiong2.mp3', - 'audio/skill/sbjieming1.mp3', - 'audio/skill/sbjieming2.mp3', - 'audio/skill/sbjiewei1.mp3', - 'audio/skill/sbjiewei2.mp3', - 'audio/skill/sbjieyin1.mp3', - 'audio/skill/sbjieyin2.mp3', - 'audio/skill/sbjieyue1.mp3', - 'audio/skill/sbjieyue2.mp3', - 'audio/skill/sbjieyue3.mp3', - 'audio/skill/sbjieyue4.mp3', - 'audio/skill/sbjijiang1.mp3', - 'audio/skill/sbjijiang2.mp3', - 'audio/skill/sbjiuyuan1.mp3', - 'audio/skill/sbjiuyuan2.mp3', - 'audio/skill/sbjizhi1.mp3', - 'audio/skill/sbjizhi2.mp3', - 'audio/skill/sbjizhu1.mp3', - 'audio/skill/sbjizhu2.mp3', - 'audio/skill/sbjizhu3.mp3', - 'audio/skill/sbjushou1.mp3', - 'audio/skill/sbjushou2.mp3', - 'audio/skill/sbjushou3.mp3', - 'audio/skill/sbjuxiang1.mp3', - 'audio/skill/sbjuxiang2.mp3', - 'audio/skill/sbkanpo1.mp3', - 'audio/skill/sbkanpo2.mp3', - 'audio/skill/sbkeji1.mp3', - 'audio/skill/sbkeji2.mp3', - 'audio/skill/sbkongcheng1.mp3', - 'audio/skill/sbkongcheng2.mp3', - 'audio/skill/sbkurou1.mp3', - 'audio/skill/sbkurou2.mp3', - 'audio/skill/sbleiji1.mp3', - 'audio/skill/sbleiji2.mp3', - 'audio/skill/sbliangzhu1.mp3', - 'audio/skill/sbliangzhu2.mp3', - 'audio/skill/sblianhuan1.mp3', - 'audio/skill/sblianhuan2.mp3', - 'audio/skill/sbliegong1.mp3', - 'audio/skill/sbliegong2.mp3', - 'audio/skill/sblieren1.mp3', - 'audio/skill/sblieren2.mp3', - 'audio/skill/sblijian1.mp3', - 'audio/skill/sblijian2.mp3', - 'audio/skill/sbliuli1.mp3', - 'audio/skill/sbliuli2.mp3', - 'audio/skill/sblongdan1.mp3', - 'audio/skill/sblongdan2.mp3', - 'audio/skill/sbluanji1.mp3', - 'audio/skill/sbluanji2.mp3', - 'audio/skill/sbluoshen1.mp3', - 'audio/skill/sbluoshen2.mp3', - 'audio/skill/sbmingce1.mp3', - 'audio/skill/sbmingce2.mp3', - 'audio/skill/sbniepan1.mp3', - 'audio/skill/sbniepan2.mp3', - 'audio/skill/sbpaoxiao1.mp3', - 'audio/skill/sbpaoxiao2.mp3', - 'audio/skill/sbqiaobian1.mp3', - 'audio/skill/sbqiaobian2.mp3', - 'audio/skill/sbqiaoshi1.mp3', - 'audio/skill/sbqiaoshi2.mp3', - 'audio/skill/sbqicai1.mp3', - 'audio/skill/sbqicai2.mp3', - 'audio/skill/sbqingzheng1.mp3', - 'audio/skill/sbqingzheng2.mp3', - 'audio/skill/sbqixi1.mp3', - 'audio/skill/sbqixi2.mp3', - 'audio/skill/sbquhu1.mp3', - 'audio/skill/sbquhu2.mp3', - 'audio/skill/sbrende1.mp3', - 'audio/skill/sbrende2.mp3', - 'audio/skill/sbrende3.mp3', - 'audio/skill/sbshipo1.mp3', - 'audio/skill/sbshipo2.mp3', - 'audio/skill/sbsongwei1.mp3', - 'audio/skill/sbsongwei2.mp3', - 'audio/skill/sbtianxiang1.mp3', - 'audio/skill/sbtianxiang2.mp3', - 'audio/skill/sbtiaoxin1.mp3', - 'audio/skill/sbtiaoxin2.mp3', - 'audio/skill/sbtieji_false.mp3', - 'audio/skill/sbtieji_true1.mp3', - 'audio/skill/sbtieji_true2.mp3', - 'audio/skill/sbtieji1.mp3', - 'audio/skill/sbtongye1.mp3', - 'audio/skill/sbtongye2.mp3', - 'audio/skill/sbwusheng1.mp3', - 'audio/skill/sbwusheng2.mp3', - 'audio/skill/sbwusheng3.mp3', - 'audio/skill/sbxiaoji1.mp3', - 'audio/skill/sbxiaoji2.mp3', - 'audio/skill/sbxiayuan1.mp3', - 'audio/skill/sbxiayuan2.mp3', - 'audio/skill/sbxieji1.mp3', - 'audio/skill/sbxieji2.mp3', - 'audio/skill/sbxieji3.mp3', - 'audio/skill/sbxingshang1.mp3', - 'audio/skill/sbxingshang2.mp3', - 'audio/skill/sbxuanhuo1.mp3', - 'audio/skill/sbxuanhuo2.mp3', - 'audio/skill/sbxueyi1.mp3', - 'audio/skill/sbxueyi2.mp3', - 'audio/skill/sbyangwei1.mp3', - 'audio/skill/sbyangwei2.mp3', - 'audio/skill/sbyanyu1.mp3', - 'audio/skill/sbyanyu2.mp3', - 'audio/skill/sbyaoming1.mp3', - 'audio/skill/sbyaoming2.mp3', - 'audio/skill/sbyijue1.mp3', - 'audio/skill/sbyijue2.mp3', - 'audio/skill/sbyingzi_sb_sunce1.mp3', - 'audio/skill/sbyingzi_sb_sunce2.mp3', - 'audio/skill/sbyingzi1.mp3', - 'audio/skill/sbyingzi2.mp3', - 'audio/skill/sbzaiqi1.mp3', - 'audio/skill/sbzaiqi2.mp3', - 'audio/skill/sbzhangwu1.mp3', - 'audio/skill/sbzhangwu2.mp3', - 'audio/skill/sbzhaxiang1.mp3', - 'audio/skill/sbzhaxiang2.mp3', - 'audio/skill/sbzhenliang1.mp3', - 'audio/skill/sbzhenliang2.mp3', - 'audio/skill/sbzhiba1.mp3', - 'audio/skill/sbzhiba2.mp3', - 'audio/skill/sbzhichi1.mp3', - 'audio/skill/sbzhichi2.mp3', - 'audio/skill/sbzhiheng1.mp3', - 'audio/skill/sbzhiheng2.mp3', - 'audio/skill/sbzhiji1.mp3', - 'audio/skill/sbzhiji2.mp3', - 'audio/skill/sbzishou1.mp3', - 'audio/skill/sbzishou2.mp3', - 'audio/skill/sbzongshi1.mp3', - 'audio/skill/sbzongshi2.mp3', - 'audio/skill/scfuhai1.mp3', - 'audio/skill/scfuhai2.mp3', - 'audio/skill/scs_bilan_enter.mp3', - 'audio/skill/scs_duangui_enter.mp3', - 'audio/skill/scs_gaowang_enter.mp3', - 'audio/skill/scs_guosheng_enter.mp3', - 'audio/skill/scs_hankui_enter.mp3', - 'audio/skill/scs_lisong_enter.mp3', - 'audio/skill/scs_sunzhang_enter.mp3', - 'audio/skill/scs_xiayun_enter.mp3', - 'audio/skill/scs_zhangrang_enter.mp3', - 'audio/skill/scs_zhaozhong_enter.mp3', - 'audio/skill/scsanruo1.mp3', - 'audio/skill/scschihe1.mp3', - 'audio/skill/scschiyan1.mp3', - 'audio/skill/scskuiji1.mp3', - 'audio/skill/scsniqu1.mp3', - 'audio/skill/scspicai1.mp3', - 'audio/skill/scstaoluan1.mp3', - 'audio/skill/scsxiaolu1.mp3', - 'audio/skill/scsyaozhuo1.mp3', - 'audio/skill/scszimou1.mp3', - 'audio/skill/sghuishi1.mp3', - 'audio/skill/sghuishi2.mp3', - 'audio/skill/sgrenwang1.mp3', - 'audio/skill/sgrenwang2.mp3', - 'audio/skill/shameng1.mp3', - 'audio/skill/shameng2.mp3', - 'audio/skill/shanduan1.mp3', - 'audio/skill/shanduan2.mp3', - 'audio/skill/shangshi1.mp3', - 'audio/skill/shangshi2.mp3', - 'audio/skill/shangshix1.mp3', - 'audio/skill/shangshix2.mp3', - 'audio/skill/shangyi1.mp3', - 'audio/skill/shangyi2.mp3', - 'audio/skill/shanjia1.mp3', - 'audio/skill/shanjia2.mp3', - 'audio/skill/shanli1.mp3', - 'audio/skill/shanli2.mp3', - 'audio/skill/shanshen1.mp3', - 'audio/skill/shanshen2.mp3', - 'audio/skill/shanxi1.mp3', - 'audio/skill/shanxi2.mp3', - 'audio/skill/shanxie1.mp3', - 'audio/skill/shanxie2.mp3', - 'audio/skill/shanzhuan1.mp3', - 'audio/skill/shanzhuan2.mp3', - 'audio/skill/shebian1.mp3', - 'audio/skill/shebian2.mp3', - 'audio/skill/shefu1.mp3', - 'audio/skill/shefu2.mp3', - 'audio/skill/shejian1.mp3', - 'audio/skill/shejian2.mp3', - 'audio/skill/shelie1.mp3', - 'audio/skill/shelie2.mp3', - 'audio/skill/shencai1.mp3', - 'audio/skill/shencai2.mp3', - 'audio/skill/shenduan1.mp3', - 'audio/skill/shenduan2.mp3', - 'audio/skill/shenfen1.mp3', - 'audio/skill/shenfen2.mp3', - 'audio/skill/shenfu1.mp3', - 'audio/skill/shenfu2.mp3', - 'audio/skill/shengxi_feiyi1.mp3', - 'audio/skill/shengxi_feiyi2.mp3', - 'audio/skill/shengxi1.mp3', - 'audio/skill/shengxi2.mp3', - 'audio/skill/shenji1.mp3', - 'audio/skill/shenji2.mp3', - 'audio/skill/shenju1.mp3', - 'audio/skill/shenju2.mp3', - 'audio/skill/shenpin1.mp3', - 'audio/skill/shenpin2.mp3', - 'audio/skill/shenqu1.mp3', - 'audio/skill/shenqu2.mp3', - 'audio/skill/shensu1_ol_xiahouyuan1.mp3', - 'audio/skill/shensu1_ol_xiahouyuan2.mp3', - 'audio/skill/shensu1_re_xiahouyuan1.mp3', - 'audio/skill/shensu1_re_xiahouyuan2.mp3', - 'audio/skill/shensu1_xiahouba1.mp3', - 'audio/skill/shensu1_xiahouba2.mp3', - 'audio/skill/shensu11.mp3', - 'audio/skill/shensu12.mp3', - 'audio/skill/shensu21.mp3', - 'audio/skill/shensu22.mp3', - 'audio/skill/shenwei1.mp3', - 'audio/skill/shenwei2.mp3', - 'audio/skill/shenxian1.mp3', - 'audio/skill/shenxian2.mp3', - 'audio/skill/shenxing1.mp3', - 'audio/skill/shenxing2.mp3', - 'audio/skill/shenzhi1.mp3', - 'audio/skill/shenzhi2.mp3', - 'audio/skill/shenzhu1.mp3', - 'audio/skill/shenzhu2.mp3', - 'audio/skill/sheyan1.mp3', - 'audio/skill/sheyan2.mp3', - 'audio/skill/sheyi1.mp3', - 'audio/skill/sheyi2.mp3', - 'audio/skill/shezang1.mp3', - 'audio/skill/shezang2.mp3', - 'audio/skill/shhlianhua1.mp3', - 'audio/skill/shhlianhua2.mp3', - 'audio/skill/shibei_xin_jushou1.mp3', - 'audio/skill/shibei_xin_jushou2.mp3', - 'audio/skill/shibei1.mp3', - 'audio/skill/shibei2.mp3', - 'audio/skill/shichou1.mp3', - 'audio/skill/shichou2.mp3', - 'audio/skill/shiduo1.mp3', - 'audio/skill/shiduo2.mp3', - 'audio/skill/shifei_re_guotufengji1.mp3', - 'audio/skill/shifei_re_guotufengji2.mp3', - 'audio/skill/shifei1.mp3', - 'audio/skill/shifei2.mp3', - 'audio/skill/shiina_feiyan1.mp3', - 'audio/skill/shiina_qingshen1.mp3', - 'audio/skill/shiina_retieji1.mp3', - 'audio/skill/shiki_omusubi1.mp3', - 'audio/skill/shiki_omusubi2.mp3', - 'audio/skill/shiming1.mp3', - 'audio/skill/shiming2.mp3', - 'audio/skill/shiorimiyuki_banyin1.mp3', - 'audio/skill/shiorimiyuki_banyin2.mp3', - 'audio/skill/shiorimiyuki_tingxian1.mp3', - 'audio/skill/shiorimiyuki_tingxian2.mp3', - 'audio/skill/shiren1.mp3', - 'audio/skill/shiren2.mp3', - 'audio/skill/shishengshibai.mp3', - 'audio/skill/shixin1.mp3', - 'audio/skill/shixin2.mp3', - 'audio/skill/shiyong1.mp3', - 'audio/skill/shiyong2.mp3', - 'audio/skill/shiyong3.mp3', - 'audio/skill/shiyuan1.mp3', - 'audio/skill/shiyuan2.mp3', - 'audio/skill/shizhan1.mp3', - 'audio/skill/shizhan2.mp3', - 'audio/skill/shoucheng1.mp3', - 'audio/skill/shoucheng2.mp3', - 'audio/skill/shoufa1.mp3', - 'audio/skill/shoufa2.mp3', - 'audio/skill/shouli1.mp3', - 'audio/skill/shouli2.mp3', - 'audio/skill/shoulijian.mp3', - 'audio/skill/shouxi1.mp3', - 'audio/skill/shouxi2.mp3', - 'audio/skill/shouye1.mp3', - 'audio/skill/shouye2.mp3', - 'audio/skill/shuaiyan1.mp3', - 'audio/skill/shuaiyan2.mp3', - 'audio/skill/shuangren1.mp3', - 'audio/skill/shuangren2.mp3', - 'audio/skill/shuangxiong_re_yanwen1.mp3', - 'audio/skill/shuangxiong_re_yanwen2.mp3', - 'audio/skill/shuangxiong1.mp3', - 'audio/skill/shuangxiong2.mp3', - 'audio/skill/shuchen1.mp3', - 'audio/skill/shuchen2.mp3', - 'audio/skill/shuimeng1.mp3', - 'audio/skill/shuimeng2.mp3', - 'audio/skill/shuishi1.mp3', - 'audio/skill/shuishi2.mp3', - 'audio/skill/shuliang1.mp3', - 'audio/skill/shuliang2.mp3', - 'audio/skill/shunshi1.mp3', - 'audio/skill/shunshi2.mp3', - 'audio/skill/shuojian1.mp3', - 'audio/skill/shuojian2.mp3', - 'audio/skill/shushen1.mp3', - 'audio/skill/shushen2.mp3', - 'audio/skill/sibian1.mp3', - 'audio/skill/sibian2.mp3', - 'audio/skill/sidi.mp3', - 'audio/skill/sidi1.mp3', - 'audio/skill/sidi2.mp3', - 'audio/skill/sijian1.mp3', - 'audio/skill/sijian2.mp3', - 'audio/skill/sijun1.mp3', - 'audio/skill/sijun2.mp3', - 'audio/skill/sishu1.mp3', - 'audio/skill/sishu2.mp3', - 'audio/skill/smyyingshi1.mp3', - 'audio/skill/smyyingshi2.mp3', - 'audio/skill/songci1.mp3', - 'audio/skill/songci2.mp3', - 'audio/skill/songshu1.mp3', - 'audio/skill/songshu2.mp3', - 'audio/skill/songwei_re_caopi1.mp3', - 'audio/skill/songwei_re_caopi2.mp3', - 'audio/skill/songwei2_re_caopi1.mp3', - 'audio/skill/songwei2_re_caopi2.mp3', - 'audio/skill/songwei21.mp3', - 'audio/skill/songwei22.mp3', - 'audio/skill/souying1.mp3', - 'audio/skill/souying2.mp3', - 'audio/skill/spchijie1.mp3', - 'audio/skill/spchijie2.mp3', - 'audio/skill/spcunsi1.mp3', - 'audio/skill/spcunsi2.mp3', - 'audio/skill/spdaizui1.mp3', - 'audio/skill/spdaizui2.mp3', - 'audio/skill/spdaming1.mp3', - 'audio/skill/spdaming2.mp3', - 'audio/skill/spdaming3.mp3', - 'audio/skill/spdaoshu1.mp3', - 'audio/skill/spdaoshu2.mp3', - 'audio/skill/spdaoshu3.mp3', - 'audio/skill/spdengli1.mp3', - 'audio/skill/spdengli2.mp3', - 'audio/skill/spdiancai1.mp3', - 'audio/skill/spdiancai2.mp3', - 'audio/skill/spdiaodu1.mp3', - 'audio/skill/spdiaodu2.mp3', - 'audio/skill/spdifei1.mp3', - 'audio/skill/spdifei2.mp3', - 'audio/skill/spell2131_1.mp3', - 'audio/skill/spell2131_2.mp3', - 'audio/skill/spfangzong1.mp3', - 'audio/skill/spfangzong2.mp3', - 'audio/skill/spfenming1.mp3', - 'audio/skill/spfenming2.mp3', - 'audio/skill/spguixiu1.mp3', - 'audio/skill/spguixiu2.mp3', - 'audio/skill/spjianyi1.mp3', - 'audio/skill/spjianyi2.mp3', - 'audio/skill/spjiedao1.mp3', - 'audio/skill/spjiedao2.mp3', - 'audio/skill/spjincui1.mp3', - 'audio/skill/spjincui2.mp3', - 'audio/skill/spjungong1.mp3', - 'audio/skill/spjungong2.mp3', - 'audio/skill/splirang1.mp3', - 'audio/skill/splirang2.mp3', - 'audio/skill/splveying1.mp3', - 'audio/skill/splveying2.mp3', - 'audio/skill/spmanwang1.mp3', - 'audio/skill/spmanwang2.mp3', - 'audio/skill/spmiewu1.mp3', - 'audio/skill/spmiewu2.mp3', - 'audio/skill/spmingshi1.mp3', - 'audio/skill/spmingshi2.mp3', - 'audio/skill/spmingxuan1.mp3', - 'audio/skill/spmingxuan2.mp3', - 'audio/skill/spolzhouxuan1.mp3', - 'audio/skill/spolzhouxuan2.mp3', - 'audio/skill/sppanqin1.mp3', - 'audio/skill/sppanqin2.mp3', - 'audio/skill/spqiai1.mp3', - 'audio/skill/spqiai2.mp3', - 'audio/skill/spqishe1.mp3', - 'audio/skill/spqishe2.mp3', - 'audio/skill/spsanchen1.mp3', - 'audio/skill/spsanchen2.mp3', - 'audio/skill/spshangyi1.mp3', - 'audio/skill/spshangyi2.mp3', - 'audio/skill/spshanxi1.mp3', - 'audio/skill/spshanxi2.mp3', - 'audio/skill/spshicai1.mp3', - 'audio/skill/spshicai2.mp3', - 'audio/skill/spshidi1.mp3', - 'audio/skill/spshidi2.mp3', - 'audio/skill/spshiji1.mp3', - 'audio/skill/spshiji2.mp3', - 'audio/skill/spsongshu1.mp3', - 'audio/skill/spsongshu2.mp3', - 'audio/skill/sptaoluan1.mp3', - 'audio/skill/sptaoluan2.mp3', - 'audio/skill/sptunjiang1.mp3', - 'audio/skill/sptunjiang2.mp3', - 'audio/skill/spwanwei1.mp3', - 'audio/skill/spwanwei2.mp3', - 'audio/skill/spweiwu1.mp3', - 'audio/skill/spweiwu2.mp3', - 'audio/skill/spwenji1.mp3', - 'audio/skill/spwenji2.mp3', - 'audio/skill/spwuku1.mp3', - 'audio/skill/spwuku2.mp3', - 'audio/skill/spxianchou1.mp3', - 'audio/skill/spxianchou2.mp3', - 'audio/skill/spxiangzhen1.mp3', - 'audio/skill/spxiangzhen2.mp3', - 'audio/skill/spxiaoni1.mp3', - 'audio/skill/spxiaoni2.mp3', - 'audio/skill/spxizhan1.mp3', - 'audio/skill/spxizhan2.mp3', - 'audio/skill/spxizhan3.mp3', - 'audio/skill/spxizhan4.mp3', - 'audio/skill/spyajun1.mp3', - 'audio/skill/spyajun2.mp3', - 'audio/skill/spyanji1.mp3', - 'audio/skill/spyanji2.mp3', - 'audio/skill/spyanji3.mp3', - 'audio/skill/spyanjiao1.mp3', - 'audio/skill/spyanjiao2.mp3', - 'audio/skill/spyilie1.mp3', - 'audio/skill/spyilie2.mp3', - 'audio/skill/spyingwu1.mp3', - 'audio/skill/spyingwu2.mp3', - 'audio/skill/spyinju1.mp3', - 'audio/skill/spyinju2.mp3', - 'audio/skill/spyishi1.mp3', - 'audio/skill/spyishi2.mp3', - 'audio/skill/spyuejian1.mp3', - 'audio/skill/spyuejian2.mp3', - 'audio/skill/spzhengjun1.mp3', - 'audio/skill/spzhengjun2.mp3', - 'audio/skill/spzhengjun3.mp3', - 'audio/skill/spzhenting1.mp3', - 'audio/skill/spzhenting2.mp3', - 'audio/skill/spzhenwei1.mp3', - 'audio/skill/spzhenwei2.mp3', - 'audio/skill/spzhuilie1.mp3', - 'audio/skill/spzhuilie2.mp3', - 'audio/skill/spzundi1.mp3', - 'audio/skill/spzundi2.mp3', - 'audio/skill/staraoshi1.mp3', - 'audio/skill/staraoshi2.mp3', - 'audio/skill/starcanxi1.mp3', - 'audio/skill/starcanxi2.mp3', - 'audio/skill/starhaoshou1.mp3', - 'audio/skill/starhaoshou2.mp3', - 'audio/skill/starjiaowang1.mp3', - 'audio/skill/starjiaowang2.mp3', - 'audio/skill/starlifeng1.mp3', - 'audio/skill/starlifeng2.mp3', - 'audio/skill/starpizhi1.mp3', - 'audio/skill/starpizhi2.mp3', - 'audio/skill/starsujun1.mp3', - 'audio/skill/starsujun2.mp3', - 'audio/skill/starweilin1.mp3', - 'audio/skill/starweilin2.mp3', - 'audio/skill/starxiaoyan1.mp3', - 'audio/skill/starxiaoyan2.mp3', - 'audio/skill/starzhangrong1.mp3', - 'audio/skill/starzhangrong2.mp3', - 'audio/skill/starzhonggu1.mp3', - 'audio/skill/starzhonggu2.mp3', - 'audio/skill/starzongshi1.mp3', - 'audio/skill/starzongshi2.mp3', - 'audio/skill/stianyi1.mp3', - 'audio/skill/stianyi2.mp3', - 'audio/skill/suishi1.mp3', - 'audio/skill/suishi2.mp3', - 'audio/skill/suizheng1.mp3', - 'audio/skill/suizheng2.mp3', - 'audio/skill/suoliang1.mp3', - 'audio/skill/suoliang2.mp3', - 'audio/skill/sushou1.mp3', - 'audio/skill/sushou2.mp3', - 'audio/skill/suzi1.mp3', - 'audio/skill/suzi2.mp3', - 'audio/skill/syjiqiao1.mp3', - 'audio/skill/syjiqiao2.mp3', - 'audio/skill/syxiongyi1.mp3', - 'audio/skill/syxiongyi2.mp3', - 'audio/skill/tairan1.mp3', - 'audio/skill/tairan2.mp3', - 'audio/skill/tamo1.mp3', - 'audio/skill/tamo2.mp3', - 'audio/skill/taoluan1.mp3', - 'audio/skill/taoluan2.mp3', - 'audio/skill/taomie1.mp3', - 'audio/skill/taomie2.mp3', - 'audio/skill/taomie3.mp3', - 'audio/skill/taoxi1.mp3', - 'audio/skill/taoxi2.mp3', - 'audio/skill/taoyin1.mp3', - 'audio/skill/taoyin2.mp3', - 'audio/skill/tashui1.mp3', - 'audio/skill/tashui2.mp3', - 'audio/skill/tengjia1.mp3', - 'audio/skill/tengjia2.mp3', - 'audio/skill/tianbian1.mp3', - 'audio/skill/tianbian2.mp3', - 'audio/skill/tiandao.mp3', - 'audio/skill/tiandu_re_guojia1.mp3', - 'audio/skill/tiandu_re_guojia2.mp3', - 'audio/skill/tiandu_xizhicai1.mp3', - 'audio/skill/tiandu_xizhicai2.mp3', - 'audio/skill/tiandu1.mp3', - 'audio/skill/tiandu2.mp3', - 'audio/skill/tianfu1.mp3', - 'audio/skill/tianfu2.mp3', - 'audio/skill/tianjie1.mp3', - 'audio/skill/tianjie2.mp3', - 'audio/skill/tianming1.mp3', - 'audio/skill/tianming2.mp3', - 'audio/skill/tianren1.mp3', - 'audio/skill/tianren2.mp3', - 'audio/skill/tianshu1.mp3', - 'audio/skill/tianshu2.mp3', - 'audio/skill/tiansuan1.mp3', - 'audio/skill/tiansuan2.mp3', - 'audio/skill/tianxiang_daxiaoqiao1.mp3', - 'audio/skill/tianxiang_daxiaoqiao2.mp3', - 'audio/skill/tianxiang_ol_xiaoqiao1.mp3', - 'audio/skill/tianxiang_ol_xiaoqiao2.mp3', - 'audio/skill/tianxiang_re_xiaoqiao1.mp3', - 'audio/skill/tianxiang_re_xiaoqiao2.mp3', - 'audio/skill/tianxiang1.mp3', - 'audio/skill/tianxiang2.mp3', - 'audio/skill/tianxing1.mp3', - 'audio/skill/tianxing2.mp3', - 'audio/skill/tianyi_re_taishici1.mp3', - 'audio/skill/tianyi_re_taishici2.mp3', - 'audio/skill/tianyi1.mp3', - 'audio/skill/tianyi2.mp3', - 'audio/skill/tianyin1.mp3', - 'audio/skill/tianyin2.mp3', - 'audio/skill/tianyun1.mp3', - 'audio/skill/tianyun2.mp3', - 'audio/skill/tianze1.mp3', - 'audio/skill/tianze2.mp3', - 'audio/skill/tianzuo1.mp3', - 'audio/skill/tianzuo2.mp3', - 'audio/skill/tiaoxin_gz_jiangwei1.mp3', - 'audio/skill/tiaoxin_gz_jiangwei2.mp3', - 'audio/skill/tiaoxin_ol_jiangwei1.mp3', - 'audio/skill/tiaoxin_ol_jiangwei2.mp3', - 'audio/skill/tiaoxin_re_jiangwei1.mp3', - 'audio/skill/tiaoxin_re_jiangwei2.mp3', - 'audio/skill/tiaoxin_sp_jiangwei1.mp3', - 'audio/skill/tiaoxin_sp_jiangwei2.mp3', - 'audio/skill/tiaoxin_xiahouba1.mp3', - 'audio/skill/tiaoxin_xiahouba2.mp3', - 'audio/skill/tiaoxin1.mp3', - 'audio/skill/tiaoxin2.mp3', - 'audio/skill/tieji1.mp3', - 'audio/skill/tieji2.mp3', - 'audio/skill/tiqi1.mp3', - 'audio/skill/tiqi2.mp3', - 'audio/skill/tongbo1.mp3', - 'audio/skill/tongbo2.mp3', - 'audio/skill/tongduo1.mp3', - 'audio/skill/tongduo2.mp3', - 'audio/skill/tongji1.mp3', - 'audio/skill/tongji2.mp3', - 'audio/skill/tongli1.mp3', - 'audio/skill/tongli2.mp3', - 'audio/skill/tongqu1.mp3', - 'audio/skill/tongqu2.mp3', - 'audio/skill/tongwei1.mp3', - 'audio/skill/tongwei2.mp3', - 'audio/skill/tongxie1.mp3', - 'audio/skill/tongxie2.mp3', - 'audio/skill/tongyuan1.mp3', - 'audio/skill/tongyuan2.mp3', - 'audio/skill/tspowei1.mp3', - 'audio/skill/tspowei2.mp3', - 'audio/skill/tspowei3.mp3', - 'audio/skill/tsumugi_mugyu1.mp3', - 'audio/skill/tsumugi_mugyu2.mp3', - 'audio/skill/tsumugi_mugyu3.mp3', - 'audio/skill/tsumugi_mugyu4.mp3', - 'audio/skill/tsumugi_mugyu5.mp3', - 'audio/skill/tuifeng1.mp3', - 'audio/skill/tuifeng2.mp3', - 'audio/skill/tuishi1.mp3', - 'audio/skill/tuishi2.mp3', - 'audio/skill/tuiyan1.mp3', - 'audio/skill/tuiyan2.mp3', - 'audio/skill/tunchu1.mp3', - 'audio/skill/tunchu2.mp3', - 'audio/skill/tuntian_gz_dengai1.mp3', - 'audio/skill/tuntian_gz_dengai2.mp3', - 'audio/skill/tuntian1.mp3', - 'audio/skill/tuntian2.mp3', - 'audio/skill/tuogu1.mp3', - 'audio/skill/tuogu2.mp3', - 'audio/skill/tuoxian.mp3', - 'audio/skill/tuoxian2.mp3', - 'audio/skill/tuxi1.mp3', - 'audio/skill/tuxi2.mp3', - 'audio/skill/tuxing1.mp3', - 'audio/skill/tuxing2.mp3', - 'audio/skill/twbingde1.mp3', - 'audio/skill/twbingde2.mp3', - 'audio/skill/twbudao1.mp3', - 'audio/skill/twbudao2.mp3', - 'audio/skill/twchaofeng1.mp3', - 'audio/skill/twchaofeng2.mp3', - 'audio/skill/twchayi1.mp3', - 'audio/skill/twchengxi1.mp3', - 'audio/skill/twchengxi2.mp3', - 'audio/skill/twchongqi1.mp3', - 'audio/skill/twchongqi2.mp3', - 'audio/skill/twchuanshu1.mp3', - 'audio/skill/twchuanshu2.mp3', - 'audio/skill/twchungang1.mp3', - 'audio/skill/twchungang2.mp3', - 'audio/skill/twdanfa1.mp3', - 'audio/skill/twdanfa2.mp3', - 'audio/skill/twdanlie1.mp3', - 'audio/skill/twdanlie2.mp3', - 'audio/skill/twdianyi1.mp3', - 'audio/skill/twdianyi2.mp3', - 'audio/skill/twdingzhen1.mp3', - 'audio/skill/twdingzhen2.mp3', - 'audio/skill/twduoren1.mp3', - 'audio/skill/twduoren2.mp3', - 'audio/skill/twfeifu1.mp3', - 'audio/skill/twfeifu2.mp3', - 'audio/skill/twfengji1.mp3', - 'audio/skill/twfengji2.mp3', - 'audio/skill/twfenwang1.mp3', - 'audio/skill/twfenwang2.mp3', - 'audio/skill/twfenwu1.mp3', - 'audio/skill/twfenwu2.mp3', - 'audio/skill/twfucuan1.mp3', - 'audio/skill/twfucuan2.mp3', - 'audio/skill/twfujian1.mp3', - 'audio/skill/twfujian2.mp3', - 'audio/skill/twfupan1.mp3', - 'audio/skill/twfupan2.mp3', - 'audio/skill/twfupan3.mp3', - 'audio/skill/twfuzuan1.mp3', - 'audio/skill/twfuzuan2.mp3', - 'audio/skill/twgezhi1.mp3', - 'audio/skill/twgezhi2.mp3', - 'audio/skill/twgongge1.mp3', - 'audio/skill/twgongge2.mp3', - 'audio/skill/twgongge3.mp3', - 'audio/skill/twhanyu1.mp3', - 'audio/skill/twhanyu2.mp3', - 'audio/skill/twhuiyuan1.mp3', - 'audio/skill/twhuiyuan2.mp3', - 'audio/skill/twhuzhong1.mp3', - 'audio/skill/twhuzhong2.mp3', - 'audio/skill/twjiange1.mp3', - 'audio/skill/twjiange2.mp3', - 'audio/skill/twjianming1.mp3', - 'audio/skill/twjianming2.mp3', - 'audio/skill/twjianwei1.mp3', - 'audio/skill/twjianwei2.mp3', - 'audio/skill/twjiaohua1.mp3', - 'audio/skill/twjiaohua2.mp3', - 'audio/skill/twjichou1.mp3', - 'audio/skill/twjichou2.mp3', - 'audio/skill/twjiekuang1.mp3', - 'audio/skill/twjiekuang2.mp3', - 'audio/skill/twjieyu1.mp3', - 'audio/skill/twjieyu2.mp3', - 'audio/skill/twjijiang1.mp3', - 'audio/skill/twjijiang2.mp3', - 'audio/skill/twjilun1.mp3', - 'audio/skill/twjilun2.mp3', - 'audio/skill/twjingce1.mp3', - 'audio/skill/twjingce2.mp3', - 'audio/skill/twjuchen1.mp3', - 'audio/skill/twjuchen2.mp3', - 'audio/skill/twjuezhu1.mp3', - 'audio/skill/twjuezhu2.mp3', - 'audio/skill/twjuntun1.mp3', - 'audio/skill/twjuntun2.mp3', - 'audio/skill/twkaiji1.mp3', - 'audio/skill/twkaiji2.mp3', - 'audio/skill/twkaizeng1.mp3', - 'audio/skill/twkaizeng2.mp3', - 'audio/skill/twkujian1.mp3', - 'audio/skill/twkujian2.mp3', - 'audio/skill/twkujian3.mp3', - 'audio/skill/twkunsi1.mp3', - 'audio/skill/twkunsi2.mp3', - 'audio/skill/twlanjiang.mp3', - 'audio/skill/twliexi1.mp3', - 'audio/skill/twliexi2.mp3', - 'audio/skill/twlijian1.mp3', - 'audio/skill/twlijian2.mp3', - 'audio/skill/twlingbao1.mp3', - 'audio/skill/twlingbao2.mp3', - 'audio/skill/twlingfa1.mp3', - 'audio/skill/twlingfa2.mp3', - 'audio/skill/twluanlve1.mp3', - 'audio/skill/twluanlve2.mp3', - 'audio/skill/twluannian1.mp3', - 'audio/skill/twluannian2.mp3', - 'audio/skill/twlvren1.mp3', - 'audio/skill/twlvren2.mp3', - 'audio/skill/twmiaolve1.mp3', - 'audio/skill/twmiaolve2.mp3', - 'audio/skill/twmutao1.mp3', - 'audio/skill/twmutao2.mp3', - 'audio/skill/twmuyue1.mp3', - 'audio/skill/twneirao1.mp3', - 'audio/skill/twneirao2.mp3', - 'audio/skill/twqingkou1.mp3', - 'audio/skill/twqingkou2.mp3', - 'audio/skill/twqingren1.mp3', - 'audio/skill/twqingren2.mp3', - 'audio/skill/twqingtao1.mp3', - 'audio/skill/twqingtao2.mp3', - 'audio/skill/twqiongji1.mp3', - 'audio/skill/twqiongji2.mp3', - 'audio/skill/twquanqian1.mp3', - 'audio/skill/twquanqian2.mp3', - 'audio/skill/twrenchou1.mp3', - 'audio/skill/twrenchou2.mp3', - 'audio/skill/twrouke1.mp3', - 'audio/skill/twrouke2.mp3', - 'audio/skill/twruilian1.mp3', - 'audio/skill/twruilian2.mp3', - 'audio/skill/twshanghe1.mp3', - 'audio/skill/twshanghe2.mp3', - 'audio/skill/twshenyi1.mp3', - 'audio/skill/twshenyi2.mp3', - 'audio/skill/twshepan1.mp3', - 'audio/skill/twshepan2.mp3', - 'audio/skill/twshexhong1.mp3', - 'audio/skill/twshexhong2.mp3', - 'audio/skill/twshezhong1.mp3', - 'audio/skill/twshezhong2.mp3', - 'audio/skill/twshigong1.mp3', - 'audio/skill/twshigong2.mp3', - 'audio/skill/twshoushou1.mp3', - 'audio/skill/twshoushou2.mp3', - 'audio/skill/twsidai1.mp3', - 'audio/skill/twsidai2.mp3', - 'audio/skill/twsidao1.mp3', - 'audio/skill/twsidao2.mp3', - 'audio/skill/twsuizheng1.mp3', - 'audio/skill/twsuizheng2.mp3', - 'audio/skill/twsuizheng3.mp3', - 'audio/skill/twtanfeng1.mp3', - 'audio/skill/twtanfeng2.mp3', - 'audio/skill/twtiaoxin1.mp3', - 'audio/skill/twtiaoxin2.mp3', - 'audio/skill/twtuidao1.mp3', - 'audio/skill/twtuidao2.mp3', - 'audio/skill/twwuhun1.mp3', - 'audio/skill/twwuhun2.mp3', - 'audio/skill/twxiafeng1.mp3', - 'audio/skill/twxiafeng2.mp3', - 'audio/skill/twxianfeng1.mp3', - 'audio/skill/twxianfeng2.mp3', - 'audio/skill/twxiawang1.mp3', - 'audio/skill/twxiawang2.mp3', - 'audio/skill/twxiawei1.mp3', - 'audio/skill/twxiawei2.mp3', - 'audio/skill/twxinghan1.mp3', - 'audio/skill/twxinghan2.mp3', - 'audio/skill/twxingzhui1.mp3', - 'audio/skill/twxingzhui2.mp3', - 'audio/skill/twxiongjun1.mp3', - 'audio/skill/twxiongjun2.mp3', - 'audio/skill/twxiongxi1.mp3', - 'audio/skill/twxiongxi2.mp3', - 'audio/skill/twxiongzheng1.mp3', - 'audio/skill/twxiongzheng2.mp3', - 'audio/skill/twxuechang1.mp3', - 'audio/skill/twxuechang2.mp3', - 'audio/skill/twyangming1.mp3', - 'audio/skill/twyangming2.mp3', - 'audio/skill/twyangshi1.mp3', - 'audio/skill/twyangshi2.mp3', - 'audio/skill/twyanshi1.mp3', - 'audio/skill/twyanshi2.mp3', - 'audio/skill/twyanshi3.mp3', - 'audio/skill/twyiju1.mp3', - 'audio/skill/twyiju2.mp3', - 'audio/skill/twyimou1.mp3', - 'audio/skill/twyimou2.mp3', - 'audio/skill/twyingji1.mp3', - 'audio/skill/twyingji2.mp3', - 'audio/skill/twyingjia1.mp3', - 'audio/skill/twyingjia2.mp3', - 'audio/skill/twyouye1.mp3', - 'audio/skill/twyouye2.mp3', - 'audio/skill/twyujue1.mp3', - 'audio/skill/twyujue2.mp3', - 'audio/skill/twyulong1.mp3', - 'audio/skill/twyulong2.mp3', - 'audio/skill/twzhangwu1.mp3', - 'audio/skill/twzhangwu2.mp3', - 'audio/skill/twzhengjian1.mp3', - 'audio/skill/twzhengjian2.mp3', - 'audio/skill/twzhenhu1.mp3', - 'audio/skill/twzhenhu2.mp3', - 'audio/skill/twzhenxi1.mp3', - 'audio/skill/twzhenxi2.mp3', - 'audio/skill/twzhian1.mp3', - 'audio/skill/twzhian2.mp3', - 'audio/skill/twzhiji1.mp3', - 'audio/skill/twzhiji2.mp3', - 'audio/skill/twzhiqu1.mp3', - 'audio/skill/twzhiqu2.mp3', - 'audio/skill/twzhongchi1.mp3', - 'audio/skill/twzhongchi2.mp3', - 'audio/skill/twzhuidu1.mp3', - 'audio/skill/twzhuidu2.mp3', - 'audio/skill/vtbguisha1.mp3', - 'audio/skill/vtbleyu1.mp3', - 'audio/skill/vtbmeiniang1.mp3', - 'audio/skill/vtbshanwu1.mp3', - 'audio/skill/vtbshuli1.mp3', - 'audio/skill/vtbtaoyan1.mp3', - 'audio/skill/vtbxianli1.mp3', - 'audio/skill/vtbyanli1.mp3', - 'audio/skill/vtbyaoli1.mp3', - 'audio/skill/vtbyuanli1.mp3', - 'audio/skill/waishi1.mp3', - 'audio/skill/waishi2.mp3', - 'audio/skill/wanggui1.mp3', - 'audio/skill/wanggui2.mp3', - 'audio/skill/wangjing1.mp3', - 'audio/skill/wangjing2.mp3', - 'audio/skill/wangong1.mp3', - 'audio/skill/wangong2.mp3', - 'audio/skill/wangxi1.mp3', - 'audio/skill/wangxi2.mp3', - 'audio/skill/wangzun1.mp3', - 'audio/skill/wangzun2.mp3', - 'audio/skill/wanlan1.mp3', - 'audio/skill/wanlan2.mp3', - 'audio/skill/wanrong1.mp3', - 'audio/skill/wanrong2.mp3', - 'audio/skill/wansha_boss_lvbu31.mp3', - 'audio/skill/wansha_boss_lvbu32.mp3', - 'audio/skill/wansha_re_jiaxu1.mp3', - 'audio/skill/wansha_re_jiaxu2.mp3', - 'audio/skill/wansha_shen_simayi1.mp3', - 'audio/skill/wansha_shen_simayi2.mp3', - 'audio/skill/wansha1.mp3', - 'audio/skill/wansha2.mp3', - 'audio/skill/wanwei1.mp3', - 'audio/skill/wanwei2.mp3', - 'audio/skill/wanyi1.mp3', - 'audio/skill/wanyi2.mp3', - 'audio/skill/weicheng1.mp3', - 'audio/skill/weicheng2.mp3', - 'audio/skill/weidi1.mp3', - 'audio/skill/weidi2.mp3', - 'audio/skill/weifeng1.mp3', - 'audio/skill/weifeng2.mp3', - 'audio/skill/weijing1.mp3', - 'audio/skill/weijing2.mp3', - 'audio/skill/weikui1.mp3', - 'audio/skill/weikui2.mp3', - 'audio/skill/weilie1.mp3', - 'audio/skill/weilie2.mp3', - 'audio/skill/weimeng1.mp3', - 'audio/skill/weimeng2.mp3', - 'audio/skill/weimu1.mp3', - 'audio/skill/weimu2.mp3', - 'audio/skill/weipo1.mp3', - 'audio/skill/weipo2.mp3', - 'audio/skill/weishu1.mp3', - 'audio/skill/weishu2.mp3', - 'audio/skill/weiyi1.mp3', - 'audio/skill/weiyi2.mp3', - 'audio/skill/weizhong1.mp3', - 'audio/skill/weizhong2.mp3', - 'audio/skill/wendao1.mp3', - 'audio/skill/wendao2.mp3', - 'audio/skill/wengua1.mp3', - 'audio/skill/wengua2.mp3', - 'audio/skill/wfyuyan1.mp3', - 'audio/skill/wfyuyan2.mp3', - 'audio/skill/wlcuorui1.mp3', - 'audio/skill/wlcuorui2.mp3', - 'audio/skill/wufei1.mp3', - 'audio/skill/wufei2.mp3', - 'audio/skill/wuhun21.mp3', - 'audio/skill/wuhun22.mp3', - 'audio/skill/wuji1.mp3', - 'audio/skill/wuji2.mp3', - 'audio/skill/wulie1.mp3', - 'audio/skill/wulie2.mp3', - 'audio/skill/wuling1.mp3', - 'audio/skill/wuling2.mp3', - 'audio/skill/wumou1.mp3', - 'audio/skill/wumou2.mp3', - 'audio/skill/wuniang1.mp3', - 'audio/skill/wuniang2.mp3', - 'audio/skill/wuqian1.mp3', - 'audio/skill/wuqian2.mp3', - 'audio/skill/wuqin1.mp3', - 'audio/skill/wuqin2.mp3', - 'audio/skill/wurong1.mp3', - 'audio/skill/wurong2.mp3', - 'audio/skill/wushen1.mp3', - 'audio/skill/wushen2.mp3', - 'audio/skill/wusheng_dc_jsp_guanyu1.mp3', - 'audio/skill/wusheng_dc_jsp_guanyu2.mp3', - 'audio/skill/wusheng_guansuo1.mp3', - 'audio/skill/wusheng_guansuo2.mp3', - 'audio/skill/wusheng_guanzhang1.mp3', - 'audio/skill/wusheng_guanzhang2.mp3', - 'audio/skill/wusheng_jsp_guanyu1.mp3', - 'audio/skill/wusheng_jsp_guanyu2.mp3', - 'audio/skill/wusheng_re_guanyu1.mp3', - 'audio/skill/wusheng_re_guanyu2.mp3', - 'audio/skill/wusheng_re_guanzhang1.mp3', - 'audio/skill/wusheng_re_guanzhang2.mp3', - 'audio/skill/wusheng1.mp3', - 'audio/skill/wusheng2.mp3', - 'audio/skill/wushuang_lvlingqi1.mp3', - 'audio/skill/wushuang_lvlingqi2.mp3', - 'audio/skill/wushuang_re_lvbu1.mp3', - 'audio/skill/wushuang_re_lvbu2.mp3', - 'audio/skill/wushuang_shen_lvbu1.mp3', - 'audio/skill/wushuang_shen_lvbu2.mp3', - 'audio/skill/wushuang_wechat_lvbu1.mp3', - 'audio/skill/wushuang_wechat_lvbu2.mp3', - 'audio/skill/wushuang1.mp3', - 'audio/skill/wushuang11.mp3', - 'audio/skill/wushuang12.mp3', - 'audio/skill/wushuang2.mp3', - 'audio/skill/wushuang21.mp3', - 'audio/skill/wushuang22.mp3', - 'audio/skill/wuxin1.mp3', - 'audio/skill/wuxin2.mp3', - 'audio/skill/wuyan1.mp3', - 'audio/skill/wuyan2.mp3', - 'audio/skill/wuyuan1.mp3', - 'audio/skill/wuyuan2.mp3', - 'audio/skill/wylianji1.mp3', - 'audio/skill/wylianji2.mp3', - 'audio/skill/xhzhiyan1.mp3', - 'audio/skill/xhzhiyan2.mp3', - 'audio/skill/xianfu1.mp3', - 'audio/skill/xianfu2.mp3', - 'audio/skill/xianfu3.mp3', - 'audio/skill/xianfu4.mp3', - 'audio/skill/xianfu5.mp3', - 'audio/skill/xianfu6.mp3', - 'audio/skill/xianghai1.mp3', - 'audio/skill/xianghai2.mp3', - 'audio/skill/xiangle_ol_liushan1.mp3', - 'audio/skill/xiangle_ol_liushan2.mp3', - 'audio/skill/xiangle_re_liushan1.mp3', - 'audio/skill/xiangle_re_liushan2.mp3', - 'audio/skill/xiangle1.mp3', - 'audio/skill/xiangle2.mp3', - 'audio/skill/xiangshu1.mp3', - 'audio/skill/xiangshu2.mp3', - 'audio/skill/xianjing1.mp3', - 'audio/skill/xianjing2.mp3', - 'audio/skill/xianshuai1.mp3', - 'audio/skill/xianshuai2.mp3', - 'audio/skill/xiansi_re_liufeng1.mp3', - 'audio/skill/xiansi_re_liufeng2.mp3', - 'audio/skill/xiansi1.mp3', - 'audio/skill/xiansi2.mp3', - 'audio/skill/xiansi21.mp3', - 'audio/skill/xiansi22.mp3', - 'audio/skill/xiantu1.mp3', - 'audio/skill/xiantu2.mp3', - 'audio/skill/xianwan1.mp3', - 'audio/skill/xianwan2.mp3', - 'audio/skill/xianwang1.mp3', - 'audio/skill/xianwang2.mp3', - 'audio/skill/xianwei1.mp3', - 'audio/skill/xianwei2.mp3', - 'audio/skill/xianzhen1.mp3', - 'audio/skill/xianzhen2.mp3', - 'audio/skill/xianzhou_xin_caifuren1.mp3', - 'audio/skill/xianzhou_xin_caifuren2.mp3', - 'audio/skill/xianzhou1.mp3', - 'audio/skill/xianzhou2.mp3', - 'audio/skill/xianzhu1.mp3', - 'audio/skill/xianzhu2.mp3', - 'audio/skill/xiaoguo1.mp3', - 'audio/skill/xiaoguo2.mp3', - 'audio/skill/xiaoji_re_sunshangxiang1.mp3', - 'audio/skill/xiaoji_re_sunshangxiang2.mp3', - 'audio/skill/xiaoji_sp_sunshangxiang1.mp3', - 'audio/skill/xiaoji_sp_sunshangxiang2.mp3', - 'audio/skill/xiaoji1.mp3', - 'audio/skill/xiaoji2.mp3', - 'audio/skill/xiaoni1.mp3', - 'audio/skill/xiaoni2.mp3', - 'audio/skill/xiaowu1.mp3', - 'audio/skill/xiaowu2.mp3', - 'audio/skill/xiaoxi_hansui1.mp3', - 'audio/skill/xiaoxi_hansui2.mp3', - 'audio/skill/xiaoxi_machao1.mp3', - 'audio/skill/xiaoxi_machao2.mp3', - 'audio/skill/xiaoxi_pangde1.mp3', - 'audio/skill/xiaoxi_pangde2.mp3', - 'audio/skill/xiashu1.mp3', - 'audio/skill/xiashu2.mp3', - 'audio/skill/xibing1.mp3', - 'audio/skill/xibing2.mp3', - 'audio/skill/xiechan1.mp3', - 'audio/skill/xiechan2.mp3', - 'audio/skill/xiecui1.mp3', - 'audio/skill/xiecui2.mp3', - 'audio/skill/xiemu1.mp3', - 'audio/skill/xiemu2.mp3', - 'audio/skill/xijue_tuxi1.mp3', - 'audio/skill/xijue_tuxi2.mp3', - 'audio/skill/xijue_xiaoguo1.mp3', - 'audio/skill/xijue_xiaoguo2.mp3', - 'audio/skill/xijue1.mp3', - 'audio/skill/xijue2.mp3', - 'audio/skill/xinanjian1.mp3', - 'audio/skill/xinanjian2.mp3', - 'audio/skill/xinbenxi1.mp3', - 'audio/skill/xinbenxi2.mp3', - 'audio/skill/xinbuyi1.mp3', - 'audio/skill/xinbuyi2.mp3', - 'audio/skill/xindanshou1.mp3', - 'audio/skill/xindanshou2.mp3', - 'audio/skill/xinduodao1.mp3', - 'audio/skill/xinduodao2.mp3', - 'audio/skill/xinenyuan1.mp3', - 'audio/skill/xinenyuan2.mp3', - 'audio/skill/xinfencheng_re_liru1.mp3', - 'audio/skill/xinfencheng_re_liru2.mp3', - 'audio/skill/xinfencheng1.mp3', - 'audio/skill/xinfencheng2.mp3', - 'audio/skill/xinfu_andong1.mp3', - 'audio/skill/xinfu_andong2.mp3', - 'audio/skill/xinfu_bijing1.mp3', - 'audio/skill/xinfu_bijing2.mp3', - 'audio/skill/xinfu_chenghao1.mp3', - 'audio/skill/xinfu_chenghao2.mp3', - 'audio/skill/xinfu_daigong1.mp3', - 'audio/skill/xinfu_daigong2.mp3', - 'audio/skill/xinfu_denglou1.mp3', - 'audio/skill/xinfu_denglou2.mp3', - 'audio/skill/xinfu_dianhu1.mp3', - 'audio/skill/xinfu_dianhu2.mp3', - 'audio/skill/xinfu_dianhua1.mp3', - 'audio/skill/xinfu_dianhua2.mp3', - 'audio/skill/xinfu_duanfa1.mp3', - 'audio/skill/xinfu_duanfa2.mp3', - 'audio/skill/xinfu_falu1.mp3', - 'audio/skill/xinfu_falu2.mp3', - 'audio/skill/xinfu_fangtong1.mp3', - 'audio/skill/xinfu_fangtong2.mp3', - 'audio/skill/xinfu_fuhai1.mp3', - 'audio/skill/xinfu_fuhai2.mp3', - 'audio/skill/xinfu_fujian1.mp3', - 'audio/skill/xinfu_fujian2.mp3', - 'audio/skill/xinfu_fuyin1.mp3', - 'audio/skill/xinfu_fuyin2.mp3', - 'audio/skill/xinfu_gongqing_gz_panjun1.mp3', - 'audio/skill/xinfu_gongqing_gz_panjun2.mp3', - 'audio/skill/xinfu_gongqing1.mp3', - 'audio/skill/xinfu_gongqing2.mp3', - 'audio/skill/xinfu_guanchao1.mp3', - 'audio/skill/xinfu_guanchao2.mp3', - 'audio/skill/xinfu_guanwei1.mp3', - 'audio/skill/xinfu_guanwei2.mp3', - 'audio/skill/xinfu_guhuo2.mp3', - 'audio/skill/xinfu_guolun1.mp3', - 'audio/skill/xinfu_guolun2.mp3', - 'audio/skill/xinfu_jianji1.mp3', - 'audio/skill/xinfu_jianji2.mp3', - 'audio/skill/xinfu_jianjie1.mp3', - 'audio/skill/xinfu_jianjie2.mp3', - 'audio/skill/xinfu_jianjie3.mp3', - 'audio/skill/xinfu_jijie1.mp3', - 'audio/skill/xinfu_jijie2.mp3', - 'audio/skill/xinfu_jijun1.mp3', - 'audio/skill/xinfu_jijun2.mp3', - 'audio/skill/xinfu_jingxie1.mp3', - 'audio/skill/xinfu_jingxie2.mp3', - 'audio/skill/xinfu_jixu1.mp3', - 'audio/skill/xinfu_jixu2.mp3', - 'audio/skill/xinfu_jiyuan1.mp3', - 'audio/skill/xinfu_jiyuan2.mp3', - 'audio/skill/xinfu_kannan1.mp3', - 'audio/skill/xinfu_kannan2.mp3', - 'audio/skill/xinfu_langxi1.mp3', - 'audio/skill/xinfu_langxi2.mp3', - 'audio/skill/xinfu_lianpian1.mp3', - 'audio/skill/xinfu_lianpian2.mp3', - 'audio/skill/xinfu_limu1.mp3', - 'audio/skill/xinfu_limu2.mp3', - 'audio/skill/xinfu_lingren1.mp3', - 'audio/skill/xinfu_lingren2.mp3', - 'audio/skill/xinfu_longyuan1.mp3', - 'audio/skill/xinfu_longyuan2.mp3', - 'audio/skill/xinfu_lveming1.mp3', - 'audio/skill/xinfu_lveming2.mp3', - 'audio/skill/xinfu_pingcai.mp3', - 'audio/skill/xinfu_qiai1.mp3', - 'audio/skill/xinfu_qiai2.mp3', - 'audio/skill/xinfu_qianchong1.mp3', - 'audio/skill/xinfu_qianchong2.mp3', - 'audio/skill/xinfu_qianchong3.mp3', - 'audio/skill/xinfu_qianxin1.mp3', - 'audio/skill/xinfu_qianxin2.mp3', - 'audio/skill/xinfu_qiaosi1.mp3', - 'audio/skill/xinfu_qiaosi2.mp3', - 'audio/skill/xinfu_sanwen1.mp3', - 'audio/skill/xinfu_sanwen2.mp3', - 'audio/skill/xinfu_shajue1.mp3', - 'audio/skill/xinfu_shajue2.mp3', - 'audio/skill/xinfu_shangjian1.mp3', - 'audio/skill/xinfu_shangjian2.mp3', - 'audio/skill/xinfu_sidao1.mp3', - 'audio/skill/xinfu_sidao2.mp3', - 'audio/skill/xinfu_songsang1.mp3', - 'audio/skill/xinfu_songsang2.mp3', - 'audio/skill/xinfu_tanbei1.mp3', - 'audio/skill/xinfu_tanbei2.mp3', - 'audio/skill/xinfu_tunan1.mp3', - 'audio/skill/xinfu_tunan2.mp3', - 'audio/skill/xinfu_tunjun1.mp3', - 'audio/skill/xinfu_tunjun2.mp3', - 'audio/skill/xinfu_tushe1.mp3', - 'audio/skill/xinfu_tushe2.mp3', - 'audio/skill/xinfu_weilu1.mp3', - 'audio/skill/xinfu_weilu2.mp3', - 'audio/skill/xinfu_wuniang1.mp3', - 'audio/skill/xinfu_wuniang2.mp3', - 'audio/skill/xinfu_xingluan1.mp3', - 'audio/skill/xinfu_xingluan2.mp3', - 'audio/skill/xinfu_xingzhao.mp3', - 'audio/skill/xinfu_xingzhao2.mp3', - 'audio/skill/xinfu_xionghuo1.mp3', - 'audio/skill/xinfu_xionghuo2.mp3', - 'audio/skill/xinfu_xunxian1.mp3', - 'audio/skill/xinfu_xunxian2.mp3', - 'audio/skill/xinfu_xushen1.mp3', - 'audio/skill/xinfu_xushen2.mp3', - 'audio/skill/xinfu_yingshi1.mp3', - 'audio/skill/xinfu_yingshi2.mp3', - 'audio/skill/xinfu_yinshi1.mp3', - 'audio/skill/xinfu_yinshi2.mp3', - 'audio/skill/xinfu_yisuan1.mp3', - 'audio/skill/xinfu_yisuan2.mp3', - 'audio/skill/xinfu_youdi1.mp3', - 'audio/skill/xinfu_youdi2.mp3', - 'audio/skill/xinfu_zengdao1.mp3', - 'audio/skill/xinfu_zengdao2.mp3', - 'audio/skill/xinfu_zhanji1.mp3', - 'audio/skill/xinfu_zhanji2.mp3', - 'audio/skill/xinfu_zhaoxin1.mp3', - 'audio/skill/xinfu_zhaoxin2.mp3', - 'audio/skill/xinfu_zhennan1.mp3', - 'audio/skill/xinfu_zhennan2.mp3', - 'audio/skill/xinfu_zhenxing1.mp3', - 'audio/skill/xinfu_zhenxing2.mp3', - 'audio/skill/xinfu_zhenyi1.mp3', - 'audio/skill/xinfu_zhenyi2.mp3', - 'audio/skill/xinfu_zuilun1.mp3', - 'audio/skill/xinfu_zuilun2.mp3', - 'audio/skill/xinfuli1.mp3', - 'audio/skill/xinfuli2.mp3', - 'audio/skill/xinganlu1.mp3', - 'audio/skill/xinganlu2.mp3', - 'audio/skill/xingbu1.mp3', - 'audio/skill/xingbu2.mp3', - 'audio/skill/xingchong1.mp3', - 'audio/skill/xingchong2.mp3', - 'audio/skill/xinghan1.mp3', - 'audio/skill/xinghan2.mp3', - 'audio/skill/xingongji1.mp3', - 'audio/skill/xingongji2.mp3', - 'audio/skill/xingqi1.mp3', - 'audio/skill/xingqi2.mp3', - 'audio/skill/xingshang1.mp3', - 'audio/skill/xingshang2.mp3', - 'audio/skill/xingshen1.mp3', - 'audio/skill/xingshen2.mp3', - 'audio/skill/xingshuai1.mp3', - 'audio/skill/xingshuai2.mp3', - 'audio/skill/xingtu1.mp3', - 'audio/skill/xingtu2.mp3', - 'audio/skill/xinguidao1.mp3', - 'audio/skill/xinguidao2.mp3', - 'audio/skill/xinguixiu1.mp3', - 'audio/skill/xinguixiu2.mp3', - 'audio/skill/xingwu1.mp3', - 'audio/skill/xingwu2.mp3', - 'audio/skill/xingxue1.mp3', - 'audio/skill/xingxue2.mp3', - 'audio/skill/xingzuo1.mp3', - 'audio/skill/xingzuo2.mp3', - 'audio/skill/xinhuangtian2_re_zhangjiao1.mp3', - 'audio/skill/xinhuangtian2_re_zhangjiao2.mp3', - 'audio/skill/xinjiangchi1.mp3', - 'audio/skill/xinjiangchi2.mp3', - 'audio/skill/xinjianying1.mp3', - 'audio/skill/xinjianying2.mp3', - 'audio/skill/xinjiaojin1.mp3', - 'audio/skill/xinjiaojin2.mp3', - 'audio/skill/xinjiefan1.mp3', - 'audio/skill/xinjiefan2.mp3', - 'audio/skill/xinjiewei1.mp3', - 'audio/skill/xinjiewei2.mp3', - 'audio/skill/xinjingce1.mp3', - 'audio/skill/xinjingce2.mp3', - 'audio/skill/xinjuece1.mp3', - 'audio/skill/xinjuece2.mp3', - 'audio/skill/xinjuejing1.mp3', - 'audio/skill/xinjuejing2.mp3', - 'audio/skill/xinjujian1.mp3', - 'audio/skill/xinjujian2.mp3', - 'audio/skill/xinjushou1.mp3', - 'audio/skill/xinjushou2.mp3', - 'audio/skill/xinjyzongshi1.mp3', - 'audio/skill/xinjyzongshi2.mp3', - 'audio/skill/xinkuangfu1.mp3', - 'audio/skill/xinkuangfu2.mp3', - 'audio/skill/xinleiji1.mp3', - 'audio/skill/xinleiji2.mp3', - 'audio/skill/xinlianhuan_ol_pangtong1.mp3', - 'audio/skill/xinlianhuan_ol_pangtong2.mp3', - 'audio/skill/xinlianhuan1.mp3', - 'audio/skill/xinlianhuan2.mp3', - 'audio/skill/xinmieji1.mp3', - 'audio/skill/xinmieji2.mp3', - 'audio/skill/xinniluan1.mp3', - 'audio/skill/xinniluan2.mp3', - 'audio/skill/xinpaiyi1.mp3', - 'audio/skill/xinpaiyi2.mp3', - 'audio/skill/xinpingkou1.mp3', - 'audio/skill/xinpingkou2.mp3', - 'audio/skill/xinpojun1.mp3', - 'audio/skill/xinpojun2.mp3', - 'audio/skill/xinqiaoshui1.mp3', - 'audio/skill/xinqiaoshui2.mp3', - 'audio/skill/xinqieting1.mp3', - 'audio/skill/xinqieting2.mp3', - 'audio/skill/xinqingxi1.mp3', - 'audio/skill/xinqingxi2.mp3', - 'audio/skill/xinqiuyuan1.mp3', - 'audio/skill/xinqiuyuan2.mp3', - 'audio/skill/xinquanji1.mp3', - 'audio/skill/xinquanji2.mp3', - 'audio/skill/xinrende1.mp3', - 'audio/skill/xinrende2.mp3', - 'audio/skill/xinsheng1.mp3', - 'audio/skill/xinsheng2.mp3', - 'audio/skill/xinshenxing1.mp3', - 'audio/skill/xinshenxing2.mp3', - 'audio/skill/xintan1.mp3', - 'audio/skill/xintan2.mp3', - 'audio/skill/xinwurong1.mp3', - 'audio/skill/xinwurong2.mp3', - 'audio/skill/xinwurong3.mp3', - 'audio/skill/xinwusheng1.mp3', - 'audio/skill/xinwusheng2.mp3', - 'audio/skill/xinwuyan1.mp3', - 'audio/skill/xinwuyan2.mp3', - 'audio/skill/xinxuanhuo1.mp3', - 'audio/skill/xinxuanhuo2.mp3', - 'audio/skill/xinyaoming1.mp3', - 'audio/skill/xinyaoming2.mp3', - 'audio/skill/xinzenhui1.mp3', - 'audio/skill/xinzenhui2.mp3', - 'audio/skill/xinzhan1.mp3', - 'audio/skill/xinzhan2.mp3', - 'audio/skill/xinzhenjun1.mp3', - 'audio/skill/xinzhenjun2.mp3', - 'audio/skill/xinzhiyan1.mp3', - 'audio/skill/xinzhiyan2.mp3', - 'audio/skill/xinzhuikong1.mp3', - 'audio/skill/xinzhuikong2.mp3', - 'audio/skill/xinzili1.mp3', - 'audio/skill/xinzili2.mp3', - 'audio/skill/xinzongxuan1.mp3', - 'audio/skill/xinzongxuan2.mp3', - 'audio/skill/xiongmang1.mp3', - 'audio/skill/xiongmang2.mp3', - 'audio/skill/xiongrao1.mp3', - 'audio/skill/xiongrao2.mp3', - 'audio/skill/xiongshu1.mp3', - 'audio/skill/xiongshu2.mp3', - 'audio/skill/xiongsuan1.mp3', - 'audio/skill/xiongsuan2.mp3', - 'audio/skill/xiongyi1.mp3', - 'audio/skill/xiongyi2.mp3', - 'audio/skill/xiongzhi1.mp3', - 'audio/skill/xiongzhi2.mp3', - 'audio/skill/xiuluo1.mp3', - 'audio/skill/xiuluo2.mp3', - 'audio/skill/xiusheng1.mp3', - 'audio/skill/xiusheng2.mp3', - 'audio/skill/xixiu1.mp3', - 'audio/skill/xixiu2.mp3', - 'audio/skill/xiyan1.mp3', - 'audio/skill/xiyan2.mp3', - 'audio/skill/xiying1.mp3', - 'audio/skill/xiying2.mp3', - 'audio/skill/xizhen1.mp3', - 'audio/skill/xizhen2.mp3', - 'audio/skill/xjshijian1.mp3', - 'audio/skill/xjshijian2.mp3', - 'audio/skill/xpchijie1.mp3', - 'audio/skill/xpchijie2.mp3', - 'audio/skill/xsqianxin1.mp3', - 'audio/skill/xsqianxin2.mp3', - 'audio/skill/xuanbei1.mp3', - 'audio/skill/xuanbei2.mp3', - 'audio/skill/xuancun1.mp3', - 'audio/skill/xuancun2.mp3', - 'audio/skill/xuanfeng_boss_lvbu31.mp3', - 'audio/skill/xuanfeng_boss_lvbu32.mp3', - 'audio/skill/xuanfeng_re_heqi1.mp3', - 'audio/skill/xuanfeng_re_heqi2.mp3', - 'audio/skill/xuanfeng_re_lingtong1.mp3', - 'audio/skill/xuanfeng_re_lingtong2.mp3', - 'audio/skill/xuanfeng_xin_lingtong1.mp3', - 'audio/skill/xuanfeng_xin_lingtong2.mp3', - 'audio/skill/xuanfeng1.mp3', - 'audio/skill/xuanfeng2.mp3', - 'audio/skill/xuanhuo1.mp3', - 'audio/skill/xuanhuo2.mp3', - 'audio/skill/xuanlve1.mp3', - 'audio/skill/xuanlve2.mp3', - 'audio/skill/xuanmu1.mp3', - 'audio/skill/xuanmu2.mp3', - 'audio/skill/xueji1.mp3', - 'audio/skill/xueji2.mp3', - 'audio/skill/xuelunyang.mp3', - 'audio/skill/xuewei1.mp3', - 'audio/skill/xuewei2.mp3', - 'audio/skill/xueyi1.mp3', - 'audio/skill/xueyi2.mp3', - 'audio/skill/xuezhao1.mp3', - 'audio/skill/xuezhao2.mp3', - 'audio/skill/xunde1.mp3', - 'audio/skill/xunde2.mp3', - 'audio/skill/xunli1.mp3', - 'audio/skill/xunli2.mp3', - 'audio/skill/xunshi1.mp3', - 'audio/skill/xunshi2.mp3', - 'audio/skill/xunxun1.mp3', - 'audio/skill/xunxun2.mp3', - 'audio/skill/xunyi1.mp3', - 'audio/skill/xunyi2.mp3', - 'audio/skill/xunzhi1.mp3', - 'audio/skill/xunzhi2.mp3', - 'audio/skill/xushen1.mp3', - 'audio/skill/xushen2.mp3', - 'audio/skill/xutuhuanjin.mp3', - 'audio/skill/xuxie1.mp3', - 'audio/skill/xuxie2.mp3', - 'audio/skill/xz_xunxun1.mp3', - 'audio/skill/xz_xunxun2.mp3', - 'audio/skill/yachai1.mp3', - 'audio/skill/yachai2.mp3', - 'audio/skill/yaner1.mp3', - 'audio/skill/yaner2.mp3', - 'audio/skill/yangjie1.mp3', - 'audio/skill/yangjie2.mp3', - 'audio/skill/yangkuang1.mp3', - 'audio/skill/yangkuang2.mp3', - 'audio/skill/yangzhong1.mp3', - 'audio/skill/yangzhong2.mp3', - 'audio/skill/yanhuo1.mp3', - 'audio/skill/yanhuo2.mp3', - 'audio/skill/yanjiao1.mp3', - 'audio/skill/yanjiao2.mp3', - 'audio/skill/yanru1.mp3', - 'audio/skill/yanru2.mp3', - 'audio/skill/yanxi1.mp3', - 'audio/skill/yanxi2.mp3', - 'audio/skill/yanxiao1.mp3', - 'audio/skill/yanxiao2.mp3', - 'audio/skill/yanyu1.mp3', - 'audio/skill/yanyu2.mp3', - 'audio/skill/yanzheng1.mp3', - 'audio/skill/yanzheng2.mp3', - 'audio/skill/yanzhu1.mp3', - 'audio/skill/yanzhu2.mp3', - 'audio/skill/yaoming1.mp3', - 'audio/skill/yaoming2.mp3', - 'audio/skill/yaopei1.mp3', - 'audio/skill/yaopei2.mp3', - 'audio/skill/yaowu1.mp3', - 'audio/skill/yaowu2.mp3', - 'audio/skill/yashi1.mp3', - 'audio/skill/yashi2.mp3', - 'audio/skill/yawang1.mp3', - 'audio/skill/yawang2.mp3', - 'audio/skill/ybzhuiji1.mp3', - 'audio/skill/ybzhuiji2.mp3', - 'audio/skill/yechou1.mp3', - 'audio/skill/yechou2.mp3', - 'audio/skill/yeyan1.mp3', - 'audio/skill/yeyan2.mp3', - 'audio/skill/yeyan3.mp3', - 'audio/skill/yicheng1.mp3', - 'audio/skill/yicheng2.mp3', - 'audio/skill/yichong1.mp3', - 'audio/skill/yichong2.mp3', - 'audio/skill/yicong1.mp3', - 'audio/skill/yicong2.mp3', - 'audio/skill/yidian1.mp3', - 'audio/skill/yidian2.mp3', - 'audio/skill/yidu1.mp3', - 'audio/skill/yidu2.mp3', - 'audio/skill/yifa1.mp3', - 'audio/skill/yifa2.mp3', - 'audio/skill/yigui1.mp3', - 'audio/skill/yigui2.mp3', - 'audio/skill/yiji1.mp3', - 'audio/skill/yiji2.mp3', - 'audio/skill/yijiao1.mp3', - 'audio/skill/yijiao2.mp3', - 'audio/skill/yijie1.mp3', - 'audio/skill/yijie2.mp3', - 'audio/skill/yijin1.mp3', - 'audio/skill/yijin2.mp3', - 'audio/skill/yijin3.mp3', - 'audio/skill/yijue1.mp3', - 'audio/skill/yijue2.mp3', - 'audio/skill/yilie1.mp3', - 'audio/skill/yilie2.mp3', - 'audio/skill/yimie1.mp3', - 'audio/skill/yimie2.mp3', - 'audio/skill/yinbing1.mp3', - 'audio/skill/yinbing2.mp3', - 'audio/skill/yingba1.mp3', - 'audio/skill/yingba2.mp3', - 'audio/skill/yingbin1.mp3', - 'audio/skill/yingbin2.mp3', - 'audio/skill/yingbing1.mp3', - 'audio/skill/yingbing2.mp3', - 'audio/skill/yingfeng1.mp3', - 'audio/skill/yingfeng2.mp3', - 'audio/skill/yinghun_ol_sunjian1.mp3', - 'audio/skill/yinghun_ol_sunjian2.mp3', - 'audio/skill/yinghun_re_sunben1.mp3', - 'audio/skill/yinghun_re_sunben2.mp3', - 'audio/skill/yinghun_re_sunce1.mp3', - 'audio/skill/yinghun_re_sunce2.mp3', - 'audio/skill/yinghun_re_sunjian1.mp3', - 'audio/skill/yinghun_re_sunjian2.mp3', - 'audio/skill/yinghun_sb_sunce1.mp3', - 'audio/skill/yinghun_sb_sunce2.mp3', - 'audio/skill/yinghun_sunce1.mp3', - 'audio/skill/yinghun_sunce2.mp3', - 'audio/skill/yinghun_sunjian1.mp3', - 'audio/skill/yinghun_sunjian2.mp3', - 'audio/skill/yinghun1.mp3', - 'audio/skill/yinghun2.mp3', - 'audio/skill/yingyang1.mp3', - 'audio/skill/yingyang2.mp3', - 'audio/skill/yingyuan1.mp3', - 'audio/skill/yingyuan2.mp3', - 'audio/skill/yingzi1.mp3', - 'audio/skill/yingzi2.mp3', - 'audio/skill/yinju1.mp3', - 'audio/skill/yinju2.mp3', - 'audio/skill/yinlang1.mp3', - 'audio/skill/yinlang2.mp3', - 'audio/skill/yinli1.mp3', - 'audio/skill/yinli2.mp3', - 'audio/skill/yinyi1.mp3', - 'audio/skill/yinyi2.mp3', - 'audio/skill/yirang_re_taoqian1.mp3', - 'audio/skill/yirang_re_taoqian2.mp3', - 'audio/skill/yirang1.mp3', - 'audio/skill/yirang2.mp3', - 'audio/skill/yise1.mp3', - 'audio/skill/yise2.mp3', - 'audio/skill/yishe1.mp3', - 'audio/skill/yishe2.mp3', - 'audio/skill/yitian.mp3', - 'audio/skill/yixiang_re_taoqian1.mp3', - 'audio/skill/yixiang_re_taoqian2.mp3', - 'audio/skill/yixiang1.mp3', - 'audio/skill/yixiang2.mp3', - 'audio/skill/yiyong1.mp3', - 'audio/skill/yiyong2.mp3', - 'audio/skill/yizan_respond_shan1.mp3', - 'audio/skill/yizan_respond_shan2.mp3', - 'audio/skill/yizhao1.mp3', - 'audio/skill/yizhao2.mp3', - 'audio/skill/yizheng1.mp3', - 'audio/skill/yizheng2.mp3', - 'audio/skill/yizhi1.mp3', - 'audio/skill/yizhi2.mp3', - 'audio/skill/yizhong1.mp3', - 'audio/skill/yizhong2.mp3', - 'audio/skill/yizhu1.mp3', - 'audio/skill/yizhu2.mp3', - 'audio/skill/yizu1.mp3', - 'audio/skill/yizu2.mp3', - 'audio/skill/yongdi_xinping1.mp3', - 'audio/skill/yongdi_xinping2.mp3', - 'audio/skill/yongdi1.mp3', - 'audio/skill/yongdi2.mp3', - 'audio/skill/yongjin_xin_lingtong1.mp3', - 'audio/skill/yongjin_xin_lingtong2.mp3', - 'audio/skill/yongjin1.mp3', - 'audio/skill/yongjin2.mp3', - 'audio/skill/yongjue1.mp3', - 'audio/skill/yongjue2.mp3', - 'audio/skill/yonglve1.mp3', - 'audio/skill/yonglve2.mp3', - 'audio/skill/yongsi1.mp3', - 'audio/skill/yongsi2.mp3', - 'audio/skill/youdi1.mp3', - 'audio/skill/youdi2.mp3', - 'audio/skill/youlong1.mp3', - 'audio/skill/youlong2.mp3', - 'audio/skill/youxu1.mp3', - 'audio/skill/youxu2.mp3', - 'audio/skill/youyan1.mp3', - 'audio/skill/youyan2.mp3', - 'audio/skill/youyi1.mp3', - 'audio/skill/youyi2.mp3', - 'audio/skill/yuanchou1.mp3', - 'audio/skill/yuanchou2.mp3', - 'audio/skill/yuanhu1.mp3', - 'audio/skill/yuanhu2.mp3', - 'audio/skill/yuanhu3.mp3', - 'audio/skill/yuanlve1.mp3', - 'audio/skill/yuanlve2.mp3', - 'audio/skill/yuanqing1.mp3', - 'audio/skill/yuanqing2.mp3', - 'audio/skill/yuanyu1.mp3', - 'audio/skill/yuanyu2.mp3', - 'audio/skill/yuanzi1.mp3', - 'audio/skill/yuanzi2.mp3', - 'audio/skill/yuce_re_manchong1.mp3', - 'audio/skill/yuce_re_manchong2.mp3', - 'audio/skill/yuce1.mp3', - 'audio/skill/yuce2.mp3', - 'audio/skill/yuehun1.mp3', - 'audio/skill/yuehun2.mp3', - 'audio/skill/yuejian1.mp3', - 'audio/skill/yuejian2.mp3', - 'audio/skill/yufeng1.mp3', - 'audio/skill/yufeng2.mp3', - 'audio/skill/yuheng1.mp3', - 'audio/skill/yuheng2.mp3', - 'audio/skill/yuhua1.mp3', - 'audio/skill/yuhua2.mp3', - 'audio/skill/yui_jiang1.mp3', - 'audio/skill/yui_jiang2.mp3', - 'audio/skill/yui_lieyin1.mp3', - 'audio/skill/yui_lieyin2.mp3', - 'audio/skill/yui_takaramono1.mp3', - 'audio/skill/yui_takaramono2.mp3', - 'audio/skill/yujue1.mp3', - 'audio/skill/yujue2.mp3', - 'audio/skill/yuqi1.mp3', - 'audio/skill/yuqi2.mp3', - 'audio/skill/yuri_wangxi1.mp3', - 'audio/skill/yuri_wangxi2.mp3', - 'audio/skill/yuri_xingdong_gain1.mp3', - 'audio/skill/yuri_xingdong_gain2.mp3', - 'audio/skill/yuri_xingdong1.mp3', - 'audio/skill/yuri_xingdong2.mp3', - 'audio/skill/yuri_xingdong3.mp3', - 'audio/skill/yusui1.mp3', - 'audio/skill/yusui2.mp3', - 'audio/skill/yuxiang.mp3', - 'audio/skill/yuxu1.mp3', - 'audio/skill/yuxu2.mp3', - 'audio/skill/yuyan1.mp3', - 'audio/skill/yuyan2.mp3', - 'audio/skill/yuyun1.mp3', - 'audio/skill/yuyun2.mp3', - 'audio/skill/yuzhang1.mp3', - 'audio/skill/yuzhang2.mp3', - 'audio/skill/zaiqi1.mp3', - 'audio/skill/zaiqi2.mp3', - 'audio/skill/zaoli1.mp3', - 'audio/skill/zaoli2.mp3', - 'audio/skill/zaoxian_re_dengai1.mp3', - 'audio/skill/zaoxian_re_dengai2.mp3', - 'audio/skill/zaoxian1.mp3', - 'audio/skill/zaoxian2.mp3', - 'audio/skill/zaoyun1.mp3', - 'audio/skill/zaoyun2.mp3', - 'audio/skill/zengou1.mp3', - 'audio/skill/zengou2.mp3', - 'audio/skill/zfengshi1.mp3', - 'audio/skill/zfengshi2.mp3', - 'audio/skill/zhafu1.mp3', - 'audio/skill/zhafu2.mp3', - 'audio/skill/zhangba_skill.mp3', - 'audio/skill/zhangming1.mp3', - 'audio/skill/zhangming2.mp3', - 'audio/skill/zhangu1.mp3', - 'audio/skill/zhangu2.mp3', - 'audio/skill/zhangwu1.mp3', - 'audio/skill/zhangwu2.mp3', - 'audio/skill/zhanjue1.mp3', - 'audio/skill/zhanjue2.mp3', - 'audio/skill/zhanshen1.mp3', - 'audio/skill/zhanshen2.mp3', - 'audio/skill/zhanwan1.mp3', - 'audio/skill/zhanwan2.mp3', - 'audio/skill/zhanyanliangzhuwenchou.mp3', - 'audio/skill/zhanyi1.mp3', - 'audio/skill/zhanyi2.mp3', - 'audio/skill/zhanyuan1.mp3', - 'audio/skill/zhanyuan2.mp3', - 'audio/skill/zhaofu1.mp3', - 'audio/skill/zhaofu2.mp3', - 'audio/skill/zhaohan1.mp3', - 'audio/skill/zhaohan2.mp3', - 'audio/skill/zhaohuo_re_taoqian1.mp3', - 'audio/skill/zhaohuo_re_taoqian2.mp3', - 'audio/skill/zhaohuo1.mp3', - 'audio/skill/zhaohuo2.mp3', - 'audio/skill/zhaolie1.mp3', - 'audio/skill/zhaolie2.mp3', - 'audio/skill/zhaoran1.mp3', - 'audio/skill/zhaoran2.mp3', - 'audio/skill/zhaosong1.mp3', - 'audio/skill/zhaosong2.mp3', - 'audio/skill/zhaotao1.mp3', - 'audio/skill/zhaotao2.mp3', - 'audio/skill/zhaxiang1.mp3', - 'audio/skill/zhaxiang2.mp3', - 'audio/skill/zhefu1.mp3', - 'audio/skill/zhefu2.mp3', - 'audio/skill/zhendu1.mp3', - 'audio/skill/zhendu2.mp3', - 'audio/skill/zhengbi1.mp3', - 'audio/skill/zhengbi2.mp3', - 'audio/skill/zhengding1.mp3', - 'audio/skill/zhengding2.mp3', - 'audio/skill/zhenge1.mp3', - 'audio/skill/zhenge2.mp3', - 'audio/skill/zhengjian1.mp3', - 'audio/skill/zhengjian2.mp3', - 'audio/skill/zhengjing_boom.mp3', - 'audio/skill/zhengjing_click.mp3', - 'audio/skill/zhengjing_finish.mp3', - 'audio/skill/zhengjing_guanju.mp3', - 'audio/skill/zhengjing1.mp3', - 'audio/skill/zhengjing2.mp3', - 'audio/skill/zhengnan1.mp3', - 'audio/skill/zhengnan2.mp3', - 'audio/skill/zhengqing1.mp3', - 'audio/skill/zhengqing2.mp3', - 'audio/skill/zhenlie_re_wangyi1.mp3', - 'audio/skill/zhenlie_re_wangyi2.mp3', - 'audio/skill/zhenlie1.mp3', - 'audio/skill/zhenlie2.mp3', - 'audio/skill/zhenshan1.mp3', - 'audio/skill/zhenshan2.mp3', - 'audio/skill/zhente1.mp3', - 'audio/skill/zhente2.mp3', - 'audio/skill/zhenwei_re_wenpin1.mp3', - 'audio/skill/zhenwei_re_wenpin2.mp3', - 'audio/skill/zhenwei1.mp3', - 'audio/skill/zhenwei2.mp3', - 'audio/skill/zhiba2_re_sunben1.mp3', - 'audio/skill/zhiba2_re_sunben2.mp3', - 'audio/skill/zhiba21.mp3', - 'audio/skill/zhiba22.mp3', - 'audio/skill/zhibian1.mp3', - 'audio/skill/zhibian2.mp3', - 'audio/skill/zhichi_re_chengong1.mp3', - 'audio/skill/zhichi_re_chengong2.mp3', - 'audio/skill/zhichi1.mp3', - 'audio/skill/zhichi2.mp3', - 'audio/skill/zhidao1.mp3', - 'audio/skill/zhidao2.mp3', - 'audio/skill/zhige1.mp3', - 'audio/skill/zhige2.mp3', - 'audio/skill/zhiheng_gz_jun_sunquan1.mp3', - 'audio/skill/zhiheng_gz_jun_sunquan2.mp3', - 'audio/skill/zhiheng1.mp3', - 'audio/skill/zhiheng2.mp3', - 'audio/skill/zhiji_re_jiangwei1.mp3', - 'audio/skill/zhiji_re_jiangwei2.mp3', - 'audio/skill/zhiji1.mp3', - 'audio/skill/zhiji2.mp3', - 'audio/skill/zhijian1.mp3', - 'audio/skill/zhijian2.mp3', - 'audio/skill/zhilve1.mp3', - 'audio/skill/zhilve2.mp3', - 'audio/skill/zhiman_guansuo1.mp3', - 'audio/skill/zhiman_guansuo2.mp3', - 'audio/skill/zhiman_re_masu1.mp3', - 'audio/skill/zhiman_re_masu2.mp3', - 'audio/skill/zhiman1.mp3', - 'audio/skill/zhiman2.mp3', - 'audio/skill/zhimeng1.mp3', - 'audio/skill/zhimeng2.mp3', - 'audio/skill/zhiming1.mp3', - 'audio/skill/zhiming2.mp3', - 'audio/skill/zhiren1.mp3', - 'audio/skill/zhiren2.mp3', - 'audio/skill/zhiri1.mp3', - 'audio/skill/zhiri2.mp3', - 'audio/skill/zhishi1.mp3', - 'audio/skill/zhishi2.mp3', - 'audio/skill/zhiwei1.mp3', - 'audio/skill/zhiwei2.mp3', - 'audio/skill/zhiyan_gexuan1.mp3', - 'audio/skill/zhiyan_re_yufan1.mp3', - 'audio/skill/zhiyan_re_yufan2.mp3', - 'audio/skill/zhiyan_xin_yufan1.mp3', - 'audio/skill/zhiyan_xin_yufan2.mp3', - 'audio/skill/zhiyan1.mp3', - 'audio/skill/zhiyan2.mp3', - 'audio/skill/zhiyi1.mp3', - 'audio/skill/zhiyi2.mp3', - 'audio/skill/zhiyu1.mp3', - 'audio/skill/zhiyu2.mp3', - 'audio/skill/zhongjian1.mp3', - 'audio/skill/zhongjian2.mp3', - 'audio/skill/zhongjie1.mp3', - 'audio/skill/zhongjie2.mp3', - 'audio/skill/zhongyi1.mp3', - 'audio/skill/zhongyi2.mp3', - 'audio/skill/zhongyong1.mp3', - 'audio/skill/zhongyong2.mp3', - 'audio/skill/zhongyun1.mp3', - 'audio/skill/zhongyun2.mp3', - 'audio/skill/zhongzuo1.mp3', - 'audio/skill/zhongzuo2.mp3', - 'audio/skill/zhoufu1.mp3', - 'audio/skill/zhoufu2.mp3', - 'audio/skill/zhoulin1.mp3', - 'audio/skill/zhoulin2.mp3', - 'audio/skill/zhouxian1.mp3', - 'audio/skill/zhouxian2.mp3', - 'audio/skill/zhouxuan1.mp3', - 'audio/skill/zhouxuan2.mp3', - 'audio/skill/zhuandui1.mp3', - 'audio/skill/zhuandui2.mp3', - 'audio/skill/zhuangdan1.mp3', - 'audio/skill/zhuangdan2.mp3', - 'audio/skill/zhuangpo1.mp3', - 'audio/skill/zhuangpo2.mp3', - 'audio/skill/zhuangrong1.mp3', - 'audio/skill/zhuangrong2.mp3', - 'audio/skill/zhuangshu1.mp3', - 'audio/skill/zhuangshu2.mp3', - 'audio/skill/zhuge_skill.mp3', - 'audio/skill/zhuhai_gz_re_xushu1.mp3', - 'audio/skill/zhuhai_gz_re_xushu2.mp3', - 'audio/skill/zhuhai1.mp3', - 'audio/skill/zhuhai2.mp3', - 'audio/skill/zhuide1.mp3', - 'audio/skill/zhuide2.mp3', - 'audio/skill/zhuihuan1.mp3', - 'audio/skill/zhuihuan2.mp3', - 'audio/skill/zhuikong1.mp3', - 'audio/skill/zhuikong2.mp3', - 'audio/skill/zhuitao1.mp3', - 'audio/skill/zhuitao2.mp3', - 'audio/skill/zhuiyi_re_bulianshi1.mp3', - 'audio/skill/zhuiyi_re_bulianshi2.mp3', - 'audio/skill/zhuiyi1.mp3', - 'audio/skill/zhuiyi2.mp3', - 'audio/skill/zhujian1.mp3', - 'audio/skill/zhujian2.mp3', - 'audio/skill/zhukou1.mp3', - 'audio/skill/zhukou2.mp3', - 'audio/skill/zhuning1.mp3', - 'audio/skill/zhuning2.mp3', - 'audio/skill/zhuosheng1.mp3', - 'audio/skill/zhuosheng2.mp3', - 'audio/skill/zhuque_skill.mp3', - 'audio/skill/zhushi1.mp3', - 'audio/skill/zhushi2.mp3', - 'audio/skill/zhuwei1.mp3', - 'audio/skill/zhuwei2.mp3', - 'audio/skill/zifu1.mp3', - 'audio/skill/zifu2.mp3', - 'audio/skill/zili_re_zhonghui1.mp3', - 'audio/skill/zili_re_zhonghui2.mp3', - 'audio/skill/zili1.mp3', - 'audio/skill/zili2.mp3', - 'audio/skill/ziliang1.mp3', - 'audio/skill/ziliang2.mp3', - 'audio/skill/ziqu1.mp3', - 'audio/skill/ziqu2.mp3', - 'audio/skill/zishou_re_liubiao1.mp3', - 'audio/skill/zishou_re_liubiao2.mp3', - 'audio/skill/zishou1.mp3', - 'audio/skill/zishou2.mp3', - 'audio/skill/zishu1.mp3', - 'audio/skill/zishu2.mp3', - 'audio/skill/ziyuan1.mp3', - 'audio/skill/ziyuan2.mp3', - 'audio/skill/zjjuxiang1.mp3', - 'audio/skill/zjjuxiang2.mp3', - 'audio/skill/zlhuji1.mp3', - 'audio/skill/zlhuji2.mp3', - 'audio/skill/zlshoufu1.mp3', - 'audio/skill/zlshoufu2.mp3', - 'audio/skill/zniaoxiang1.mp3', - 'audio/skill/zniaoxiang2.mp3', - 'audio/skill/zongfan1.mp3', - 'audio/skill/zongfan2.mp3', - 'audio/skill/zonghuo.mp3', - 'audio/skill/zongkui_tw_beimihu1.mp3', - 'audio/skill/zongkui_tw_beimihu2.mp3', - 'audio/skill/zongkui1.mp3', - 'audio/skill/zongkui2.mp3', - 'audio/skill/zongshi1.mp3', - 'audio/skill/zongshi2.mp3', - 'audio/skill/zongxuan1.mp3', - 'audio/skill/zongxuan2.mp3', - 'audio/skill/zongzuo1.mp3', - 'audio/skill/zongzuo2.mp3', - 'audio/skill/zuici1.mp3', - 'audio/skill/zuici2.mp3', - 'audio/skill/zuixiang.mp3', - 'audio/skill/zunwei1.mp3', - 'audio/skill/zunwei2.mp3', - 'audio/skill/zuoding_re_zhongyao1.mp3', - 'audio/skill/zuoding_re_zhongyao2.mp3', - 'audio/skill/zuoding1.mp3', - 'audio/skill/zuoding2.mp3', - 'audio/skill/zuoxing1.mp3', - 'audio/skill/zuoxing2.mp3', - 'audio/skill/zyqiao1.mp3', - 'audio/skill/zyqiao2.mp3', - /*skill audio end*/ - - /*voice begin*/ - 'audio/voice/male/0.mp3', - 'audio/voice/male/1.mp3', - 'audio/voice/male/2.mp3', - 'audio/voice/male/3.mp3', - 'audio/voice/male/4.mp3', - 'audio/voice/male/5.mp3', - 'audio/voice/male/6.mp3', - 'audio/voice/male/7.mp3', - 'audio/voice/male/8.mp3', - 'audio/voice/male/9.mp3', - 'audio/voice/male/10.mp3', - 'audio/voice/male/11.mp3', - 'audio/voice/male/12.mp3', - 'audio/voice/male/13.mp3', - 'audio/voice/male/14.mp3', - 'audio/voice/male/15.mp3', - 'audio/voice/male/16.mp3', - 'audio/voice/male/17.mp3', - 'audio/voice/male/18.mp3', - 'audio/voice/male/19.mp3', - 'audio/voice/male/20.mp3', - 'audio/voice/male/21.mp3', - 'audio/voice/male/22.mp3', - 'audio/voice/female/0.mp3', - 'audio/voice/female/1.mp3', - 'audio/voice/female/2.mp3', - 'audio/voice/female/3.mp3', - 'audio/voice/female/4.mp3', - 'audio/voice/female/5.mp3', - 'audio/voice/female/6.mp3', - 'audio/voice/female/7.mp3', - 'audio/voice/female/8.mp3', - 'audio/voice/female/9.mp3', - 'audio/voice/female/10.mp3', - 'audio/voice/female/11.mp3', - 'audio/voice/female/12.mp3', - 'audio/voice/female/13.mp3', - 'audio/voice/female/14.mp3', - 'audio/voice/female/15.mp3', - 'audio/voice/female/16.mp3', - 'audio/voice/female/17.mp3', - 'audio/voice/female/18.mp3', - 'audio/voice/female/19.mp3', - 'audio/voice/female/20.mp3', - 'audio/voice/female/21.mp3', - 'audio/voice/female/22.mp3', - /*voice end*/ - /*audio end*/ - - 'font/huangcao.woff2', - 'font/shousha.woff2', - 'font/xiaozhuan.woff2', - 'font/xingkai.woff2', - 'font/xinwei.woff2', - 'font/yuanli.woff2', - - /*background image begin*/ - 'image/background/beipan_bg.jpg', - 'image/background/heaven_bg.jpg', - 'image/background/huangtian_bg.jpg', - 'image/background/key_bg.jpg', - 'image/background/kyoani_bg.jpg', - 'image/background/lanting_bg.jpg', - 'image/background/lingju_bg.jpg', - 'image/background/noname_bg.jpg', - 'image/background/ol_bg.jpg', - 'image/background/oltianhou_club_bg.jpg', - 'image/background/oltianhou_diamond_bg.jpg', - 'image/background/oltianhou_heart_bg.jpg', - 'image/background/oltianhou_spade_bg.jpg', - 'image/background/planetarian_bg.jpg', - 'image/background/sanying_bg.jpg', - 'image/background/september_bg.jpg', - 'image/background/shengshi_bg.jpg', - 'image/background/taoyuan_bg.jpg', - 'image/background/wangshi_bg.jpg', - 'image/background/wuming_bg.jpg', - 'image/background/xiaowu_bg.jpg', - 'image/background/xinsha_bg.jpg', - 'image/background/xiongxin_bg.jpg', - 'image/background/yinxiang_bg.jpg', - 'image/background/zhanhuo_bg.jpg', - 'image/background/zhanyun_bg.jpg', - 'image/background/zhulin_bg.jpg', - /*background image end*/ - - /*card image begin*/ - 'image/card/bagua.png', - 'image/card/baihupifeng.png', - 'image/card/baishouzhihu.png', - 'image/card/baiyidujiang.png', - 'image/card/baiyin.png', - 'image/card/bingliang.png', - 'image/card/binglinchengxia.png', - 'image/card/binglinchengxiax.png', - 'image/card/bingpotong.png', - 'image/card/bintieshuangji.png', - 'image/card/cangchizhibi.png', - 'image/card/caochuan.png', - 'image/card/caochuanjiejian.png', - 'image/card/caomu.png', - 'image/card/caoyao.png', - 'image/card/cardtempname_bg.png', - 'image/card/changandajian_equip1.png', - 'image/card/charge.png', - 'image/card/cheliji_feilunzhanyu.png', - 'image/card/cheliji_sichengliangyu.png', - 'image/card/cheliji_tiejixuanyu.png', - 'image/card/chenghuodajie.png', - 'image/card/chenhuodajie.png', - 'image/card/chiling.png', - 'image/card/chilongya.png', - 'image/card/chitu.png', - 'image/card/chiyuxi.png', - 'image/card/chuansongmen.png', - 'image/card/chunbing.png', - 'image/card/chuqibuyi.png', - 'image/card/cisha.png', - 'image/card/cixiong.png', - 'image/card/cooperation_damage.png', - 'image/card/dagongche.png', - 'image/card/daihuofenglun.png', - 'image/card/dawan.png', - 'image/card/db_atk1.jpg', - 'image/card/db_atk1_出阵迎战.jpg', - 'image/card/db_atk1_反抗.jpg', - 'image/card/db_atk1_固守城池.jpg', - 'image/card/db_atk2.jpg', - 'image/card/db_atk2_拱卫中军.jpg', - 'image/card/db_atk2_归顺.jpg', - 'image/card/db_atk2_突出重围.jpg', - 'image/card/db_def1.jpg', - 'image/card/db_def1_围城断粮.jpg', - 'image/card/db_def1_镇压.jpg', - 'image/card/db_def1_直取敌营.jpg', - 'image/card/db_def2.jpg', - 'image/card/db_def2_安抚.jpg', - 'image/card/db_def2_擂鼓进军.jpg', - 'image/card/db_def2_扰阵疲敌.jpg', - 'image/card/diaobingqianjiang.png', - 'image/card/diaohulishan.png', - 'image/card/dilu.png', - 'image/card/dinglanyemingzhu.png', - 'image/card/dinvxuanshuang.png', - 'image/card/diqi.png', - 'image/card/donghuangzhong.png', - 'image/card/dongzhuxianji.png', - 'image/card/du.png', - 'image/card/duanjian.png', - 'image/card/dunpaigedang.png', - 'image/card/dz_mantianguohai.png', - 'image/card/expandedSlots.png', - 'image/card/fangtian.png', - 'image/card/feibiao.png', - 'image/card/feilongduofeng.png', - 'image/card/fengchu_card.png', - 'image/card/fengxueren.png', - 'image/card/fengyinzhidan.png', - 'image/card/fudichouxin.png', - 'image/card/fulei.png', - 'image/card/fuxiqin.png', - 'image/card/geanguanhuo.png', - 'image/card/gongshoujianbei.png', - 'image/card/gouhunluo.png', - 'image/card/group_jin.png', - 'image/card/group_key.png', - 'image/card/group_qun.png', - 'image/card/group_shen.png', - 'image/card/group_shu.png', - 'image/card/group_unknown.png', - 'image/card/group_wei.png', - 'image/card/group_western.png', - 'image/card/group_wu.png', - 'image/card/group_ye.png', - 'image/card/guaguliaodu.png', - 'image/card/guangshatianyi.png', - 'image/card/guanshi.png', - 'image/card/guding.png', - 'image/card/gudonggeng.png', - 'image/card/guilingzhitao.png', - 'image/card/guisheqi.png', - 'image/card/guiyanfadao.png', - 'image/card/guiyoujie.png', - 'image/card/guohe.png', - 'image/card/gw_aerdeyin.jpg', - 'image/card/gw_ansha.jpg', - 'image/card/gw_aozuzhilei.jpg', - 'image/card/gw_baishuang.jpg', - 'image/card/gw_baobaoshu.jpg', - 'image/card/gw_baoxueyaoshui.jpg', - 'image/card/gw_birinongwu.jpg', - 'image/card/gw_butianshu.jpg', - 'image/card/gw_chongci.jpg', - 'image/card/gw_ciguhanshuang.jpg', - 'image/card/gw_dieyi.png', - 'image/card/gw_dudayuanshuai1.jpg', - 'image/card/gw_dudayuanshuai2.jpg', - 'image/card/gw_fuyuan.jpg', - 'image/card/gw_ganhan.jpg', - 'image/card/gw_guaiwuchaoxue.jpg', - 'image/card/gw_huangjiashenpan.jpg', - 'image/card/gw_hudiewu.jpg', - 'image/card/gw_kunenfayin.jpg', - 'image/card/gw_lang.jpg', - 'image/card/gw_leizhoushu.jpg', - 'image/card/gw_niuquzhijing.jpg', - 'image/card/gw_nuhaifengbao.jpg', - 'image/card/gw_poxiao.jpg', - 'image/card/gw_qinpendayu.jpg', - 'image/card/gw_shanbengshu.jpg', - 'image/card/gw_shizizhaohuan.jpg', - 'image/card/gw_tongdi.jpg', - 'image/card/gw_tunshi.jpg', - 'image/card/gw_wenyi.jpg', - 'image/card/gw_wuyao.jpg', - 'image/card/gw_xianzumaijiu.jpg', - 'image/card/gw_xinsheng.jpg', - 'image/card/gw_yanziyaoshui.jpg', - 'image/card/gw_yigeniyin.jpg', - 'image/card/gw_youer.jpg', - 'image/card/gw_zhihuanjun.jpg', - 'image/card/gw_zhongmozhizhan.jpg', - 'image/card/gw_zhuoshao.jpg', - 'image/card/gw_zirankuizeng.jpg', - 'image/card/gw_zuihouyuanwang.jpg', - 'image/card/gw_zumoshoukao.jpg', - 'image/card/gx_chongyingshenfu.png', - 'image/card/gx_lingbaoxianhu.png', - 'image/card/gx_taijifuchen.png', - 'image/card/gz_guguoanbang.png', - 'image/card/gz_haolingtianxia.png', - 'image/card/gz_kefuzhongyuan.png', - 'image/card/gz_wenheluanwu.png', - 'image/card/hanbing.png', - 'image/card/handcard.png', - 'image/card/haotianta.png', - 'image/card/heiguangkai.png', - 'image/card/heilonglinpian.png', - 'image/card/hina_shenji.png', - 'image/card/hongshui.png', - 'image/card/hsbaowu_cangbaotu.jpg', - 'image/card/hsbaowu_huangjinyuanhou.jpg', - 'image/card/hsdusu_huangxuecao.jpg', - 'image/card/hsdusu_huoyanhua.jpg', - 'image/card/hsdusu_kuyecao.jpg', - 'image/card/hsdusu_shinancao.jpg', - 'image/card/hsdusu_xueji.jpg', - 'image/card/hsfashu_anyingjingxiang.jpg', - 'image/card/hsfashu_buwendingyibian.jpg', - 'image/card/hsjixie_zhadan.jpg', - 'image/card/hslingjian_jinjilengdong.jpg', - 'image/card/hslingjian_shengxiuhaojiao.jpg', - 'image/card/hslingjian_shijianhuisu.jpg', - 'image/card/hslingjian_xingtigaizao.jpg', - 'image/card/hslingjian_xuanfengzhiren.jpg', - 'image/card/hslingjian_yinmilichang.jpg', - 'image/card/hslingjian_zhongxinghujia.jpg', - 'image/card/hsmengjing_feicuiyoulong.jpg', - 'image/card/hsmengjing_huanxiaojiemei.jpg', - 'image/card/hsmengjing_mengjing.jpg', - 'image/card/hsmengjing_mengye.jpg', - 'image/card/hsmengjing_suxing.jpg', - 'image/card/hsqingyu_feibiao.jpg', - 'image/card/hsqingyu_hufu.jpg', - 'image/card/hsqingyu_shandian.jpg', - 'image/card/hsqingyu_zhanfang.jpg', - 'image/card/hsqingyu_zhao.jpg', - 'image/card/hsqizhou_feng.jpg', - 'image/card/hsqizhou_huo.jpg', - 'image/card/hsqizhou_shui.jpg', - 'image/card/hsqizhou_tu.jpg', - 'image/card/hsshenqi_kongbusangzhong.jpg', - 'image/card/hsshenqi_morijingxiang.jpg', - 'image/card/hsshenqi_nengliangzhiguang.jpg', - 'image/card/hstianqi_dalian.jpg', - 'image/card/hstianqi_nazigelin.jpg', - 'image/card/hstianqi_shali.jpg', - 'image/card/hstianqi_suolasi.jpg', - 'image/card/hsyaoshui.jpg', - 'image/card/hszuzhou_guhuo.jpg', - 'image/card/hszuzhou_nvwudeganguo.jpg', - 'image/card/hszuzhou_nvwudepingguo.jpg', - 'image/card/hszuzhou_nvwudexuetu.jpg', - 'image/card/hszuzhou_wushushike.jpg', - 'image/card/hualiu.png', - 'image/card/huanglinzhicong.png', - 'image/card/huanpodan.png', - 'image/card/hufu.png', - 'image/card/huimiezhichui.png', - 'image/card/huogong.png', - 'image/card/huoshan.png', - 'image/card/huoshaolianying.png', - 'image/card/huxinjing.png', - 'image/card/identity_commoner.jpg', - 'image/card/identity_enemy.jpg', - 'image/card/identity_fan.jpg', - 'image/card/identity_friend.jpg', - 'image/card/identity_nei.jpg', - 'image/card/identity_zhong.jpg', - 'image/card/identity_zhu.jpg', - 'image/card/jiedao.png', - 'image/card/jiejia.png', - 'image/card/jiguanfeng.png', - 'image/card/jiguanshu.png', - 'image/card/jiguantong.png', - 'image/card/jiguanyaoshu.png', - 'image/card/jiguanyuan.png', - 'image/card/jihuocard.png', - 'image/card/jinchan.png', - 'image/card/jingfanma.png', - 'image/card/jingleishan.png', - 'image/card/jinhe.png', - 'image/card/jinlianzhu.png', - 'image/card/jintuiziru.png', - 'image/card/jiu.png', - 'image/card/jiuwei.png', - 'image/card/jiwangkailai.png', - 'image/card/juedou.png', - 'image/card/jueying.png', - 'image/card/kaihua.png', - 'image/card/kamome_suitcase.png', - 'image/card/kano_paibingbuzhen.png', - 'image/card/kongdongyin.png', - 'image/card/kunlunjingc.png', - 'image/card/kuwu.png', - 'image/card/langeguaiyi.png', - 'image/card/lanyinjia.png', - 'image/card/lebu.png', - 'image/card/lianjunshengyan.png', - 'image/card/lianyaohu.png', - 'image/card/linghunzhihuo.png', - 'image/card/lingjiandai.png', - 'image/card/liufengsan.png', - 'image/card/liulongcanjia.png', - 'image/card/liutouge.png', - 'image/card/liuxiaxianniang.png', - 'image/card/liuxinghuoyu.png', - 'image/card/liyutang.png', - 'image/card/longxugou.png', - 'image/card/lukai_club.png', - 'image/card/lukai_diamond.png', - 'image/card/lukai_heart.png', - 'image/card/lukai_spade.png', - 'image/card/lulitongxin.png', - 'image/card/luojingxiashi.png', - 'image/card/luyugeng.png', - 'image/card/ly_piliche.png', - 'image/card/mapodoufu.png', - 'image/card/mianju.png', - 'image/card/mianlijinzhen.png', - 'image/card/miki_binoculars.png', - 'image/card/miki_hydrogladiator.png', - 'image/card/mingguangkai.png', - 'image/card/minguangkai.png', - 'image/card/mizhilianou.png', - 'image/card/molicha.png', - 'image/card/monkey.png', - 'image/card/mtg_bingheyaosai.jpg', - 'image/card/mtg_cangbaohaiwan.jpg', - 'image/card/mtg_duzhao.jpg', - 'image/card/mtg_feixu.jpg', - 'image/card/mtg_haidao.jpg', - 'image/card/mtg_lindixiliu.jpg', - 'image/card/mtg_linzhongjianta.jpg', - 'image/card/mtg_longlushanfeng.jpg', - 'image/card/mtg_shamolvzhou.jpg', - 'image/card/mtg_shuimomuxue.jpg', - 'image/card/mtg_yixialan.jpg', - 'image/card/mtg_youlin.jpg', - 'image/card/mujiaren.png', - 'image/card/muniu.png', - 'image/card/muniu_small.png', - 'image/card/mutoumianju.png', - 'image/card/nanman.png', - 'image/card/numa.png', - 'image/card/nvwashi.png', - 'image/card/nvzhuang.png', - 'image/card/pangufu.png', - 'image/card/pantao.png', - 'image/card/pss_paper.png', - 'image/card/pss_scissor.png', - 'image/card/pss_stone.png', - 'image/card/pyzhuren_club.png', - 'image/card/pyzhuren_diamond.png', - 'image/card/pyzhuren_heart.png', - 'image/card/pyzhuren_shandian.png', - 'image/card/pyzhuren_spade.png', - 'image/card/qiankunbiao.png', - 'image/card/qiankundai.png', - 'image/card/qiaosi_card1.png', - 'image/card/qiaosi_card2.png', - 'image/card/qiaosi_card3.png', - 'image/card/qiaosi_card4.png', - 'image/card/qiaosi_card5.png', - 'image/card/qiaosi_card6.png', - 'image/card/qibaodao.png', - 'image/card/qijia.png', - 'image/card/qilin.png', - 'image/card/qinggang.png', - 'image/card/qinglianxindeng.png', - 'image/card/qinglong.png', - 'image/card/qinglonglingzhu.png', - 'image/card/qinglongzhigui.png', - 'image/card/qingtuan.png', - 'image/card/qixingbaodao.png', - 'image/card/qizhengxiangsheng.png', - 'image/card/renwang.png', - 'image/card/rewrite_bagua.png', - 'image/card/rewrite_baiyin.png', - 'image/card/rewrite_lanyinjia.png', - 'image/card/rewrite_renwang.png', - 'image/card/rewrite_tengjia.png', - 'image/card/rewrite_zhuge.png', - 'image/card/ruyijingubang.png', - 'image/card/sadengjinhuan.png', - 'image/card/sanjian.png', - 'image/card/sanlve.png', - 'image/card/serafuku.png', - 'image/card/sex_double.png', - 'image/card/sex_female.png', - 'image/card/sex_male.png', - 'image/card/sex_male_castrated.png', - 'image/card/sex_none.png', - 'image/card/sex_unknown.png', - 'image/card/sha.png', - 'image/card/shan.png', - 'image/card/shandian.png', - 'image/card/shandianjian.png', - 'image/card/shatang.png', - 'image/card/shencaojie.png', - 'image/card/shenenshu.png', - 'image/card/shengdong.png', - 'image/card/shenhuofeiya.png', - 'image/card/shenmiguo.png', - 'image/card/shennongding.png', - 'image/card/shentoumianju.png', - 'image/card/shezhanqunru.png', - 'image/card/shield.png', - 'image/card/shihuawuqi.png', - 'image/card/shihuifen.png', - 'image/card/shijieshu.png', - 'image/card/shoulijian.png', - 'image/card/shuchui.png', - 'image/card/shuijing_card.png', - 'image/card/shuiyanqijun.png', - 'image/card/shuiyanqijunx.png', - 'image/card/shujinsan.png', - 'image/card/shunshou.png', - 'image/card/sifeizhenmian.png', - 'image/card/sizhaojian.png', - 'image/card/suijiyingbian.png', - 'image/card/suolianjia.png', - 'image/card/taigongyinfu.png', - 'image/card/taipingyaoshu.png', - 'image/card/tanhuadong.png', - 'image/card/tanshezhiren.png', - 'image/card/tao.png', - 'image/card/taoyuan.png', - 'image/card/tengjia.png', - 'image/card/tianjitu.png', - 'image/card/tianxianjiu.png', - 'image/card/tiaojiyanmei.png', - 'image/card/tiesuo.png', - 'image/card/tiesuo_mark.png', - 'image/card/tongque.png', - 'image/card/toulianghuanzhu.png', - 'image/card/toushiche.png', - 'image/card/tuhunsha.png', - 'image/card/tuixinzhifu.png', - 'image/card/tunliang.png', - 'image/card/tuteng1.jpg', - 'image/card/tuteng2.jpg', - 'image/card/tuteng3.jpg', - 'image/card/tuteng4.jpg', - 'image/card/tuteng5.jpg', - 'image/card/tuteng6.jpg', - 'image/card/tuteng7.jpg', - 'image/card/tuteng8.jpg', - 'image/card/wangmeizhike.png', - 'image/card/wanjian.png', - 'image/card/wenhuangsan.png', - 'image/card/wolong_card.png', - 'image/card/wufengjian.png', - 'image/card/wugu.png', - 'image/card/wuliu.png', - 'image/card/wutiesuolian.png', - 'image/card/wuxie.png', - 'image/card/wuxinghelingshan.png', - 'image/card/wuxingpan.png', - 'image/card/wuzhong.png', - 'image/card/wy_meirenji.png', - 'image/card/wy_xiaolicangdao.png', - 'image/card/xiajiao.png', - 'image/card/xianluhui.png', - 'image/card/xiaolicangdao.png', - 'image/card/xiayuncailing.png', - 'image/card/xietianzi.png', - 'image/card/xinge.png', - 'image/card/xingjiegoutong.png', - 'image/card/xingjunyan.png', - 'image/card/xionghuangjiu.png', - 'image/card/xixueguizhihuan.png', - 'image/card/xuanjian_card.png', - 'image/card/xuanwuzhihuang.png', - 'image/card/xuanyuanjian.png', - 'image/card/xuejibingbao.png', - 'image/card/xuelunyang.png', - 'image/card/xumou_jsrg.jpg', - 'image/card/yajiaoqiang.png', - 'image/card/yangpijuan.png', - 'image/card/yanjiadan_club.png', - 'image/card/yanjiadan_diamond.png', - 'image/card/yanjiadan_heart.png', - 'image/card/yanjiadan_spade.png', - 'image/card/yanxiao_card.jpg', - 'image/card/yexingyi.png', - 'image/card/yihuajiemu.png', - 'image/card/yinfengjia.png', - 'image/card/yinfengyi.png', - 'image/card/ying.png', - 'image/card/yinyueqiang.png', - 'image/card/yitianjian.png', - 'image/card/yiyi.png', - 'image/card/yonglv.png', - 'image/card/youdishenru.png', - 'image/card/yougeng.png', - 'image/card/yuanbaorou.png', - 'image/card/yuanjiao.png', - 'image/card/yuanjun.png', - 'image/card/yuansuhuimie.png', - 'image/card/yuchandui.png', - 'image/card/yuchangen.png', - 'image/card/yuchankan.png', - 'image/card/yuchankun.png', - 'image/card/yuchanli.png', - 'image/card/yuchanqian.png', - 'image/card/yuchanxun.png', - 'image/card/yuchanzhen.png', - 'image/card/yufulu.png', - 'image/card/yuheng.png', - 'image/card/yunvyuanshen.png', - 'image/card/yuruyi.png', - 'image/card/yuxi.png', - 'image/card/zengbin.png', - 'image/card/zhadan.png', - 'image/card/zhangba.png', - 'image/card/zhanxiang.png', - 'image/card/zhaogujing.png', - 'image/card/zhaomingdan.png', - 'image/card/zhaoshu.png', - 'image/card/zheji.png', - 'image/card/zhibi.png', - 'image/card/zhiliaobo.png', - 'image/card/zhiluxiaohu.png', - 'image/card/zhuahuang.png', - 'image/card/zhuangshu_basic.png', - 'image/card/zhuangshu_equip.png', - 'image/card/zhuangshu_trick.png', - 'image/card/zhufangshenshi.png', - 'image/card/zhuge.png', - 'image/card/zhujinqiyuan.png', - 'image/card/zhulu_card.png', - 'image/card/zhungangshuo.png', - 'image/card/zhuque.png', - 'image/card/zhuquezhizhang.png', - 'image/card/zixin.png', - 'image/card/ziyangdan.png', - 'image/card/zong.png', - /*card image end*/ - - /*character image begin*/ - 'image/character/ahuinan.jpg', - 'image/character/bailingyun.jpg', - 'image/character/baiwuchang.jpg', - 'image/character/baosanniang.jpg', - 'image/character/baoxin.jpg', - 'image/character/beimihu.jpg', - 'image/character/bianfuren.jpg', - 'image/character/bianxi.jpg', - 'image/character/boss_zhaoyun.jpg', - 'image/character/bulianshi.jpg', - 'image/character/buzhi.jpg', - 'image/character/caifuren.jpg', - 'image/character/caimaozhangyun.jpg', - 'image/character/caiwenji.jpg', - 'image/character/caiyang.jpg', - 'image/character/caiyong.jpg', - 'image/character/caizhenji.jpg', - 'image/character/caoang.jpg', - 'image/character/caoanmin.jpg', - 'image/character/caobuxing.jpg', - 'image/character/caocao.jpg', - 'image/character/caochong.jpg', - 'image/character/caochun.jpg', - 'image/character/caohong.jpg', - 'image/character/caohua.jpg', - 'image/character/caojie.jpg', - 'image/character/caojinyu.jpg', - 'image/character/caomao.jpg', - 'image/character/caopi.jpg', - 'image/character/caoren.jpg', - 'image/character/caorui.jpg', - 'image/character/caoshuang.jpg', - 'image/character/caosong.jpg', - 'image/character/caoxi.jpg', - 'image/character/caoxian.jpg', - 'image/character/caoxiancaohua.jpg', - 'image/character/caoxing.jpg', - 'image/character/caoxiu.jpg', - 'image/character/caoyi.jpg', - 'image/character/caoying.jpg', - 'image/character/caoyu.jpg', - 'image/character/caozhang.jpg', - 'image/character/caozhen.jpg', - 'image/character/caozhi.jpg', - 'image/character/cenhun.jpg', - 'image/character/cheliji.jpg', - 'image/character/chendao.jpg', - 'image/character/chendeng.jpg', - 'image/character/chendong.jpg', - 'image/character/chengbing.jpg', - 'image/character/chengjichengcui.jpg', - 'image/character/chengong.jpg', - 'image/character/chengpu.jpg', - 'image/character/chengui.jpg', - 'image/character/chengyu.jpg', - 'image/character/chenjiao.jpg', - 'image/character/chenlin.jpg', - 'image/character/chenqun.jpg', - 'image/character/chenshi.jpg', - 'image/character/chentai.jpg', - 'image/character/chunyuqiong.jpg', - 'image/character/clan_hanrong.jpg', - 'image/character/clan_hanshao.jpg', - 'image/character/clan_wanghun.jpg', - 'image/character/clan_wangling.jpg', - 'image/character/clan_wanglun.jpg', - 'image/character/clan_wangyun.jpg', - 'image/character/clan_wuban.jpg', - 'image/character/clan_wukuang.jpg', - 'image/character/clan_wuqiao.jpg', - 'image/character/clan_wuxian.jpg', - 'image/character/clan_xuncai.jpg', - 'image/character/clan_xuncan.jpg', - 'image/character/clan_xunchen.jpg', - 'image/character/clan_xunshu.jpg', - 'image/character/clan_xunyou.jpg', - 'image/character/clan_zhonghui.jpg', - 'image/character/clan_zhongyan.jpg', - 'image/character/clan_zhongyu.jpg', - 'image/character/cuimao.jpg', - 'image/character/cuiyan.jpg', - 'image/character/daqiao.jpg', - 'image/character/daxiaoqiao.jpg', - 'image/character/db_key_hina.jpg', - 'image/character/db_key_liyingxia.jpg', - 'image/character/db_wenyang.jpg', - 'image/character/dc_bulianshi.jpg', - 'image/character/dc_caiyang.jpg', - 'image/character/dc_caocao.jpg', - 'image/character/dc_caoshuang.jpg', - 'image/character/dc_caozhi.jpg', - 'image/character/dc_chenqun.jpg', - 'image/character/dc_daxiaoqiao.jpg', - 'image/character/dc_dongzhao.jpg', - 'image/character/dc_duyu.jpg', - 'image/character/dc_fuwan.jpg', - 'image/character/dc_ganfuren.jpg', - 'image/character/dc_gaolan.jpg', - 'image/character/dc_gongsunzan.jpg', - 'image/character/dc_guansuo.jpg', - 'image/character/dc_huangchengyan.jpg', - 'image/character/dc_huanghao.jpg', - 'image/character/dc_huangquan.jpg', - 'image/character/dc_huangzu.jpg', - 'image/character/dc_huban.jpg', - 'image/character/dc_hujinding.jpg', - 'image/character/dc_huojun.jpg', - 'image/character/dc_jiachong.jpg', - 'image/character/dc_jiben.jpg', - 'image/character/dc_jikang.jpg', - 'image/character/dc_jiling.jpg', - 'image/character/dc_jsp_guanyu.jpg', - 'image/character/dc_kongrong.jpg', - 'image/character/dc_liru.jpg', - 'image/character/dc_liuba.jpg', - 'image/character/dc_liubei.jpg', - 'image/character/dc_liuli.jpg', - 'image/character/dc_liuye.jpg', - 'image/character/dc_liuyu.jpg', - 'image/character/dc_luotong.jpg', - 'image/character/dc_lvkuanglvxiang.jpg', - 'image/character/dc_mengda.jpg', - 'image/character/dc_mifuren.jpg', - 'image/character/dc_ruiji.jpg', - 'image/character/dc_sb_lusu.jpg', - 'image/character/dc_sb_simayi.jpg', - 'image/character/dc_sb_simayi_shadow.jpg', - 'image/character/dc_sb_zhouyu.jpg', - 'image/character/dc_shixie.jpg', - 'image/character/dc_simashi.jpg', - 'image/character/dc_sp_jiaxu.jpg', - 'image/character/dc_sp_machao.jpg', - 'image/character/dc_sunce.jpg', - 'image/character/dc_sunchen.jpg', - 'image/character/dc_sunhanhua.jpg', - 'image/character/dc_sunquan.jpg', - 'image/character/dc_sunru.jpg', - 'image/character/dc_sunziliufang.jpg', - 'image/character/dc_tengfanglan.jpg', - 'image/character/dc_wangchang.jpg', - 'image/character/dc_wangjun.jpg', - 'image/character/dc_wangling.jpg', - 'image/character/dc_wangyun.jpg', - 'image/character/dc_wuban.jpg', - 'image/character/dc_xiahouba.jpg', - 'image/character/dc_xujing.jpg', - 'image/character/dc_xushu.jpg', - 'image/character/dc_yangbiao.jpg', - 'image/character/dc_yanghu.jpg', - 'image/character/dc_yuejiu.jpg', - 'image/character/dc_zhangmancheng.jpg', - 'image/character/dc_zhaotongzhaoguang.jpg', - 'image/character/dc_zhaoxiang.jpg', - 'image/character/dc_zhaoyǎn.jpg', - 'image/character/dc_zhaoyun.jpg', - 'image/character/dc_zhouxuān.jpg', - 'image/character/dc_zhuling.jpg', - 'image/character/ddd_baosanniang.jpg', - 'image/character/ddd_caomao.jpg', - 'image/character/ddd_caoshuang.jpg', - 'image/character/ddd_dingfeng.jpg', - 'image/character/ddd_guanning.jpg', - 'image/character/ddd_handang.jpg', - 'image/character/ddd_jianshuo.jpg', - 'image/character/ddd_kebineng.jpg', - 'image/character/ddd_liangxi.jpg', - 'image/character/ddd_lie.jpg', - 'image/character/ddd_liuba.jpg', - 'image/character/ddd_liuhong.jpg', - 'image/character/ddd_liuye.jpg', - 'image/character/ddd_sunliang.jpg', - 'image/character/ddd_wangkanglvkai.jpg', - 'image/character/ddd_wuzhi.jpg', - 'image/character/ddd_xiahouxuan.jpg', - 'image/character/ddd_xianglang.jpg', - 'image/character/ddd_xinxianying.jpg', - 'image/character/ddd_xuelingyun.jpg', - 'image/character/ddd_xujing.jpg', - 'image/character/ddd_yujin.jpg', - 'image/character/ddd_zhangkai.jpg', - 'image/character/ddd_zhaoang.jpg', - 'image/character/ddd_zhenji.jpg', - 'image/character/ddd_zhouchu.jpg', - 'image/character/default_silhouette_female.jpg', - 'image/character/default_silhouette_male.jpg', - 'image/character/dengai.jpg', - 'image/character/dengzhi.jpg', - 'image/character/dengzhong.jpg', - 'image/character/dianwei.jpg', - 'image/character/diaochan.jpg', - 'image/character/dingfeng.jpg', - 'image/character/dingshangwan.jpg', - 'image/character/dingyuan.jpg', - 'image/character/diy_caiwenji.jpg', - 'image/character/diy_feishi.jpg', - 'image/character/diy_hanlong.jpg', - 'image/character/diy_huangzhong.jpg', - 'image/character/diy_liufu.jpg', - 'image/character/diy_liuyan.jpg', - 'image/character/diy_liuzan.jpg', - 'image/character/diy_lukang.jpg', - 'image/character/diy_menghuo.jpg', - 'image/character/diy_tianyu.jpg', - 'image/character/diy_weiyan.jpg', - 'image/character/diy_wenyang.jpg', - 'image/character/diy_xizhenxihong.jpg', - 'image/character/diy_xuhuang.jpg', - 'image/character/diy_yangyi.jpg', - 'image/character/diy_yuji.jpg', - 'image/character/diy_zaozhirenjun.jpg', - 'image/character/diy_zhenji.jpg', - 'image/character/diy_zhouyu.jpg', - 'image/character/dongbai.jpg', - 'image/character/dongcheng.jpg', - 'image/character/dongguiren.jpg', - 'image/character/dongtuna.jpg', - 'image/character/dongwan.jpg', - 'image/character/dongxie.jpg', - 'image/character/dongyun.jpg', - 'image/character/dongzhao.jpg', - 'image/character/dongzhuo.jpg', - 'image/character/duanjiong.jpg', - 'image/character/duanqiaoxiao.jpg', - 'image/character/duanwei.jpg', - 'image/character/dufuren.jpg', - 'image/character/duji.jpg', - 'image/character/dukui.jpg', - 'image/character/duosidawang.jpg', - 'image/character/duxi.jpg', - 'image/character/duyu.jpg', - 'image/character/fanchou.jpg', - 'image/character/fanjiangzhangda.jpg', - 'image/character/fanyufeng.jpg', - 'image/character/fazheng.jpg', - 'image/character/feiyao.jpg', - 'image/character/feiyi.jpg', - 'image/character/fengfang.jpg', - 'image/character/fengfangnv.jpg', - 'image/character/fengxi.jpg', - 'image/character/fuhuanghou.jpg', - 'image/character/fuqian.jpg', - 'image/character/furong.jpg', - 'image/character/furongfuqian.jpg', - 'image/character/fuwan.jpg', - 'image/character/ganfuren.jpg', - 'image/character/ganfurenmifuren.jpg', - 'image/character/ganning.jpg', - 'image/character/gaogan.jpg', - 'image/character/gaolan.jpg', - 'image/character/gaoshun.jpg', - 'image/character/gaoxiang.jpg', - 'image/character/gexuan.jpg', - 'image/character/gjqt_aruan.jpg', - 'image/character/gjqt_bailitusu.jpg', - 'image/character/gjqt_beiluo.jpg', - 'image/character/gjqt_cenying.jpg', - 'image/character/gjqt_chuqi.jpg', - 'image/character/gjqt_fanglansheng.jpg', - 'image/character/gjqt_fengqingxue.jpg', - 'image/character/gjqt_hongyu.jpg', - 'image/character/gjqt_ouyangshaogong.jpg', - 'image/character/gjqt_wenrenyu.jpg', - 'image/character/gjqt_xiangling.jpg', - 'image/character/gjqt_xiayize.jpg', - 'image/character/gjqt_xieyi.jpg', - 'image/character/gjqt_xunfang.jpg', - 'image/character/gjqt_yanjiaxieyi.jpg', - 'image/character/gjqt_yinqianshang.jpg', - 'image/character/gjqt_yuewuyi.jpg', - 'image/character/gjqt_yunwuyue.jpg', - 'image/character/gongsundu.jpg', - 'image/character/gongsunkang.jpg', - 'image/character/gongsunyuan.jpg', - 'image/character/gongsunzan.jpg', - 'image/character/guanhai.jpg', - 'image/character/guanlu.jpg', - 'image/character/guanning.jpg', - 'image/character/guānning.jpg', - 'image/character/guanping.jpg', - 'image/character/guanqiujian.jpg', - 'image/character/guansuo.jpg', - 'image/character/guanxingzhangbao.jpg', - 'image/character/guanyinping.jpg', - 'image/character/guanyu.jpg', - 'image/character/guanzhang.jpg', - 'image/character/guohuai.jpg', - 'image/character/guohuanghou.jpg', - 'image/character/guojia.jpg', - 'image/character/guosi.jpg', - 'image/character/guotu.jpg', - 'image/character/guotufengji.jpg', - 'image/character/guozhao.jpg', - 'image/character/guyong.jpg', - 'image/character/gw_aigeleisi.jpg', - 'image/character/gw_aimin.jpg', - 'image/character/gw_airuiting.jpg', - 'image/character/gw_aisinie.jpg', - 'image/character/gw_aokeweisite.jpg', - 'image/character/gw_bierna.jpg', - 'image/character/gw_bulanwang.jpg', - 'image/character/gw_dagong.jpg', - 'image/character/gw_diandian.jpg', - 'image/character/gw_enxier.jpg', - 'image/character/gw_falanxisika.jpg', - 'image/character/gw_feilafanruide.jpg', - 'image/character/gw_fenghuang.jpg', - 'image/character/gw_fuertaisite.jpg', - 'image/character/gw_fulisi.jpg', - 'image/character/gw_gaier.jpg', - 'image/character/gw_haizhiyezhu.jpg', - 'image/character/gw_haluo.jpg', - 'image/character/gw_hanmuduoer.jpg', - 'image/character/gw_hengsaite.jpg', - 'image/character/gw_huoge.jpg', - 'image/character/gw_jieluote.jpg', - 'image/character/gw_kaerweite.jpg', - 'image/character/gw_kairuisi.jpg', - 'image/character/gw_kanbi.jpg', - 'image/character/gw_kaxier.jpg', - 'image/character/gw_kuite.jpg', - 'image/character/gw_laduoweide.jpg', - 'image/character/gw_lanbote.jpg', - 'image/character/gw_laomaotou.jpg', - 'image/character/gw_laomaotou2.jpg', - 'image/character/gw_linjing.jpg', - 'image/character/gw_luobo.jpg', - 'image/character/gw_luoqi.jpg', - 'image/character/gw_meizi.jpg', - 'image/character/gw_mieren.jpg', - 'image/character/gw_nitelila.jpg', - 'image/character/gw_nvyemo.jpg', - 'image/character/gw_oudimu.jpg', - 'image/character/gw_puxila.jpg', - 'image/character/gw_qigaiwang.jpg', - 'image/character/gw_sanhanya.jpg', - 'image/character/gw_saqiya.jpg', - 'image/character/gw_saqiya1.jpg', - 'image/character/gw_saqiya2.jpg', - 'image/character/gw_shanhu.jpg', - 'image/character/gw_shasixiwusi.jpg', - 'image/character/gw_telisi.jpg', - 'image/character/gw_xigedelifa.jpg', - 'image/character/gw_xili.jpg', - 'image/character/gw_yenaifa.jpg', - 'image/character/gw_yioufeisi.jpg', - 'image/character/gw_yioufeisisp.jpg', - 'image/character/gw_yisilinni.jpg', - 'image/character/gw_zhangyujushou.jpg', - 'image/character/gw_zhuoertan.jpg', - 'image/character/gz_caohong.jpg', - 'image/character/gz_caopi.jpg', - 'image/character/gz_chengong.jpg', - 'image/character/gz_dengai.jpg', - 'image/character/gz_dengzhi.jpg', - 'image/character/gz_dianwei.jpg', - 'image/character/gz_diaochan.jpg', - 'image/character/gz_dingfeng.jpg', - 'image/character/gz_fazheng.jpg', - 'image/character/gz_fengxi.jpg', - 'image/character/gz_ganfuren.jpg', - 'image/character/gz_gongsunyuan.jpg', - 'image/character/gz_guanyu.jpg', - 'image/character/gz_guohuai.jpg', - 'image/character/gz_guojia.jpg', - 'image/character/gz_hetaihou.jpg', - 'image/character/gz_huangyueying.jpg', - 'image/character/gz_huangzhong.jpg', - 'image/character/gz_huangzu.jpg', - 'image/character/gz_jiangwei.jpg', - 'image/character/gz_jiaxu.jpg', - 'image/character/gz_lingtong.jpg', - 'image/character/gz_liuba.jpg', - 'image/character/gz_liuqi.jpg', - 'image/character/gz_lukang.jpg', - 'image/character/gz_luxun.jpg', - 'image/character/gz_lvbu.jpg', - 'image/character/gz_lvlingqi.jpg', - 'image/character/gz_madai.jpg', - 'image/character/gz_masu.jpg', - 'image/character/gz_miheng.jpg', - 'image/character/gz_panfeng.jpg', - 'image/character/gz_panjun.jpg', - 'image/character/gz_pengyang.jpg', - 'image/character/gz_re_xushu.jpg', - 'image/character/gz_re_yuanshao.jpg', - 'image/character/gz_shamoke.jpg', - 'image/character/gz_shixie.jpg', - 'image/character/gz_simazhao.jpg', - 'image/character/gz_sp_zhugeliang.jpg', - 'image/character/gz_sunce.jpg', - 'image/character/gz_sunjian.jpg', - 'image/character/gz_sunshangxiang.jpg', - 'image/character/gz_tangzi.jpg', - 'image/character/gz_wangping.jpg', - 'image/character/gz_wenqin.jpg', - 'image/character/gz_wuguotai.jpg', - 'image/character/gz_wujing.jpg', - 'image/character/gz_xf_sufei.jpg', - 'image/character/gz_xiahouba.jpg', - 'image/character/gz_xiahouyuan.jpg', - 'image/character/gz_xiaoqiao.jpg', - 'image/character/gz_xunyou.jpg', - 'image/character/gz_xusheng.jpg', - 'image/character/gz_xuyou.jpg', - 'image/character/gz_yanbaihu.jpg', - 'image/character/gz_yangwan.jpg', - 'image/character/gz_yuanshu.jpg', - 'image/character/gz_yuejin.jpg', - 'image/character/gz_yuji.jpg', - 'image/character/gz_yujin.jpg', - 'image/character/gz_zhanglu.jpg', - 'image/character/gz_zhangxiu.jpg', - 'image/character/gz_zhenji.jpg', - 'image/character/gz_zhonghui.jpg', - 'image/character/gz_zhouyu.jpg', - 'image/character/gz_zhugeke.jpg', - 'image/character/gz_zhugeliang.jpg', - 'image/character/gz_zhuling.jpg', - 'image/character/gz_zuoci.jpg', - 'image/character/hanba.jpg', - 'image/character/handang.jpg', - 'image/character/hanfu.jpg', - 'image/character/hanhaoshihuan.jpg', - 'image/character/hanlong.jpg', - 'image/character/hanmeng.jpg', - 'image/character/hansui.jpg', - 'image/character/haomeng.jpg', - 'image/character/haopu.jpg', - 'image/character/haozhao.jpg', - 'image/character/heiwuchang.jpg', - 'image/character/hejin.jpg', - 'image/character/heqi.jpg', - 'image/character/hetaihou.jpg', - 'image/character/heyan.jpg', - 'image/character/hhzz_kanade.jpg', - 'image/character/hhzz_shiona.jpg', - 'image/character/hhzz_takaramono1.jpg', - 'image/character/hhzz_takaramono2.jpg', - 'image/character/hidden_image.jpg', - 'image/character/hs_aedwin.jpg', - 'image/character/hs_aerfusi.jpg', - 'image/character/hs_aiqinvyao.jpg', - 'image/character/hs_alakir.jpg', - 'image/character/hs_alextrasza.jpg', - 'image/character/hs_alleria.jpg', - 'image/character/hs_amala.jpg', - 'image/character/hs_anduin.jpg', - 'image/character/hs_anomalus.jpg', - 'image/character/hs_antonidas.jpg', - 'image/character/hs_ashamoer.jpg', - 'image/character/hs_aya.jpg', - 'image/character/hs_baiguyoulong.jpg', - 'image/character/hs_bannabusi.jpg', - 'image/character/hs_barnes.jpg', - 'image/character/hs_bchillmaw.jpg', - 'image/character/hs_bilanyoulong.jpg', - 'image/character/hs_bingshuangnvwang.jpg', - 'image/character/hs_blingtron.jpg', - 'image/character/hs_bolvar.jpg', - 'image/character/hs_brann.jpg', - 'image/character/hs_duyaxinshi.jpg', - 'image/character/hs_enzoth.jpg', - 'image/character/hs_fachaotuteng.jpg', - 'image/character/hs_fandral.jpg', - 'image/character/hs_fengjianhuanfengzhe.jpg', - 'image/character/hs_fenjie.jpg', - 'image/character/hs_finley.jpg', - 'image/character/hs_fuding.jpg', - 'image/character/hs_guldan.jpg', - 'image/character/hs_hajiasha.jpg', - 'image/character/hs_hallazeal.jpg', - 'image/character/hs_heifengqishi.jpg', - 'image/character/hs_hemite.jpg', - 'image/character/hs_hudunren.jpg', - 'image/character/hs_huolituteng.jpg', - 'image/character/hs_huzhixiannv.jpg', - 'image/character/hs_jaina.jpg', - 'image/character/hs_jgarrosh.jpg', - 'image/character/hs_jiawodun.jpg', - 'image/character/hs_jiaziruila.jpg', - 'image/character/hs_jinglinglong.jpg', - 'image/character/hs_kaituozhe.jpg', - 'image/character/hs_kalimosi.jpg', - 'image/character/hs_kazhakusi.jpg', - 'image/character/hs_kchromaggus.jpg', - 'image/character/hs_kcthun.jpg', - 'image/character/hs_khadgar.jpg', - 'image/character/hs_lafamu.jpg', - 'image/character/hs_laila.jpg', - 'image/character/hs_laxiao.jpg', - 'image/character/hs_lazi.jpg', - 'image/character/hs_liadrin.jpg', - 'image/character/hs_loatheb.jpg', - 'image/character/hs_lreno.jpg', - 'image/character/hs_lrexxar.jpg', - 'image/character/hs_lrhonin.jpg', - 'image/character/hs_magni.jpg', - 'image/character/hs_malfurion.jpg', - 'image/character/hs_malorne.jpg', - 'image/character/hs_malygos.jpg', - 'image/character/hs_manyututeng.jpg', - 'image/character/hs_medivh.jpg', - 'image/character/hs_mijiaojisi.jpg', - 'image/character/hs_mojinbaozi.jpg', - 'image/character/hs_morgl.jpg', - 'image/character/hs_nate.jpg', - 'image/character/hs_neptulon.jpg', - 'image/character/hs_nozdormu.jpg', - 'image/character/hs_nuogefu.jpg', - 'image/character/hs_pengpeng.jpg', - 'image/character/hs_pyros.jpg', - 'image/character/hs_pyros1.jpg', - 'image/character/hs_pyros2.jpg', - 'image/character/hs_ronghejuren.jpg', - 'image/character/hs_ruanniguai.jpg', - 'image/character/hs_sainaliusi.jpg', - 'image/character/hs_sapphiron.jpg', - 'image/character/hs_selajin.jpg', - 'image/character/hs_selajin2.jpg', - 'image/character/hs_shaku.jpg', - 'image/character/hs_shanlingjuren.jpg', - 'image/character/hs_shifazhe.jpg', - 'image/character/hs_shirencao.jpg', - 'image/character/hs_shizugui.jpg', - 'image/character/hs_shuiwenxuejia.jpg', - 'image/character/hs_siwangxianzhi.jpg', - 'image/character/hs_siwangzhiyi.jpg', - 'image/character/hs_sthrall.jpg', - 'image/character/hs_taisi.jpg', - 'image/character/hs_tanghangu.jpg', - 'image/character/hs_tgolem.jpg', - 'image/character/hs_totemic.jpg', - 'image/character/hs_trueheart.jpg', - 'image/character/hs_tuoqi.jpg', - 'image/character/hs_tyrande.jpg', - 'image/character/hs_waleera.jpg', - 'image/character/hs_walian.jpg', - 'image/character/hs_wolazi.jpg', - 'image/character/hs_wujiyuansu.jpg', - 'image/character/hs_wuther.jpg', - 'image/character/hs_wuyaowang.jpg', - 'image/character/hs_wvelen.jpg', - 'image/character/hs_xialikeer.jpg', - 'image/character/hs_xiangyaqishi.jpg', - 'image/character/hs_xsylvanas.jpg', - 'image/character/hs_xuanzhuanjijia.jpg', - 'image/character/hs_xuefashi.jpg', - 'image/character/hs_xukongzhiying.jpg', - 'image/character/hs_yangyanwageli.jpg', - 'image/character/hs_yashaji.jpg', - 'image/character/hs_yelinchulong.jpg', - 'image/character/hs_yelinlonghou.jpg', - 'image/character/hs_yelise.jpg', - 'image/character/hs_yinggencao.jpg', - 'image/character/hs_yngvar.jpg', - 'image/character/hs_yogg.jpg', - 'image/character/hs_ysera.jpg', - 'image/character/hs_yuhuozhe.jpg', - 'image/character/hs_zhanzhenggushu.jpg', - 'image/character/hs_zhihuanhua.jpg', - 'image/character/hs_zhishigushu.jpg', - 'image/character/hs_zhouzhuo.jpg', - 'image/character/huaman.jpg', - 'image/character/huanfan.jpg', - 'image/character/huangchengyan.jpg', - 'image/character/huangfusong.jpg', - 'image/character/huanggai.jpg', - 'image/character/huanghao.jpg', - 'image/character/huangjinleishi.jpg', - 'image/character/huangyueying.jpg', - 'image/character/huangzhong.jpg', - 'image/character/huangzu.jpg', - 'image/character/huatuo.jpg', - 'image/character/huaxin.jpg', - 'image/character/huaxiong.jpg', - 'image/character/huban.jpg', - 'image/character/hucheer.jpg', - 'image/character/hujinding.jpg', - 'image/character/huojun.jpg', - 'image/character/huzhao.jpg', - 'image/character/jiachong.jpg', - 'image/character/jiakui.jpg', - 'image/character/jiangfei.jpg', - 'image/character/jianggan.jpg', - 'image/character/jiangqing.jpg', - 'image/character/jiangwei.jpg', - 'image/character/jianyong.jpg', - 'image/character/jiaxu.jpg', - 'image/character/jikang.jpg', - 'image/character/jiling.jpg', - 'image/character/jin_guohuai.jpg', - 'image/character/jin_jiachong.jpg', - 'image/character/jin_simashi.jpg', - 'image/character/jin_simayi.jpg', - 'image/character/jin_simazhao.jpg', - 'image/character/jin_wangyuanji.jpg', - 'image/character/jin_xiahouhui.jpg', - 'image/character/jin_yanghu.jpg', - 'image/character/jin_yanghuiyu.jpg', - 'image/character/jin_zhangchunhua.jpg', - 'image/character/jin_zhouchu.jpg', - 'image/character/jsp_caoren.jpg', - 'image/character/jsp_guanyu.jpg', - 'image/character/jsp_huangyueying.jpg', - 'image/character/jsp_liubei.jpg', - 'image/character/jsp_zhaoyun.jpg', - 'image/character/jsrg_caocao.jpg', - 'image/character/jsrg_caofang.jpg', - 'image/character/jsrg_chendeng.jpg', - 'image/character/jsrg_chunyuqiong.jpg', - 'image/character/jsrg_dongbai.jpg', - 'image/character/jsrg_fanjiangzhangda.jpg', - 'image/character/jsrg_gaoxiang.jpg', - 'image/character/jsrg_guanyu.jpg', - 'image/character/jsrg_guojia.jpg', - 'image/character/jsrg_guoxun.jpg', - 'image/character/jsrg_guozhao.jpg', - 'image/character/jsrg_hansui.jpg', - 'image/character/jsrg_hejin.jpg', - 'image/character/jsrg_huangfusong.jpg', - 'image/character/jsrg_huangzhong.jpg', - 'image/character/jsrg_jiangwei.jpg', - 'image/character/jsrg_kongrong.jpg', - 'image/character/jsrg_liubei.jpg', - 'image/character/jsrg_liuhong.jpg', - 'image/character/jsrg_liuyan.jpg', - 'image/character/jsrg_liuyong.jpg', - 'image/character/jsrg_lougui.jpg', - 'image/character/jsrg_luxun.jpg', - 'image/character/jsrg_lvbu.jpg', - 'image/character/jsrg_machao.jpg', - 'image/character/jsrg_nanhualaoxian.jpg', - 'image/character/jsrg_pangtong.jpg', - 'image/character/jsrg_qiaoxuan.jpg', - 'image/character/jsrg_simayi.jpg', - 'image/character/jsrg_sunce.jpg', - 'image/character/jsrg_sunjian.jpg', - 'image/character/jsrg_sunjun.jpg', - 'image/character/jsrg_sunlubansunluyu.jpg', - 'image/character/jsrg_sunshangxiang.jpg', - 'image/character/jsrg_wangyun.jpg', - 'image/character/jsrg_weiwenzhugezhi.jpg', - 'image/character/jsrg_xiahouen.jpg', - 'image/character/jsrg_xiahourong.jpg', - 'image/character/jsrg_xugong.jpg', - 'image/character/jsrg_xushao.jpg', - 'image/character/jsrg_xuyou.jpg', - 'image/character/jsrg_yangbiao.jpg', - 'image/character/jsrg_zhangchu.jpg', - 'image/character/jsrg_zhangfei.jpg', - 'image/character/jsrg_zhanghe.jpg', - 'image/character/jsrg_zhangliao.jpg', - 'image/character/jsrg_zhangren.jpg', - 'image/character/jsrg_zhangxuan.jpg', - 'image/character/jsrg_zhaoyun.jpg', - 'image/character/jsrg_zhenji.jpg', - 'image/character/jsrg_zhugeliang.jpg', - 'image/character/jsrg_zhujun.jpg', - 'image/character/jsrg_zoushi.jpg', - 'image/character/jun_caocao.jpg', - 'image/character/jun_liubei.jpg', - 'image/character/jun_sunquan.jpg', - 'image/character/jun_zhangjiao.jpg', - 'image/character/junk_duanwei.jpg', - 'image/character/junk_guanyu.jpg', - 'image/character/junk_huangyueying.jpg', - 'image/character/junk_lidian.jpg', - 'image/character/junk_liubei.jpg', - 'image/character/junk_simayi.jpg', - 'image/character/junk_sunquan.jpg', - 'image/character/junk_xuyou.jpg', - 'image/character/junk_zhangjiao.jpg', - 'image/character/junk_zhangrang.jpg', - 'image/character/kaisa.jpg', - 'image/character/kanze.jpg', - 'image/character/kebineng.jpg', - 'image/character/key_abyusa.jpg', - 'image/character/key_akane.jpg', - 'image/character/key_akiko.jpg', - 'image/character/key_ao.jpg', - 'image/character/key_asara.jpg', - 'image/character/key_ayato.jpg', - 'image/character/key_chihaya.jpg', - 'image/character/key_doruji.jpg', - 'image/character/key_erika.jpg', - 'image/character/key_fuuko.jpg', - 'image/character/key_godan.jpg', - 'image/character/key_harukakanata.jpg', - 'image/character/key_haruko.jpg', - 'image/character/key_hina.jpg', - 'image/character/key_hinata.jpg', - 'image/character/key_hiroto.jpg', - 'image/character/key_hisako.jpg', - 'image/character/key_inari.jpg', - 'image/character/key_iriya.jpg', - 'image/character/key_iwasawa.jpg', - 'image/character/key_jojiro.jpg', - 'image/character/key_kagari.jpg', - 'image/character/key_kamome.jpg', - 'image/character/key_kano.jpg', - 'image/character/key_kaori.jpg', - 'image/character/key_kengo.jpg', - 'image/character/key_kiyu.jpg', - 'image/character/key_komari.jpg', - 'image/character/key_kotarou.jpg', - 'image/character/key_kotomi.jpg', - 'image/character/key_kotori.jpg', - 'image/character/key_kud.jpg', - 'image/character/key_kyoko.jpg', - 'image/character/key_kyou.jpg', - 'image/character/key_kyouko.jpg', - 'image/character/key_kyousuke.jpg', - 'image/character/key_lucia.jpg', - 'image/character/key_masato.jpg', - 'image/character/key_mia.jpg', - 'image/character/key_michiru.jpg', - 'image/character/key_midori.jpg', - 'image/character/key_miki.jpg', - 'image/character/key_minagi.jpg', - 'image/character/key_mio.jpg', - 'image/character/key_misa.jpg', - 'image/character/key_misuzu.jpg', - 'image/character/key_nagisa.jpg', - 'image/character/key_nao.jpg', - 'image/character/key_noda.jpg', - 'image/character/key_rei.jpg', - 'image/character/key_riki.jpg', - 'image/character/key_rin.jpg', - 'image/character/key_rumi.jpg', - 'image/character/key_ryoichi.jpg', - 'image/character/key_sakuya.jpg', - 'image/character/key_sasami.jpg', - 'image/character/key_satomi.jpg', - 'image/character/key_saya.jpg', - 'image/character/key_seira.jpg', - 'image/character/key_shiina.jpg', - 'image/character/key_shiki.jpg', - 'image/character/key_shiori.jpg', - 'image/character/key_shiorimiyuki.jpg', - 'image/character/key_shiroha.jpg', - 'image/character/key_shizuku.jpg', - 'image/character/key_shizuru.jpg', - 'image/character/key_sunohara.jpg', - 'image/character/key_tenzen.jpg', - 'image/character/key_tomoya.jpg', - 'image/character/key_tomoyo.jpg', - 'image/character/key_tsumugi.jpg', - 'image/character/key_umi.jpg', - 'image/character/key_ushio.jpg', - 'image/character/key_yoshino.jpg', - 'image/character/key_youta.jpg', - 'image/character/key_yui.jpg', - 'image/character/key_yuiko.jpg', - 'image/character/key_yukine.jpg', - 'image/character/key_yukito.jpg', - 'image/character/key_yuri.jpg', - 'image/character/key_yusa.jpg', - 'image/character/key_yuu.jpg', - 'image/character/key_yuuki.jpg', - 'image/character/key_yuzuru.jpg', - 'image/character/kongrong.jpg', - 'image/character/kuailiangkuaiyue.jpg', - 'image/character/kuaiqi.jpg', - 'image/character/laimin.jpg', - 'image/character/laiyinger.jpg', - 'image/character/le_shen_jiaxu.jpg', - 'image/character/leibo.jpg', - 'image/character/leitong.jpg', - 'image/character/liangxing.jpg', - 'image/character/liaohua.jpg', - 'image/character/libai.jpg', - 'image/character/licaiwei.jpg', - 'image/character/lifeng.jpg', - 'image/character/lijue.jpg', - 'image/character/lingcao.jpg', - 'image/character/lingju.jpg', - 'image/character/lingtong.jpg', - 'image/character/liqueguosi.jpg', - 'image/character/liru.jpg', - 'image/character/lisu.jpg', - 'image/character/litong.jpg', - 'image/character/liuba.jpg', - 'image/character/liubei.jpg', - 'image/character/liubian.jpg', - 'image/character/liubiao.jpg', - 'image/character/liuchen.jpg', - 'image/character/liucheng.jpg', - 'image/character/liuchongluojun.jpg', - 'image/character/liufeng.jpg', - 'image/character/liuhong.jpg', - 'image/character/liuhui.jpg', - 'image/character/liupan.jpg', - 'image/character/liupi.jpg', - 'image/character/liuqi.jpg', - 'image/character/liushan.jpg', - 'image/character/liuxie.jpg', - 'image/character/liuyan.jpg', - 'image/character/liuyao.jpg', - 'image/character/liuye.jpg', - 'image/character/liuyong.jpg', - 'image/character/liuyu.jpg', - 'image/character/liuzan.jpg', - 'image/character/liuzhang.jpg', - 'image/character/liwan.jpg', - 'image/character/liwei.jpg', - 'image/character/liyan.jpg', - 'image/character/liyi.jpg', - 'image/character/liyixiejing.jpg', - 'image/character/longwang.jpg', - 'image/character/longyufei.jpg', - 'image/character/luji.jpg', - 'image/character/lukai.jpg', - 'image/character/lukang.jpg', - 'image/character/luotong.jpg', - 'image/character/luoxian.jpg', - 'image/character/lushi.jpg', - 'image/character/luxun.jpg', - 'image/character/luyi.jpg', - 'image/character/luyusheng.jpg', - 'image/character/luzhi.jpg', - 'image/character/lvboshe.jpg', - 'image/character/lvbu.jpg', - 'image/character/lvdai.jpg', - 'image/character/lvfan.jpg', - 'image/character/lvkai.jpg', - 'image/character/lvkuanglvxiang.jpg', - 'image/character/lvlingqi.jpg', - 'image/character/lvmeng.jpg', - 'image/character/lvqian.jpg', - 'image/character/machao.jpg', - 'image/character/macheng.jpg', - 'image/character/madai.jpg', - 'image/character/majun.jpg', - 'image/character/maliang.jpg', - 'image/character/malingli.jpg', - 'image/character/mamian.jpg', - 'image/character/mamidi.jpg', - 'image/character/manchong.jpg', - 'image/character/mangyachang.jpg', - 'image/character/masu.jpg', - 'image/character/mateng.jpg', - 'image/character/maxiumatie.jpg', - 'image/character/mayuanyi.jpg', - 'image/character/mayunlu.jpg', - 'image/character/mazhong.jpg', - 'image/character/mb_chengui.jpg', - 'image/character/mb_huban.jpg', - 'image/character/mb_sunluyu.jpg', - 'image/character/mb_xianglang.jpg', - 'image/character/mengda.jpg', - 'image/character/menghuo.jpg', - 'image/character/mengjie.jpg', - 'image/character/mengyou.jpg', - 'image/character/mifangfushiren.jpg', - 'image/character/mifuren.jpg', - 'image/character/miheng.jpg', - 'image/character/mizhu.jpg', - 'image/character/mp_liuling.jpg', - 'image/character/mtg_ayeni.jpg', - 'image/character/mtg_jiding.jpg', - 'image/character/mtg_jiesi.jpg', - 'image/character/mtg_lilianna.jpg', - 'image/character/mtg_nisha.jpg', - 'image/character/mtg_qianzhuo.jpg', - 'image/character/muludawang.jpg', - 'image/character/mushun.jpg', - 'image/character/nanhualaoxian.jpg', - 'image/character/nashime.jpg', - 'image/character/new_caoren.jpg', - 'image/character/nezha.jpg', - 'image/character/nianshou.jpg', - 'image/character/niufu.jpg', - 'image/character/niujin.jpg', - 'image/character/niutou.jpg', - 'image/character/noname.jpg', - 'image/character/noname_machao.png', - 'image/character/noname_sunce.png', - 'image/character/ns_caimao.jpg', - 'image/character/ns_caoanmin.jpg', - 'image/character/ns_caocao.jpg', - 'image/character/ns_caocaosp.jpg', - 'image/character/ns_caoshuang.jpg', - 'image/character/ns_chendao.jpg', - 'image/character/ns_chengpu.jpg', - 'image/character/ns_chentai.jpg', - 'image/character/ns_duangui.jpg', - 'image/character/ns_duji.jpg', - 'image/character/ns_fanchou.jpg', - 'image/character/ns_guanlu.jpg', - 'image/character/ns_huamulan.jpg', - 'image/character/ns_huangchengyan.jpg', - 'image/character/ns_huangwudie.jpg', - 'image/character/ns_huangzu.jpg', - 'image/character/ns_jiaxu.jpg', - 'image/character/ns_jinke.jpg', - 'image/character/ns_lijue.jpg', - 'image/character/ns_limi.jpg', - 'image/character/ns_lisu.jpg', - 'image/character/ns_liuzhang.jpg', - 'image/character/ns_luyusheng.jpg', - 'image/character/ns_lvmeng.jpg', - 'image/character/ns_lvzhi.jpg', - 'image/character/ns_masu.jpg', - 'image/character/ns_mengyou.jpg', - 'image/character/ns_nanhua.jpg', - 'image/character/ns_nanhua_left.jpg', - 'image/character/ns_nanhua_right.jpg', - 'image/character/ns_ruanji.jpg', - 'image/character/ns_shenpei.jpg', - 'image/character/ns_simazhao.jpg', - 'image/character/ns_sunchensunjun.jpg', - 'image/character/ns_sundeng.jpg', - 'image/character/ns_sunjian.jpg', - 'image/character/ns_sunyi.jpg', - 'image/character/ns_wangyue.jpg', - 'image/character/ns_wangyun.jpg', - 'image/character/ns_wenchou.jpg', - 'image/character/ns_xinnanhua.jpg', - 'image/character/ns_xinxianying.jpg', - 'image/character/ns_yanghu.jpg', - 'image/character/ns_yangyi.jpg', - 'image/character/ns_yanliang.jpg', - 'image/character/ns_yuanxi.jpg', - 'image/character/ns_yuji.jpg', - 'image/character/ns_yujisp.jpg', - 'image/character/ns_zanghong.jpg', - 'image/character/ns_zhangbao.jpg', - 'image/character/ns_zhangji.jpg', - 'image/character/ns_zhangning.jpg', - 'image/character/ns_zhangwei.jpg', - 'image/character/ns_zhangxiu.jpg', - 'image/character/ns_zhonglimu.jpg', - 'image/character/ns_zhugeliang.jpg', - 'image/character/ns_zuoci.jpg', - 'image/character/ol_bianfuren.jpg', - 'image/character/ol_caiwenji.jpg', - 'image/character/ol_caozhang.jpg', - 'image/character/ol_chendeng.jpg', - 'image/character/ol_chengpu.jpg', - 'image/character/ol_dengai.jpg', - 'image/character/ol_dengzhi.jpg', - 'image/character/ol_dianwei.jpg', - 'image/character/ol_dingshangwan.jpg', - 'image/character/ol_dingyuan.jpg', - 'image/character/ol_dongzhao.jpg', - 'image/character/ol_dongzhuo.jpg', - 'image/character/ol_feiyi.jpg', - 'image/character/ol_furong.jpg', - 'image/character/ol_gaoshun.jpg', - 'image/character/ol_guohuai.jpg', - 'image/character/ol_huangzhong.jpg', - 'image/character/ol_huaxin.jpg', - 'image/character/ol_huaxiong.jpg', - 'image/character/ol_huban.jpg', - 'image/character/ol_hujinding.jpg', - 'image/character/ol_jiangwei.jpg', - 'image/character/ol_jianyong.jpg', - 'image/character/ol_lingtong.jpg', - 'image/character/ol_lisu.jpg', - 'image/character/ol_liuba.jpg', - 'image/character/ol_liushan.jpg', - 'image/character/ol_liuyu.jpg', - 'image/character/ol_liwan.jpg', - 'image/character/ol_lukai.jpg', - 'image/character/ol_lusu.jpg', - 'image/character/ol_luyusheng.jpg', - 'image/character/ol_maliang.jpg', - 'image/character/ol_mengda.jpg', - 'image/character/ol_pangde.jpg', - 'image/character/ol_pangtong.jpg', - 'image/character/ol_pengyang.jpg', - 'image/character/ol_puyuan.jpg', - 'image/character/ol_qianzhao.jpg', - 'image/character/ol_sb_guanyu.jpg', - 'image/character/ol_sb_jiangwei.jpg', - 'image/character/ol_sb_taishici.jpg', - 'image/character/ol_sb_yuanshao.jpg', - 'image/character/ol_sb_yuanshao_shadow.jpg', - 'image/character/ol_sp_zhugeliang.jpg', - 'image/character/ol_sunjian.jpg', - 'image/character/ol_wanglang.jpg', - 'image/character/ol_wangrong.jpg', - 'image/character/ol_weiyan.jpg', - 'image/character/ol_wenqin.jpg', - 'image/character/ol_xiahouyuan.jpg', - 'image/character/ol_xiaoqiao.jpg', - 'image/character/ol_xinxianying.jpg', - 'image/character/ol_xuhuang.jpg', - 'image/character/ol_xunyu.jpg', - 'image/character/ol_yangyi.jpg', - 'image/character/ol_yanwen.jpg', - 'image/character/ol_yuanshao.jpg', - 'image/character/ol_yuanshu.jpg', - 'image/character/ol_yufan.jpg', - 'image/character/ol_yujin.jpg', - 'image/character/ol_zhangchangpu.jpg', - 'image/character/ol_zhangliao.jpg', - 'image/character/ol_zhangrang.jpg', - 'image/character/ol_zhangyì.jpg', - 'image/character/ol_zhangzhang.jpg', - 'image/character/ol_zhouqun.jpg', - 'image/character/ol_zhujun.jpg', - 'image/character/ol_zhuling.jpg', - 'image/character/ol_zhurong.jpg', - 'image/character/old_bulianshi.jpg', - 'image/character/old_caocao.jpg', - 'image/character/old_caochong.jpg', - 'image/character/old_caochun.jpg', - 'image/character/old_caoren.jpg', - 'image/character/old_caorui.jpg', - 'image/character/old_caoxiu.jpg', - 'image/character/old_caozhen.jpg', - 'image/character/old_chendao.jpg', - 'image/character/old_chenqun.jpg', - 'image/character/old_dingfeng.jpg', - 'image/character/old_fuhuanghou.jpg', - 'image/character/old_gaoshun.jpg', - 'image/character/old_guanqiujian.jpg', - 'image/character/old_guanyinping.jpg', - 'image/character/old_guanyu.jpg', - 'image/character/old_guanzhang.jpg', - 'image/character/old_handang.jpg', - 'image/character/old_huangfusong.jpg', - 'image/character/old_huanghao.jpg', - 'image/character/old_huatuo.jpg', - 'image/character/old_huaxiong.jpg', - 'image/character/old_jiakui.jpg', - 'image/character/old_lingju.jpg', - 'image/character/old_lingtong.jpg', - 'image/character/old_liubiao.jpg', - 'image/character/old_liuzan.jpg', - 'image/character/old_liyan.jpg', - 'image/character/old_machao.jpg', - 'image/character/old_madai.jpg', - 'image/character/old_majun.jpg', - 'image/character/old_maliang.jpg', - 'image/character/old_quancong.jpg', - 'image/character/old_re_lidian.jpg', - 'image/character/old_shen_zhaoyun.jpg', - 'image/character/old_shixie.jpg', - 'image/character/old_wanglang.jpg', - 'image/character/old_wangyi.jpg', - 'image/character/old_wangyun.jpg', - 'image/character/old_xiaoqiao.jpg', - 'image/character/old_xusheng.jpg', - 'image/character/old_yangyan.jpg', - 'image/character/old_yangzhi.jpg', - 'image/character/old_yuanshu.jpg', - 'image/character/old_zhangfei.jpg', - 'image/character/old_zhangxingcai.jpg', - 'image/character/old_zhaoyun.jpg', - 'image/character/old_zhonghui.jpg', - 'image/character/old_zhoutai.jpg', - 'image/character/old_zhugezhan.jpg', - 'image/character/old_zhuhuan.jpg', - 'image/character/old_zhuran.jpg', - 'image/character/old_zhuzhi.jpg', - 'image/character/oldre_liubiao.jpg', - 'image/character/ow_ana.jpg', - 'image/character/ow_banzang.jpg', - 'image/character/ow_baolei.jpg', - 'image/character/ow_chanyata.jpg', - 'image/character/ow_dva.jpg', - 'image/character/ow_falaozhiying.jpg', - 'image/character/ow_heibaihe.jpg', - 'image/character/ow_heiying.jpg', - 'image/character/ow_kuangshu.jpg', - 'image/character/ow_laiyinhate.jpg', - 'image/character/ow_liekong.jpg', - 'image/character/ow_luba.jpg', - 'image/character/ow_luxiao.jpg', - 'image/character/ow_maikelei.jpg', - 'image/character/ow_mei.jpg', - 'image/character/ow_orisa.jpg', - 'image/character/ow_shibing.jpg', - 'image/character/ow_sishen.jpg', - 'image/character/ow_tianshi.jpg', - 'image/character/ow_tuobiang.jpg', - 'image/character/ow_wensidun.jpg', - 'image/character/ow_yuanshi.jpg', - 'image/character/ow_zhaliya.jpg', - 'image/character/ow_zhixuzhiguang.jpg', - 'image/character/pal_anu.jpg', - 'image/character/pal_changqing.jpg', - 'image/character/pal_hanlingsha.jpg', - 'image/character/pal_jiangcheng.jpg', - 'image/character/pal_jiangyunfan.jpg', - 'image/character/pal_jingtian.jpg', - 'image/character/pal_jushifang.jpg', - 'image/character/pal_leiyuange.jpg', - 'image/character/pal_linyueru.jpg', - 'image/character/pal_liumengli.jpg', - 'image/character/pal_lixiaoyao.jpg', - 'image/character/pal_longkui.jpg', - 'image/character/pal_longkuigui.jpg', - 'image/character/pal_longyou.jpg', - 'image/character/pal_luozhaoyan.jpg', - 'image/character/pal_mingxiu.jpg', - 'image/character/pal_muchanglan.jpg', - 'image/character/pal_murongziying.jpg', - 'image/character/pal_nangonghuang.jpg', - 'image/character/pal_shenqishuang.jpg', - 'image/character/pal_sumei.jpg', - 'image/character/pal_tangyurou.jpg', - 'image/character/pal_wangpengxu.jpg', - 'image/character/pal_wangxiaohu.jpg', - 'image/character/pal_wenhui.jpg', - 'image/character/pal_xia.jpg', - 'image/character/pal_xiahoujinxuan.jpg', - 'image/character/pal_xianqing.jpg', - 'image/character/pal_xiaoman.jpg', - 'image/character/pal_xingxuan.jpg', - 'image/character/pal_xuanxiao.jpg', - 'image/character/pal_xuejian.jpg', - 'image/character/pal_yuejinzhao.jpg', - 'image/character/pal_yueqi.jpg', - 'image/character/pal_yuntianhe.jpg', - 'image/character/pal_zhaoliner.jpg', - 'image/character/pal_zixuan.jpg', - 'image/character/panfeng.jpg', - 'image/character/pangde.jpg', - 'image/character/pangdegong.jpg', - 'image/character/panghui.jpg', - 'image/character/pangshanmin.jpg', - 'image/character/pangtong.jpg', - 'image/character/panjun.jpg', - 'image/character/panshu.jpg', - 'image/character/panzhangmazhong.jpg', - 'image/character/pe_mengda.jpg', - 'image/character/pe_sunchen.jpg', - 'image/character/pe_wangyun.jpg', - 'image/character/pe_wenqin.jpg', - 'image/character/pe_zhonghui.jpg', - 'image/character/peixiu.jpg', - 'image/character/peiyuanshao.jpg', - 'image/character/pengyang.jpg', - 'image/character/pk_sp_duyu.jpg', - 'image/character/prp_zhugeliang.jpg', - 'image/character/ps_caopi.jpg', - 'image/character/ps_caozhi.jpg', - 'image/character/ps_guanyu.jpg', - 'image/character/ps_jiaxu.jpg', - 'image/character/ps_jin_simayi.jpg', - 'image/character/ps_lvbu.jpg', - 'image/character/ps_machao.jpg', - 'image/character/ps_shen_machao.jpg', - 'image/character/ps_simayi.jpg', - 'image/character/ps_zhugeliang.jpg', - 'image/character/ps1059_guojia.jpg', - 'image/character/ps1062_zhouyu.jpg', - 'image/character/ps2063_zhaoyun.jpg', - 'image/character/ps2066_zhugeliang.jpg', - 'image/character/ps2067_zhaoyun.jpg', - 'image/character/ps2068_simayi.jpg', - 'image/character/ps2070_guojia.jpg', - 'image/character/ps2080_zhouyu.jpg', - 'image/character/pujing.jpg', - 'image/character/puyuan.jpg', - 'image/character/qianzhao.jpg', - 'image/character/qiaogong.jpg', - 'image/character/qiaorui.jpg', - 'image/character/qiaozhou.jpg', - 'image/character/qinghegongzhu.jpg', - 'image/character/qinlang.jpg', - 'image/character/qinmi.jpg', - 'image/character/qinyilu.jpg', - 'image/character/qiuliju.jpg', - 'image/character/quancong.jpg', - 'image/character/quanhuijie.jpg', - 'image/character/quhuang.jpg', - 'image/character/quyi.jpg', - 'image/character/re_baosanniang.jpg', - 'image/character/re_bulianshi.jpg', - 'image/character/re_caifuren.jpg', - 'image/character/re_caiwenji.jpg', - 'image/character/re_caiyong.jpg', - 'image/character/re_caocao.jpg', - 'image/character/re_caochong.jpg', - 'image/character/re_caopi.jpg', - 'image/character/re_caorui.jpg', - 'image/character/re_caoxiu.jpg', - 'image/character/re_caozhang.jpg', - 'image/character/re_caozhen.jpg', - 'image/character/re_caozhi.jpg', - 'image/character/re_chendeng.jpg', - 'image/character/re_chengong.jpg', - 'image/character/re_chengpu.jpg', - 'image/character/re_chenqun.jpg', - 'image/character/re_chunyuqiong.jpg', - 'image/character/re_daqiao.jpg', - 'image/character/re_dengai.jpg', - 'image/character/re_dengzhi.jpg', - 'image/character/re_dianwei.jpg', - 'image/character/re_diaochan.jpg', - 'image/character/re_dongbai.jpg', - 'image/character/re_dongcheng.jpg', - 'image/character/re_dongzhuo.jpg', - 'image/character/re_duji.jpg', - 'image/character/re_fazheng.jpg', - 'image/character/re_fengfangnv.jpg', - 'image/character/re_fuhuanghou.jpg', - 'image/character/re_ganning.jpg', - 'image/character/re_gaoshun.jpg', - 'image/character/re_gongsunyuan.jpg', - 'image/character/re_gongsunzan.jpg', - 'image/character/re_guanping.jpg', - 'image/character/re_guanqiujian.jpg', - 'image/character/re_guanyu.jpg', - 'image/character/re_guanzhang.jpg', - 'image/character/re_guohuai.jpg', - 'image/character/re_guohuanghou.jpg', - 'image/character/re_guojia.jpg', - 'image/character/re_guotufengji.jpg', - 'image/character/re_guyong.jpg', - 'image/character/re_handang.jpg', - 'image/character/re_hanhaoshihuan.jpg', - 'image/character/re_hansui.jpg', - 'image/character/re_hejin.jpg', - 'image/character/re_heqi.jpg', - 'image/character/re_huanggai.jpg', - 'image/character/re_huangyueying.jpg', - 'image/character/re_huangzhong.jpg', - 'image/character/re_huatuo.jpg', - 'image/character/re_huaxiong.jpg', - 'image/character/re_hucheer.jpg', - 'image/character/re_jiangwei.jpg', - 'image/character/re_jianyong.jpg', - 'image/character/re_jiaxu.jpg', - 'image/character/re_jikang.jpg', - 'image/character/re_jsp_huangyueying.jpg', - 'image/character/re_jsp_pangtong.jpg', - 'image/character/re_jushou.jpg', - 'image/character/re_kanze.jpg', - 'image/character/re_liaohua.jpg', - 'image/character/re_lidian.jpg', - 'image/character/re_lingtong.jpg', - 'image/character/re_liru.jpg', - 'image/character/re_liubei.jpg', - 'image/character/re_liubiao.jpg', - 'image/character/re_liuchen.jpg', - 'image/character/re_liufeng.jpg', - 'image/character/re_liushan.jpg', - 'image/character/re_liuzan.jpg', - 'image/character/re_lusu.jpg', - 'image/character/re_luxun.jpg', - 'image/character/re_lvbu.jpg', - 'image/character/re_lvmeng.jpg', - 'image/character/re_machao.jpg', - 'image/character/re_madai.jpg', - 'image/character/re_maliang.jpg', - 'image/character/re_manchong.jpg', - 'image/character/re_masu.jpg', - 'image/character/re_mazhong.jpg', - 'image/character/re_menghuo.jpg', - 'image/character/re_miheng.jpg', - 'image/character/re_nanhualaoxian.jpg', - 'image/character/re_niujin.jpg', - 'image/character/re_panfeng.jpg', - 'image/character/re_pangde.jpg', - 'image/character/re_pangdegong.jpg', - 'image/character/re_pangtong.jpg', - 'image/character/re_panshu.jpg', - 'image/character/re_panzhangmazhong.jpg', - 'image/character/re_quancong.jpg', - 'image/character/re_quyi.jpg', - 'image/character/re_simayi.jpg', - 'image/character/re_sp_taishici.jpg', - 'image/character/re_sp_zhugeliang.jpg', - 'image/character/re_sunben.jpg', - 'image/character/re_sunce.jpg', - 'image/character/re_sundeng.jpg', - 'image/character/re_sunjian.jpg', - 'image/character/re_sunluban.jpg', - 'image/character/re_sunluyu.jpg', - 'image/character/re_sunquan.jpg', - 'image/character/re_sunshangxiang.jpg', - 'image/character/re_sunxiu.jpg', - 'image/character/re_sunyi.jpg', - 'image/character/re_taishici.jpg', - 'image/character/re_taoqian.jpg', - 'image/character/re_wangyi.jpg', - 'image/character/re_wangyun.jpg', - 'image/character/re_weiwenzhugezhi.jpg', - 'image/character/re_weiyan.jpg', - 'image/character/re_wenpin.jpg', - 'image/character/re_wuguotai.jpg', - 'image/character/re_wuyi.jpg', - 'image/character/re_xiahoudun.jpg', - 'image/character/re_xiahoushi.jpg', - 'image/character/re_xiahouyuan.jpg', - 'image/character/re_xiaoqiao.jpg', - 'image/character/re_xinxianying.jpg', - 'image/character/re_xugong.jpg', - 'image/character/re_xuhuang.jpg', - 'image/character/re_xunchen.jpg', - 'image/character/re_xunyou.jpg', - 'image/character/re_xunyu.jpg', - 'image/character/re_xusheng.jpg', - 'image/character/re_xushu.jpg', - 'image/character/re_xuzhu.jpg', - 'image/character/re_yanwen.jpg', - 'image/character/re_yuanshao.jpg', - 'image/character/re_yuanshu.jpg', - 'image/character/re_yufan.jpg', - 'image/character/re_yuji.jpg', - 'image/character/re_yujin.jpg', - 'image/character/re_zhangbao.jpg', - 'image/character/re_zhangchunhua.jpg', - 'image/character/re_zhangfei.jpg', - 'image/character/re_zhanggong.jpg', - 'image/character/re_zhanghe.jpg', - 'image/character/re_zhangjiao.jpg', - 'image/character/re_zhangliang.jpg', - 'image/character/re_zhangliao.jpg', - 'image/character/re_zhangsong.jpg', - 'image/character/re_zhangyi.jpg', - 'image/character/re_zhangzhang.jpg', - 'image/character/re_zhaoyun.jpg', - 'image/character/re_zhenji.jpg', - 'image/character/re_zhonghui.jpg', - 'image/character/re_zhongyao.jpg', - 'image/character/re_zhoucang.jpg', - 'image/character/re_zhouyu.jpg', - 'image/character/re_zhugeliang.jpg', - 'image/character/re_zhuhuan.jpg', - 'image/character/re_zhuran.jpg', - 'image/character/re_zhurong.jpg', - 'image/character/re_zhuzhi.jpg', - 'image/character/re_zoushi.jpg', - 'image/character/re_zuoci.jpg', - 'image/character/ruanhui.jpg', - 'image/character/ruanji.jpg', - 'image/character/ruanyu.jpg', - 'image/character/ruiji.jpg', - 'image/character/sb_caocao.jpg', - 'image/character/sb_caopi.jpg', - 'image/character/sb_caoren.jpg', - 'image/character/sb_chengong.jpg', - 'image/character/sb_daqiao.jpg', - 'image/character/sb_diaochan.jpg', - 'image/character/sb_fazheng.jpg', - 'image/character/sb_ganning.jpg', - 'image/character/sb_guanyu.jpg', - 'image/character/sb_huanggai.jpg', - 'image/character/sb_huangyueying.jpg', - 'image/character/sb_huangzhong.jpg', - 'image/character/sb_huaxiong.jpg', - 'image/character/sb_jiangwei.jpg', - 'image/character/sb_liubei.jpg', - 'image/character/sb_liubiao.jpg', - 'image/character/sb_lvmeng.jpg', - 'image/character/sb_machao.jpg', - 'image/character/sb_menghuo.jpg', - 'image/character/sb_pangtong.jpg', - 'image/character/sb_sp_zhugeliang.jpg', - 'image/character/sb_sunce.jpg', - 'image/character/sb_sunquan.jpg', - 'image/character/sb_sunshangxiang.jpg', - 'image/character/sb_xiahoushi.jpg', - 'image/character/sb_xiaoqiao.jpg', - 'image/character/sb_xuhuang.jpg', - 'image/character/sb_yl_luzhi.jpg', - 'image/character/sb_yuanshao.jpg', - 'image/character/sb_yujin.jpg', - 'image/character/sb_zhangfei.jpg', - 'image/character/sb_zhanghe.jpg', - 'image/character/sb_zhangjiao.jpg', - 'image/character/sb_zhaoyun.jpg', - 'image/character/sb_zhenji.jpg', - 'image/character/sb_zhouyu.jpg', - 'image/character/sb_zhugeliang.jpg', - 'image/character/sb_zhurong.jpg', - 'image/character/scs_bilan.jpg', - 'image/character/scs_bilan_dead.jpg', - 'image/character/scs_duangui.jpg', - 'image/character/scs_duangui_dead.jpg', - 'image/character/scs_gaowang.jpg', - 'image/character/scs_gaowang_dead.jpg', - 'image/character/scs_guosheng.jpg', - 'image/character/scs_guosheng_dead.jpg', - 'image/character/scs_hankui.jpg', - 'image/character/scs_hankui_dead.jpg', - 'image/character/scs_lisong.jpg', - 'image/character/scs_lisong_dead.jpg', - 'image/character/scs_sunzhang.jpg', - 'image/character/scs_sunzhang_dead.jpg', - 'image/character/scs_xiayun.jpg', - 'image/character/scs_xiayun_dead.jpg', - 'image/character/scs_zhangrang.jpg', - 'image/character/scs_zhangrang_dead.jpg', - 'image/character/scs_zhaozhong.jpg', - 'image/character/scs_zhaozhong_dead.jpg', - 'image/character/shamoke.jpg', - 'image/character/shen_caocao.jpg', - 'image/character/shen_caopi.jpg', - 'image/character/shen_dengai.jpg', - 'image/character/shen_dianwei.jpg', - 'image/character/shen_diaochan.jpg', - 'image/character/shen_ganning.jpg', - 'image/character/shen_guanyu.jpg', - 'image/character/shen_guojia.jpg', - 'image/character/shen_huatuo.jpg', - 'image/character/shen_jiangwei.jpg', - 'image/character/shen_jiaxu.jpg', - 'image/character/shen_liubei.jpg', - 'image/character/shen_luxun.jpg', - 'image/character/shen_lvbu.jpg', - 'image/character/shen_lvmeng.jpg', - 'image/character/shen_machao.jpg', - 'image/character/shen_simayi.jpg', - 'image/character/shen_sunce.jpg', - 'image/character/shen_sunquan.jpg', - 'image/character/shen_taishici.jpg', - 'image/character/shen_xunyu.jpg', - 'image/character/shen_xuzhu.jpg', - 'image/character/shen_zhangfei.jpg', - 'image/character/shen_zhangjiao.jpg', - 'image/character/shen_zhangliao.jpg', - 'image/character/shen_zhaoyun.jpg', - 'image/character/shen_zhenji.jpg', - 'image/character/shen_zhouyu.jpg', - 'image/character/shen_zhugeliang.jpg', - 'image/character/shenpei.jpg', - 'image/character/shibao.jpg', - 'image/character/shibing1.jpg', - 'image/character/shibing2.jpg', - 'image/character/shichangshi.jpg', - 'image/character/shichangshi_dead.jpg', - 'image/character/shixie.jpg', - 'image/character/shiyi.jpg', - 'image/character/simafu.jpg', - 'image/character/simahui.jpg', - 'image/character/simalang.jpg', - 'image/character/simashi.jpg', - 'image/character/simayi.jpg', - 'image/character/simazhao.jpg', - 'image/character/simazhou.jpg', - 'image/character/sp_bianfuren.jpg', - 'image/character/sp_caiwenji.jpg', - 'image/character/sp_caoren.jpg', - 'image/character/sp_caosong.jpg', - 'image/character/sp_chendong.jpg', - 'image/character/sp_chenzhen.jpg', - 'image/character/sp_cuiyan.jpg', - 'image/character/sp_daqiao.jpg', - 'image/character/sp_diaochan.jpg', - 'image/character/sp_dongzhuo.jpg', - 'image/character/sp_duyu.jpg', - 'image/character/sp_fuhuanghou.jpg', - 'image/character/sp_fuwan.jpg', - 'image/character/sp_ganning.jpg', - 'image/character/sp_gaolan.jpg', - 'image/character/sp_gongsunzan.jpg', - 'image/character/sp_huaman.jpg', - 'image/character/sp_huangfusong.jpg', - 'image/character/sp_huaxin.jpg', - 'image/character/sp_jianggan.jpg', - 'image/character/sp_jiangqing.jpg', - 'image/character/sp_jiangwan.jpg', - 'image/character/sp_jiangwei.jpg', - 'image/character/sp_jiaxu.jpg', - 'image/character/sp_jiben.jpg', - 'image/character/sp_key_kanade.jpg', - 'image/character/sp_key_yuri.jpg', - 'image/character/sp_kongrong.jpg', - 'image/character/sp_liubei.jpg', - 'image/character/sp_liuqi.jpg', - 'image/character/sp_liuxie.jpg', - 'image/character/sp_lvfan.jpg', - 'image/character/sp_lvmeng.jpg', - 'image/character/sp_machao.jpg', - 'image/character/sp_maojie.jpg', - 'image/character/sp_menghuo.jpg', - 'image/character/sp_mifangfushiren.jpg', - 'image/character/sp_mifuren.jpg', - 'image/character/sp_mushun.jpg', - 'image/character/sp_ol_zhanghe.jpg', - 'image/character/sp_pangde.jpg', - 'image/character/sp_pangtong.jpg', - 'image/character/sp_pengyang.jpg', - 'image/character/sp_shenpei.jpg', - 'image/character/sp_simazhao.jpg', - 'image/character/sp_sufei.jpg', - 'image/character/sp_sunshangxiang.jpg', - 'image/character/sp_sunshao.jpg', - 'image/character/sp_taishici.jpg', - 'image/character/sp_wangcan.jpg', - 'image/character/sp_wangshuang.jpg', - 'image/character/sp_wangyuanji.jpg', - 'image/character/sp_xiahoudun.jpg', - 'image/character/sp_xiahoushi.jpg', - 'image/character/sp_xinpi.jpg', - 'image/character/sp_xinxianying.jpg', - 'image/character/sp_xujing.jpg', - 'image/character/sp_xunchen.jpg', - 'image/character/sp_xuyou.jpg', - 'image/character/sp_yanghu.jpg', - 'image/character/sp_yangwan.jpg', - 'image/character/sp_zhangchangpu.jpg', - 'image/character/sp_zhangfei.jpg', - 'image/character/sp_zhanghe.jpg', - 'image/character/sp_zhangjiao.jpg', - 'image/character/sp_zhangliao.jpg', - 'image/character/sp_zhangwen.jpg', - 'image/character/sp_zhaoyun.jpg', - 'image/character/sp_zhugeliang.jpg', - 'image/character/sp_zhujun.jpg', - 'image/character/sp_zongyu.jpg', - 'image/character/star_caoren.jpg', - 'image/character/star_dongzhuo.jpg', - 'image/character/star_yuanshao.jpg', - 'image/character/star_yuanshu.jpg', - 'image/character/star_zhangchunhua.jpg', - 'image/character/std_panfeng.jpg', - 'image/character/sunce.jpg', - 'image/character/sunchen.jpg', - 'image/character/sundeng.jpg', - 'image/character/sunhanhua.jpg', - 'image/character/sunhao.jpg', - 'image/character/sunhong.jpg', - 'image/character/sunhuan.jpg', - 'image/character/sunjian.jpg', - 'image/character/sunlang.jpg', - 'image/character/sunli.jpg', - 'image/character/sunliang.jpg', - 'image/character/sunlingluan.jpg', - 'image/character/sunluban.jpg', - 'image/character/sunluyu.jpg', - 'image/character/sunqian.jpg', - 'image/character/sunquan.jpg', - 'image/character/sunru.jpg', - 'image/character/sunshangxiang.jpg', - 'image/character/sunshao.jpg', - 'image/character/sunwukong.jpg', - 'image/character/sunxiu.jpg', - 'image/character/sunyang.jpg', - 'image/character/sunyi.jpg', - 'image/character/sunyu.jpg', - 'image/character/sunziliufang.jpg', - 'image/character/swd_anka.jpg', - 'image/character/swd_chenfu.jpg', - 'image/character/swd_chengyaojin.jpg', - 'image/character/swd_chenjingchou.jpg', - 'image/character/swd_cheyun.jpg', - 'image/character/swd_chunyuheng.jpg', - 'image/character/swd_duanmeng.jpg', - 'image/character/swd_duguningke.jpg', - 'image/character/swd_duopeng.jpg', - 'image/character/swd_fengtianling.jpg', - 'image/character/swd_fengyu.jpg', - 'image/character/swd_fu.jpg', - 'image/character/swd_fuyan.jpg', - 'image/character/swd_guyue.jpg', - 'image/character/swd_haidapang.jpg', - 'image/character/swd_hanlong.jpg', - 'image/character/swd_hanluo.jpg', - 'image/character/swd_hengai.jpg', - 'image/character/swd_huanglei.jpg', - 'image/character/swd_huanyuanzhi.jpg', - 'image/character/swd_huiyan.jpg', - 'image/character/swd_hupo.jpg', - 'image/character/swd_huyue.jpg', - 'image/character/swd_huzhongxian.jpg', - 'image/character/swd_jialanduo.jpg', - 'image/character/swd_jiangwu.jpg', - 'image/character/swd_jiangziya.jpg', - 'image/character/swd_jiliang.jpg', - 'image/character/swd_jipeng.jpg', - 'image/character/swd_jiting.jpg', - 'image/character/swd_jiuyou.jpg', - 'image/character/swd_kama.jpg', - 'image/character/swd_kangnalishi.jpg', - 'image/character/swd_kendi.jpg', - 'image/character/swd_lanmoshen.jpg', - 'image/character/swd_lanyin.jpg', - 'image/character/swd_lilian.jpg', - 'image/character/swd_linyue.jpg', - 'image/character/swd_luchengxuan.jpg', - 'image/character/swd_maixing.jpg', - 'image/character/swd_miles.jpg', - 'image/character/swd_moye.jpg', - 'image/character/swd_murongshi.jpg', - 'image/character/swd_muyue.jpg', - 'image/character/swd_muyun.jpg', - 'image/character/swd_nicole.jpg', - 'image/character/swd_qi.jpg', - 'image/character/swd_qiner.jpg', - 'image/character/swd_qinshubao.jpg', - 'image/character/swd_quxian.jpg', - 'image/character/swd_rongshuang.jpg', - 'image/character/swd_septem.jpg', - 'image/character/swd_shangzhang.jpg', - 'image/character/swd_shanxiaoxiao.jpg', - 'image/character/swd_shaowei.jpg', - 'image/character/swd_shuijing.jpg', - 'image/character/swd_shuwaner.jpg', - 'image/character/swd_sikongyu.jpg', - 'image/character/swd_situqiang.jpg', - 'image/character/swd_tuobayuer.jpg', - 'image/character/swd_tuwei.jpg', - 'image/character/swd_wangsiyue.jpg', - 'image/character/swd_weida.jpg', - 'image/character/swd_wushi.jpg', - 'image/character/swd_xiaohuanglong.jpg', - 'image/character/swd_xiarou.jpg', - 'image/character/swd_xiyan.jpg', - 'image/character/swd_xuanyuanjiantong.jpg', - 'image/character/swd_xuanyuanjianxian.jpg', - 'image/character/swd_yeyaxi.jpg', - 'image/character/swd_youzhao.jpg', - 'image/character/swd_yuchiyanhong.jpg', - 'image/character/swd_yuli.jpg', - 'image/character/swd_yunhu.jpg', - 'image/character/swd_yuwentuo.jpg', - 'image/character/swd_yuxiaoxue.jpg', - 'image/character/swd_zhanggao.jpg', - 'image/character/swd_zhaoyun.jpg', - 'image/character/swd_zhiyin.jpg', - 'image/character/swd_zhuoshanzhu.jpg', - 'image/character/swd_zidashu.jpg', - 'image/character/swd_ziqiao.jpg', - 'image/character/tadun.jpg', - 'image/character/taishici.jpg', - 'image/character/tangji.jpg', - 'image/character/tangzi.jpg', - 'image/character/taoqian.jpg', - 'image/character/taoshen.jpg', - 'image/character/tengfanglan.jpg', - 'image/character/tenggongzhu.jpg', - 'image/character/tengyin.jpg', - 'image/character/tianchou.jpg', - 'image/character/tianfeng.jpg', - 'image/character/tianshangyi.jpg', - 'image/character/tianyu.jpg', - 'image/character/tongyuan.jpg', - 'image/character/tw_baoxin.jpg', - 'image/character/tw_beimihu.jpg', - 'image/character/tw_bianfuren.jpg', - 'image/character/tw_bingyuan.jpg', - 'image/character/tw_caoang.jpg', - 'image/character/tw_caocao.jpg', - 'image/character/tw_caohong.jpg', - 'image/character/tw_caoxiu.jpg', - 'image/character/tw_caozhao.jpg', - 'image/character/tw_chendong.jpg', - 'image/character/tw_chengpu.jpg', - 'image/character/tw_chenzhen.jpg', - 'image/character/tw_daxiaoqiao.jpg', - 'image/character/tw_dengzhi.jpg', - 'image/character/tw_dingfeng.jpg', - 'image/character/tw_dongzhao.jpg', - 'image/character/tw_fanchou.jpg', - 'image/character/tw_feiyi.jpg', - 'image/character/tw_fengxí.jpg', - 'image/character/tw_furong.jpg', - 'image/character/tw_fuwan.jpg', - 'image/character/tw_gexuan.jpg', - 'image/character/tw_gongsunfan.jpg', - 'image/character/tw_guanqiujian.jpg', - 'image/character/tw_guohuai.jpg', - 'image/character/tw_guyong.jpg', - 'image/character/tw_handang.jpg', - 'image/character/tw_haomeng.jpg', - 'image/character/tw_hejin.jpg', - 'image/character/tw_hucheer.jpg', - 'image/character/tw_huchuquan.jpg', - 'image/character/tw_huojun.jpg', - 'image/character/tw_jiangji.jpg', - 'image/character/tw_jiangqing.jpg', - 'image/character/tw_jianshuo.jpg', - 'image/character/tw_jiling.jpg', - 'image/character/tw_liufuren.jpg', - 'image/character/tw_liuhong.jpg', - 'image/character/tw_liuzhang.jpg', - 'image/character/tw_liwei.jpg', - 'image/character/tw_madai.jpg', - 'image/character/tw_maliang.jpg', - 'image/character/tw_mateng.jpg', - 'image/character/tw_mayunlu.jpg', - 'image/character/tw_menghuo.jpg', - 'image/character/tw_niufudongxie.jpg', - 'image/character/tw_niujin.jpg', - 'image/character/tw_ol_sunjian.jpg', - 'image/character/tw_puyangxing.jpg', - 'image/character/tw_qiaogong.jpg', - 'image/character/tw_qiaorui.jpg', - 'image/character/tw_re_caohong.jpg', - 'image/character/tw_re_fazheng.jpg', - 'image/character/tw_shen_guanyu.jpg', - 'image/character/tw_shen_lvmeng.jpg', - 'image/character/tw_sunyi.jpg', - 'image/character/tw_tianyu.jpg', - 'image/character/tw_wangcan.jpg', - 'image/character/tw_wangchang.jpg', - 'image/character/tw_wangling.jpg', - 'image/character/tw_weixu.jpg', - 'image/character/tw_wujing.jpg', - 'image/character/tw_xiahouba.jpg', - 'image/character/tw_xiahouen.jpg', - 'image/character/tw_xiahoushang.jpg', - 'image/character/tw_xuezong.jpg', - 'image/character/tw_xujing.jpg', - 'image/character/tw_xunchen.jpg', - 'image/character/tw_yangang.jpg', - 'image/character/tw_yangyi.jpg', - 'image/character/tw_yanxiang.jpg', - 'image/character/tw_yl_luzhi.jpg', - 'image/character/tw_yufuluo.jpg', - 'image/character/tw_yujin.jpg', - 'image/character/tw_zangba.jpg', - 'image/character/tw_zhangfei.jpg', - 'image/character/tw_zhanghong.jpg', - 'image/character/tw_zhangji.jpg', - 'image/character/tw_zhangmancheng.jpg', - 'image/character/tw_zhangnan.jpg', - 'image/character/tw_zhangning.jpg', - 'image/character/tw_zhangzhao.jpg', - 'image/character/tw_zhaoxiang.jpg', - 'image/character/tw_zhouchu.jpg', - 'image/character/tw_zhugeguo.jpg', - 'image/character/tw_zongyu.jpg', - 'image/character/tw_zumao.jpg', - 'image/character/vtb_xiaojiu.jpg', - 'image/character/vtb_xiaole.jpg', - 'image/character/vtb_xiaosha.jpg', - 'image/character/vtb_xiaoshan.jpg', - 'image/character/vtb_xiaotao.jpg', - 'image/character/wangcan.jpg', - 'image/character/wangfuzhaolei.jpg', - 'image/character/wangguan.jpg', - 'image/character/wangji.jpg', - 'image/character/wangjun.jpg', - 'image/character/wanglang.jpg', - 'image/character/wanglie.jpg', - 'image/character/wangling.jpg', - 'image/character/wangping.jpg', - 'image/character/wangrong.jpg', - 'image/character/wangshuang.jpg', - 'image/character/wangtao.jpg', - 'image/character/wangwei.jpg', - 'image/character/wangxiang.jpg', - 'image/character/wangyan.jpg', - 'image/character/wangyi.jpg', - 'image/character/wangyuanji.jpg', - 'image/character/wangyue.jpg', - 'image/character/wangyun.jpg', - 'image/character/wanniangongzhu.jpg', - 'image/character/weiguan.jpg', - 'image/character/weiwenzhugezhi.jpg', - 'image/character/weiyan.jpg', - 'image/character/weizi.jpg', - 'image/character/wenpin.jpg', - 'image/character/wenqin.jpg', - 'image/character/wenyang.jpg', - 'image/character/wolongfengchu.jpg', - 'image/character/wu_luxun.jpg', - 'image/character/wu_zhugeliang.jpg', - 'image/character/wu_zhutiexiong.jpg', - 'image/character/wuanguo.jpg', - 'image/character/wuban.jpg', - 'image/character/wufan.jpg', - 'image/character/wuguotai.jpg', - 'image/character/wujing.jpg', - 'image/character/wulan.jpg', - 'image/character/wutugu.jpg', - 'image/character/wuxian.jpg', - 'image/character/wuyan.jpg', - 'image/character/wuyi.jpg', - 'image/character/xf_huangquan.jpg', - 'image/character/xf_sufei.jpg', - 'image/character/xf_tangzi.jpg', - 'image/character/xf_yiji.jpg', - 'image/character/xia_dianwei.jpg', - 'image/character/xia_liubei.jpg', - 'image/character/xia_liyàn.jpg', - 'image/character/xia_lusu.jpg', - 'image/character/xia_tongyuan.jpg', - 'image/character/xia_wangyue.jpg', - 'image/character/xia_xiahoudun.jpg', - 'image/character/xia_xiahousone.jpg', - 'image/character/xia_xiahouzie.jpg', - 'image/character/xia_xushu.jpg', - 'image/character/xia_zhangwei.jpg', - 'image/character/xia_zhaoe.jpg', - 'image/character/xiahouba.jpg', - 'image/character/xiahoudun.jpg', - 'image/character/xiahoujie.jpg', - 'image/character/xiahoulingnv.jpg', - 'image/character/xiahoumao.jpg', - 'image/character/xiahoushi.jpg', - 'image/character/xiahouxuan.jpg', - 'image/character/xiahouyuan.jpg', - 'image/character/xiangchong.jpg', - 'image/character/xianglang.jpg', - 'image/character/xiaoqiao.jpg', - 'image/character/xiaoyuehankehan.jpg', - 'image/character/xielingyu.jpg', - 'image/character/xin_baosanniang.jpg', - 'image/character/xin_caifuren.jpg', - 'image/character/xin_caoxiu.jpg', - 'image/character/xin_caozhang.jpg', - 'image/character/xin_caozhen.jpg', - 'image/character/xin_chengpu.jpg', - 'image/character/xin_fazheng.jpg', - 'image/character/xin_fuhuanghou.jpg', - 'image/character/xin_gaoshun.jpg', - 'image/character/xin_gongsunzan.jpg', - 'image/character/xin_guohuai.jpg', - 'image/character/xin_guozhao.jpg', - 'image/character/xin_guyong.jpg', - 'image/character/xin_handang.jpg', - 'image/character/xin_hansui.jpg', - 'image/character/xin_jianyong.jpg', - 'image/character/xin_jushou.jpg', - 'image/character/xin_liaohua.jpg', - 'image/character/xin_lingtong.jpg', - 'image/character/xin_liru.jpg', - 'image/character/xin_liubiao.jpg', - 'image/character/xin_mamidi.jpg', - 'image/character/xin_masu.jpg', - 'image/character/xin_panzhangmazhong.jpg', - 'image/character/xin_quancong.jpg', - 'image/character/xin_sunliang.jpg', - 'image/character/xin_sunluban.jpg', - 'image/character/xin_sunxiu.jpg', - 'image/character/xin_wuguotai.jpg', - 'image/character/xin_wuyi.jpg', - 'image/character/xin_xiahoudun.jpg', - 'image/character/xin_xusheng.jpg', - 'image/character/xin_xushu.jpg', - 'image/character/xin_yuanshao.jpg', - 'image/character/xin_yufan.jpg', - 'image/character/xin_yuji.jpg', - 'image/character/xin_yujin.jpg', - 'image/character/xin_zhangfei.jpg', - 'image/character/xin_zhangyi.jpg', - 'image/character/xin_zhonghui.jpg', - 'image/character/xin_zhoucang.jpg', - 'image/character/xin_zhoutai.jpg', - 'image/character/xin_zhuhuan.jpg', - 'image/character/xin_zhuran.jpg', - 'image/character/xin_zhuzhi.jpg', - 'image/character/xinchang.jpg', - 'image/character/xingdaorong.jpg', - 'image/character/xinpi.jpg', - 'image/character/xinping.jpg', - 'image/character/xinxianying.jpg', - 'image/character/xizheng.jpg', - 'image/character/xizhicai.jpg', - 'image/character/xuangongzhu.jpg', - 'image/character/xuelingyun.jpg', - 'image/character/xuezong.jpg', - 'image/character/xugong.jpg', - 'image/character/xuhuang.jpg', - 'image/character/xujing.jpg', - 'image/character/xunchen.jpg', - 'image/character/xunyou.jpg', - 'image/character/xunyu.jpg', - 'image/character/xurong.jpg', - 'image/character/xushao.jpg', - 'image/character/xusheng.jpg', - 'image/character/xushi.jpg', - 'image/character/xushu.jpg', - 'image/character/xuyou.jpg', - 'image/character/xuzhu.jpg', - 'image/character/yanbaihu.jpg', - 'image/character/yanfuren.jpg', - 'image/character/yangbiao.jpg', - 'image/character/yangfu.jpg', - 'image/character/yanghong.jpg', - 'image/character/yanghuiyu.jpg', - 'image/character/yangwan.jpg', - 'image/character/yangxiu.jpg', - 'image/character/yangyan.jpg', - 'image/character/yangyi.jpg', - 'image/character/yangzhi.jpg', - 'image/character/yanjun.jpg', - 'image/character/yanpu.jpg', - 'image/character/yanrou.jpg', - 'image/character/yanwen.jpg', - 'image/character/yanxiang.jpg', - 'image/character/yanyan.jpg', - 'image/character/yeshiwen.jpg', - 'image/character/yinfuren.jpg', - 'image/character/yj_caoang.jpg', - 'image/character/yj_caocao.jpg', - 'image/character/yj_caohong.jpg', - 'image/character/yj_dongzhuo.jpg', - 'image/character/yj_ganning.jpg', - 'image/character/yj_huangzhong.jpg', - 'image/character/yj_jiaxu.jpg', - 'image/character/yj_jushou.jpg', - 'image/character/yj_liru.jpg', - 'image/character/yj_qiaozhou.jpg', - 'image/character/yj_sufei.jpg', - 'image/character/yj_weiyan.jpg', - 'image/character/yj_xuhuang.jpg', - 'image/character/yj_xuyou.jpg', - 'image/character/yj_zhangfei.jpg', - 'image/character/yj_zhanghe.jpg', - 'image/character/yj_zhangliao.jpg', - 'image/character/yj_zhenji.jpg', - 'image/character/yj_zhoubuyi.jpg', - 'image/character/yl_luzhi.jpg', - 'image/character/yl_yuanshu.jpg', - 'image/character/yongjian_ganning.jpg', - 'image/character/yuanhuan.jpg', - 'image/character/yuanji.jpg', - 'image/character/yuanshu.jpg', - 'image/character/yuantanyuanshang.jpg', - 'image/character/yuantanyuanxiyuanshang.jpg', - 'image/character/yue_caiwenji.jpg', - 'image/character/yue_daqiao.jpg', - 'image/character/yue_xiaoqiao.jpg', - 'image/character/yue_zhoufei.jpg', - 'image/character/yuechen.jpg', - 'image/character/yuejin.jpg', - 'image/character/yuejiu.jpg', - 'image/character/yufan.jpg', - 'image/character/yuji.jpg', - 'image/character/yujin.jpg', - 'image/character/yujin_yujin.jpg', - 'image/character/yxs_aijiyanhou.jpg', - 'image/character/yxs_baosi.jpg', - 'image/character/yxs_bole.jpg', - 'image/character/yxs_caocao.jpg', - 'image/character/yxs_chengjisihan.jpg', - 'image/character/yxs_chengyaojin.jpg', - 'image/character/yxs_diaochan.jpg', - 'image/character/yxs_direnjie.jpg', - 'image/character/yxs_fuermosi.jpg', - 'image/character/yxs_goujian.jpg', - 'image/character/yxs_guiguzi.jpg', - 'image/character/yxs_handingdun.jpg', - 'image/character/yxs_huamulan.jpg', - 'image/character/yxs_jinke.jpg', - 'image/character/yxs_kaisa.jpg', - 'image/character/yxs_lanlinwang.jpg', - 'image/character/yxs_libai.jpg', - 'image/character/yxs_lishimin.jpg', - 'image/character/yxs_luban.jpg', - 'image/character/yxs_luobinhan.jpg', - 'image/character/yxs_luocheng.jpg', - 'image/character/yxs_luzhishen.jpg', - 'image/character/yxs_lvzhi.jpg', - 'image/character/yxs_meixi.jpg', - 'image/character/yxs_mingchenghuanghou.jpg', - 'image/character/yxs_mozi.jpg', - 'image/character/yxs_nandinggeer.jpg', - 'image/character/yxs_napolun.jpg', - 'image/character/yxs_qinqiong.jpg', - 'image/character/yxs_sunwu.jpg', - 'image/character/yxs_tangbohu.jpg', - 'image/character/yxs_wangzhaojun.jpg', - 'image/character/yxs_weizhongxian.jpg', - 'image/character/yxs_wuzetian.jpg', - 'image/character/yxs_xiangyu.jpg', - 'image/character/yxs_xiaoqiao.jpg', - 'image/character/yxs_yangguang.jpg', - 'image/character/yxs_yangyuhuan.jpg', - 'image/character/yxs_yingzheng.jpg', - 'image/character/yxs_yuefei.jpg', - 'image/character/yxs_yujix.jpg', - 'image/character/yxs_zhangsanfeng.jpg', - 'image/character/yxs_zhaoyong.jpg', - 'image/character/yxs_zhuyuanzhang.jpg', - 'image/character/zangba.jpg', - 'image/character/zerong.jpg', - 'image/character/zhangbao.jpg', - 'image/character/zhangchangpu.jpg', - 'image/character/zhangchu.jpg', - 'image/character/zhangchunhua.jpg', - 'image/character/zhangfei.jpg', - 'image/character/zhangfen.jpg', - 'image/character/zhanggong.jpg', - 'image/character/zhanghe.jpg', - 'image/character/zhangheng.jpg', - 'image/character/zhanghu.jpg', - 'image/character/zhanghua.jpg', - 'image/character/zhanghuyuechen.jpg', - 'image/character/zhangji.jpg', - 'image/character/zhangjiao.jpg', - 'image/character/zhangjinyun.jpg', - 'image/character/zhangkai.jpg', - 'image/character/zhangliang.jpg', - 'image/character/zhangliao.jpg', - 'image/character/zhangling.jpg', - 'image/character/zhanglu.jpg', - 'image/character/zhangmiao.jpg', - 'image/character/zhangning.jpg', - 'image/character/zhangqiying.jpg', - 'image/character/zhangrang.jpg', - 'image/character/zhangren.jpg', - 'image/character/zhangshiping.jpg', - 'image/character/zhangsong.jpg', - 'image/character/zhangwen.jpg', - 'image/character/zhangxingcai.jpg', - 'image/character/zhangxiu.jpg', - 'image/character/zhangxuan.jpg', - 'image/character/zhangxun.jpg', - 'image/character/zhangyan.jpg', - 'image/character/zhangyao.jpg', - 'image/character/zhangyi.jpg', - 'image/character/zhangyì.jpg', - 'image/character/zhangzhang.jpg', - 'image/character/zhangzhi.jpg', - 'image/character/zhangzhongjing.jpg', - 'image/character/zhaoang.jpg', - 'image/character/zhaotongzhaoguang.jpg', - 'image/character/zhaoxiang.jpg', - 'image/character/zhaoyan.jpg', - 'image/character/zhaoyǎn.jpg', - 'image/character/zhaoyun.jpg', - 'image/character/zhaozhi.jpg', - 'image/character/zhaozhong.jpg', - 'image/character/zhenghun.jpg', - 'image/character/zhengxuan.jpg', - 'image/character/zhenji.jpg', - 'image/character/zhonghui.jpg', - 'image/character/zhongyan.jpg', - 'image/character/zhongyao.jpg', - 'image/character/zhoubuyi.jpg', - 'image/character/zhoucang.jpg', - 'image/character/zhouchu.jpg', - 'image/character/zhoufang.jpg', - 'image/character/zhoufei.jpg', - 'image/character/zhouqun.jpg', - 'image/character/zhoushan.jpg', - 'image/character/zhoutai.jpg', - 'image/character/zhouyi.jpg', - 'image/character/zhouyu.jpg', - 'image/character/zhugedan.jpg', - 'image/character/zhugeguo.jpg', - 'image/character/zhugejin.jpg', - 'image/character/zhugeke.jpg', - 'image/character/zhugeliang.jpg', - 'image/character/zhugemengxue.jpg', - 'image/character/zhugeruoxue.jpg', - 'image/character/zhugeshang.jpg', - 'image/character/zhugezhan.jpg', - 'image/character/zhuhuan.jpg', - 'image/character/zhujianping.jpg', - 'image/character/zhujun.jpg', - 'image/character/zhuling.jpg', - 'image/character/zhuran.jpg', - 'image/character/zhurong.jpg', - 'image/character/zhutiexiong.jpg', - 'image/character/zhuzhi.jpg', - 'image/character/zongyu.jpg', - 'image/character/zoushi.jpg', - 'image/character/zumao.jpg', - 'image/character/zuoci.jpg', - 'image/character/zuofen.jpg', - /*character image end*/ - - 'image/emotion/shibing_emotion/1.gif', - 'image/emotion/shibing_emotion/2.gif', - 'image/emotion/shibing_emotion/3.gif', - 'image/emotion/shibing_emotion/4.gif', - 'image/emotion/shibing_emotion/5.gif', - 'image/emotion/shibing_emotion/6.gif', - 'image/emotion/shibing_emotion/7.gif', - 'image/emotion/shibing_emotion/8.gif', - 'image/emotion/shibing_emotion/9.gif', - 'image/emotion/shibing_emotion/10.gif', - 'image/emotion/shibing_emotion/11.gif', - 'image/emotion/shibing_emotion/12.gif', - 'image/emotion/shibing_emotion/13.gif', - 'image/emotion/shibing_emotion/14.gif', - 'image/emotion/shibing_emotion/15.gif', - 'image/emotion/guojia_emotion/1.gif', - 'image/emotion/guojia_emotion/2.gif', - 'image/emotion/guojia_emotion/3.gif', - 'image/emotion/guojia_emotion/4.gif', - 'image/emotion/guojia_emotion/5.gif', - 'image/emotion/guojia_emotion/6.gif', - 'image/emotion/guojia_emotion/7.gif', - 'image/emotion/guojia_emotion/8.gif', - 'image/emotion/guojia_emotion/9.gif', - 'image/emotion/guojia_emotion/10.gif', - 'image/emotion/guojia_emotion/11.gif', - 'image/emotion/guojia_emotion/12.gif', - 'image/emotion/guojia_emotion/13.gif', - 'image/emotion/guojia_emotion/14.gif', - 'image/emotion/guojia_emotion/15.gif', - 'image/emotion/guojia_emotion/16.gif', - 'image/emotion/guojia_emotion/17.gif', - 'image/emotion/guojia_emotion/18.gif', - 'image/emotion/guojia_emotion/19.gif', - 'image/emotion/guojia_emotion/20.gif', - 'image/emotion/zhenji_emotion/1.gif', - 'image/emotion/zhenji_emotion/2.gif', - 'image/emotion/zhenji_emotion/3.gif', - 'image/emotion/zhenji_emotion/4.gif', - 'image/emotion/zhenji_emotion/5.gif', - 'image/emotion/zhenji_emotion/6.gif', - 'image/emotion/zhenji_emotion/7.gif', - 'image/emotion/zhenji_emotion/8.gif', - 'image/emotion/zhenji_emotion/9.gif', - 'image/emotion/zhenji_emotion/10.gif', - 'image/emotion/zhenji_emotion/11.gif', - 'image/emotion/zhenji_emotion/12.gif', - 'image/emotion/zhenji_emotion/13.gif', - 'image/emotion/zhenji_emotion/14.gif', - 'image/emotion/zhenji_emotion/15.gif', - 'image/emotion/zhenji_emotion/16.gif', - 'image/emotion/zhenji_emotion/17.gif', - 'image/emotion/zhenji_emotion/18.gif', - 'image/emotion/zhenji_emotion/19.gif', - 'image/emotion/zhenji_emotion/20.gif', - 'image/emotion/xiaojiu_emotion/1.gif', - 'image/emotion/xiaojiu_emotion/2.gif', - 'image/emotion/xiaojiu_emotion/3.gif', - 'image/emotion/xiaojiu_emotion/4.gif', - 'image/emotion/xiaojiu_emotion/5.gif', - 'image/emotion/xiaojiu_emotion/6.gif', - 'image/emotion/xiaojiu_emotion/7.gif', - 'image/emotion/xiaojiu_emotion/8.gif', - 'image/emotion/xiaojiu_emotion/9.gif', - 'image/emotion/xiaojiu_emotion/10.gif', - 'image/emotion/xiaojiu_emotion/11.gif', - 'image/emotion/xiaojiu_emotion/12.gif', - 'image/emotion/xiaojiu_emotion/13.gif', - 'image/emotion/xiaojiu_emotion/14.gif', - 'image/emotion/xiaojiu_emotion/15.gif', - 'image/emotion/xiaojiu_emotion/16.gif', - 'image/emotion/xiaojiu_emotion/17.gif', - 'image/emotion/xiaojiu_emotion/18.gif', - 'image/emotion/xiaojiu_emotion/19.gif', - 'image/emotion/xiaojiu_emotion/20.gif', - 'image/emotion/xiaokuo_emotion/1.gif', - 'image/emotion/xiaokuo_emotion/2.gif', - 'image/emotion/xiaokuo_emotion/3.gif', - 'image/emotion/xiaokuo_emotion/4.gif', - 'image/emotion/xiaokuo_emotion/5.gif', - 'image/emotion/xiaokuo_emotion/6.gif', - 'image/emotion/xiaokuo_emotion/7.gif', - 'image/emotion/xiaokuo_emotion/8.gif', - 'image/emotion/xiaosha_emotion/1.gif', - 'image/emotion/xiaosha_emotion/2.gif', - 'image/emotion/xiaosha_emotion/3.gif', - 'image/emotion/xiaosha_emotion/4.gif', - 'image/emotion/xiaosha_emotion/5.gif', - 'image/emotion/xiaosha_emotion/6.gif', - 'image/emotion/xiaosha_emotion/7.gif', - 'image/emotion/xiaosha_emotion/8.gif', - 'image/emotion/xiaosha_emotion/9.gif', - 'image/emotion/xiaosha_emotion/10.gif', - 'image/emotion/xiaosha_emotion/11.gif', - 'image/emotion/xiaosha_emotion/12.gif', - 'image/emotion/xiaosha_emotion/13.gif', - 'image/emotion/xiaosha_emotion/14.gif', - 'image/emotion/xiaosha_emotion/15.gif', - 'image/emotion/xiaosha_emotion/16.gif', - 'image/emotion/xiaosha_emotion/17.gif', - 'image/emotion/xiaosha_emotion/18.gif', - 'image/emotion/xiaosha_emotion/19.gif', - 'image/emotion/xiaosha_emotion/20.gif', - 'image/emotion/xiaotao_emotion/1.gif', - 'image/emotion/xiaotao_emotion/2.gif', - 'image/emotion/xiaotao_emotion/3.gif', - 'image/emotion/xiaotao_emotion/4.gif', - 'image/emotion/xiaotao_emotion/5.gif', - 'image/emotion/xiaotao_emotion/6.gif', - 'image/emotion/xiaotao_emotion/7.gif', - 'image/emotion/xiaotao_emotion/8.gif', - 'image/emotion/xiaotao_emotion/9.gif', - 'image/emotion/xiaotao_emotion/10.gif', - 'image/emotion/xiaotao_emotion/11.gif', - 'image/emotion/xiaotao_emotion/12.gif', - 'image/emotion/xiaotao_emotion/13.gif', - 'image/emotion/xiaotao_emotion/14.gif', - 'image/emotion/xiaotao_emotion/15.gif', - 'image/emotion/xiaotao_emotion/16.gif', - 'image/emotion/xiaotao_emotion/17.gif', - 'image/emotion/xiaotao_emotion/18.gif', - 'image/emotion/xiaotao_emotion/19.gif', - 'image/emotion/xiaotao_emotion/20.gif', - 'image/emotion/xiaowu_emotion/1.gif', - 'image/emotion/xiaowu_emotion/2.gif', - 'image/emotion/xiaowu_emotion/3.gif', - 'image/emotion/xiaowu_emotion/4.gif', - 'image/emotion/xiaowu_emotion/5.gif', - 'image/emotion/xiaowu_emotion/6.gif', - 'image/emotion/xiaowu_emotion/7.gif', - 'image/emotion/xiaowu_emotion/8.gif', - 'image/emotion/xiaowu_emotion/9.gif', - 'image/emotion/xiaowu_emotion/10.gif', - 'image/emotion/xiaowu_emotion/11.gif', - 'image/emotion/xiaowu_emotion/12.gif', - 'image/emotion/xiaowu_emotion/13.gif', - 'image/emotion/xiaowu_emotion/14.gif', - 'image/emotion/throw_emotion/egg1.png', - 'image/emotion/throw_emotion/egg2.png', - 'image/emotion/throw_emotion/flower1.png', - 'image/emotion/throw_emotion/flower2.png', - 'image/emotion/throw_emotion/shoe1.png', - 'image/emotion/throw_emotion/shoe2.png', - 'image/emotion/throw_emotion/jiasuo1.png', - 'image/emotion/throw_emotion/jiasuo2.png', - 'image/emotion/throw_emotion/wine1.png', - 'image/emotion/throw_emotion/wine2.png', - 'image/emotion/throw_emotion/yuxisx1.png', - 'image/emotion/throw_emotion/yuxisx2.png', - - 'image/mode/boss/card/chixueqingfeng.png', - 'image/mode/boss/card/chiyanzhenhunqin.png', - 'image/mode/boss/card/guilongzhanyuedao.png', - 'image/mode/boss/card/guofengyupao.png', - 'image/mode/boss/card/honghuangzhili.png', - 'image/mode/boss/card/hongmianbaihuapao.png', - 'image/mode/boss/card/juechenjinge.png', - 'image/mode/boss/card/linglongshimandai.png', - 'image/mode/boss/card/qimenbagua.png', - 'image/mode/boss/card/sadouchengbing.png', - 'image/mode/boss/card/shufazijinguan.png', - 'image/mode/boss/card/wushuangfangtianji.png', - 'image/mode/boss/card/xiuluolianyuji.png', - 'image/mode/boss/card/xuwangzhimian.png', - 'image/mode/boss/card/yihuajiemu.png', - 'image/mode/boss/card/qicaishenlu.png', - 'image/mode/boss/card/longfenghemingjian.png', - 'image/mode/boss/card/boss_mengpohuihun.png', - 'image/mode/boss/card/gubuzifeng.png', - 'image/mode/boss/card/jinwuluorigong.png', - 'image/mode/boss/card/lingsheji.png', - 'image/mode/boss/card/shanrangzhaoshu.png', - 'image/mode/boss/card/xingtianpojunfu.png', - 'image/mode/boss/card/niaobaidaowenha.png', - - 'image/mode/boss/character/boss_baihu.jpg', - 'image/mode/boss/character/boss_baimangshilian.jpg', - 'image/mode/boss/character/boss_baiwuchang.jpg', - 'image/mode/boss/character/boss_bianchengwang.jpg', - 'image/mode/boss/character/boss_bifang.jpg', - 'image/mode/boss/character/boss_caiwenji.jpg', - 'image/mode/boss/character/boss_caocao.jpg', - 'image/mode/boss/character/boss_chi.jpg', - 'image/mode/boss/character/boss_chiyanshilian.jpg', - 'image/mode/boss/character/boss_chujiangwang.jpg', - 'image/mode/boss/character/boss_diaochan.jpg', - 'image/mode/boss/character/boss_dizangwang.jpg', - 'image/mode/boss/character/boss_dongzhuo.jpg', - 'image/mode/boss/character/boss_dushiwang.jpg', - 'image/mode/boss/character/boss_guojia.jpg', - 'image/mode/boss/character/boss_heiwuchang.jpg', - 'image/mode/boss/character/boss_huangyueying.jpg', - 'image/mode/boss/character/boss_huatuo.jpg', - 'image/mode/boss/character/boss_hundun.jpg', - 'image/mode/boss/character/boss_huoshenzhurong.jpg', - 'image/mode/boss/character/boss_jinshenrushou.jpg', - 'image/mode/boss/character/boss_liang.jpg', - 'image/mode/boss/character/boss_liubei.jpg', - 'image/mode/boss/character/boss_luocha.jpg', - 'image/mode/boss/character/boss_luxun.jpg', - 'image/mode/boss/character/boss_lvbu1.jpg', - 'image/mode/boss/character/boss_lvbu2.jpg', - 'image/mode/boss/character/boss_lvbu3.jpg', - 'image/mode/boss/character/boss_mamian.jpg', - 'image/mode/boss/character/boss_mengpo.jpg', - 'image/mode/boss/character/boss_mingxingzhu.jpg', - 'image/mode/boss/character/boss_mo.jpg', - 'image/mode/boss/character/boss_mushengoumang.jpg', - 'image/mode/boss/character/boss_nianshou.jpg', - 'image/mode/boss/character/boss_nianshou_baonu.jpg', - 'image/mode/boss/character/boss_nianshou_heti.jpg', - 'image/mode/boss/character/boss_nianshou_jingjue.jpg', - 'image/mode/boss/character/boss_nianshou_renxing.jpg', - 'image/mode/boss/character/boss_nianshou_ruizhi.jpg', - 'image/mode/boss/character/boss_niutou.jpg', - 'image/mode/boss/character/boss_pangtong.jpg', - 'image/mode/boss/character/boss_pingdengwang.jpg', - 'image/mode/boss/character/boss_qinglong.jpg', - 'image/mode/boss/character/boss_qingmushilian.jpg', - 'image/mode/boss/character/boss_qinguangwang.jpg', - 'image/mode/boss/character/boss_qiongqi.jpg', - 'image/mode/boss/character/boss_satan.jpg', - 'image/mode/boss/character/boss_shaohao.jpg', - 'image/mode/boss/character/boss_shuijing.jpg', - 'image/mode/boss/character/boss_shuishengonggong.jpg', - 'image/mode/boss/character/boss_shuishenxuanming.jpg', - 'image/mode/boss/character/boss_shujing.jpg', - 'image/mode/boss/character/boss_songdiwang.jpg', - 'image/mode/boss/character/boss_sunshangxiang.jpg', - 'image/mode/boss/character/boss_taihao.jpg', - 'image/mode/boss/character/boss_taishanwang.jpg', - 'image/mode/boss/character/boss_taotie.jpg', - 'image/mode/boss/character/boss_taowu.jpg', - 'image/mode/boss/character/boss_wang.jpg', - 'image/mode/boss/character/boss_wuguanwang.jpg', - 'image/mode/boss/character/boss_xiangliu.jpg', - 'image/mode/boss/character/boss_xuanlinshilian.jpg', - 'image/mode/boss/character/boss_xuanwu.jpg', - 'image/mode/boss/character/boss_yandi.jpg', - 'image/mode/boss/character/boss_yanling.jpg', - 'image/mode/boss/character/boss_yanluowang.jpg', - 'image/mode/boss/character/boss_yecha.jpg', - 'image/mode/boss/character/boss_yingzhao.jpg', - 'image/mode/boss/character/boss_yuji.jpg', - 'image/mode/boss/character/boss_zhangchunhua.jpg', - 'image/mode/boss/character/boss_zhangjiao.jpg', - 'image/mode/boss/character/boss_zhenji.jpg', - 'image/mode/boss/character/boss_zhouyu.jpg', - 'image/mode/boss/character/boss_zhuanlunwang.jpg', - 'image/mode/boss/character/boss_zhuanxu.jpg', - 'image/mode/boss/character/boss_zhugeliang.jpg', - 'image/mode/boss/character/boss_zhuoguiquxie.jpg', - 'image/mode/boss/character/boss_zhuque.jpg', - 'image/mode/boss/character/boss_zhuyan.jpg', - 'image/mode/boss/character/boss_zhuyin.jpg', - 'image/mode/boss/character/boss_zuoci.jpg', - - 'image/mode/chess/card/chess_chuzhang.png', - 'image/mode/chess/card/chess_shezhang.png', - 'image/mode/chess/character/chess_beimingjukun.jpg', - 'image/mode/chess/character/chess_caocao.jpg', - 'image/mode/chess/character/chess_diaochan.jpg', - 'image/mode/chess/character/chess_dongzhuo.jpg', - 'image/mode/chess/character/chess_huangzhong.jpg', - 'image/mode/chess/character/chess_huatuo.jpg', - 'image/mode/chess/character/chess_jinchidiao.jpg', - 'image/mode/chess/character/chess_sunshangxiang.jpg', - 'image/mode/chess/character/chess_taishici.jpg', - 'image/mode/chess/character/chess_wuzhaojinlong.jpg', - 'image/mode/chess/character/chess_xingtian.jpg', - 'image/mode/chess/character/chess_zhangliao.jpg', - 'image/mode/chess/character/leader_caocao.jpg', - 'image/mode/chess/character/leader_liubei.jpg', - 'image/mode/chess/character/leader_sunquan.jpg', - 'image/mode/chess/character/leader_yuri.jpg', - 'image/mode/chess/difficulty/leader_easy.jpg', - 'image/mode/chess/difficulty/leader_hard.jpg', - 'image/mode/chess/difficulty/leader_medium.jpg', - 'image/mode/stone/card/spell_ansezhadan.jpg', - 'image/mode/stone/card/spell_anyingkuangluan.jpg', - 'image/mode/stone/card/spell_anyinglieyan.jpg', - 'image/mode/stone/card/spell_anyingxingtai.jpg', - 'image/mode/stone/card/spell_anzhongpohuai.jpg', - 'image/mode/stone/card/spell_aoshufeidan.jpg', - 'image/mode/stone/card/spell_aoshuzhihui.jpg', - 'image/mode/stone/card/spell_baofengxue.jpg', - 'image/mode/stone/card/spell_beici.jpg', - 'image/mode/stone/card/spell_bianxingshu.jpg', - 'image/mode/stone/card/spell_bingdong.jpg', - 'image/mode/stone/card/spell_binghuan.jpg', - 'image/mode/stone/card/spell_canying.jpg', - 'image/mode/stone/card/spell_chazhuangshandian.jpg', - 'image/mode/stone/card/spell_chenmo.jpg', - 'image/mode/stone/card/spell_chirehuoba.jpg', - 'image/mode/stone/card/spell_chongfeng.jpg', - 'image/mode/stone/card/spell_cigu.jpg', - 'image/mode/stone/card/spell_cisha.jpg', - 'image/mode/stone/card/spell_conglinzhihun.jpg', - 'image/mode/stone/card/spell_daoshan.jpg', - 'image/mode/stone/card/spell_diyulieyan.jpg', - 'image/mode/stone/card/spell_dubiao.jpg', - 'image/mode/stone/card/spell_dunpaimengji.jpg', - 'image/mode/stone/card/spell_duochongsheji.jpg', - 'image/mode/stone/card/spell_emozhinu.jpg', - 'image/mode/stone/card/spell_emozhixin.jpg', - 'image/mode/stone/card/spell_enzeshu.jpg', - 'image/mode/stone/card/spell_fengnu.jpg', - 'image/mode/stone/card/spell_fengxian.jpg', - 'image/mode/stone/card/spell_fennu.jpg', - 'image/mode/stone/card/spell_fennuzhichui.jpg', - 'image/mode/stone/card/spell_fuchoudaji.jpg', - 'image/mode/stone/card/spell_fuchouzhinu.jpg', - 'image/mode/stone/card/spell_fugen.jpg', - 'image/mode/stone/card/spell_fushishu.jpg', - 'image/mode/stone/card/spell_guanmenfanggou.jpg', - 'image/mode/stone/card/spell_hanbingjian.jpg', - 'image/mode/stone/card/spell_hanbingpingzhang.jpg', - 'image/mode/stone/card/spell_heiandiyu.jpg', - 'image/mode/stone/card/spell_heianqiyue.jpg', - 'image/mode/stone/card/spell_hengsao.jpg', - 'image/mode/stone/card/spell_huoqiushu.jpg', - 'image/mode/stone/card/spell_huotigenxu.jpg', - 'image/mode/stone/card/spell_jianrenluanwu.jpg', - 'image/mode/stone/card/spell_jingshenkongzhi.jpg', - 'image/mode/stone/card/spell_jingxiang.jpg', - 'image/mode/stone/card/spell_jinyingduijue.jpg', - 'image/mode/stone/card/spell_jipao.jpg', - 'image/mode/stone/card/spell_juemingluandou.jpg', - 'image/mode/stone/card/spell_kongxinshu.jpg', - 'image/mode/stone/card/spell_kuaisusheji.jpg', - 'image/mode/stone/card/spell_kuaisuzhiliao.jpg', - 'image/mode/stone/card/spell_kuangbao.jpg', - 'image/mode/stone/card/spell_laojiuhuoba.jpg', - 'image/mode/stone/card/spell_lianhuanbaolie.jpg', - 'image/mode/stone/card/spell_lierenyinji.jpg', - 'image/mode/stone/card/spell_lieyanfengbao.jpg', - 'image/mode/stone/card/spell_liliangdaijia.jpg', - 'image/mode/stone/card/spell_liliangzhufu.jpg', - 'image/mode/stone/card/spell_linghunhongxi.jpg', - 'image/mode/stone/card/spell_maizang.jpg', - 'image/mode/stone/card/spell_mengun.jpg', - 'image/mode/stone/card/spell_modaoyou.jpg', - 'image/mode/stone/card/spell_morizaihuo.jpg', - 'image/mode/stone/card/spell_naluzhiguang.jpg', - 'image/mode/stone/card/spell_niuquxukong.jpg', - 'image/mode/stone/card/spell_nuhuozhongshao.jpg', - 'image/mode/stone/card/spell_nuxi.jpg', - 'image/mode/stone/card/spell_piaoqie.jpg', - 'image/mode/stone/card/spell_qiangfengsheji.jpg', - 'image/mode/stone/card/spell_rongyanbaolie.jpg', - 'image/mode/stone/card/spell_sanghunzhao.jpg', - 'image/mode/stone/card/spell_shalumingling.jpg', - 'image/mode/stone/card/spell_shandianfengbao.jpg', - 'image/mode/stone/card/spell_shengerpingdeng.jpg', - 'image/mode/stone/card/spell_shengguangzhadan.jpg', - 'image/mode/stone/card/spell_shengliaoshu.jpg', - 'image/mode/stone/card/spell_shenpan.jpg', - 'image/mode/stone/card/spell_shenshengfennu.jpg', - 'image/mode/stone/card/spell_shenshengxinxing.jpg', - 'image/mode/stone/card/spell_shihuawuqi.jpg', - 'image/mode/stone/card/spell_shixue.jpg', - 'image/mode/stone/card/spell_sijidaifa.jpg', - 'image/mode/stone/card/spell_siwangchanrao.jpg', - 'image/mode/stone/card/spell_tanxianmao.jpg', - 'image/mode/stone/card/spell_tianjiangzhuqun.jpg', - 'image/mode/stone/card/spell_wangzhezhufu.jpg', - 'image/mode/stone/card/spell_weijisifu.jpg', - 'image/mode/stone/card/spell_wuyashenxiang.jpg', - 'image/mode/stone/card/spell_xianzuzhaohuan.jpg', - 'image/mode/stone/card/spell_xianzuzhihun.jpg', - 'image/mode/stone/card/spell_xianzuzhiliao.jpg', - 'image/mode/stone/card/spell_xianzuzhishi.jpg', - 'image/mode/stone/card/spell_xiaoguibaopo.jpg', - 'image/mode/stone/card/spell_xiaoshi.jpg', - 'image/mode/stone/card/spell_xingchenzhuiluo.jpg', - 'image/mode/stone/card/spell_xinlinghanbao.jpg', - 'image/mode/stone/card/spell_xinlingshijie.jpg', - 'image/mode/stone/card/spell_xishengqiyue.jpg', - 'image/mode/stone/card/spell_xuanfengzhan.jpg', - 'image/mode/stone/card/spell_yanbaoshu.jpg', - 'image/mode/stone/card/spell_yanmie.jpg', - 'image/mode/stone/card/spell_yaoshu.jpg', - 'image/mode/stone/card/spell_yemanpaoxiao.jpg', - 'image/mode/stone/card/spell_yexingchengzhang.jpg', - 'image/mode/stone/card/spell_yexinglanghun.jpg', - 'image/mode/stone/card/spell_yingyongdaji.jpg', - 'image/mode/stone/card/spell_yongshizhufu.jpg', - 'image/mode/stone/card/spell_zhandounuhuo.jpg', - 'image/mode/stone/card/spell_zhansha.jpg', - 'image/mode/stone/card/spell_zhaohuanchongwu.jpg', - 'image/mode/stone/card/spell_zhengqianghaosheng.jpg', - 'image/mode/stone/card/spell_zhenyanshu.jpg', - 'image/mode/stone/card/spell_zhihuizhufu.jpg', - 'image/mode/stone/card/spell_zhiliaoshui.jpg', - 'image/mode/stone/card/spell_zhiliaozhichu.jpg', - 'image/mode/stone/card/spell_zhiliaozhihuan.jpg', - 'image/mode/stone/card/spell_zhongnian.jpg', - 'image/mode/stone/card/spell_zhuizongshu.jpg', - 'image/mode/stone/card/spell_zhumo.jpg', - 'image/mode/stone/card/spell_zidanshangtang.jpg', - 'image/mode/stone/card/spell_ziranzhili.jpg', - 'image/mode/stone/card/spell_ziyang.jpg', - 'image/mode/stone/card/spell_zuozhandongyuan.jpg', - 'image/mode/stone/card/spell_zuzhou.jpg', - 'image/mode/stone/career/druid.png', - 'image/mode/stone/career/hunter.png', - 'image/mode/stone/career/knight.png', - 'image/mode/stone/career/mage.png', - 'image/mode/stone/career/paladin.png', - 'image/mode/stone/career/priest.png', - 'image/mode/stone/career/rogue.png', - 'image/mode/stone/career/shaman.png', - 'image/mode/stone/career/warlock.png', - 'image/mode/stone/career/warrior.png', - 'image/mode/stone/character/stone_aidewen.jpg', - 'image/mode/stone/character/stone_aihaozhihun.jpg', - 'image/mode/stone/character/stone_alaikesita.jpg', - 'image/mode/stone/character/stone_andongni.jpg', - 'image/mode/stone/character/stone_anyingzisi.jpg', - 'image/mode/stone/character/stone_aolajier.jpg', - 'image/mode/stone/character/stone_aomishouwei.jpg', - 'image/mode/stone/character/stone_aoshushi.jpg', - 'image/mode/stone/character/stone_baohuzhishu.jpg', - 'image/mode/stone/character/stone_baoqishi.jpg', - 'image/mode/stone/character/stone_baoweizhe.jpg', - 'image/mode/stone/character/stone_beijunmushi.jpg', - 'image/mode/stone/character/stone_caoyuanshi.jpg', - 'image/mode/stone/character/stone_chidunshinv.jpg', - 'image/mode/stone/character/stone_chidunweishi.jpg', - 'image/mode/stone/character/stone_chilundashi.jpg', - 'image/mode/stone/character/stone_cike.jpg', - 'image/mode/stone/character/stone_conglinshouwei.jpg', - 'image/mode/stone/character/stone_conglinxiaoshou.jpg', - 'image/mode/stone/character/stone_damoshatuo.jpg', - 'image/mode/stone/character/stone_daomufeizei.jpg', - 'image/mode/stone/character/stone_dijieshicong.jpg', - 'image/mode/stone/character/stone_diyuhuo.jpg', - 'image/mode/stone/character/stone_diyuhuox.jpg', - 'image/mode/stone/character/stone_duyanhaidao.jpg', - 'image/mode/stone/character/stone_fachao.jpg', - 'image/mode/stone/character/stone_falifulong.jpg', - 'image/mode/stone/character/stone_famingjia.jpg', - 'image/mode/stone/character/stone_faqishi.jpg', - 'image/mode/stone/character/stone_fatiaozhuru.jpg', - 'image/mode/stone/character/stone_fennuxiaoji.jpg', - 'image/mode/stone/character/stone_fuding.jpg', - 'image/mode/stone/character/stone_fuhuokaijia.jpg', - 'image/mode/stone/character/stone_fukongmoyan.jpg', - 'image/mode/stone/character/stone_gangtiewushi.jpg', - 'image/mode/stone/character/stone_geluomashi.jpg', - 'image/mode/stone/character/stone_guangmingquan.jpg', - 'image/mode/stone/character/stone_guangyaozhizi.jpg', - 'image/mode/stone/character/stone_guanliyuan.jpg', - 'image/mode/stone/character/stone_guiqishi.jpg', - 'image/mode/stone/character/stone_haidao.jpg', - 'image/mode/stone/character/stone_haidaotoumu.jpg', - 'image/mode/stone/character/stone_hanguangzhizhe.jpg', - 'image/mode/stone/character/stone_heianjiaotu.jpg', - 'image/mode/stone/character/stone_heishitanfan.jpg', - 'image/mode/stone/character/stone_heitieairen.jpg', - 'image/mode/stone/character/stone_heiyaoyaoshou.jpg', - 'image/mode/stone/character/stone_honglongyongshi.jpg', - 'image/mode/stone/character/stone_huangjialeixiang.jpg', - 'image/mode/stone/character/stone_huangyeqishi.jpg', - 'image/mode/stone/character/stone_hudunren.jpg', - 'image/mode/stone/character/stone_huofu.jpg', - 'image/mode/stone/character/stone_huoli.jpg', - 'image/mode/stone/character/stone_huoqiangshou.jpg', - 'image/mode/stone/character/stone_huoshanxiemu.jpg', - 'image/mode/stone/character/stone_huoshe.jpg', - 'image/mode/stone/character/stone_huoyanweishi.jpg', - 'image/mode/stone/character/stone_huoyao.jpg', - 'image/mode/stone/character/stone_huoyuansu.jpg', - 'image/mode/stone/character/stone_jialakesi.jpg', - 'image/mode/stone/character/stone_jialakesix.jpg', - 'image/mode/stone/character/stone_jiangong.jpg', - 'image/mode/stone/character/stone_jiewangzhu.jpg', - 'image/mode/stone/character/stone_jingxiang.jpg', - 'image/mode/stone/character/stone_jingyingweishi.jpg', - 'image/mode/stone/character/stone_jujishou.jpg', - 'image/mode/stone/character/stone_junxuguan.jpg', - 'image/mode/stone/character/stone_juxingchanchu.jpg', - 'image/mode/stone/character/stone_kaodalalong.jpg', - 'image/mode/stone/character/stone_kelushi.jpg', - 'image/mode/stone/character/stone_kongjuzhanma.jpg', - 'image/mode/stone/character/stone_kuangyedoushi.jpg', - 'image/mode/stone/character/stone_kuangzhanshi.jpg', - 'image/mode/stone/character/stone_kutongsiseng.jpg', - 'image/mode/stone/character/stone_langren.jpg', - 'image/mode/stone/character/stone_lansaizhanshi.jpg', - 'image/mode/stone/character/stone_leiouke.jpg', - 'image/mode/stone/character/stone_liebao.jpg', - 'image/mode/stone/character/stone_liegou.jpg', - 'image/mode/stone/character/stone_liewangshouwei.jpg', - 'image/mode/stone/character/stone_lieyanxiaogui.jpg', - 'image/mode/stone/character/stone_lifaji.jpg', - 'image/mode/stone/character/stone_lindishuyao.jpg', - 'image/mode/stone/character/stone_linghunjisi.jpg', - 'image/mode/stone/character/stone_longmianjiaoguan.jpg', - 'image/mode/stone/character/stone_longwangpeiou.jpg', - 'image/mode/stone/character/stone_mafengzhuru.jpg', - 'image/mode/stone/character/stone_maligousi.jpg', - 'image/mode/stone/character/stone_meimo.jpg', - 'image/mode/stone/character/stone_mengmaren.jpg', - 'image/mode/stone/character/stone_mianyang.jpg', - 'image/mode/stone/character/stone_mingguangjisi.jpg', - 'image/mode/stone/character/stone_misha.jpg', - 'image/mode/stone/character/stone_morishouwei.jpg', - 'image/mode/stone/character/stone_muguangchulong.jpg', - 'image/mode/stone/character/stone_muyangren.jpg', - 'image/mode/stone/character/stone_nianqingjisi.jpg', - 'image/mode/stone/character/stone_nuoziduomu.jpg', - 'image/mode/stone/character/stone_peilianshi.jpg', - 'image/mode/stone/character/stone_qiezei.jpg', - 'image/mode/stone/character/stone_qingwa.jpg', - 'image/mode/stone/character/stone_renyaqishi.jpg', - 'image/mode/stone/character/stone_sainaliusi.jpg', - 'image/mode/stone/character/stone_senlinlang.jpg', - 'image/mode/stone/character/stone_shachuisaman.jpg', - 'image/mode/stone/character/stone_shalinxingzhe.jpg', - 'image/mode/stone/character/stone_shengdianzhishi.jpg', - 'image/mode/stone/character/stone_shengguanghuwei.jpg', - 'image/mode/stone/character/stone_shengjiachong.jpg', - 'image/mode/stone/character/stone_shenmiqishou.jpg', - 'image/mode/stone/character/stone_shenshengyongshi.jpg', - 'image/mode/stone/character/stone_shifazhe.jpg', - 'image/mode/stone/character/stone_shihualong.jpg', - 'image/mode/stone/character/stone_shishigui.jpg', - 'image/mode/stone/character/stone_shixiangweishi.jpg', - 'image/mode/stone/character/stone_shuiyuansu.jpg', - 'image/mode/stone/character/stone_shumiao.jpg', - 'image/mode/stone/character/stone_shuren.jpg', - 'image/mode/stone/character/stone_shurenx.jpg', - 'image/mode/stone/character/stone_shurenxx.jpg', - 'image/mode/stone/character/stone_siwangzhiyi.jpg', - 'image/mode/stone/character/stone_suoxiaojishi.jpg', - 'image/mode/stone/character/stone_tegong.jpg', - 'image/mode/stone/character/stone_tongkunvwang.jpg', - 'image/mode/stone/character/stone_tujiu.jpg', - 'image/mode/stone/character/stone_tuteng1.jpg', - 'image/mode/stone/character/stone_tuteng2.jpg', - 'image/mode/stone/character/stone_tuteng3.jpg', - 'image/mode/stone/character/stone_tuteng4.jpg', - 'image/mode/stone/character/stone_tutengshi.jpg', - 'image/mode/stone/character/stone_tutengyongshi.jpg', - 'image/mode/stone/character/stone_tuyuansu.jpg', - 'image/mode/stone/character/stone_wanshiyuansu.jpg', - 'image/mode/stone/character/stone_weilun.jpg', - 'image/mode/stone/character/stone_wujiyuansu.jpg', - 'image/mode/stone/character/stone_wushixuetu.jpg', - 'image/mode/stone/character/stone_wuyi.jpg', - 'image/mode/stone/character/stone_xiaogui.jpg', - 'image/mode/stone/character/stone_xiaoguishouling.jpg', - 'image/mode/stone/character/stone_xiaojingling.jpg', - 'image/mode/stone/character/stone_xinbing.jpg', - 'image/mode/stone/character/stone_xiushuihaidao.jpg', - 'image/mode/stone/character/stone_xuefanzhanshi.jpg', - 'image/mode/stone/character/stone_xuejuren.jpg', - 'image/mode/stone/character/stone_xukongkongmo.jpg', - 'image/mode/stone/character/stone_xukongxingzhe.jpg', - 'image/mode/stone/character/stone_xulingwushi.jpg', - 'image/mode/stone/character/stone_xunmashi.jpg', - 'image/mode/stone/character/stone_xunmenglong.jpg', - 'image/mode/stone/character/stone_xunshoushi.jpg', - 'image/mode/stone/character/stone_yanjingshe.jpg', - 'image/mode/stone/character/stone_yanshushi.jpg', - 'image/mode/stone/character/stone_yaosaishouwei.jpg', - 'image/mode/stone/character/stone_yingxiongzhihun.jpg', - 'image/mode/stone/character/stone_yisela.jpg', - 'image/mode/stone/character/stone_youlinglang.jpg', - 'image/mode/stone/character/stone_yuanguanying.jpg', - 'image/mode/stone/character/stone_yuanhou.jpg', - 'image/mode/stone/character/stone_yurenqishi.jpg', - 'image/mode/stone/character/stone_zhaohuanzhe.jpg', - 'image/mode/stone/character/stone_zhifuzhe.jpg', - 'image/mode/stone/character/stone_zhihuiguan.jpg', - 'image/mode/stone/character/stone_zhiyuzhe.jpg', - 'image/mode/stone/character/stone_zhongshi.jpg', - 'image/mode/stone/character/stone_zhucangzhe.jpg', - 'image/mode/stone/character/stone_zhujiashi.jpg', - 'image/mode/stone/character/stone_zhumo.jpg', - 'image/mode/stone/character/stone_zongxiong.jpg', - 'image/mode/stone/character/stone_zousishangfan.jpg', - 'image/mode/tafang/character/tafang_mech_dubiaoxianjing.jpg', - 'image/mode/tafang/character/tafang_mech_gongchengche.jpg', - 'image/mode/tafang/character/tafang_mech_guangmingquan.jpg', - 'image/mode/tafang/character/tafang_mech_jiguanren.jpg', - 'image/mode/tafang/character/tafang_mech_jiqishi.jpg', - 'image/mode/tafang/character/tafang_mech_mutong.jpg', - 'image/mode/tafang/character/tafang_mech_nengliangqiu.jpg', - 'image/mode/tafang/character/tafang_mech_shanggukanshou.jpg', - 'image/mode/tafang/character/tafang_mech_shenmidiaoxiang.jpg', - 'image/mode/tafang/character/tafang_mech_shenpanxianjing.jpg', - 'image/mode/tafang/character/tafang_mech_shiyuansu.jpg', - 'image/mode/tafang/character/tafang_mech_toushiche.jpg', - 'image/mode/tafang/character/tafang_mech_tutengzhen.jpg', - 'image/mode/tafang/character/tafang_mech_weixingxianjing.jpg', - 'image/mode/tafang/character/tafang_mech_wuyashenxiang.jpg', - 'image/mode/versus/character/boss_chiyuzhuque.jpg', - 'image/mode/versus/character/boss_duanyuzhongda.jpg', - 'image/mode/versus/character/boss_fudibian.jpg', - 'image/mode/versus/character/boss_gongshenyueying.jpg', - 'image/mode/versus/character/boss_jiarenzidan.jpg', - 'image/mode/versus/character/boss_jileibaihu.jpg', - 'image/mode/versus/character/boss_juechenmiaocai.jpg', - 'image/mode/versus/character/boss_liedixuande.jpg', - 'image/mode/versus/character/boss_lieshiyazi.jpg', - 'image/mode/versus/character/boss_lingjiaxuanwu.jpg', - 'image/mode/versus/character/boss_qiaokuijunyi.jpg', - 'image/mode/versus/character/boss_shihuosuanni.jpg', - 'image/mode/versus/character/boss_tianhoukongming.jpg', - 'image/mode/versus/character/boss_tuntianchiwen.jpg', - 'image/mode/versus/character/boss_yuhuoshiyuan.jpg', - 'image/mode/versus/character/boss_yunpingqinglong.jpg', - 'image/mode/versus/character/boss_baijiwenyuan.jpg', - 'image/mode/versus/character/boss_fuweizilong.jpg', - 'image/mode/versus/character/boss_kumuyuanrang.jpg', - 'image/mode/versus/character/boss_yihanyunchang.jpg', - 'image/mode/versus/character/liuqi.jpg', - 'image/mode/versus/character/tangzi.jpg', - - /*splash image begin*/ - 'image/splash/style1.jpg', - 'image/splash/style2.jpg', - 'image/splash/style1/boss.jpg', - 'image/splash/style1/brawl.jpg', - 'image/splash/style1/chess.jpg', - 'image/splash/style1/connect.jpg', - 'image/splash/style1/doudizhu.jpg', - 'image/splash/style1/guozhan.jpg', - 'image/splash/style1/identity.jpg', - 'image/splash/style1/single.jpg', - 'image/splash/style1/stone.jpg', - 'image/splash/style1/tafang.jpg', - 'image/splash/style1/versus.jpg', - 'image/splash/style2/boss.jpg', - 'image/splash/style2/brawl.jpg', - 'image/splash/style2/chess.jpg', - 'image/splash/style2/connect.jpg', - 'image/splash/style2/doudizhu.jpg', - 'image/splash/style2/guozhan.jpg', - 'image/splash/style2/identity.jpg', - 'image/splash/style2/single.jpg', - 'image/splash/style2/stone.jpg', - 'image/splash/style2/tafang.jpg', - 'image/splash/style2/versus.jpg', - /*splash image end*/ - - 'theme/music/grid.png', - 'theme/music/wood.png', - 'theme/music/wood3.png', - 'theme/simple/card.png', - 'theme/simple/card2.png', - 'theme/simple/grid.png', - 'theme/simple/unknown.png', - 'theme/simple/wood.png', - 'theme/simple/wood3.png', - 'theme/style/card/image/border_bronze.jpg', - 'theme/style/card/image/border_gold.jpg', - 'theme/style/card/image/border_map.jpg', - 'theme/style/card/image/border_silver.jpg', - 'theme/style/card/image/border_wood.jpg', - 'theme/style/card/image/new.png', - 'theme/style/card/image/ol.png', - 'theme/style/cardback/image/feicheng.png', - 'theme/style/cardback/image/feicheng2.png', - 'theme/style/cardback/image/liusha.png', - 'theme/style/cardback/image/liusha2.png', - 'theme/style/cardback/image/new.png', - 'theme/style/cardback/image/new2.png', - 'theme/style/cardback/image/official.png', - 'theme/style/cardback/image/official2.png', - 'theme/style/cardback/image/ol.png', - 'theme/style/cardback/image/ol2.png', - 'theme/style/hp/image/emotion1.png', - 'theme/style/hp/image/emotion2.png', - 'theme/style/hp/image/emotion3.png', - 'theme/style/hp/image/emotion4.png', - 'theme/style/hp/image/glass1.png', - 'theme/style/hp/image/glass2.png', - 'theme/style/hp/image/glass3.png', - 'theme/style/hp/image/glass4.png', - 'theme/style/hp/image/official1.png', - 'theme/style/hp/image/official2.png', - 'theme/style/hp/image/official3.png', - 'theme/style/hp/image/official4.png', - 'theme/style/hp/image/ol1.png', - 'theme/style/hp/image/ol2.png', - 'theme/style/hp/image/ol3.png', - 'theme/style/hp/image/ol4.png', - 'theme/style/hp/image/round1.png', - 'theme/style/hp/image/round2.png', - 'theme/style/hp/image/round3.png', - 'theme/style/hp/image/round4.png', - 'theme/style/player/bronze1.png', - 'theme/style/player/bronze2.png', - 'theme/style/player/bronze3.png', - 'theme/style/player/bronze_d1.png', - 'theme/style/player/bronze_d2.png', - 'theme/style/player/gold1.png', - 'theme/style/player/gold2.png', - 'theme/style/player/gold3.png', - 'theme/style/player/gold_d1.png', - 'theme/style/player/gold_d2.png', - 'theme/style/player/silver1.png', - 'theme/style/player/silver2.png', - 'theme/style/player/silver3.png', - 'theme/style/player/silver_d1.png', - 'theme/style/player/silver_d2.png', - 'theme/woodden/grid.png', - 'theme/woodden/wood.jpg', - 'theme/woodden/wood.png', - 'theme/woodden/wood2.jpg', - 'theme/woodden/wood2.png' -]; -window.noname_skin_list={}; \ No newline at end of file +window.noname_asset_list = [ + "v1.10.10", + /*audio start*/ + "audio/background/aozhan_chaoming.mp3", + "audio/background/aozhan_online.mp3", + "audio/background/aozhan_rewrite.mp3", + "audio/background/music_danji.mp3", + "audio/background/music_default.mp3", + "audio/background/music_diaochan.mp3", + "audio/background/music_jifeng.mp3", + "audio/background/music_jilve.mp3", + "audio/background/music_phliosophy.mp3", + "audio/background/music_shezhan.mp3", + /*cardaudio start*/ + "audio/card/default.mp3", + + "audio/card/female/caomu.mp3", + "audio/card/female/chiling.mp3", + "audio/card/female/diaohulishan.mp3", + "audio/card/female/fulei.mp3", + "audio/card/female/huoshaolianying.mp3", + "audio/card/female/jinchan.mp3", + "audio/card/female/lianjunshengyan.mp3", + "audio/card/female/lulitongxin.mp3", + "audio/card/female/qijia.mp3", + "audio/card/female/shengdong.mp3", + "audio/card/female/shuiyanqijun.mp3", + "audio/card/female/xietianzi.mp3", + "audio/card/female/zengbin.mp3", + "audio/card/female/chuqibuyi.mp3", + "audio/card/female/dongzhuxianji.mp3", + "audio/card/female/sha_ice.mp3", + "audio/card/female/suijiyingbian.mp3", + "audio/card/female/zhujinqiyuan.mp3", + "audio/card/female/binglinchengxiax.mp3", + "audio/card/female/chenghuodajie.mp3", + "audio/card/female/dz_mantianguohai.mp3", + "audio/card/female/guaguliaodu.mp3", + "audio/card/female/gz_guguoanbang.mp3", + "audio/card/female/gz_haolingtianxia.mp3", + "audio/card/female/gz_kefuzhongyuan.mp3", + "audio/card/female/gz_wenheluanwu.mp3", + "audio/card/female/kaihua.mp3", + "audio/card/female/qizhengxiangsheng.mp3", + "audio/card/female/sha_stab.mp3", + "audio/card/female/tiaojiyanmei.mp3", + "audio/card/female/tuixinzhifu.mp3", + + "audio/card/female/bagua.mp3", + "audio/card/female/baiyin.mp3", + "audio/card/female/chitu.mp3", + "audio/card/female/cixiong.mp3", + "audio/card/female/dawan.mp3", + "audio/card/female/dilu.mp3", + "audio/card/female/fangtian.mp3", + "audio/card/female/guanshi.mp3", + "audio/card/female/guding.mp3", + "audio/card/female/hanbing.mp3", + "audio/card/female/hualiu.mp3", + "audio/card/female/jueying.mp3", + "audio/card/female/muniu.mp3", + "audio/card/female/qilin.mp3", + "audio/card/female/qinggang.mp3", + "audio/card/female/qinglong.mp3", + "audio/card/female/renwang.mp3", + "audio/card/female/sanjian.mp3", + "audio/card/female/tengjia.mp3", + "audio/card/female/wuliu.mp3", + "audio/card/female/zhangba.mp3", + "audio/card/female/zhuahuang.mp3", + "audio/card/female/zhuge.mp3", + "audio/card/female/zhuque.mp3", + "audio/card/female/zixin.mp3", + + "audio/card/female/bingliang.mp3", + "audio/card/female/guohe.mp3", + "audio/card/female/huogong.mp3", + "audio/card/female/jiedao.mp3", + "audio/card/female/jiu.mp3", + "audio/card/female/juedou.mp3", + "audio/card/female/lebu.mp3", + "audio/card/female/nanman.mp3", + "audio/card/female/sha.mp3", + "audio/card/female/sha_fire.mp3", + "audio/card/female/sha_thunder.mp3", + "audio/card/female/shan.mp3", + "audio/card/female/shandian.mp3", + "audio/card/female/shunshou.mp3", + "audio/card/female/taoyuan.mp3", + "audio/card/female/tiesuo.mp3", + "audio/card/female/wanjian.mp3", + "audio/card/female/wugu.mp3", + "audio/card/female/wuxie.mp3", + "audio/card/female/wuzhong.mp3", + "audio/card/female/yiyi.mp3", + "audio/card/female/yuanjiao.mp3", + "audio/card/female/zhibi.mp3", + + "audio/card/male/caomu.mp3", + "audio/card/male/chiling.mp3", + "audio/card/male/diaohulishan.mp3", + "audio/card/male/fulei.mp3", + "audio/card/male/huoshaolianying.mp3", + "audio/card/male/jinchan.mp3", + "audio/card/male/lianjunshengyan.mp3", + "audio/card/male/lulitongxin.mp3", + "audio/card/male/qijia.mp3", + "audio/card/male/shengdong.mp3", + "audio/card/male/shuiyanqijun.mp3", + "audio/card/male/xietianzi.mp3", + "audio/card/male/zengbin.mp3", + "audio/card/male/chuqibuyi.mp3", + "audio/card/male/dongzhuxianji.mp3", + "audio/card/male/sha_ice.mp3", + "audio/card/male/suijiyingbian.mp3", + "audio/card/male/zhujinqiyuan.mp3", + "audio/card/male/binglinchengxiax.mp3", + "audio/card/male/chenghuodajie.mp3", + "audio/card/male/dz_mantianguohai.mp3", + "audio/card/male/guaguliaodu.mp3", + "audio/card/male/gz_guguoanbang.mp3", + "audio/card/male/gz_haolingtianxia.mp3", + "audio/card/male/gz_kefuzhongyuan.mp3", + "audio/card/male/gz_wenheluanwu.mp3", + "audio/card/male/kaihua.mp3", + "audio/card/male/qizhengxiangsheng.mp3", + "audio/card/male/sha_stab.mp3", + "audio/card/male/tiaojiyanmei.mp3", + "audio/card/male/tuixinzhifu.mp3", + + "audio/card/male/bagua.mp3", + "audio/card/male/baiyin.mp3", + "audio/card/male/chitu.mp3", + "audio/card/male/cixiong.mp3", + "audio/card/male/dawan.mp3", + "audio/card/male/dilu.mp3", + "audio/card/male/fangtian.mp3", + "audio/card/male/guanshi.mp3", + "audio/card/male/guding.mp3", + "audio/card/male/hanbing.mp3", + "audio/card/male/hualiu.mp3", + "audio/card/male/jueying.mp3", + "audio/card/male/muniu.mp3", + "audio/card/male/qilin.mp3", + "audio/card/male/qinggang.mp3", + "audio/card/male/qinglong.mp3", + "audio/card/male/renwang.mp3", + "audio/card/male/sanjian.mp3", + "audio/card/male/tengjia.mp3", + "audio/card/male/wuliu.mp3", + "audio/card/male/zhangba.mp3", + "audio/card/male/zhuahuang.mp3", + "audio/card/male/zhuge.mp3", + "audio/card/male/zhuque.mp3", + "audio/card/male/zixin.mp3", + + "audio/card/male/bingliang.mp3", + "audio/card/male/guohe.mp3", + "audio/card/male/huogong.mp3", + "audio/card/male/jiedao.mp3", + "audio/card/male/jiu.mp3", + "audio/card/male/juedou.mp3", + "audio/card/male/lebu.mp3", + "audio/card/male/nanman.mp3", + "audio/card/male/sha.mp3", + "audio/card/male/sha_fire.mp3", + "audio/card/male/sha_thunder.mp3", + "audio/card/male/shan.mp3", + "audio/card/male/shandian.mp3", + "audio/card/male/shunshou.mp3", + "audio/card/male/taoyuan.mp3", + "audio/card/male/tiesuo.mp3", + "audio/card/male/wanjian.mp3", + "audio/card/male/wugu.mp3", + "audio/card/male/wuxie.mp3", + "audio/card/male/wuzhong.mp3", + "audio/card/male/yiyi.mp3", + "audio/card/male/yuanjiao.mp3", + "audio/card/male/zhibi.mp3", + /*cardaudio end*/ + + /*dieaudio begin*/ + "audio/die/ahuinan.mp3", + "audio/die/bailingyun.mp3", + "audio/die/baosanniang.mp3", + "audio/die/beimihu.mp3", + "audio/die/bianfuren.mp3", + "audio/die/bianxi.mp3", + "audio/die/boss_lvbu1.mp3", + "audio/die/boss_lvbu2.mp3", + "audio/die/boss_lvbu3.mp3", + "audio/die/boss_wuguanwang.mp3", + "audio/die/boss_zhaoyun.mp3", + "audio/die/bulianshi.mp3", + "audio/die/buzhi.mp3", + "audio/die/caesar.mp3", + "audio/die/caifuren.mp3", + "audio/die/caimaozhangyun.mp3", + "audio/die/caiwenji.mp3", + "audio/die/caiyong.mp3", + "audio/die/caizhaoji.mp3", + "audio/die/caizhenji.mp3", + "audio/die/caoang.mp3", + "audio/die/caoanmin.mp3", + "audio/die/caocao.mp3", + "audio/die/caochong.mp3", + "audio/die/caochun.mp3", + "audio/die/caohong.mp3", + "audio/die/caohua.mp3", + "audio/die/caojie.mp3", + "audio/die/caojinyu.mp3", + "audio/die/caomao.mp3", + "audio/die/caopi.mp3", + "audio/die/caoren.mp3", + "audio/die/caorui.mp3", + "audio/die/caoshuang.mp3", + "audio/die/caosong.mp3", + "audio/die/caoxi.mp3", + "audio/die/caoxian.mp3", + "audio/die/caoxiancaohua.mp3", + "audio/die/caoxing.mp3", + "audio/die/caoxiu.mp3", + "audio/die/caoyi.mp3", + "audio/die/caoying.mp3", + "audio/die/caoyu.mp3", + "audio/die/caozhang.mp3", + "audio/die/caozhen.mp3", + "audio/die/caozhi.mp3", + "audio/die/cenhun.mp3", + "audio/die/cheliji.mp3", + "audio/die/chendao.mp3", + "audio/die/chendeng.mp3", + "audio/die/chendong.mp3", + "audio/die/chengbing.mp3", + "audio/die/chengjichengcui.mp3", + "audio/die/chengong.mp3", + "audio/die/chengpu.mp3", + "audio/die/chengui.mp3", + "audio/die/chengyu.mp3", + "audio/die/chenjiao.mp3", + "audio/die/chenlin.mp3", + "audio/die/chenqun.mp3", + "audio/die/chenshi.mp3", + "audio/die/chentai.mp3", + "audio/die/chenwudongxi.mp3", + "audio/die/chunyuqiong.mp3", + "audio/die/clan_hanrong.mp3", + "audio/die/clan_hanshao.mp3", + "audio/die/clan_wanghun.mp3", + "audio/die/clan_wangling.mp3", + "audio/die/clan_wanglun.mp3", + "audio/die/clan_wangyun.mp3", + "audio/die/clan_wuban.mp3", + "audio/die/clan_wukuang.mp3", + "audio/die/clan_wuxian.mp3", + "audio/die/clan_xuncai.mp3", + "audio/die/clan_xuncan.mp3", + "audio/die/clan_xunchen.mp3", + "audio/die/clan_xunshu.mp3", + "audio/die/clan_xunyou.mp3", + "audio/die/clan_zhonghui.mp3", + "audio/die/clan_zhongyan.mp3", + "audio/die/clan_zhongyu.mp3", + "audio/die/cuimao.mp3", + "audio/die/cuiyan.mp3", + "audio/die/daqiao.mp3", + "audio/die/daxiaoqiao.mp3", + "audio/die/db_wenyang.mp3", + "audio/die/dc_bulianshi.mp3", + "audio/die/dc_caiyang.mp3", + "audio/die/dc_caoshuang.mp3", + "audio/die/dc_caozhi.mp3", + "audio/die/dc_chenqun.mp3", + "audio/die/dc_dengzhi.mp3", + "audio/die/dc_dongzhao.mp3", + "audio/die/dc_duyu.mp3", + "audio/die/dc_gaolan.mp3", + "audio/die/dc_gongsunzan.mp3", + "audio/die/dc_huangchengyan.mp3", + "audio/die/dc_huanghao.mp3", + "audio/die/dc_huangquan.mp3", + "audio/die/dc_huangzu.mp3", + "audio/die/dc_huban.mp3", + "audio/die/dc_hujinding.mp3", + "audio/die/dc_huojun.mp3", + "audio/die/dc_jiachong.mp3", + "audio/die/dc_jiben.mp3", + "audio/die/dc_jiling.mp3", + "audio/die/dc_liru.mp3", + "audio/die/dc_liuba.mp3", + "audio/die/dc_liuli.mp3", + "audio/die/dc_liuye.mp3", + "audio/die/dc_liuyu.mp3", + "audio/die/dc_luotong.mp3", + "audio/die/dc_lvkuanglvxiang.mp3", + "audio/die/dc_mengda.mp3", + "audio/die/dc_ruiji.mp3", + "audio/die/dc_sb_lusu.mp3", + "audio/die/dc_sb_simayi.mp3", + "audio/die/dc_sb_simayi_shadow.mp3", + "audio/die/dc_sb_zhouyu.mp3", + "audio/die/dc_sp_jiaxu.mp3", + "audio/die/dc_sunchen.mp3", + "audio/die/dc_sunhanhua.mp3", + "audio/die/dc_sunru.mp3", + "audio/die/dc_sunziliufang.mp3", + "audio/die/dc_tengfanglan.mp3", + "audio/die/dc_wangchang.mp3", + "audio/die/dc_wangjun.mp3", + "audio/die/dc_wangyun.mp3", + "audio/die/dc_wuban.mp3", + "audio/die/dc_xujing.mp3", + "audio/die/dc_xushu.mp3", + "audio/die/dc_yangbiao.mp3", + "audio/die/dc_yanghu.mp3", + "audio/die/dc_yuejiu.mp3", + "audio/die/dc_zhangmancheng.mp3", + "audio/die/dc_zhaotongzhaoguang.mp3", + "audio/die/dc_zhaoyǎn.mp3", + "audio/die/dc_zhaoyun.mp3", + "audio/die/dc_zhouxuān.mp3", + "audio/die/dc_zhuling.mp3", + "audio/die/dengai.mp3", + "audio/die/dengshizai.mp3", + "audio/die/dengzhi.mp3", + "audio/die/dengzhong.mp3", + "audio/die/dianwei.mp3", + "audio/die/diaochan.mp3", + "audio/die/dingfeng.mp3", + "audio/die/dingshangwan.mp3", + "audio/die/dingyuan.mp3", + "audio/die/dongbai.mp3", + "audio/die/dongcheng.mp3", + "audio/die/dongguiren.mp3", + "audio/die/dongtuna.mp3", + "audio/die/dongwan.mp3", + "audio/die/dongxie.mp3", + "audio/die/dongyun.mp3", + "audio/die/dongzhao.mp3", + "audio/die/dongzhuo.mp3", + "audio/die/duanjiong.mp3", + "audio/die/duanqiaoxiao.mp3", + "audio/die/duanwei.mp3", + "audio/die/dufuren.mp3", + "audio/die/duji.mp3", + "audio/die/dukui.mp3", + "audio/die/duosidawang.mp3", + "audio/die/duxi.mp3", + "audio/die/duyu.mp3", + "audio/die/erqiao.mp3", + "audio/die/erzhang.mp3", + "audio/die/fanchou.mp3", + "audio/die/fanjiangzhangda.mp3", + "audio/die/fanyufeng.mp3", + "audio/die/fazheng.mp3", + "audio/die/feiyi.mp3", + "audio/die/fengfang.mp3", + "audio/die/fengfangnv.mp3", + "audio/die/fengxi.mp3", + "audio/die/fuhuanghou.mp3", + "audio/die/furong.mp3", + "audio/die/furongfuqian.mp3", + "audio/die/fuwan.mp3", + "audio/die/ganfuren.mp3", + "audio/die/ganfurenmifuren.mp3", + "audio/die/ganning.mp3", + "audio/die/gaogan.mp3", + "audio/die/gaolan.mp3", + "audio/die/gaoshun.mp3", + "audio/die/gaoxiang.mp3", + "audio/die/gexuan.mp3", + "audio/die/gongsundu.mp3", + "audio/die/gongsunkang.mp3", + "audio/die/gongsunyuan.mp3", + "audio/die/gongsunzan.mp3", + "audio/die/guanhai.mp3", + "audio/die/guanlu.mp3", + "audio/die/guanning.mp3", + "audio/die/guānning.mp3", + "audio/die/guanping.mp3", + "audio/die/guanqiujian.mp3", + "audio/die/guanxingzhangbao.mp3", + "audio/die/guanyinping.mp3", + "audio/die/guanyu.mp3", + "audio/die/guanzhang.mp3", + "audio/die/guohuai.mp3", + "audio/die/guohuanghou.mp3", + "audio/die/guojia.mp3", + "audio/die/guosi.mp3", + "audio/die/guotu.mp3", + "audio/die/guotufengji.mp3", + "audio/die/guozhao.mp3", + "audio/die/guyong.mp3", + "audio/die/guzhielai.mp3", + "audio/die/gz_dc_yanghu.mp3", + "audio/die/gz_dengzhi.mp3", + "audio/die/gz_gongsunyuan.mp3", + "audio/die/gz_huangzu.mp3", + "audio/die/gz_jun_caocao.mp3", + "audio/die/gz_jun_liubei.mp3", + "audio/die/gz_jun_sunquan.mp3", + "audio/die/gz_jun_zhangjiao.mp3", + "audio/die/gz_liuba.mp3", + "audio/die/gz_liuqi.mp3", + "audio/die/gz_lukang.mp3", + "audio/die/gz_luxun.mp3", + "audio/die/gz_miheng.mp3", + "audio/die/gz_panjun.mp3", + "audio/die/gz_pengyang.mp3", + "audio/die/gz_re_xushu.mp3", + "audio/die/gz_shixie.mp3", + "audio/die/gz_simazhao.mp3", + "audio/die/gz_sunchen.mp3", + "audio/die/gz_tangzi.mp3", + "audio/die/gz_wenqin.mp3", + "audio/die/gz_wujing.mp3", + "audio/die/gz_xf_sufei.mp3", + "audio/die/gz_xiahouba.mp3", + "audio/die/gz_xuyou.mp3", + "audio/die/gz_yanbaihu.mp3", + "audio/die/gz_zhanglu.mp3", + "audio/die/gz_zhonghui.mp3", + "audio/die/gz_zhugeke.mp3", + "audio/die/gz_zhuling.mp3", + "audio/die/hanba.mp3", + "audio/die/handang.mp3", + "audio/die/hanfu.mp3", + "audio/die/hanhaoshihuan.mp3", + "audio/die/hanlong.mp3", + "audio/die/hanmeng.mp3", + "audio/die/hansui.mp3", + "audio/die/haomeng.mp3", + "audio/die/haopu.mp3", + "audio/die/haozhao.mp3", + "audio/die/hejin.mp3", + "audio/die/heqi.mp3", + "audio/die/hetaihou.mp3", + "audio/die/heyan.mp3", + "audio/die/huaman.mp3", + "audio/die/huanfan.mp3", + "audio/die/huangchengyan.mp3", + "audio/die/huangfusong.mp3", + "audio/die/huanggai.mp3", + "audio/die/huanghao.mp3", + "audio/die/huangquan.mp3", + "audio/die/huangyueying.mp3", + "audio/die/huangzhong.mp3", + "audio/die/huangzu.mp3", + "audio/die/huatuo.mp3", + "audio/die/huaxin.mp3", + "audio/die/huaxiong.mp3", + "audio/die/hucheer.mp3", + "audio/die/hujinding.mp3", + "audio/die/huojun.mp3", + "audio/die/huzhao.mp3", + "audio/die/jiachong.mp3", + "audio/die/jiakui.mp3", + "audio/die/jiangboyue.mp3", + "audio/die/jiangfei.mp3", + "audio/die/jianggan.mp3", + "audio/die/jiangqin.mp3", + "audio/die/jiangwanfeiyi.mp3", + "audio/die/jiangwei.mp3", + "audio/die/jianyong.mp3", + "audio/die/jiawenhe.mp3", + "audio/die/jiaxu.mp3", + "audio/die/jikang.mp3", + "audio/die/jiling.mp3", + "audio/die/jin_guohuai.mp3", + "audio/die/jin_jiachong.mp3", + "audio/die/jin_simashi.mp3", + "audio/die/jin_simayi.mp3", + "audio/die/jin_simazhao.mp3", + "audio/die/jin_wangyuanji.mp3", + "audio/die/jin_xiahouhui.mp3", + "audio/die/jin_yanghu.mp3", + "audio/die/jin_yanghuiyu.mp3", + "audio/die/jin_zhangchunhua.mp3", + "audio/die/jin_zhouchu.mp3", + "audio/die/jinxuandi.mp3", + "audio/die/jsp_caoren.mp3", + "audio/die/jsp_guanyu.mp3", + "audio/die/jsp_huangyueying.mp3", + "audio/die/junk_guanyu.mp3", + "audio/die/kanze.mp3", + "audio/die/kebineng.mp3", + "audio/die/key_abyusa.mp3", + "audio/die/key_hinata.mp3", + "audio/die/key_hisako.mp3", + "audio/die/key_noda.mp3", + "audio/die/key_saya.mp3", + "audio/die/key_shiina.mp3", + "audio/die/key_shiki.mp3", + "audio/die/key_shiorimiyuki.mp3", + "audio/die/key_yui.mp3", + "audio/die/key_yuri.mp3", + "audio/die/kongrong.mp3", + "audio/die/kuailiangkuaiyue.mp3", + "audio/die/kuaiqi.mp3", + "audio/die/laimin.mp3", + "audio/die/laiyinger.mp3", + "audio/die/leibo.mp3", + "audio/die/leitong.mp3", + "audio/die/liangxing.mp3", + "audio/die/liaohua.mp3", + "audio/die/libai.mp3", + "audio/die/licaiwei.mp3", + "audio/die/lidian.mp3", + "audio/die/lifeng.mp3", + "audio/die/lijue.mp3", + "audio/die/lingcao.mp3", + "audio/die/lingju.mp3", + "audio/die/lingtong.mp3", + "audio/die/liqueguosi.mp3", + "audio/die/liru.mp3", + "audio/die/lisu.mp3", + "audio/die/litong.mp3", + "audio/die/liuba.mp3", + "audio/die/liubei.mp3", + "audio/die/liubian.mp3", + "audio/die/liubiao.mp3", + "audio/die/liuchen.mp3", + "audio/die/liucheng.mp3", + "audio/die/liuchongluojun.mp3", + "audio/die/liufeng.mp3", + "audio/die/liuhong.mp3", + "audio/die/liuhui.mp3", + "audio/die/liupi.mp3", + "audio/die/liuqi.mp3", + "audio/die/liushan.mp3", + "audio/die/liuxie.mp3", + "audio/die/liuyan.mp3", + "audio/die/liuyao.mp3", + "audio/die/liuye.mp3", + "audio/die/liuyong.mp3", + "audio/die/liuyu.mp3", + "audio/die/liuzan.mp3", + "audio/die/liuzhang.mp3", + "audio/die/liwan.mp3", + "audio/die/liyan.mp3", + "audio/die/liyi.mp3", + "audio/die/liyixiejing.mp3", + "audio/die/longwang.mp3", + "audio/die/luboyan.mp3", + "audio/die/luji.mp3", + "audio/die/lukai.mp3", + "audio/die/lukang.mp3", + "audio/die/luotong.mp3", + "audio/die/luoxian.mp3", + "audio/die/lushi.mp3", + "audio/die/lusu.mp3", + "audio/die/luxun.mp3", + "audio/die/luyi.mp3", + "audio/die/luyusheng.mp3", + "audio/die/luzhi.mp3", + "audio/die/lvboshe.mp3", + "audio/die/lvbu.mp3", + "audio/die/lvdai.mp3", + "audio/die/lvfan.mp3", + "audio/die/lvkai.mp3", + "audio/die/lvkuanglvxiang.mp3", + "audio/die/lvlingqi.mp3", + "audio/die/lvmeng.mp3", + "audio/die/lvqian.mp3", + "audio/die/machao.mp3", + "audio/die/macheng.mp3", + "audio/die/madai.mp3", + "audio/die/majun.mp3", + "audio/die/maliang.mp3", + "audio/die/malingli.mp3", + "audio/die/mamidi.mp3", + "audio/die/manchong.mp3", + "audio/die/mangyachang.mp3", + "audio/die/mateng.mp3", + "audio/die/maxiumatie.mp3", + "audio/die/mayuanyi.mp3", + "audio/die/mayunlu.mp3", + "audio/die/mazhong.mp3", + "audio/die/mb_chengui.mp3", + "audio/die/mb_huban.mp3", + "audio/die/mb_xianglang.mp3", + "audio/die/mengda.mp3", + "audio/die/menghuo.mp3", + "audio/die/mengjie.mp3", + "audio/die/mengyou.mp3", + "audio/die/mifangfushiren.mp3", + "audio/die/mifuren.mp3", + "audio/die/miheng.mp3", + "audio/die/mizhu.mp3", + "audio/die/mp_liuling.mp3", + "audio/die/muludawang.mp3", + "audio/die/mushun.mp3", + "audio/die/nanhualaoxian.mp3", + "audio/die/nashime.mp3", + "audio/die/neo_xuchu.mp3", + "audio/die/neo_zhouyu.mp3", + "audio/die/new_caoren.mp3", + "audio/die/nezha.mp3", + "audio/die/niufu.mp3", + "audio/die/niujin.mp3", + "audio/die/ns_zanghong.mp3", + "audio/die/ol_caiwenji.mp3", + "audio/die/ol_chendeng.mp3", + "audio/die/ol_dengai.mp3", + "audio/die/ol_dengzhi.mp3", + "audio/die/ol_dianwei.mp3", + "audio/die/ol_dingshangwan.mp3", + "audio/die/ol_dingyuan.mp3", + "audio/die/ol_dongzhao.mp3", + "audio/die/ol_dongzhuo.mp3", + "audio/die/ol_feiyi.mp3", + "audio/die/ol_furong.mp3", + "audio/die/ol_huangzhong.mp3", + "audio/die/ol_huaxin.mp3", + "audio/die/ol_huban.mp3", + "audio/die/ol_hujinding.mp3", + "audio/die/ol_jiangwei.mp3", + "audio/die/ol_lisu.mp3", + "audio/die/ol_liuba.mp3", + "audio/die/ol_liushan.mp3", + "audio/die/ol_lusu.mp3", + "audio/die/ol_masu.mp3", + "audio/die/ol_mengda.mp3", + "audio/die/ol_pangde.mp3", + "audio/die/ol_pangtong.mp3", + "audio/die/ol_puyuan.mp3", + "audio/die/ol_qianzhao.mp3", + "audio/die/ol_sb_guanyu.mp3", + "audio/die/ol_sb_jiangwei.mp3", + "audio/die/ol_sb_taishici.mp3", + "audio/die/ol_sb_yuanshao.mp3", + "audio/die/ol_sb_yuanshao_shadow.mp3", + "audio/die/ol_sp_zhugeliang.mp3", + "audio/die/ol_sunjian.mp3", + "audio/die/ol_wangrong.mp3", + "audio/die/ol_weiyan.mp3", + "audio/die/ol_wenqin.mp3", + "audio/die/ol_xiahouyuan.mp3", + "audio/die/ol_xiaoqiao.mp3", + "audio/die/ol_xuhuang.mp3", + "audio/die/ol_xunyu.mp3", + "audio/die/ol_yangyi.mp3", + "audio/die/ol_yanwen.mp3", + "audio/die/ol_yuanshao.mp3", + "audio/die/ol_yujin.mp3", + "audio/die/ol_zhangyì.mp3", + "audio/die/ol_zhangzhang.mp3", + "audio/die/ol_zhouqun.mp3", + "audio/die/ol_zhujun.mp3", + "audio/die/ol_zhuling.mp3", + "audio/die/ol_zhurong.mp3", + "audio/die/old_guanzhang.mp3", + "audio/die/old_madai.mp3", + "audio/die/old_quancong.mp3", + "audio/die/old_wangyi.mp3", + "audio/die/old_zhuhuan.mp3", + "audio/die/panfeng.mp3", + "audio/die/pangde.mp3", + "audio/die/pangdegong.mp3", + "audio/die/panghui.mp3", + "audio/die/panglingming.mp3", + "audio/die/pangshanmin.mp3", + "audio/die/pangtong.mp3", + "audio/die/panjun.mp3", + "audio/die/panshu.mp3", + "audio/die/panzhangmazhong.mp3", + "audio/die/peixiu.mp3", + "audio/die/peiyuanshao.mp3", + "audio/die/puyuan.mp3", + "audio/die/qianzhao.mp3", + "audio/die/qiaogong.mp3", + "audio/die/qiaorui.mp3", + "audio/die/qiaozhou.mp3", + "audio/die/qinghegongzhu.mp3", + "audio/die/qinlang.mp3", + "audio/die/qinmi.mp3", + "audio/die/qinyilu.mp3", + "audio/die/qiuliju.mp3", + "audio/die/quancong.mp3", + "audio/die/quanhuijie.mp3", + "audio/die/quhuang.mp3", + "audio/die/quyi.mp3", + "audio/die/re_bulianshi.mp3", + "audio/die/re_caifuren.mp3", + "audio/die/re_caiwenji.mp3", + "audio/die/re_caiyong.mp3", + "audio/die/re_caocao.mp3", + "audio/die/re_caochong.mp3", + "audio/die/re_caopi.mp3", + "audio/die/re_caoxiu.mp3", + "audio/die/re_caozhang.mp3", + "audio/die/re_caozhen.mp3", + "audio/die/re_caozhi.mp3", + "audio/die/re_chendeng.mp3", + "audio/die/re_chengong.mp3", + "audio/die/re_chengpu.mp3", + "audio/die/re_chenqun.mp3", + "audio/die/re_chunyuqiong.mp3", + "audio/die/re_daqiao.mp3", + "audio/die/re_dengai.mp3", + "audio/die/re_dianwei.mp3", + "audio/die/re_diaochan.mp3", + "audio/die/re_dongbai.mp3", + "audio/die/re_dongcheng.mp3", + "audio/die/re_dongzhuo.mp3", + "audio/die/re_duji.mp3", + "audio/die/re_fazheng.mp3", + "audio/die/re_fengfangnv.mp3", + "audio/die/re_fuhuanghou.mp3", + "audio/die/re_ganning.mp3", + "audio/die/re_gaoshun.mp3", + "audio/die/re_gongsunyuan.mp3", + "audio/die/re_gongsunzan.mp3", + "audio/die/re_guanping.mp3", + "audio/die/re_guanyu.mp3", + "audio/die/re_guanzhang.mp3", + "audio/die/re_guohuai.mp3", + "audio/die/re_guohuanghou.mp3", + "audio/die/re_guojia.mp3", + "audio/die/re_guotufengji.mp3", + "audio/die/re_guyong.mp3", + "audio/die/re_handang.mp3", + "audio/die/re_hanhaoshihuan.mp3", + "audio/die/re_huanggai.mp3", + "audio/die/re_huangyueying.mp3", + "audio/die/re_huangzhong.mp3", + "audio/die/re_huatuo.mp3", + "audio/die/re_huaxiong.mp3", + "audio/die/re_hucheer.mp3", + "audio/die/re_jiangwei.mp3", + "audio/die/re_jianyong.mp3", + "audio/die/re_jiaxu.mp3", + "audio/die/re_jsp_huangyueying.mp3", + "audio/die/re_jsp_pangtong.mp3", + "audio/die/re_jushou.mp3", + "audio/die/re_liaohua.mp3", + "audio/die/re_lingtong.mp3", + "audio/die/re_liru.mp3", + "audio/die/re_liubei.mp3", + "audio/die/re_liubiao.mp3", + "audio/die/re_liuchen.mp3", + "audio/die/re_liufeng.mp3", + "audio/die/re_liushan.mp3", + "audio/die/re_liuzan.mp3", + "audio/die/re_lusu.mp3", + "audio/die/re_luxun.mp3", + "audio/die/re_lvbu.mp3", + "audio/die/re_lvmeng.mp3", + "audio/die/re_machao.mp3", + "audio/die/re_madai.mp3", + "audio/die/re_manchong.mp3", + "audio/die/re_masu.mp3", + "audio/die/re_mazhong.mp3", + "audio/die/re_menghuo.mp3", + "audio/die/re_miheng.mp3", + "audio/die/re_nanhualaoxian.mp3", + "audio/die/re_panfeng.mp3", + "audio/die/re_pangde.mp3", + "audio/die/re_pangdegong.mp3", + "audio/die/re_pangtong.mp3", + "audio/die/re_panshu.mp3", + "audio/die/re_panzhangmazhong.mp3", + "audio/die/re_quancong.mp3", + "audio/die/re_simayi.mp3", + "audio/die/re_sp_taishici.mp3", + "audio/die/re_sp_zhugeliang.mp3", + "audio/die/re_sunben.mp3", + "audio/die/re_sunce.mp3", + "audio/die/re_sundeng.mp3", + "audio/die/re_sunjian.mp3", + "audio/die/re_sunluban.mp3", + "audio/die/re_sunquan.mp3", + "audio/die/re_sunshangxiang.mp3", + "audio/die/re_sunxiu.mp3", + "audio/die/re_sunyi.mp3", + "audio/die/re_taishici.mp3", + "audio/die/re_taoqian.mp3", + "audio/die/re_wangyi.mp3", + "audio/die/re_weiyan.mp3", + "audio/die/re_wenpin.mp3", + "audio/die/re_wuguotai.mp3", + "audio/die/re_wuyi.mp3", + "audio/die/re_xiahoudun.mp3", + "audio/die/re_xiahoushi.mp3", + "audio/die/re_xiahouyuan.mp3", + "audio/die/re_xiaoqiao.mp3", + "audio/die/re_xuhuang.mp3", + "audio/die/re_xunchen.mp3", + "audio/die/re_xunyou.mp3", + "audio/die/re_xunyu.mp3", + "audio/die/re_xusheng.mp3", + "audio/die/re_xushu.mp3", + "audio/die/re_xuzhu.mp3", + "audio/die/re_yanwen.mp3", + "audio/die/re_yuanshu.mp3", + "audio/die/re_yufan.mp3", + "audio/die/re_yuji.mp3", + "audio/die/re_zhangchunhua.mp3", + "audio/die/re_zhangfei.mp3", + "audio/die/re_zhanghe.mp3", + "audio/die/re_zhangjiao.mp3", + "audio/die/re_zhangliang.mp3", + "audio/die/re_zhangliao.mp3", + "audio/die/re_zhangsong.mp3", + "audio/die/re_zhangyi.mp3", + "audio/die/re_zhangzhang.mp3", + "audio/die/re_zhaoyun.mp3", + "audio/die/re_zhenji.mp3", + "audio/die/re_zhonghui.mp3", + "audio/die/re_zhongyao.mp3", + "audio/die/re_zhoucang.mp3", + "audio/die/re_zhouyu.mp3", + "audio/die/re_zhugeliang.mp3", + "audio/die/re_zhuhuan.mp3", + "audio/die/re_zhuran.mp3", + "audio/die/re_zhurong.mp3", + "audio/die/re_zhuzhi.mp3", + "audio/die/re_zoushi.mp3", + "audio/die/re_zuoci.mp3", + "audio/die/ruanhui.mp3", + "audio/die/ruanji.mp3", + "audio/die/ruanyu.mp3", + "audio/die/ruiji.mp3", + "audio/die/sb_caocao.mp3", + "audio/die/sb_caopi.mp3", + "audio/die/sb_caoren.mp3", + "audio/die/sb_chengong.mp3", + "audio/die/sb_daqiao.mp3", + "audio/die/sb_diaochan.mp3", + "audio/die/sb_fazheng.mp3", + "audio/die/sb_ganning.mp3", + "audio/die/sb_guanyu.mp3", + "audio/die/sb_huanggai.mp3", + "audio/die/sb_huangyueying.mp3", + "audio/die/sb_huangzhong.mp3", + "audio/die/sb_huaxiong.mp3", + "audio/die/sb_jiangwei.mp3", + "audio/die/sb_liubei.mp3", + "audio/die/sb_liubiao.mp3", + "audio/die/sb_lvmeng.mp3", + "audio/die/sb_machao.mp3", + "audio/die/sb_menghuo.mp3", + "audio/die/sb_pangtong.mp3", + "audio/die/sb_sp_zhugeliang.mp3", + "audio/die/sb_sunce.mp3", + "audio/die/sb_sunquan.mp3", + "audio/die/sb_sunshangxiang.mp3", + "audio/die/sb_xiahoushi.mp3", + "audio/die/sb_xiaoqiao.mp3", + "audio/die/sb_xuhuang.mp3", + "audio/die/sb_xunyu.mp3", + "audio/die/sb_yl_luzhi.mp3", + "audio/die/sb_yuanshao.mp3", + "audio/die/sb_yujin.mp3", + "audio/die/sb_zhangfei.mp3", + "audio/die/sb_zhanghe.mp3", + "audio/die/sb_zhangjiao.mp3", + "audio/die/sb_zhaoyun.mp3", + "audio/die/sb_zhenji.mp3", + "audio/die/sb_zhouyu.mp3", + "audio/die/sb_zhugeliang.mp3", + "audio/die/sb_zhurong.mp3", + "audio/die/shamoke.mp3", + "audio/die/shen_caocao.mp3", + "audio/die/shen_caopi.mp3", + "audio/die/shen_dengai.mp3", + "audio/die/shen_dianwei.mp3", + "audio/die/shen_diaochan.mp3", + "audio/die/shen_ganning.mp3", + "audio/die/shen_guanyu.mp3", + "audio/die/shen_guojia.mp3", + "audio/die/shen_huatuo.mp3", + "audio/die/shen_jiangwei.mp3", + "audio/die/shen_liubei.mp3", + "audio/die/shen_lusu.mp3", + "audio/die/shen_luxun.mp3", + "audio/die/shen_lvbu.mp3", + "audio/die/shen_lvbu1.mp3", + "audio/die/shen_lvbu2.mp3", + "audio/die/shen_lvmeng.mp3", + "audio/die/shen_machao.mp3", + "audio/die/shen_simayi.mp3", + "audio/die/shen_sunce.mp3", + "audio/die/shen_sunquan.mp3", + "audio/die/shen_taishici.mp3", + "audio/die/shen_xunyu.mp3", + "audio/die/shen_xuzhu.mp3", + "audio/die/shen_zhangfei.mp3", + "audio/die/shen_zhangjiao.mp3", + "audio/die/shen_zhangliao.mp3", + "audio/die/shen_zhaoyun.mp3", + "audio/die/shen_zhenji.mp3", + "audio/die/shen_zhouyu.mp3", + "audio/die/shen_zhugeliang.mp3", + "audio/die/shenpei.mp3", + "audio/die/shibao.mp3", + "audio/die/shichangshi.mp3", + "audio/die/shichangshiRest.mp3", + "audio/die/shixie.mp3", + "audio/die/shiyi.mp3", + "audio/die/simafu.mp3", + "audio/die/simahui.mp3", + "audio/die/simalang.mp3", + "audio/die/simashi.mp3", + "audio/die/simayi.mp3", + "audio/die/simazhao.mp3", + "audio/die/simazhou.mp3", + "audio/die/sp_bianfuren.mp3", + "audio/die/sp_caiwenji.mp3", + "audio/die/sp_caohong.mp3", + "audio/die/sp_caoren.mp3", + "audio/die/sp_caosong.mp3", + "audio/die/sp_chendong.mp3", + "audio/die/sp_chenzhen.mp3", + "audio/die/sp_cuiyan.mp3", + "audio/die/sp_dongzhuo.mp3", + "audio/die/sp_duyu.mp3", + "audio/die/sp_gaolan.mp3", + "audio/die/sp_guanyu.mp3", + "audio/die/sp_huaman.mp3", + "audio/die/sp_huangfusong.mp3", + "audio/die/sp_huaxin.mp3", + "audio/die/sp_jianggan.mp3", + "audio/die/sp_jiangqing.mp3", + "audio/die/sp_jiangwan.mp3", + "audio/die/sp_jiangwei.mp3", + "audio/die/sp_jiaxu.mp3", + "audio/die/sp_key_kanade.mp3", + "audio/die/sp_kongrong.mp3", + "audio/die/sp_lvfan.mp3", + "audio/die/sp_machao.mp3", + "audio/die/sp_maojie.mp3", + "audio/die/sp_menghuo.mp3", + "audio/die/sp_mifangfushiren.mp3", + "audio/die/sp_mifuren.mp3", + "audio/die/sp_ol_zhanghe.mp3", + "audio/die/sp_pangde.mp3", + "audio/die/sp_pangtong.mp3", + "audio/die/sp_pengyang.mp3", + "audio/die/sp_shenpei.mp3", + "audio/die/sp_sufei.mp3", + "audio/die/sp_sunshangxiang.mp3", + "audio/die/sp_sunshao.mp3", + "audio/die/sp_taishici.mp3", + "audio/die/sp_wangcan.mp3", + "audio/die/sp_wangshuang.mp3", + "audio/die/sp_wenpin.mp3", + "audio/die/sp_xiahoudun.mp3", + "audio/die/sp_xinpi.mp3", + "audio/die/sp_xujing.mp3", + "audio/die/sp_xunchen.mp3", + "audio/die/sp_xusheng.mp3", + "audio/die/sp_xuyou.mp3", + "audio/die/sp_yanghu.mp3", + "audio/die/sp_yangwan.mp3", + "audio/die/sp_yuji.mp3", + "audio/die/sp_zhangchangpu.mp3", + "audio/die/sp_zhanghe.mp3", + "audio/die/sp_zhangliao.mp3", + "audio/die/sp_zhangwen.mp3", + "audio/die/sp_zhugeliang.mp3", + "audio/die/sp_zhujun.mp3", + "audio/die/sp_zongyu.mp3", + "audio/die/st_xushu.mp3", + "audio/die/st_yuanshu.mp3", + "audio/die/star_caoren.mp3", + "audio/die/star_dongzhuo.mp3", + "audio/die/star_yuanshao.mp3", + "audio/die/star_yuanshu.mp3", + "audio/die/sufei.mp3", + "audio/die/sunce.mp3", + "audio/die/sundeng.mp3", + "audio/die/sunhanhua.mp3", + "audio/die/sunhao.mp3", + "audio/die/sunhong.mp3", + "audio/die/sunhuan.mp3", + "audio/die/sunjian.mp3", + "audio/die/sunlang.mp3", + "audio/die/sunliang.mp3", + "audio/die/sunlingluan.mp3", + "audio/die/sunluban.mp3", + "audio/die/sunluyu.mp3", + "audio/die/sunqian.mp3", + "audio/die/sunquan.mp3", + "audio/die/sunru.mp3", + "audio/die/sunshangxiang.mp3", + "audio/die/sunshao.mp3", + "audio/die/sunwukong.mp3", + "audio/die/sunxiu.mp3", + "audio/die/sunyi.mp3", + "audio/die/sunyu.mp3", + "audio/die/sunziliufang.mp3", + "audio/die/tadun.mp3", + "audio/die/taishici.mp3", + "audio/die/tangji.mp3", + "audio/die/tangzi.mp3", + "audio/die/taoqian.mp3", + "audio/die/taoshen.mp3", + "audio/die/tengfanglan.mp3", + "audio/die/tenggongzhu.mp3", + "audio/die/tengyin.mp3", + "audio/die/tianchou.mp3", + "audio/die/tianfeng.mp3", + "audio/die/tianshangyi.mp3", + "audio/die/tianyu.mp3", + "audio/die/tongyuan.mp3", + "audio/die/tw_baoxin.mp3", + "audio/die/tw_beimihu.mp3", + "audio/die/tw_bingyuan.mp3", + "audio/die/tw_caocao.mp3", + "audio/die/tw_caozhao.mp3", + "audio/die/tw_chenzhen.mp3", + "audio/die/tw_dongzhao.mp3", + "audio/die/tw_fengxí.mp3", + "audio/die/tw_gexuan.mp3", + "audio/die/tw_gongsunfan.mp3", + "audio/die/tw_haomeng.mp3", + "audio/die/tw_huchuquan.mp3", + "audio/die/tw_huojun.mp3", + "audio/die/tw_jiangji.mp3", + "audio/die/tw_jiangwei.mp3", + "audio/die/tw_jianshuo.mp3", + "audio/die/tw_liubei.mp3", + "audio/die/tw_liufuren.mp3", + "audio/die/tw_liuhong.mp3", + "audio/die/tw_liwei.mp3", + "audio/die/tw_mateng.mp3", + "audio/die/tw_niufudongxie.mp3", + "audio/die/tw_puyangxing.mp3", + "audio/die/tw_qiaorui.mp3", + "audio/die/tw_shen_guanyu.mp3", + "audio/die/tw_shen_lvmeng.mp3", + "audio/die/tw_tianyu.mp3", + "audio/die/tw_wangcan.mp3", + "audio/die/tw_wangchang.mp3", + "audio/die/tw_weixu.mp3", + "audio/die/tw_xiahouen.mp3", + "audio/die/tw_xiahoushang.mp3", + "audio/die/tw_yangang.mp3", + "audio/die/tw_yanxiang.mp3", + "audio/die/tw_yufuluo.mp3", + "audio/die/tw_yujin.mp3", + "audio/die/tw_zhanghong.mp3", + "audio/die/tw_zhangji.mp3", + "audio/die/tw_zhangnan.mp3", + "audio/die/tw_zhangning.mp3", + "audio/die/tw_zhangzhao.mp3", + "audio/die/vtb_xiaojiu.mp3", + "audio/die/vtb_xiaole.mp3", + "audio/die/vtb_xiaosha.mp3", + "audio/die/vtb_xiaoshan.mp3", + "audio/die/vtb_xiaotao.mp3", + "audio/die/wangcan.mp3", + "audio/die/wangfuzhaolei.mp3", + "audio/die/wangguan.mp3", + "audio/die/wangji.mp3", + "audio/die/wangjun.mp3", + "audio/die/wanglang.mp3", + "audio/die/wanglie.mp3", + "audio/die/wangling.mp3", + "audio/die/wangping.mp3", + "audio/die/wangrong.mp3", + "audio/die/wangshuang.mp3", + "audio/die/wangtao.mp3", + "audio/die/wangwei.mp3", + "audio/die/wangxiang.mp3", + "audio/die/wangyan.mp3", + "audio/die/wangyi.mp3", + "audio/die/wangyuanji.mp3", + "audio/die/wangyue.mp3", + "audio/die/wangyun.mp3", + "audio/die/wanniangongzhu.mp3", + "audio/die/weiguan.mp3", + "audio/die/weiwenzhugezhi.mp3", + "audio/die/weiyan.mp3", + "audio/die/weizi.mp3", + "audio/die/wenpin.mp3", + "audio/die/wenyang.mp3", + "audio/die/wis_huaxiong.mp3", + "audio/die/wis_jiangwan.mp3", + "audio/die/wis_jiangwei.mp3", + "audio/die/wis_shuijing.mp3", + "audio/die/wis_sunce.mp3", + "audio/die/wis_tianfeng.mp3", + "audio/die/wis_xuyou.mp3", + "audio/die/wis_zhangzhao.mp3", + "audio/die/wolongfengchu.mp3", + "audio/die/wu_luxun.mp3", + "audio/die/wu_zhugeliang.mp3", + "audio/die/wu_zhutiexiong.mp3", + "audio/die/wuanguo.mp3", + "audio/die/wuban.mp3", + "audio/die/wufan.mp3", + "audio/die/wuguotai.mp3", + "audio/die/wujing.mp3", + "audio/die/wulan.mp3", + "audio/die/wutugu.mp3", + "audio/die/wuxian.mp3", + "audio/die/wuyan.mp3", + "audio/die/wuyi.mp3", + "audio/die/xf_yiji.mp3", + "audio/die/xia_dianwei.mp3", + "audio/die/xia_liubei.mp3", + "audio/die/xia_liyàn.mp3", + "audio/die/xia_lusu.mp3", + "audio/die/xia_tongyuan.mp3", + "audio/die/xia_wangyue.mp3", + "audio/die/xia_xiahoudun.mp3", + "audio/die/xia_xiahousone.mp3", + "audio/die/xia_xiahouzie.mp3", + "audio/die/xia_xushu.mp3", + "audio/die/xia_zhangwei.mp3", + "audio/die/xia_zhaoe.mp3", + "audio/die/xiahouba.mp3", + "audio/die/xiahoudun.mp3", + "audio/die/xiahoujie.mp3", + "audio/die/xiahoujuan.mp3", + "audio/die/xiahoulingnv.mp3", + "audio/die/xiahoumao.mp3", + "audio/die/xiahoushi.mp3", + "audio/die/xiahouxuan.mp3", + "audio/die/xiahouyuan.mp3", + "audio/die/xiangchong.mp3", + "audio/die/xianglang.mp3", + "audio/die/xiangrang.mp3", + "audio/die/xiaoqiao.mp3", + "audio/die/xiaoyuehankehan.mp3", + "audio/die/xielingyu.mp3", + "audio/die/xin_caifuren.mp3", + "audio/die/xin_caoxiu.mp3", + "audio/die/xin_caozhang.mp3", + "audio/die/xin_caozhen.mp3", + "audio/die/xin_chengpu.mp3", + "audio/die/xin_fazheng.mp3", + "audio/die/xin_fuhuanghou.mp3", + "audio/die/xin_gaoshun.mp3", + "audio/die/xin_gongsunzan.mp3", + "audio/die/xin_guohuai.mp3", + "audio/die/xin_guozhao.mp3", + "audio/die/xin_guyong.mp3", + "audio/die/xin_handang.mp3", + "audio/die/xin_hansui.mp3", + "audio/die/xin_jianyong.mp3", + "audio/die/xin_jushou.mp3", + "audio/die/xin_liaohua.mp3", + "audio/die/xin_lingtong.mp3", + "audio/die/xin_liubiao.mp3", + "audio/die/xin_mamidi.mp3", + "audio/die/xin_panzhangmazhong.mp3", + "audio/die/xin_quancong.mp3", + "audio/die/xin_sunluban.mp3", + "audio/die/xin_sunxiu.mp3", + "audio/die/xin_wuguotai.mp3", + "audio/die/xin_wuyi.mp3", + "audio/die/xin_xusheng.mp3", + "audio/die/xin_xushu.mp3", + "audio/die/xin_yuanshao.mp3", + "audio/die/xin_yufan.mp3", + "audio/die/xin_yuji.mp3", + "audio/die/xin_zhangyi.mp3", + "audio/die/xin_zhonghui.mp3", + "audio/die/xin_zhuhuan.mp3", + "audio/die/xin_zhuran.mp3", + "audio/die/xin_zhuzhi.mp3", + "audio/die/xinchang.mp3", + "audio/die/xinfu_yuji.mp3", + "audio/die/xingdaorong.mp3", + "audio/die/xinpi.mp3", + "audio/die/xinping.mp3", + "audio/die/xinxianying.mp3", + "audio/die/xinzhongyong.mp3", + "audio/die/xizheng.mp3", + "audio/die/xizhicai.mp3", + "audio/die/xuangongzhu.mp3", + "audio/die/xuelingyun.mp3", + "audio/die/xuezong.mp3", + "audio/die/xugong.mp3", + "audio/die/xuhuang.mp3", + "audio/die/xujing.mp3", + "audio/die/xunchen.mp3", + "audio/die/xunyou.mp3", + "audio/die/xunyu.mp3", + "audio/die/xurong.mp3", + "audio/die/xushao.mp3", + "audio/die/xusheng.mp3", + "audio/die/xushi.mp3", + "audio/die/xushu.mp3", + "audio/die/xuyou.mp3", + "audio/die/xuzhu.mp3", + "audio/die/yanbaihu.mp3", + "audio/die/yanfuren.mp3", + "audio/die/yangbiao.mp3", + "audio/die/yangfu.mp3", + "audio/die/yanghong.mp3", + "audio/die/yanghuiyu.mp3", + "audio/die/yangwan.mp3", + "audio/die/yangxiu.mp3", + "audio/die/yangyan.mp3", + "audio/die/yangyi.mp3", + "audio/die/yangzhi.mp3", + "audio/die/yanjun.mp3", + "audio/die/yanpu.mp3", + "audio/die/yanrou.mp3", + "audio/die/yanwen.mp3", + "audio/die/yanyan.mp3", + "audio/die/yinfuren.mp3", + "audio/die/yitianjian.mp3", + "audio/die/yj_ganning.mp3", + "audio/die/yj_huangzhong.mp3", + "audio/die/yj_jushou.mp3", + "audio/die/yj_qiaozhou.mp3", + "audio/die/yj_sufei.mp3", + "audio/die/yj_weiyan.mp3", + "audio/die/yj_xuhuang.mp3", + "audio/die/yj_zhanghe.mp3", + "audio/die/yj_zhangliao.mp3", + "audio/die/yj_zhoubuyi.mp3", + "audio/die/yl_luzhi.mp3", + "audio/die/yl_yuanshu.mp3", + "audio/die/yuanhuan.mp3", + "audio/die/yuanji.mp3", + "audio/die/yuanshao.mp3", + "audio/die/yuanshu.mp3", + "audio/die/yuantanyuanshang.mp3", + "audio/die/yuantanyuanxiyuanshang.mp3", + "audio/die/yue_caiwenji.mp3", + "audio/die/yue_daqiao.mp3", + "audio/die/yue_xiaoqiao.mp3", + "audio/die/yue_zhoufei.mp3", + "audio/die/yuechen.mp3", + "audio/die/yuejin.mp3", + "audio/die/yuejiu.mp3", + "audio/die/yufan.mp3", + "audio/die/yuji.mp3", + "audio/die/yujin.mp3", + "audio/die/yujin_yujin.mp3", + "audio/die/zangba.mp3", + "audio/die/zerong.mp3", + "audio/die/zhangbao.mp3", + "audio/die/zhangchangpu.mp3", + "audio/die/zhangchu.mp3", + "audio/die/zhangchunhua.mp3", + "audio/die/zhangfei.mp3", + "audio/die/zhangfen.mp3", + "audio/die/zhanggong.mp3", + "audio/die/zhanggongqi.mp3", + "audio/die/zhanghe.mp3", + "audio/die/zhangheng.mp3", + "audio/die/zhanghu.mp3", + "audio/die/zhanghua.mp3", + "audio/die/zhanghuyuechen.mp3", + "audio/die/zhangji.mp3", + "audio/die/zhangjiao.mp3", + "audio/die/zhangjinyun.mp3", + "audio/die/zhangjunyi.mp3", + "audio/die/zhangkai.mp3", + "audio/die/zhangliao.mp3", + "audio/die/zhangling.mp3", + "audio/die/zhanglu.mp3", + "audio/die/zhangmancheng.mp3", + "audio/die/zhangmiao.mp3", + "audio/die/zhangning.mp3", + "audio/die/zhangqiying.mp3", + "audio/die/zhangrang.mp3", + "audio/die/zhangren.mp3", + "audio/die/zhangshiping.mp3", + "audio/die/zhangsong.mp3", + "audio/die/zhangwen.mp3", + "audio/die/zhangxingcai.mp3", + "audio/die/zhangxiu.mp3", + "audio/die/zhangxuan.mp3", + "audio/die/zhangxun.mp3", + "audio/die/zhangyan.mp3", + "audio/die/zhangyao.mp3", + "audio/die/zhangyi.mp3", + "audio/die/zhangyì.mp3", + "audio/die/zhangzhang.mp3", + "audio/die/zhangzhi.mp3", + "audio/die/zhangzhongjing.mp3", + "audio/die/zhaoang.mp3", + "audio/die/zhaotongzhaoguang.mp3", + "audio/die/zhaoxiang.mp3", + "audio/die/zhaoyan.mp3", + "audio/die/zhaoyǎn.mp3", + "audio/die/zhaoyun.mp3", + "audio/die/zhaozhi.mp3", + "audio/die/zhaozhong.mp3", + "audio/die/zhenghun.mp3", + "audio/die/zhengxuan.mp3", + "audio/die/zhenji.mp3", + "audio/die/zhiling.mp3", + "audio/die/zhonghui.mp3", + "audio/die/zhongshiji.mp3", + "audio/die/zhongyan.mp3", + "audio/die/zhongyao.mp3", + "audio/die/zhoubuyi.mp3", + "audio/die/zhoucang.mp3", + "audio/die/zhouchu.mp3", + "audio/die/zhoufang.mp3", + "audio/die/zhoufei.mp3", + "audio/die/zhouqun.mp3", + "audio/die/zhoushan.mp3", + "audio/die/zhoutai.mp3", + "audio/die/zhouyi.mp3", + "audio/die/zhouyu.mp3", + "audio/die/zhugedan.mp3", + "audio/die/zhugeguo.mp3", + "audio/die/zhugejin.mp3", + "audio/die/zhugeke.mp3", + "audio/die/zhugeliang.mp3", + "audio/die/zhugemengxue.mp3", + "audio/die/zhugeruoxue.mp3", + "audio/die/zhugeshang.mp3", + "audio/die/zhugezhan.mp3", + "audio/die/zhuhuan.mp3", + "audio/die/zhujianping.mp3", + "audio/die/zhujun.mp3", + "audio/die/zhuling.mp3", + "audio/die/zhuran.mp3", + "audio/die/zhurong.mp3", + "audio/die/zhutiexiong.mp3", + "audio/die/zhuzhi.mp3", + "audio/die/zongyu.mp3", + "audio/die/zoushi.mp3", + "audio/die/zumao.mp3", + "audio/die/zuoci.mp3", + "audio/die/zuofen.mp3", + /*effect audio end*/ + + /*skill audio begin*/ + "audio/skill/abyusa_dunying1.mp3", + "audio/skill/abyusa_dunying2.mp3", + "audio/skill/abyusa_jueqing1.mp3", + "audio/skill/abyusa_jueqing2.mp3", + "audio/skill/aichen1.mp3", + "audio/skill/aichen2.mp3", + "audio/skill/anguo1.mp3", + "audio/skill/anguo2.mp3", + "audio/skill/anjian1.mp3", + "audio/skill/anjian2.mp3", + "audio/skill/anxian1.mp3", + "audio/skill/anxian2.mp3", + "audio/skill/anxu1.mp3", + "audio/skill/anxu2.mp3", + "audio/skill/anyong1.mp3", + "audio/skill/anyong2.mp3", + "audio/skill/aocai_gz_zhugeke1.mp3", + "audio/skill/aocai_gz_zhugeke2.mp3", + "audio/skill/aocai1.mp3", + "audio/skill/aocai2.mp3", + "audio/skill/bagua_skill.mp3", + "audio/skill/baijia_tw_beimihu1.mp3", + "audio/skill/baijia_tw_beimihu2.mp3", + "audio/skill/baijia1.mp3", + "audio/skill/baijia2.mp3", + "audio/skill/baiyi1.mp3", + "audio/skill/baiyi2.mp3", + "audio/skill/baiyin_skill.mp3", + "audio/skill/baoling1.mp3", + "audio/skill/baoling2.mp3", + "audio/skill/baonu1.mp3", + "audio/skill/baonu2.mp3", + "audio/skill/baonue2_re_dongzhuo1.mp3", + "audio/skill/baonue2_re_dongzhuo2.mp3", + "audio/skill/baonue21.mp3", + "audio/skill/baonue22.mp3", + "audio/skill/baoqie1.mp3", + "audio/skill/baoqie2.mp3", + "audio/skill/baoshu1.mp3", + "audio/skill/baoshu2.mp3", + "audio/skill/bazhan1.mp3", + "audio/skill/bazhan2.mp3", + "audio/skill/bazhen_ol_pangtong1.mp3", + "audio/skill/bazhen_ol_pangtong2.mp3", + "audio/skill/bazhen_ol_sp_zhugeliang1.mp3", + "audio/skill/bazhen_ol_sp_zhugeliang2.mp3", + "audio/skill/bazhen_re_sp_zhugeliang1.mp3", + "audio/skill/bazhen_re_sp_zhugeliang2.mp3", + "audio/skill/bazhen1.mp3", + "audio/skill/bazhen2.mp3", + "audio/skill/beige_ol_caiwenji1.mp3", + "audio/skill/beige_ol_caiwenji2.mp3", + "audio/skill/beige_re_caiwenji1.mp3", + "audio/skill/beige_re_caiwenji2.mp3", + "audio/skill/beige1.mp3", + "audio/skill/beige2.mp3", + "audio/skill/beini1.mp3", + "audio/skill/beini2.mp3", + "audio/skill/beishui1.mp3", + "audio/skill/beishui2.mp3", + "audio/skill/beizhan1.mp3", + "audio/skill/beizhan2.mp3", + "audio/skill/beizhu1.mp3", + "audio/skill/beizhu2.mp3", + "audio/skill/beizhu3.mp3", + "audio/skill/benghuai_ol_dongzhuo1.mp3", + "audio/skill/benghuai_ol_dongzhuo2.mp3", + "audio/skill/benghuai_re_dongzhuo1.mp3", + "audio/skill/benghuai_re_dongzhuo2.mp3", + "audio/skill/benghuai_zhugedan1.mp3", + "audio/skill/benghuai_zhugedan2.mp3", + "audio/skill/benghuai1.mp3", + "audio/skill/benghuai2.mp3", + "audio/skill/benxi1.mp3", + "audio/skill/benxi2.mp3", + "audio/skill/benyu1.mp3", + "audio/skill/benyu2.mp3", + "audio/skill/biaozhao1.mp3", + "audio/skill/biaozhao2.mp3", + "audio/skill/biejun1.mp3", + "audio/skill/biejun2.mp3", + "audio/skill/bifa1.mp3", + "audio/skill/bifa2.mp3", + "audio/skill/bihuo1.mp3", + "audio/skill/bihuo2.mp3", + "audio/skill/biluan1.mp3", + "audio/skill/biluan2.mp3", + "audio/skill/binghuo1.mp3", + "audio/skill/binghuo2.mp3", + "audio/skill/bingjie1.mp3", + "audio/skill/bingjie2.mp3", + "audio/skill/binglun1.mp3", + "audio/skill/binglun2.mp3", + "audio/skill/bingqing1.mp3", + "audio/skill/bingqing2.mp3", + "audio/skill/bingxin1.mp3", + "audio/skill/bingxin2.mp3", + "audio/skill/bingyi_xin_guyong1.mp3", + "audio/skill/bingyi_xin_guyong2.mp3", + "audio/skill/bingyi1.mp3", + "audio/skill/bingyi2.mp3", + "audio/skill/bingzheng1.mp3", + "audio/skill/bingzheng2.mp3", + "audio/skill/bixiong1.mp3", + "audio/skill/bixiong2.mp3", + "audio/skill/biyue1.mp3", + "audio/skill/biyue2.mp3", + "audio/skill/bizheng1.mp3", + "audio/skill/bizheng2.mp3", + "audio/skill/bizhuan1.mp3", + "audio/skill/bizhuan2.mp3", + "audio/skill/bmcanshi_tw_beimihu1.mp3", + "audio/skill/bmcanshi_tw_beimihu2.mp3", + "audio/skill/bmcanshi1.mp3", + "audio/skill/bmcanshi2.mp3", + "audio/skill/bolan1.mp3", + "audio/skill/bolan2.mp3", + "audio/skill/boming1.mp3", + "audio/skill/boming2.mp3", + "audio/skill/boss_baolin.mp3", + "audio/skill/boss_baonu1.mp3", + "audio/skill/boss_baonu2.mp3", + "audio/skill/boss_biantianx1.mp3", + "audio/skill/boss_biantianx2.mp3", + "audio/skill/boss_bufo.mp3", + "audio/skill/boss_chiying1.mp3", + "audio/skill/boss_chiying2.mp3", + "audio/skill/boss_chuanyun.mp3", + "audio/skill/boss_dayuan.mp3", + "audio/skill/boss_diting.mp3", + "audio/skill/boss_fanshi.mp3", + "audio/skill/boss_fengxing.mp3", + "audio/skill/boss_gongshenjg1.mp3", + "audio/skill/boss_gongshenjg2.mp3", + "audio/skill/boss_guihan1.mp3", + "audio/skill/boss_guihan2.mp3", + "audio/skill/boss_honglian1.mp3", + "audio/skill/boss_honglian2.mp3", + "audio/skill/boss_hujia1.mp3", + "audio/skill/boss_hujia2.mp3", + "audio/skill/boss_huodi1.mp3", + "audio/skill/boss_huodi2.mp3", + "audio/skill/boss_jingmiao1.mp3", + "audio/skill/boss_jingmiao2.mp3", + "audio/skill/boss_jizhen1.mp3", + "audio/skill/boss_jizhen2.mp3", + "audio/skill/boss_jizhi1.mp3", + "audio/skill/boss_jizhi2.mp3", + "audio/skill/boss_jueji1.mp3", + "audio/skill/boss_jueji2.mp3", + "audio/skill/boss_leiji1.mp3", + "audio/skill/boss_leiji2.mp3", + "audio/skill/boss_leili1.mp3", + "audio/skill/boss_leili2.mp3", + "audio/skill/boss_lingfeng1.mp3", + "audio/skill/boss_lingfeng2.mp3", + "audio/skill/boss_qiangzheng1.mp3", + "audio/skill/boss_qiangzheng2.mp3", + "audio/skill/boss_qiwu.mp3", + "audio/skill/boss_shengshou.mp3", + "audio/skill/boss_shiyou.mp3", + "audio/skill/boss_skonghun.mp3", + "audio/skill/boss_tianyu.mp3", + "audio/skill/boss_tianyujg.mp3", + "audio/skill/boss_wanghun.mp3", + "audio/skill/boss_wangshi.mp3", + "audio/skill/boss_wuliang.mp3", + "audio/skill/boss_wuxin1.mp3", + "audio/skill/boss_wuxin2.mp3", + "audio/skill/boss_xianyin1.mp3", + "audio/skill/boss_xianyin2.mp3", + "audio/skill/boss_xuanlei.mp3", + "audio/skill/boss_yuhuojg.mp3", + "audio/skill/boss_zhinang1.mp3", + "audio/skill/boss_zhinang2.mp3", + "audio/skill/botu1.mp3", + "audio/skill/botu2.mp3", + "audio/skill/boyan1.mp3", + "audio/skill/boyan2.mp3", + "audio/skill/buchen1.mp3", + "audio/skill/buchen2.mp3", + "audio/skill/buqi1.mp3", + "audio/skill/buqi2.mp3", + "audio/skill/buqu1.mp3", + "audio/skill/buqu2.mp3", + "audio/skill/bushi1.mp3", + "audio/skill/bushi2.mp3", + "audio/skill/busuan1.mp3", + "audio/skill/busuan2.mp3", + "audio/skill/buxu1.mp3", + "audio/skill/buxu2.mp3", + "audio/skill/buyi_re_wuguotai1.mp3", + "audio/skill/buyi_re_wuguotai2.mp3", + "audio/skill/buyi1.mp3", + "audio/skill/buyi2.mp3", + "audio/skill/caishi1.mp3", + "audio/skill/caishi2.mp3", + "audio/skill/caiwang1.mp3", + "audio/skill/caiwang2.mp3", + "audio/skill/caiyi1.mp3", + "audio/skill/caiyi2.mp3", + "audio/skill/caiyuan1.mp3", + "audio/skill/caiyuan2.mp3", + "audio/skill/caizhaoji_hujia.mp3", + "audio/skill/cangchu1.mp3", + "audio/skill/cangchu2.mp3", + "audio/skill/cangji.mp3", + "audio/skill/cangzhuo1.mp3", + "audio/skill/cangzhuo2.mp3", + "audio/skill/canmou1.mp3", + "audio/skill/canmou2.mp3", + "audio/skill/canshi1.mp3", + "audio/skill/canshi2.mp3", + "audio/skill/caozhao1.mp3", + "audio/skill/caozhao2.mp3", + "audio/skill/changbiao1.mp3", + "audio/skill/changbiao2.mp3", + "audio/skill/chanhui1.mp3", + "audio/skill/chanhui2.mp3", + "audio/skill/channi1.mp3", + "audio/skill/channi2.mp3", + "audio/skill/chanyuan1.mp3", + "audio/skill/chanyuan2.mp3", + "audio/skill/chaofeng1.mp3", + "audio/skill/chaofeng2.mp3", + "audio/skill/chenggong1.mp3", + "audio/skill/chenggong2.mp3", + "audio/skill/chengshang1.mp3", + "audio/skill/chengshang2.mp3", + "audio/skill/chengwu1.mp3", + "audio/skill/chengwu2.mp3", + "audio/skill/chengxiang1.mp3", + "audio/skill/chengxiang2.mp3", + "audio/skill/chengye1.mp3", + "audio/skill/chengye2.mp3", + "audio/skill/chengye3.mp3", + "audio/skill/chengzhang1.mp3", + "audio/skill/chengzhang2.mp3", + "audio/skill/chengzhao1.mp3", + "audio/skill/chengzhao2.mp3", + "audio/skill/chenjian1.mp3", + "audio/skill/chenjian2.mp3", + "audio/skill/chenjie1.mp3", + "audio/skill/chenjie2.mp3", + "audio/skill/chenqing1.mp3", + "audio/skill/chenqing2.mp3", + "audio/skill/chexuan1.mp3", + "audio/skill/chexuan2.mp3", + "audio/skill/chijie.mp3", + "audio/skill/chizhong1.mp3", + "audio/skill/chizhong2.mp3", + "audio/skill/chongxin1.mp3", + "audio/skill/chongxin2.mp3", + "audio/skill/chongxu1.mp3", + "audio/skill/chongxu2.mp3", + "audio/skill/chongzhen1.mp3", + "audio/skill/chongzhen2.mp3", + "audio/skill/chouce1.mp3", + "audio/skill/chouce2.mp3", + "audio/skill/choufa1.mp3", + "audio/skill/choufa2.mp3", + "audio/skill/chouhai1.mp3", + "audio/skill/chouhai2.mp3", + "audio/skill/choujue1.mp3", + "audio/skill/choujue2.mp3", + "audio/skill/chouliang.mp3", + "audio/skill/choulve1.mp3", + "audio/skill/choulve2.mp3", + "audio/skill/choutao1.mp3", + "audio/skill/choutao2.mp3", + "audio/skill/chuaili1.mp3", + "audio/skill/chuaili2.mp3", + "audio/skill/chuanshu1.mp3", + "audio/skill/chuanshu2.mp3", + "audio/skill/chuanxin1.mp3", + "audio/skill/chuanxin2.mp3", + "audio/skill/chuanyun.mp3", + "audio/skill/chuhai1.mp3", + "audio/skill/chuhai2.mp3", + "audio/skill/chuhai3.mp3", + "audio/skill/chuiti1.mp3", + "audio/skill/chuiti2.mp3", + "audio/skill/chulao1.mp3", + "audio/skill/chulao2.mp3", + "audio/skill/chunlao_xin_chengpu1.mp3", + "audio/skill/chunlao_xin_chengpu2.mp3", + "audio/skill/chunlao1.mp3", + "audio/skill/chunlao2.mp3", + "audio/skill/chuyuan1.mp3", + "audio/skill/chuyuan2.mp3", + "audio/skill/cibei1.mp3", + "audio/skill/cibei2.mp3", + "audio/skill/cihuang1.mp3", + "audio/skill/cihuang2.mp3", + "audio/skill/ciwei1.mp3", + "audio/skill/ciwei2.mp3", + "audio/skill/cixiao1.mp3", + "audio/skill/cixiao2.mp3", + "audio/skill/cixiong_skill.mp3", + "audio/skill/clanbaichu1.mp3", + "audio/skill/clanbaichu2.mp3", + "audio/skill/clanbalong1.mp3", + "audio/skill/clanbalong2.mp3", + "audio/skill/clanbaozu_clan_zhonghui1.mp3", + "audio/skill/clanbaozu_clan_zhonghui2.mp3", + "audio/skill/clanbaozu_clan_zhongyan1.mp3", + "audio/skill/clanbaozu_clan_zhongyan2.mp3", + "audio/skill/clanbaozu_clan_zhongyu1.mp3", + "audio/skill/clanbaozu_clan_zhongyu2.mp3", + "audio/skill/clanbeishi1.mp3", + "audio/skill/clanbeishi2.mp3", + "audio/skill/clanbolong1.mp3", + "audio/skill/clanbolong2.mp3", + "audio/skill/clanchenya1.mp3", + "audio/skill/clanchenya2.mp3", + "audio/skill/clandaojie_clan_xuncai1.mp3", + "audio/skill/clandaojie_clan_xuncai2.mp3", + "audio/skill/clandaojie_clan_xuncan1.mp3", + "audio/skill/clandaojie_clan_xuncan2.mp3", + "audio/skill/clandaojie_clan_xunchen1.mp3", + "audio/skill/clandaojie_clan_xunchen2.mp3", + "audio/skill/clandaojie_clan_xunshu1.mp3", + "audio/skill/clandaojie_clan_xunshu2.mp3", + "audio/skill/clandaojie_clan_xunyou1.mp3", + "audio/skill/clandaojie_clan_xunyou2.mp3", + "audio/skill/clandianzhan1.mp3", + "audio/skill/clandianzhan2.mp3", + "audio/skill/clanfangzhen1.mp3", + "audio/skill/clanfangzhen2.mp3", + "audio/skill/clanfenchai1.mp3", + "audio/skill/clanfenchai2.mp3", + "audio/skill/clanfuxun1.mp3", + "audio/skill/clanfuxun2.mp3", + "audio/skill/clanguangu1.mp3", + "audio/skill/clanguangu2.mp3", + "audio/skill/clanguixiang1.mp3", + "audio/skill/clanguixiang2.mp3", + "audio/skill/clanhuanghan1.mp3", + "audio/skill/clanhuanghan2.mp3", + "audio/skill/clanhuanjia1.mp3", + "audio/skill/clanhuanjia2.mp3", + "audio/skill/clanhuanyin1.mp3", + "audio/skill/clanhuanyin2.mp3", + "audio/skill/clanjianyuan1.mp3", + "audio/skill/clanjianyuan2.mp3", + "audio/skill/clanjiejian1.mp3", + "audio/skill/clanjiejian2.mp3", + "audio/skill/clanjiexuan1.mp3", + "audio/skill/clanjiexuan2.mp3", + "audio/skill/clanlianhe1.mp3", + "audio/skill/clanlianhe2.mp3", + "audio/skill/clanlianzhu1.mp3", + "audio/skill/clanlianzhu2.mp3", + "audio/skill/clanlieshi1.mp3", + "audio/skill/clanlieshi2.mp3", + "audio/skill/clanliuju1.mp3", + "audio/skill/clanliuju2.mp3", + "audio/skill/clanmingjie1.mp3", + "audio/skill/clanmingjie2.mp3", + "audio/skill/clanmuyin_clan_wuban1.mp3", + "audio/skill/clanmuyin_clan_wuban2.mp3", + "audio/skill/clanmuyin_clan_wukuang1.mp3", + "audio/skill/clanmuyin_clan_wukuang2.mp3", + "audio/skill/clanmuyin_clan_wuxian1.mp3", + "audio/skill/clanmuyin_clan_wuxian2.mp3", + "audio/skill/clanqiuxin1.mp3", + "audio/skill/clanqiuxin2.mp3", + "audio/skill/clansankuang1.mp3", + "audio/skill/clansankuang2.mp3", + "audio/skill/clanshangshen1.mp3", + "audio/skill/clanshangshen2.mp3", + "audio/skill/clanshenjun1.mp3", + "audio/skill/clanshenjun2.mp3", + "audio/skill/clanxiaoyong1.mp3", + "audio/skill/clanxiaoyong2.mp3", + "audio/skill/clanxieshu1.mp3", + "audio/skill/clanxieshu2.mp3", + "audio/skill/clanxumin_clan_hanrong1.mp3", + "audio/skill/clanxumin_clan_hanrong2.mp3", + "audio/skill/clanxumin_clan_hanshao1.mp3", + "audio/skill/clanxumin_clan_hanshao2.mp3", + "audio/skill/clanyirong1.mp3", + "audio/skill/clanyirong2.mp3", + "audio/skill/clanyunshen1.mp3", + "audio/skill/clanyunshen2.mp3", + "audio/skill/clanyuzhi1.mp3", + "audio/skill/clanyuzhi2.mp3", + "audio/skill/clanzhanding1.mp3", + "audio/skill/clanzhanding2.mp3", + "audio/skill/clanzhongliu_clan_wanghun1.mp3", + "audio/skill/clanzhongliu_clan_wanghun2.mp3", + "audio/skill/clanzhongliu_clan_wangling1.mp3", + "audio/skill/clanzhongliu_clan_wangling2.mp3", + "audio/skill/clanzhongliu_clan_wanglun1.mp3", + "audio/skill/clanzhongliu_clan_wanglun2.mp3", + "audio/skill/clanzhongliu_clan_wangyun1.mp3", + "audio/skill/clanzhongliu_clan_wangyun2.mp3", + "audio/skill/congjian1.mp3", + "audio/skill/congjian2.mp3", + "audio/skill/cslilu1.mp3", + "audio/skill/cslilu2.mp3", + "audio/skill/csyizheng1.mp3", + "audio/skill/csyizheng2.mp3", + "audio/skill/cuguo1.mp3", + "audio/skill/cuguo2.mp3", + "audio/skill/cuijian1.mp3", + "audio/skill/cuijian2.mp3", + "audio/skill/cuijin1.mp3", + "audio/skill/cuijin2.mp3", + "audio/skill/cuijue1.mp3", + "audio/skill/cuijue2.mp3", + "audio/skill/cunsi1.mp3", + "audio/skill/cunsi2.mp3", + "audio/skill/cuorui1.mp3", + "audio/skill/cuorui2.mp3", + "audio/skill/cxliushi1.mp3", + "audio/skill/cxliushi2.mp3", + "audio/skill/dahe.mp3", + "audio/skill/daiyan1.mp3", + "audio/skill/daiyan2.mp3", + "audio/skill/daming1.mp3", + "audio/skill/daming2.mp3", + "audio/skill/dangmo1.mp3", + "audio/skill/dangmo2.mp3", + "audio/skill/dangxian_guansuo1.mp3", + "audio/skill/dangxian_guansuo2.mp3", + "audio/skill/dangxian_re_liaohua1.mp3", + "audio/skill/dangxian_re_liaohua2.mp3", + "audio/skill/dangxian_xin_liaohua1.mp3", + "audio/skill/dangxian_xin_liaohua2.mp3", + "audio/skill/dangxian1.mp3", + "audio/skill/dangxian2.mp3", + "audio/skill/dangzai1.mp3", + "audio/skill/dangzai2.mp3", + "audio/skill/danji1.mp3", + "audio/skill/danji2.mp3", + "audio/skill/danlao1.mp3", + "audio/skill/danlao2.mp3", + "audio/skill/danshou1.mp3", + "audio/skill/danshou2.mp3", + "audio/skill/danxin1.mp3", + "audio/skill/danxin2.mp3", + "audio/skill/daoji1.mp3", + "audio/skill/daoji2.mp3", + "audio/skill/daoshu1.mp3", + "audio/skill/daoshu2.mp3", + "audio/skill/dawu1.mp3", + "audio/skill/dawu2.mp3", + "audio/skill/dbchongjian1.mp3", + "audio/skill/dbchongjian2.mp3", + "audio/skill/dbchoujue1.mp3", + "audio/skill/dbchoujue2.mp3", + "audio/skill/dbquedi1.mp3", + "audio/skill/dbquedi2.mp3", + "audio/skill/dbzhuifeng1.mp3", + "audio/skill/dbzhuifeng2.mp3", + "audio/skill/dcaichen1.mp3", + "audio/skill/dcaichen2.mp3", + "audio/skill/dcaishou1.mp3", + "audio/skill/dcaishou2.mp3", + "audio/skill/dcanliao1.mp3", + "audio/skill/dcanliao2.mp3", + "audio/skill/dcanxu1.mp3", + "audio/skill/dcanxu2.mp3", + "audio/skill/dcanzhi1.mp3", + "audio/skill/dcanzhi2.mp3", + "audio/skill/dcbeifen1.mp3", + "audio/skill/dcbeifen2.mp3", + "audio/skill/dcbeini1.mp3", + "audio/skill/dcbeini2.mp3", + "audio/skill/dcbenshi1.mp3", + "audio/skill/dcbenshi2.mp3", + "audio/skill/dcbianzhuang1.mp3", + "audio/skill/dcbianzhuang2.mp3", + "audio/skill/dcbihuo1.mp3", + "audio/skill/dcbihuo2.mp3", + "audio/skill/dcbingji1.mp3", + "audio/skill/dcbingji2.mp3", + "audio/skill/dccaisi1.mp3", + "audio/skill/dccaisi2.mp3", + "audio/skill/dccaixia1.mp3", + "audio/skill/dccaixia2.mp3", + "audio/skill/dccaizhuang1.mp3", + "audio/skill/dccaizhuang2.mp3", + "audio/skill/dccansi1.mp3", + "audio/skill/dccansi2.mp3", + "audio/skill/dcchaixie1.mp3", + "audio/skill/dcchaixie2.mp3", + "audio/skill/dcchangqu1.mp3", + "audio/skill/dcchangqu2.mp3", + "audio/skill/dcchanjuan1.mp3", + "audio/skill/dcchanjuan2.mp3", + "audio/skill/dcchenyong1.mp3", + "audio/skill/dcchenyong2.mp3", + "audio/skill/dcchiying1.mp3", + "audio/skill/dcchiying2.mp3", + "audio/skill/dcchongwang1.mp3", + "audio/skill/dcchongwang2.mp3", + "audio/skill/dcchongxu1.mp3", + "audio/skill/dcchongxu2.mp3", + "audio/skill/dcchongyi1.mp3", + "audio/skill/dcchongyi2.mp3", + "audio/skill/dccibei1.mp3", + "audio/skill/dccibei2.mp3", + "audio/skill/dccongshi1.mp3", + "audio/skill/dccongshi2.mp3", + "audio/skill/dcctjiuxian1.mp3", + "audio/skill/dcctjiuxian2.mp3", + "audio/skill/dccuichuan1.mp3", + "audio/skill/dccuichuan2.mp3", + "audio/skill/dccuijin1.mp3", + "audio/skill/dccuijin2.mp3", + "audio/skill/dccuixin1.mp3", + "audio/skill/dccuixin2.mp3", + "audio/skill/dccunwei1.mp3", + "audio/skill/dccunwei2.mp3", + "audio/skill/dcdanyi1.mp3", + "audio/skill/dcdanyi2.mp3", + "audio/skill/dcdanying1.mp3", + "audio/skill/dcdanying2.mp3", + "audio/skill/dcdehua1.mp3", + "audio/skill/dcdehua2.mp3", + "audio/skill/dcdeshao1.mp3", + "audio/skill/dcdeshao2.mp3", + "audio/skill/dcdeshi1.mp3", + "audio/skill/dcdeshi2.mp3", + "audio/skill/dcdingji1.mp3", + "audio/skill/dcdingji2.mp3", + "audio/skill/dcditing1.mp3", + "audio/skill/dcditing2.mp3", + "audio/skill/dcdouzhen1.mp3", + "audio/skill/dcdouzhen2.mp3", + "audio/skill/dcdyqingshi1.mp3", + "audio/skill/dcdyqingshi2.mp3", + "audio/skill/dcenyu1.mp3", + "audio/skill/dcenyu2.mp3", + "audio/skill/dcfangdu1.mp3", + "audio/skill/dcfangdu2.mp3", + "audio/skill/dcfanshi1.mp3", + "audio/skill/dcfanshi2.mp3", + "audio/skill/dcfanyin1.mp3", + "audio/skill/dcfanyin2.mp3", + "audio/skill/dcfaqi1.mp3", + "audio/skill/dcfaqi2.mp3", + "audio/skill/dcfencheng1.mp3", + "audio/skill/dcfencheng2.mp3", + "audio/skill/dcfengyan1.mp3", + "audio/skill/dcfengyan2.mp3", + "audio/skill/dcfengying1.mp3", + "audio/skill/dcfengying2.mp3", + "audio/skill/dcfozong1.mp3", + "audio/skill/dcfozong2.mp3", + "audio/skill/dcfudao1.mp3", + "audio/skill/dcfudao2.mp3", + "audio/skill/dcfudou1.mp3", + "audio/skill/dcfudou2.mp3", + "audio/skill/dcfuli1.mp3", + "audio/skill/dcfuli2.mp3", + "audio/skill/dcfumou1.mp3", + "audio/skill/dcfumou2.mp3", + "audio/skill/dcfuning1.mp3", + "audio/skill/dcfuning2.mp3", + "audio/skill/dcfuxue1.mp3", + "audio/skill/dcfuxue2.mp3", + "audio/skill/dcgeyuan1.mp3", + "audio/skill/dcgeyuan2.mp3", + "audio/skill/dcgonghu1.mp3", + "audio/skill/dcgonghu2.mp3", + "audio/skill/dcguangshi1.mp3", + "audio/skill/dcguangshi2.mp3", + "audio/skill/dcgue1.mp3", + "audio/skill/dcgue2.mp3", + "audio/skill/dcgusuan1.mp3", + "audio/skill/dcgusuan2.mp3", + "audio/skill/dchanying1.mp3", + "audio/skill/dchanying2.mp3", + "audio/skill/dchaochong1.mp3", + "audio/skill/dchaochong2.mp3", + "audio/skill/dchuace1.mp3", + "audio/skill/dchuace2.mp3", + "audio/skill/dchuagui1.mp3", + "audio/skill/dchuagui2.mp3", + "audio/skill/dchuahuo1.mp3", + "audio/skill/dchuahuo2.mp3", + "audio/skill/dchuayi1.mp3", + "audio/skill/dchuayi2.mp3", + "audio/skill/dchuiling1.mp3", + "audio/skill/dchuiling2.mp3", + "audio/skill/dchuishu1.mp3", + "audio/skill/dchuishu2.mp3", + "audio/skill/dchuizhi1.mp3", + "audio/skill/dchuizhi2.mp3", + "audio/skill/dchumei1.mp3", + "audio/skill/dchumei2.mp3", + "audio/skill/dcjianguo1.mp3", + "audio/skill/dcjianguo2.mp3", + "audio/skill/dcjianji1.mp3", + "audio/skill/dcjianji2.mp3", + "audio/skill/dcjianying1.mp3", + "audio/skill/dcjianying2.mp3", + "audio/skill/dcjianzheng1.mp3", + "audio/skill/dcjianzheng2.mp3", + "audio/skill/dcjianzhuan1.mp3", + "audio/skill/dcjianzhuan2.mp3", + "audio/skill/dcjiaofeng1.mp3", + "audio/skill/dcjiaofeng2.mp3", + "audio/skill/dcjiaoxia1.mp3", + "audio/skill/dcjiaoxia2.mp3", + "audio/skill/dcjichun1.mp3", + "audio/skill/dcjichun2.mp3", + "audio/skill/dcjieling1.mp3", + "audio/skill/dcjieling2.mp3", + "audio/skill/dcjieshu1.mp3", + "audio/skill/dcjieshu2.mp3", + "audio/skill/dcjiexing1.mp3", + "audio/skill/dcjiexing2.mp3", + "audio/skill/dcjiezhen1.mp3", + "audio/skill/dcjiezhen2.mp3", + "audio/skill/dcjijiao1.mp3", + "audio/skill/dcjijiao2.mp3", + "audio/skill/dcjincui1.mp3", + "audio/skill/dcjincui2.mp3", + "audio/skill/dcjinggong1.mp3", + "audio/skill/dcjinggong2.mp3", + "audio/skill/dcjingzao1.mp3", + "audio/skill/dcjingzao2.mp3", + "audio/skill/dcjini1.mp3", + "audio/skill/dcjini2.mp3", + "audio/skill/dcjinjian1.mp3", + "audio/skill/dcjinjian2.mp3", + "audio/skill/dcjinjie1.mp3", + "audio/skill/dcjinjie2.mp3", + "audio/skill/dcjinjin1.mp3", + "audio/skill/dcjinjin2.mp3", + "audio/skill/dcjiudun1.mp3", + "audio/skill/dcjiudun2.mp3", + "audio/skill/dcjiushi1.mp3", + "audio/skill/dcjiushi2.mp3", + "audio/skill/dcjizhong1.mp3", + "audio/skill/dcjizhong2.mp3", + "audio/skill/dcjue1.mp3", + "audio/skill/dcjue2.mp3", + "audio/skill/dcjuejing1.mp3", + "audio/skill/dcjuejing2.mp3", + "audio/skill/dcjuying1.mp3", + "audio/skill/dcjuying2.mp3", + "audio/skill/dckaiji1.mp3", + "audio/skill/dckaiji2.mp3", + "audio/skill/dckanji1.mp3", + "audio/skill/dckanji2.mp3", + "audio/skill/dclbjiuxian1.mp3", + "audio/skill/dclbjiuxian2.mp3", + "audio/skill/dcliangxiu1.mp3", + "audio/skill/dcliangxiu2.mp3", + "audio/skill/dclianzhi1.mp3", + "audio/skill/dclianzhi2.mp3", + "audio/skill/dclibang1.mp3", + "audio/skill/dclibang2.mp3", + "audio/skill/dcliehou1.mp3", + "audio/skill/dcliehou2.mp3", + "audio/skill/dcligong1.mp3", + "audio/skill/dcligong2.mp3", + "audio/skill/dclingfang1.mp3", + "audio/skill/dclingfang2.mp3", + "audio/skill/dclinghui1.mp3", + "audio/skill/dclinghui2.mp3", + "audio/skill/dclingkong1.mp3", + "audio/skill/dclingkong2.mp3", + "audio/skill/dclingxi1.mp3", + "audio/skill/dclingxi2.mp3", + "audio/skill/dclingyin1.mp3", + "audio/skill/dclingyin2.mp3", + "audio/skill/dclingyue1.mp3", + "audio/skill/dclingyue2.mp3", + "audio/skill/dcliuzhuan1.mp3", + "audio/skill/dcliuzhuan2.mp3", + "audio/skill/dcliying1.mp3", + "audio/skill/dcliying2.mp3", + "audio/skill/dclonggong1.mp3", + "audio/skill/dclonggong2.mp3", + "audio/skill/dclonghun1.mp3", + "audio/skill/dclonghun2.mp3", + "audio/skill/dclongsong1.mp3", + "audio/skill/dclongsong2.mp3", + "audio/skill/dcluochong1.mp3", + "audio/skill/dcluochong2.mp3", + "audio/skill/dclvecheng1.mp3", + "audio/skill/dclvecheng2.mp3", + "audio/skill/dcmanzhi1.mp3", + "audio/skill/dcmanzhi2.mp3", + "audio/skill/dcmengjie1.mp3", + "audio/skill/dcmengjie2.mp3", + "audio/skill/dcmieji1.mp3", + "audio/skill/dcmieji2.mp3", + "audio/skill/dcmingfa1.mp3", + "audio/skill/dcmingfa2.mp3", + "audio/skill/dcminze1.mp3", + "audio/skill/dcminze2.mp3", + "audio/skill/dcmiyi1.mp3", + "audio/skill/dcmiyi2.mp3", + "audio/skill/dcmiyun1.mp3", + "audio/skill/dcmiyun2.mp3", + "audio/skill/dcmoyu1.mp3", + "audio/skill/dcmoyu2.mp3", + "audio/skill/dcneifa1.mp3", + "audio/skill/dcneifa2.mp3", + "audio/skill/dcniji1.mp3", + "audio/skill/dcniji2.mp3", + "audio/skill/dcnuanhui1.mp3", + "audio/skill/dcnuanhui2.mp3", + "audio/skill/dcnuchen1.mp3", + "audio/skill/dcnuchen2.mp3", + "audio/skill/dcnutao1.mp3", + "audio/skill/dcnutao2.mp3", + "audio/skill/dcnutao3.mp3", + "audio/skill/dcnutao4.mp3", + "audio/skill/dcpandi1.mp3", + "audio/skill/dcpandi2.mp3", + "audio/skill/dcpeiqi1.mp3", + "audio/skill/dcpeiqi2.mp3", + "audio/skill/dcpijing1.mp3", + "audio/skill/dcpijing2.mp3", + "audio/skill/dcpingxi1.mp3", + "audio/skill/dcpingxi2.mp3", + "audio/skill/dcpitian1.mp3", + "audio/skill/dcpitian2.mp3", + "audio/skill/dcporui1.mp3", + "audio/skill/dcporui2.mp3", + "audio/skill/dcposuo1.mp3", + "audio/skill/dcposuo2.mp3", + "audio/skill/dcpoyuan1.mp3", + "audio/skill/dcpoyuan2.mp3", + "audio/skill/dcqiangzhi1.mp3", + "audio/skill/dcqiangzhi2.mp3", + "audio/skill/dcqianzheng1.mp3", + "audio/skill/dcqianzheng2.mp3", + "audio/skill/dcqiaomeng1.mp3", + "audio/skill/dcqiaomeng2.mp3", + "audio/skill/dcqijing1.mp3", + "audio/skill/dcqijing2.mp3", + "audio/skill/dcqinghuang1.mp3", + "audio/skill/dcqinghuang2.mp3", + "audio/skill/dcqingren1.mp3", + "audio/skill/dcqingren2.mp3", + "audio/skill/dcqingshi1.mp3", + "audio/skill/dcqingshi2.mp3", + "audio/skill/dcqingyan1.mp3", + "audio/skill/dcqingyan2.mp3", + "audio/skill/dcqinqing1.mp3", + "audio/skill/dcqinqing2.mp3", + "audio/skill/dcqinshen1.mp3", + "audio/skill/dcqinshen2.mp3", + "audio/skill/dcqiongying1.mp3", + "audio/skill/dcqiongying2.mp3", + "audio/skill/dcqiqin_yue_daqiao1.mp3", + "audio/skill/dcqiqin_yue_daqiao2.mp3", + "audio/skill/dcqiqin1.mp3", + "audio/skill/dcqiqin2.mp3", + "audio/skill/dcquanjian1.mp3", + "audio/skill/dcquanjian2.mp3", + "audio/skill/dcquanshou1.mp3", + "audio/skill/dcquanshou2.mp3", + "audio/skill/dcrihui1.mp3", + "audio/skill/dcrihui2.mp3", + "audio/skill/dcruizhan1.mp3", + "audio/skill/dcruizhan2.mp3", + "audio/skill/dcruxian1.mp3", + "audio/skill/dcruxian2.mp3", + "audio/skill/dcruyi1.mp3", + "audio/skill/dcruyi2.mp3", + "audio/skill/dcsantou1.mp3", + "audio/skill/dcsantou2.mp3", + "audio/skill/dcsaowei1.mp3", + "audio/skill/dcsaowei2.mp3", + "audio/skill/dcsbmengmou1.mp3", + "audio/skill/dcsbmengmou2.mp3", + "audio/skill/dcsbmingshi1.mp3", + "audio/skill/dcsbmingshi2.mp3", + "audio/skill/dcsbpingliao_dc_sb_simayi_shadow1.mp3", + "audio/skill/dcsbpingliao_dc_sb_simayi_shadow2.mp3", + "audio/skill/dcsbpingliao1.mp3", + "audio/skill/dcsbpingliao2.mp3", + "audio/skill/dcsbquanmou_dc_sb_simayi_shadow1.mp3", + "audio/skill/dcsbquanmou_dc_sb_simayi_shadow2.mp3", + "audio/skill/dcsbquanmou1.mp3", + "audio/skill/dcsbquanmou2.mp3", + "audio/skill/dcsbronghuo1.mp3", + "audio/skill/dcsbronghuo2.mp3", + "audio/skill/dcsbyingmou1.mp3", + "audio/skill/dcsbyingmou2.mp3", + "audio/skill/dcshangyu1.mp3", + "audio/skill/dcshangyu2.mp3", + "audio/skill/dcshengdu1.mp3", + "audio/skill/dcshengdu2.mp3", + "audio/skill/dcshexue1.mp3", + "audio/skill/dcshexue2.mp3", + "audio/skill/dcshibei1.mp3", + "audio/skill/dcshibei2.mp3", + "audio/skill/dcshiji1.mp3", + "audio/skill/dcshiji2.mp3", + "audio/skill/dcshilie1.mp3", + "audio/skill/dcshilie2.mp3", + "audio/skill/dcshixian1.mp3", + "audio/skill/dcshixian2.mp3", + "audio/skill/dcshizhao1.mp3", + "audio/skill/dcshizhao2.mp3", + "audio/skill/dcshizong1.mp3", + "audio/skill/dcshizong2.mp3", + "audio/skill/dcshoutan1.mp3", + "audio/skill/dcshoutan2.mp3", + "audio/skill/dcshouze.mp3", + "audio/skill/dcshuaijie1.mp3", + "audio/skill/dcshuaijie2.mp3", + "audio/skill/dcshuangjia1.mp3", + "audio/skill/dcshuangjia2.mp3", + "audio/skill/dcshuangren1.mp3", + "audio/skill/dcshuangren2.mp3", + "audio/skill/dcshuhe1.mp3", + "audio/skill/dcshuhe2.mp3", + "audio/skill/dcsigong1.mp3", + "audio/skill/dcsigong2.mp3", + "audio/skill/dcsilun1.mp3", + "audio/skill/dcsilun2.mp3", + "audio/skill/dcsilve1.mp3", + "audio/skill/dcsilve2.mp3", + "audio/skill/dcsitian1.mp3", + "audio/skill/dcsitian2.mp3", + "audio/skill/dcsuifu1.mp3", + "audio/skill/dcsuifu2.mp3", + "audio/skill/dcsushou1.mp3", + "audio/skill/dcsushou2.mp3", + "audio/skill/dctaji1.mp3", + "audio/skill/dctaji2.mp3", + "audio/skill/dctianji1.mp3", + "audio/skill/dctianji2.mp3", + "audio/skill/dctingxian1.mp3", + "audio/skill/dctingxian2.mp3", + "audio/skill/dctongguan1.mp3", + "audio/skill/dctongguan2.mp3", + "audio/skill/dctongliao1.mp3", + "audio/skill/dctongliao2.mp3", + "audio/skill/dctongliao3.mp3", + "audio/skill/dctongye1.mp3", + "audio/skill/dctongye2.mp3", + "audio/skill/dctujue1.mp3", + "audio/skill/dctujue2.mp3", + "audio/skill/dctuoyu1.mp3", + "audio/skill/dctuoyu2.mp3", + "audio/skill/dcwanglu1.mp3", + "audio/skill/dcwanglu2.mp3", + "audio/skill/dcwangyuan1.mp3", + "audio/skill/dcwangyuan2.mp3", + "audio/skill/dcweidang1.mp3", + "audio/skill/dcweidang2.mp3", + "audio/skill/dcweiwan1.mp3", + "audio/skill/dcweiwan2.mp3", + "audio/skill/dcwencan1.mp3", + "audio/skill/dcwencan2.mp3", + "audio/skill/dcwudao1.mp3", + "audio/skill/dcwudao2.mp3", + "audio/skill/dcwudao3.mp3", + "audio/skill/dcwujie1.mp3", + "audio/skill/dcwujie2.mp3", + "audio/skill/dcwumei1.mp3", + "audio/skill/dcwumei2.mp3", + "audio/skill/dcwuyuan1.mp3", + "audio/skill/dcwuyuan2.mp3", + "audio/skill/dcxiace1.mp3", + "audio/skill/dcxiace2.mp3", + "audio/skill/dcxialei1.mp3", + "audio/skill/dcxialei2.mp3", + "audio/skill/dcxiangmian1.mp3", + "audio/skill/dcxiangmian2.mp3", + "audio/skill/dcxiangshu1.mp3", + "audio/skill/dcxiangshu2.mp3", + "audio/skill/dcxianjin1.mp3", + "audio/skill/dcxianjin2.mp3", + "audio/skill/dcxianshu1.mp3", + "audio/skill/dcxianshu2.mp3", + "audio/skill/dcxianzhu1.mp3", + "audio/skill/dcxianzhu2.mp3", + "audio/skill/dcxiaojuan1.mp3", + "audio/skill/dcxiaojuan2.mp3", + "audio/skill/dcxiaoren1.mp3", + "audio/skill/dcxiaoren2.mp3", + "audio/skill/dcxiaoxi1.mp3", + "audio/skill/dcxiaoxi2.mp3", + "audio/skill/dcxiaoyin1.mp3", + "audio/skill/dcxiaoyin2.mp3", + "audio/skill/dcxieshou1.mp3", + "audio/skill/dcxieshou2.mp3", + "audio/skill/dcxinyou1.mp3", + "audio/skill/dcxinyou2.mp3", + "audio/skill/dcxiongmu1.mp3", + "audio/skill/dcxiongmu2.mp3", + "audio/skill/dcxiuwen1.mp3", + "audio/skill/dcxiuwen2.mp3", + "audio/skill/dcxuewei1.mp3", + "audio/skill/dcxuewei2.mp3", + "audio/skill/dcxunbie1.mp3", + "audio/skill/dcxunbie2.mp3", + "audio/skill/dcxunji1.mp3", + "audio/skill/dcxunji2.mp3", + "audio/skill/dcxunjie1.mp3", + "audio/skill/dcxunjie2.mp3", + "audio/skill/dcyaoyi1.mp3", + "audio/skill/dcyaoyi2.mp3", + "audio/skill/dcyicong1.mp3", + "audio/skill/dcyicong2.mp3", + "audio/skill/dcyijia1.mp3", + "audio/skill/dcyijia2.mp3", + "audio/skill/dcyingtu1.mp3", + "audio/skill/dcyingtu2.mp3", + "audio/skill/dcyingyu1.mp3", + "audio/skill/dcyingyu2.mp3", + "audio/skill/dcyinjun1.mp3", + "audio/skill/dcyinjun2.mp3", + "audio/skill/dcyinlu1.mp3", + "audio/skill/dcyinlu2.mp3", + "audio/skill/dcyinshi1.mp3", + "audio/skill/dcyinshi2.mp3", + "audio/skill/dcyishu1.mp3", + "audio/skill/dcyishu2.mp3", + "audio/skill/dcyiyong1.mp3", + "audio/skill/dcyiyong2.mp3", + "audio/skill/dcyongbi1.mp3", + "audio/skill/dcyongbi2.mp3", + "audio/skill/dcyouqi1.mp3", + "audio/skill/dcyouqi2.mp3", + "audio/skill/dcyouzhan1.mp3", + "audio/skill/dcyouzhan2.mp3", + "audio/skill/dcyuandi1.mp3", + "audio/skill/dcyuandi2.mp3", + "audio/skill/dcyuanmo1.mp3", + "audio/skill/dcyuanmo2.mp3", + "audio/skill/dcyuguan1.mp3", + "audio/skill/dcyuguan2.mp3", + "audio/skill/dcyuxin1.mp3", + "audio/skill/dcyuxin2.mp3", + "audio/skill/dczecai1.mp3", + "audio/skill/dczecai2.mp3", + "audio/skill/dczhangcai1.mp3", + "audio/skill/dczhangcai2.mp3", + "audio/skill/dczhanmeng1.mp3", + "audio/skill/dczhanmeng2.mp3", + "audio/skill/dczhanyi1.mp3", + "audio/skill/dczhanyi2.mp3", + "audio/skill/dczhaohan1.mp3", + "audio/skill/dczhaohan2.mp3", + "audio/skill/dczhaowen1.mp3", + "audio/skill/dczhaowen2.mp3", + "audio/skill/dczhengxu1.mp3", + "audio/skill/dczhengxu2.mp3", + "audio/skill/dczhenze1.mp3", + "audio/skill/dczhenze2.mp3", + "audio/skill/dczhifou1.mp3", + "audio/skill/dczhifou2.mp3", + "audio/skill/dczhizhe1.mp3", + "audio/skill/dczhizhe2.mp3", + "audio/skill/dczhongji1.mp3", + "audio/skill/dczhongji2.mp3", + "audio/skill/dczhongjie1.mp3", + "audio/skill/dczhongjie2.mp3", + "audio/skill/dczhouli2.mp3", + "audio/skill/dczhubi1.mp3", + "audio/skill/dczhubi2.mp3", + "audio/skill/dczhuiyi1.mp3", + "audio/skill/dczhuiyi2.mp3", + "audio/skill/dczhuoli1.mp3", + "audio/skill/dczigu1.mp3", + "audio/skill/dczigu2.mp3", + "audio/skill/dczimu1.mp3", + "audio/skill/dczixi1.mp3", + "audio/skill/dczixi2.mp3", + "audio/skill/dczuojian1.mp3", + "audio/skill/dczuojian2.mp3", + "audio/skill/dczuowei1.mp3", + "audio/skill/dczuowei2.mp3", + "audio/skill/debao1.mp3", + "audio/skill/debao2.mp3", + "audio/skill/decadejingce1.mp3", + "audio/skill/decadejingce2.mp3", + "audio/skill/decadejinjiu1.mp3", + "audio/skill/decadejinjiu2.mp3", + "audio/skill/decadepojun1.mp3", + "audio/skill/decadepojun2.mp3", + "audio/skill/decadexianzhen1.mp3", + "audio/skill/decadexianzhen2.mp3", + "audio/skill/decadezhenjun1.mp3", + "audio/skill/decadezhenjun2.mp3", + "audio/skill/decadezishou1.mp3", + "audio/skill/decadezishou2.mp3", + "audio/skill/decadezongshi1.mp3", + "audio/skill/decadezongshi2.mp3", + "audio/skill/dengji1.mp3", + "audio/skill/dengji2.mp3", + "audio/skill/dengzhi.mp3", + "audio/skill/dezhang1.mp3", + "audio/skill/dezhang2.mp3", + "audio/skill/diancai1.mp3", + "audio/skill/diancai2.mp3", + "audio/skill/diaodu1.mp3", + "audio/skill/diaodu2.mp3", + "audio/skill/diaoling1.mp3", + "audio/skill/diaoling2.mp3", + "audio/skill/diezhang1.mp3", + "audio/skill/diezhang2.mp3", + "audio/skill/difa1.mp3", + "audio/skill/difa2.mp3", + "audio/skill/dili_chigang1.mp3", + "audio/skill/dili_chigang2.mp3", + "audio/skill/dili_jiaohui1.mp3", + "audio/skill/dili_jiaohui2.mp3", + "audio/skill/dili_qionglan1.mp3", + "audio/skill/dili_qionglan2.mp3", + "audio/skill/dili_quandao1.mp3", + "audio/skill/dili_quandao2.mp3", + "audio/skill/dili_shengzhi1.mp3", + "audio/skill/dili_shengzhi2.mp3", + "audio/skill/dili_yuanlv1.mp3", + "audio/skill/dili_yuanlv2.mp3", + "audio/skill/dili1.mp3", + "audio/skill/dili2.mp3", + "audio/skill/dimeng1.mp3", + "audio/skill/dimeng2.mp3", + "audio/skill/dingfa1.mp3", + "audio/skill/dingfa2.mp3", + "audio/skill/dinghan1.mp3", + "audio/skill/dinghan2.mp3", + "audio/skill/dingpan1.mp3", + "audio/skill/dingpan2.mp3", + "audio/skill/dingpin1.mp3", + "audio/skill/dingpin2.mp3", + "audio/skill/dingzhou1.mp3", + "audio/skill/dingzhou2.mp3", + "audio/skill/disordersidi1.mp3", + "audio/skill/disordersidi2.mp3", + "audio/skill/donggui1.mp3", + "audio/skill/donggui2.mp3", + "audio/skill/drlt_congjian1.mp3", + "audio/skill/drlt_congjian2.mp3", + "audio/skill/drlt_duorui1.mp3", + "audio/skill/drlt_duorui2.mp3", + "audio/skill/drlt_hongju1.mp3", + "audio/skill/drlt_hongju2.mp3", + "audio/skill/drlt_huairou1.mp3", + "audio/skill/drlt_huairou2.mp3", + "audio/skill/drlt_jieying1.mp3", + "audio/skill/drlt_jieying2.mp3", + "audio/skill/drlt_jueyan1.mp3", + "audio/skill/drlt_jueyan2.mp3", + "audio/skill/drlt_poshi1.mp3", + "audio/skill/drlt_poshi2.mp3", + "audio/skill/drlt_poxi1.mp3", + "audio/skill/drlt_poxi2.mp3", + "audio/skill/drlt_qianjie1.mp3", + "audio/skill/drlt_qianjie2.mp3", + "audio/skill/drlt_qingce1.mp3", + "audio/skill/drlt_qingce2.mp3", + "audio/skill/drlt_wanglie1.mp3", + "audio/skill/drlt_wanglie2.mp3", + "audio/skill/drlt_weidi1.mp3", + "audio/skill/drlt_weidi2.mp3", + "audio/skill/drlt_xiongluan1.mp3", + "audio/skill/drlt_xiongluan2.mp3", + "audio/skill/drlt_yongsi1.mp3", + "audio/skill/drlt_yongsi2.mp3", + "audio/skill/drlt_zhenggu1.mp3", + "audio/skill/drlt_zhenggu2.mp3", + "audio/skill/drlt_zhenrong1.mp3", + "audio/skill/drlt_zhenrong2.mp3", + "audio/skill/drlt_zhiti1.mp3", + "audio/skill/drlt_zhiti2.mp3", + "audio/skill/duanbi1.mp3", + "audio/skill/duanbi2.mp3", + "audio/skill/duanbing_heqi1.mp3", + "audio/skill/duanbing_heqi2.mp3", + "audio/skill/duanbing1.mp3", + "audio/skill/duanbing2.mp3", + "audio/skill/duanchang_ol_caiwenji1.mp3", + "audio/skill/duanchang_ol_caiwenji2.mp3", + "audio/skill/duanchang_re_caiwenji1.mp3", + "audio/skill/duanchang_re_caiwenji2.mp3", + "audio/skill/duanchang1.mp3", + "audio/skill/duanchang2.mp3", + "audio/skill/duanliang1_re_xuhuang1.mp3", + "audio/skill/duanliang1_re_xuhuang2.mp3", + "audio/skill/duanliang11.mp3", + "audio/skill/duanliang12.mp3", + "audio/skill/duansuo1.mp3", + "audio/skill/duansuo2.mp3", + "audio/skill/duanwan1.mp3", + "audio/skill/duanwan2.mp3", + "audio/skill/duanxie1.mp3", + "audio/skill/duanxie2.mp3", + "audio/skill/dujin1.mp3", + "audio/skill/dujin2.mp3", + "audio/skill/duliang1.mp3", + "audio/skill/duliang2.mp3", + "audio/skill/dulie1.mp3", + "audio/skill/dulie2.mp3", + "audio/skill/dunshi1.mp3", + "audio/skill/dunshi2.mp3", + "audio/skill/dunxi1.mp3", + "audio/skill/dunxi2.mp3", + "audio/skill/duodao1.mp3", + "audio/skill/duodao2.mp3", + "audio/skill/duoduan1.mp3", + "audio/skill/duoduan2.mp3", + "audio/skill/duoji1.mp3", + "audio/skill/duoji2.mp3", + "audio/skill/duoshi1.mp3", + "audio/skill/duoshi2.mp3", + "audio/skill/dushi1.mp3", + "audio/skill/dushi2.mp3", + "audio/skill/duwang1.mp3", + "audio/skill/duwang2.mp3", + "audio/skill/duwu1.mp3", + "audio/skill/duwu2.mp3", + "audio/skill/dzgengzhan1.mp3", + "audio/skill/dzgengzhan2.mp3", + "audio/skill/dzkanpo1.mp3", + "audio/skill/dzkanpo2.mp3", + "audio/skill/ejian1.mp3", + "audio/skill/ejian2.mp3", + "audio/skill/enyuan1.mp3", + "audio/skill/enyuan2.mp3", + "audio/skill/equan1.mp3", + "audio/skill/equan2.mp3", + "audio/skill/faen1.mp3", + "audio/skill/faen2.mp3", + "audio/skill/fanghun1.mp3", + "audio/skill/fanghun2.mp3", + "audio/skill/fangquan1.mp3", + "audio/skill/fangquan2.mp3", + "audio/skill/fangtian_skill.mp3", + "audio/skill/fangzhu1.mp3", + "audio/skill/fangzhu2.mp3", + "audio/skill/fanjian1.mp3", + "audio/skill/fanjian2.mp3", + "audio/skill/fankui1.mp3", + "audio/skill/fankui2.mp3", + "audio/skill/fanxiang1.mp3", + "audio/skill/fanxiang2.mp3", + "audio/skill/fencheng1.mp3", + "audio/skill/fencheng2.mp3", + "audio/skill/fengji1.mp3", + "audio/skill/fengji2.mp3", + "audio/skill/fengjie1.mp3", + "audio/skill/fengjie2.mp3", + "audio/skill/fengliang1.mp3", + "audio/skill/fengliang2.mp3", + "audio/skill/fenglve1.mp3", + "audio/skill/fenglve2.mp3", + "audio/skill/fengpo1.mp3", + "audio/skill/fengpo2.mp3", + "audio/skill/fengwu1.mp3", + "audio/skill/fengwu2.mp3", + "audio/skill/fengxiang1.mp3", + "audio/skill/fengxiang2.mp3", + "audio/skill/fengyang1.mp3", + "audio/skill/fengyang2.mp3", + "audio/skill/fengying1.mp3", + "audio/skill/fengying2.mp3", + "audio/skill/fenji1.mp3", + "audio/skill/fenji2.mp3", + "audio/skill/fenli_xin_zhuhuan1.mp3", + "audio/skill/fenli_xin_zhuhuan2.mp3", + "audio/skill/fenli1.mp3", + "audio/skill/fenli2.mp3", + "audio/skill/fenming1.mp3", + "audio/skill/fenming2.mp3", + "audio/skill/fenrui1.mp3", + "audio/skill/fenrui2.mp3", + "audio/skill/fensi1.mp3", + "audio/skill/fensi2.mp3", + "audio/skill/fentian1.mp3", + "audio/skill/fentian2.mp3", + "audio/skill/fenwei_heqi1.mp3", + "audio/skill/fenwei_heqi2.mp3", + "audio/skill/fenwei1.mp3", + "audio/skill/fenwei2.mp3", + "audio/skill/fenxin1.mp3", + "audio/skill/fenxin2.mp3", + "audio/skill/fenxun1.mp3", + "audio/skill/fenxun2.mp3", + "audio/skill/fenyin1.mp3", + "audio/skill/fenyin2.mp3", + "audio/skill/fenyong1.mp3", + "audio/skill/fenyong2.mp3", + "audio/skill/fenyue1.mp3", + "audio/skill/fenyue2.mp3", + "audio/skill/fubi1.mp3", + "audio/skill/fubi2.mp3", + "audio/skill/fuhan1.mp3", + "audio/skill/fuhan2.mp3", + "audio/skill/fuhun_re_guanzhang1.mp3", + "audio/skill/fuhun_re_guanzhang2.mp3", + "audio/skill/fuhun1.mp3", + "audio/skill/fuhun2.mp3", + "audio/skill/fuli1.mp3", + "audio/skill/fuli2.mp3", + "audio/skill/fulin1.mp3", + "audio/skill/fulin2.mp3", + "audio/skill/fuman1.mp3", + "audio/skill/fuman2.mp3", + "audio/skill/fumian1.mp3", + "audio/skill/fumian2.mp3", + "audio/skill/funan1.mp3", + "audio/skill/funan2.mp3", + "audio/skill/fuping1.mp3", + "audio/skill/fuping2.mp3", + "audio/skill/fuqi1.mp3", + "audio/skill/fuqi2.mp3", + "audio/skill/fuyuan1.mp3", + "audio/skill/fuyuan2.mp3", + "audio/skill/fuzhong1.mp3", + "audio/skill/fuzhong2.mp3", + "audio/skill/fuzhu1.mp3", + "audio/skill/fuzhu2.mp3", + "audio/skill/fyjianyu1.mp3", + "audio/skill/fyjianyu2.mp3", + "audio/skill/fz_liegong.mp3", + "audio/skill/fz_new_longdan.mp3", + "audio/skill/fz_new_paoxiao.mp3", + "audio/skill/fz_new_tieji.mp3", + "audio/skill/fz_wusheng.mp3", + "audio/skill/fz_xinkuanggu.mp3", + "audio/skill/ganglie1.mp3", + "audio/skill/ganglie2.mp3", + "audio/skill/gangzhi1.mp3", + "audio/skill/gangzhi2.mp3", + "audio/skill/ganlu1.mp3", + "audio/skill/ganlu2.mp3", + "audio/skill/gaoling1.mp3", + "audio/skill/gaoling2.mp3", + "audio/skill/gaoyuan1.mp3", + "audio/skill/gaoyuan2.mp3", + "audio/skill/gebo1.mp3", + "audio/skill/gebo2.mp3", + "audio/skill/gnjinfan1.mp3", + "audio/skill/gnjinfan2.mp3", + "audio/skill/gnsheque1.mp3", + "audio/skill/gnsheque2.mp3", + "audio/skill/gongao1.mp3", + "audio/skill/gongao2.mp3", + "audio/skill/gonghuan1.mp3", + "audio/skill/gonghuan2.mp3", + "audio/skill/gongji1.mp3", + "audio/skill/gongji2.mp3", + "audio/skill/gongjian1.mp3", + "audio/skill/gongjian2.mp3", + "audio/skill/gongsun1.mp3", + "audio/skill/gongsun2.mp3", + "audio/skill/gongxin_gexuan1.mp3", + "audio/skill/gongxin_re_lvmeng1.mp3", + "audio/skill/gongxin_re_lvmeng2.mp3", + "audio/skill/gongxin1.mp3", + "audio/skill/gongxin2.mp3", + "audio/skill/gongxiu1.mp3", + "audio/skill/gongxiu2.mp3", + "audio/skill/guanshi_skill.mp3", + "audio/skill/guanxing_gexuan1.mp3", + "audio/skill/guanxing_jiangwei1.mp3", + "audio/skill/guanxing_jiangwei2.mp3", + "audio/skill/guanxing_ol_jiangwei1.mp3", + "audio/skill/guanxing_ol_jiangwei2.mp3", + "audio/skill/guanxing_re_jiangwei1.mp3", + "audio/skill/guanxing_re_jiangwei2.mp3", + "audio/skill/guanxing_re_zhugeliang1.mp3", + "audio/skill/guanxing_re_zhugeliang2.mp3", + "audio/skill/guanxing1.mp3", + "audio/skill/guanxing2.mp3", + "audio/skill/guanxu1.mp3", + "audio/skill/guanxu2.mp3", + "audio/skill/guanzong1.mp3", + "audio/skill/guanzong2.mp3", + "audio/skill/guding_skill.mp3", + "audio/skill/guhuo_guess1.mp3", + "audio/skill/guhuo_guess2.mp3", + "audio/skill/guhuo1.mp3", + "audio/skill/guhuo2.mp3", + "audio/skill/guicai1.mp3", + "audio/skill/guicai2.mp3", + "audio/skill/guidao_sp_zhangjiao1.mp3", + "audio/skill/guidao_sp_zhangjiao2.mp3", + "audio/skill/guidao1.mp3", + "audio/skill/guidao2.mp3", + "audio/skill/guili1.mp3", + "audio/skill/guili2.mp3", + "audio/skill/guiming1.mp3", + "audio/skill/guiming2.mp3", + "audio/skill/guimou1.mp3", + "audio/skill/guimou2.mp3", + "audio/skill/guixin1.mp3", + "audio/skill/guixin2.mp3", + "audio/skill/guixiu1.mp3", + "audio/skill/guixiu2.mp3", + "audio/skill/guizao1.mp3", + "audio/skill/guizao2.mp3", + "audio/skill/guizhen1.mp3", + "audio/skill/guizhen2.mp3", + "audio/skill/guju_tw_beimihu1.mp3", + "audio/skill/guju_tw_beimihu2.mp3", + "audio/skill/guju1.mp3", + "audio/skill/guju2.mp3", + "audio/skill/guose1.mp3", + "audio/skill/guose2.mp3", + "audio/skill/guowu1.mp3", + "audio/skill/guowu2.mp3", + "audio/skill/gushe1.mp3", + "audio/skill/gushe2.mp3", + "audio/skill/guying1.mp3", + "audio/skill/guying2.mp3", + "audio/skill/guzheng_re_zhangzhang1.mp3", + "audio/skill/guzheng_re_zhangzhang2.mp3", + "audio/skill/guzheng1.mp3", + "audio/skill/guzheng2.mp3", + "audio/skill/gxlianhua1.mp3", + "audio/skill/gxlianhua2.mp3", + "audio/skill/gz_jun_liubei.mp3", + "audio/skill/gz_jun_sunquan.mp3", + "audio/skill/gzbaolie1.mp3", + "audio/skill/gzbaolie2.mp3", + "audio/skill/gzbiluan1.mp3", + "audio/skill/gzbiluan2.mp3", + "audio/skill/gzbuqu1.mp3", + "audio/skill/gzbuqu2.mp3", + "audio/skill/gzbushi1.mp3", + "audio/skill/gzbushi2.mp3", + "audio/skill/gzchenglve1.mp3", + "audio/skill/gzchenglve2.mp3", + "audio/skill/gzcongcha1.mp3", + "audio/skill/gzcongcha2.mp3", + "audio/skill/gzduannian1.mp3", + "audio/skill/gzduannian2.mp3", + "audio/skill/gzduwu1.mp3", + "audio/skill/gzduwu2.mp3", + "audio/skill/gzfangyuan1.mp3", + "audio/skill/gzfangyuan2.mp3", + "audio/skill/gzfankui1.mp3", + "audio/skill/gzfankui2.mp3", + "audio/skill/gzfudi1.mp3", + "audio/skill/gzfudi2.mp3", + "audio/skill/gzhuaiyi1.mp3", + "audio/skill/gzhuaiyi2.mp3", + "audio/skill/gzjiancai1.mp3", + "audio/skill/gzjiancai2.mp3", + "audio/skill/gzjianliang1.mp3", + "audio/skill/gzjianliang2.mp3", + "audio/skill/gzjieyue1.mp3", + "audio/skill/gzjieyue2.mp3", + "audio/skill/gzjili1.mp3", + "audio/skill/gzjili2.mp3", + "audio/skill/gzjinfa1.mp3", + "audio/skill/gzjinfa2.mp3", + "audio/skill/gzjixi.mp3", + "audio/skill/gzjixi1.mp3", + "audio/skill/gzjuejue1.mp3", + "audio/skill/gzjuejue2.mp3", + "audio/skill/gzkuangcai1.mp3", + "audio/skill/gzkuangcai2.mp3", + "audio/skill/gzlianpian1.mp3", + "audio/skill/gzlianpian2.mp3", + "audio/skill/gzlianyou1.mp3", + "audio/skill/gzlianyou2.mp3", + "audio/skill/gzlixia1.mp3", + "audio/skill/gzlixia2.mp3", + "audio/skill/gzmidao1.mp3", + "audio/skill/gzmidao2.mp3", + "audio/skill/gzpaiyi1.mp3", + "audio/skill/gzpaiyi2.mp3", + "audio/skill/gzquanji1.mp3", + "audio/skill/gzquanji2.mp3", + "audio/skill/gzshejian1.mp3", + "audio/skill/gzshejian2.mp3", + "audio/skill/gzshicai1.mp3", + "audio/skill/gzshicai2.mp3", + "audio/skill/gzshilu1.mp3", + "audio/skill/gzshilu2.mp3", + "audio/skill/gzsuzhi1.mp3", + "audio/skill/gzsuzhi2.mp3", + "audio/skill/gztunjiang1.mp3", + "audio/skill/gztunjiang2.mp3", + "audio/skill/gzweimeng1.mp3", + "audio/skill/gzweimeng2.mp3", + "audio/skill/gzwenji1.mp3", + "audio/skill/gzwenji2.mp3", + "audio/skill/gzxingzhao_xunxun1.mp3", + "audio/skill/gzxingzhao_xunxun2.mp3", + "audio/skill/gzxingzhao1.mp3", + "audio/skill/gzxingzhao2.mp3", + "audio/skill/gzxiongnve1.mp3", + "audio/skill/gzxiongnve2.mp3", + "audio/skill/gzxishe1.mp3", + "audio/skill/gzxishe2.mp3", + "audio/skill/gzyinghun_re_sunyi1.mp3", + "audio/skill/gzyjili1.mp3", + "audio/skill/gzyjili2.mp3", + "audio/skill/gzzhaoxin1.mp3", + "audio/skill/gzzhaoxin2.mp3", + "audio/skill/gzzhidao1.mp3", + "audio/skill/gzzhidao2.mp3", + "audio/skill/gzzisui1.mp3", + "audio/skill/gzzisui2.mp3", + "audio/skill/gzzongyu1.mp3", + "audio/skill/gzzongyu2.mp3", + "audio/skill/hanbing_skill.mp3", + "audio/skill/hannan1.mp3", + "audio/skill/hannan2.mp3", + "audio/skill/hanyong1.mp3", + "audio/skill/hanyong2.mp3", + "audio/skill/hanzhan1.mp3", + "audio/skill/hanzhan2.mp3", + "audio/skill/haoshi1.mp3", + "audio/skill/haoshi2.mp3", + "audio/skill/heji1.mp3", + "audio/skill/heji2.mp3", + "audio/skill/hengjiang1.mp3", + "audio/skill/hengjiang2.mp3", + "audio/skill/hengwu1.mp3", + "audio/skill/hengwu2.mp3", + "audio/skill/hengzheng1.mp3", + "audio/skill/hengzheng2.mp3", + "audio/skill/heqia1.mp3", + "audio/skill/heqia2.mp3", + "audio/skill/hezhong1.mp3", + "audio/skill/hezhong2.mp3", + "audio/skill/hfjieying1.mp3", + "audio/skill/hfjieying2.mp3", + "audio/skill/hinata_ehou1.mp3", + "audio/skill/hinata_ehou2.mp3", + "audio/skill/hinata_qiulve1.mp3", + "audio/skill/hinata_qiulve2.mp3", + "audio/skill/hisako_yinbao1.mp3", + "audio/skill/hisako_yinbao2.mp3", + "audio/skill/hmxili1.mp3", + "audio/skill/hmxili2.mp3", + "audio/skill/hongde1.mp3", + "audio/skill/hongde2.mp3", + "audio/skill/hongfa_hp.mp3", + "audio/skill/hongfa1.mp3", + "audio/skill/hongfa2.mp3", + "audio/skill/hongyan.mp3", + "audio/skill/hongyi1.mp3", + "audio/skill/hongyi2.mp3", + "audio/skill/hongyuan1.mp3", + "audio/skill/hongyuan2.mp3", + "audio/skill/houfeng1.mp3", + "audio/skill/houfeng2.mp3", + "audio/skill/houfeng3.mp3", + "audio/skill/huaibi1.mp3", + "audio/skill/huaibi2.mp3", + "audio/skill/huaiyi1.mp3", + "audio/skill/huaiyi2.mp3", + "audio/skill/huaiyuan1.mp3", + "audio/skill/huaiyuan2.mp3", + "audio/skill/huamu1.mp3", + "audio/skill/huamu2.mp3", + "audio/skill/huamu3.mp3", + "audio/skill/huamu4.mp3", + "audio/skill/huamu5.mp3", + "audio/skill/huamu6.mp3", + "audio/skill/huangjintianbingfu1.mp3", + "audio/skill/huangjintianbingfu2.mp3", + "audio/skill/huangkong1.mp3", + "audio/skill/huangkong2.mp3", + "audio/skill/huangtian2_re_zhangjiao1.mp3", + "audio/skill/huangtian2_re_zhangjiao2.mp3", + "audio/skill/huangtian2_zhangjiao1.mp3", + "audio/skill/huangtian2_zhangjiao2.mp3", + "audio/skill/huangtian21.mp3", + "audio/skill/huangtian22.mp3", + "audio/skill/huanhua1.mp3", + "audio/skill/huanhua2.mp3", + "audio/skill/huanshi1.mp3", + "audio/skill/huanshi2.mp3", + "audio/skill/huantu1.mp3", + "audio/skill/huantu2.mp3", + "audio/skill/huaping.mp3", + "audio/skill/huaping1.mp3", + "audio/skill/huaping2.mp3", + "audio/skill/huashen21.mp3", + "audio/skill/huashen22.mp3", + "audio/skill/huguan_wangyue1.mp3", + "audio/skill/huguan_wangyue2.mp3", + "audio/skill/huguan1.mp3", + "audio/skill/huguan2.mp3", + "audio/skill/huibian1.mp3", + "audio/skill/huibian2.mp3", + "audio/skill/huilei1.mp3", + "audio/skill/huilei2.mp3", + "audio/skill/huimin1.mp3", + "audio/skill/huimin2.mp3", + "audio/skill/huirong1.mp3", + "audio/skill/huirong2.mp3", + "audio/skill/huisheng_dc_huanghao1.mp3", + "audio/skill/huisheng_dc_huanghao2.mp3", + "audio/skill/huisheng1.mp3", + "audio/skill/huisheng2.mp3", + "audio/skill/huishi1.mp3", + "audio/skill/huishi2.mp3", + "audio/skill/huituo1.mp3", + "audio/skill/huituo2.mp3", + "audio/skill/hujia_re_caocao1.mp3", + "audio/skill/hujia_re_caocao2.mp3", + "audio/skill/hujia1.mp3", + "audio/skill/hujia2.mp3", + "audio/skill/hunzi1.mp3", + "audio/skill/hunzi2.mp3", + "audio/skill/huoji1.mp3", + "audio/skill/huoji2.mp3", + "audio/skill/huomo_huzhao1.mp3", + "audio/skill/huomo_huzhao2.mp3", + "audio/skill/huomo_re_zhongyao1.mp3", + "audio/skill/huomo_re_zhongyao2.mp3", + "audio/skill/huomo1.mp3", + "audio/skill/huomo2.mp3", + "audio/skill/huoshaowuchao.mp3", + "audio/skill/huoshou1_re_menghuo1.mp3", + "audio/skill/huoshou1_re_menghuo2.mp3", + "audio/skill/huoshou11.mp3", + "audio/skill/huoshou12.mp3", + "audio/skill/huoshui1.mp3", + "audio/skill/huoshui2.mp3", + "audio/skill/huoxin1.mp3", + "audio/skill/huoxin2.mp3", + "audio/skill/huwei1.mp3", + "audio/skill/huwei2.mp3", + "audio/skill/huxiao1.mp3", + "audio/skill/huxiao2.mp3", + "audio/skill/huyuan1.mp3", + "audio/skill/huyuan2.mp3", + "audio/skill/hxrenshi1.mp3", + "audio/skill/hxrenshi2.mp3", + "audio/skill/jiahe_put1.mp3", + "audio/skill/jiahe_put2.mp3", + "audio/skill/jiahe1.mp3", + "audio/skill/jiahe2.mp3", + "audio/skill/jianan1.mp3", + "audio/skill/jianan2.mp3", + "audio/skill/jianchu_re_pangde1.mp3", + "audio/skill/jianchu_re_pangde2.mp3", + "audio/skill/jianchu1.mp3", + "audio/skill/jianchu2.mp3", + "audio/skill/jiang_re_sunben1.mp3", + "audio/skill/jiang_re_sunben2.mp3", + "audio/skill/jiang_re_sunce1.mp3", + "audio/skill/jiang_re_sunce2.mp3", + "audio/skill/jiang_sp_lvmeng1.mp3", + "audio/skill/jiang_sp_lvmeng2.mp3", + "audio/skill/jiang1.mp3", + "audio/skill/jiang2.mp3", + "audio/skill/jiangchi1.mp3", + "audio/skill/jiangchi2.mp3", + "audio/skill/jianglue1.mp3", + "audio/skill/jianglue2.mp3", + "audio/skill/jiangxi1.mp3", + "audio/skill/jiangxi2.mp3", + "audio/skill/jianhui1.mp3", + "audio/skill/jianhui2.mp3", + "audio/skill/jianliang1.mp3", + "audio/skill/jianliang2.mp3", + "audio/skill/jianshoudaiyuan.mp3", + "audio/skill/jianshu1.mp3", + "audio/skill/jianshu2.mp3", + "audio/skill/jianxiong1.mp3", + "audio/skill/jianxiong2.mp3", + "audio/skill/jianyan1.mp3", + "audio/skill/jianyan2.mp3", + "audio/skill/jianying1.mp3", + "audio/skill/jianying2.mp3", + "audio/skill/jianzhan1.mp3", + "audio/skill/jianzhan2.mp3", + "audio/skill/jianzheng1.mp3", + "audio/skill/jianzheng2.mp3", + "audio/skill/jiaojin1.mp3", + "audio/skill/jiaojin2.mp3", + "audio/skill/jiaoxia1.mp3", + "audio/skill/jiaoxia2.mp3", + "audio/skill/jiaoying1.mp3", + "audio/skill/jiaoying2.mp3", + "audio/skill/jiaozhao1.mp3", + "audio/skill/jiaozhao2.mp3", + "audio/skill/jiaozi1.mp3", + "audio/skill/jiaozi2.mp3", + "audio/skill/jibing1.mp3", + "audio/skill/jibing2.mp3", + "audio/skill/jici1.mp3", + "audio/skill/jici2.mp3", + "audio/skill/jidian1.mp3", + "audio/skill/jidian2.mp3", + "audio/skill/jiebing1.mp3", + "audio/skill/jiebing2.mp3", + "audio/skill/jiefan_re_handang1.mp3", + "audio/skill/jiefan_re_handang2.mp3", + "audio/skill/jiefan1.mp3", + "audio/skill/jiefan2.mp3", + "audio/skill/jieliang1.mp3", + "audio/skill/jieliang2.mp3", + "audio/skill/jielie1.mp3", + "audio/skill/jielie2.mp3", + "audio/skill/jieming1.mp3", + "audio/skill/jieming2.mp3", + "audio/skill/jiewei1.mp3", + "audio/skill/jiewei2.mp3", + "audio/skill/jiexun1.mp3", + "audio/skill/jiexun2.mp3", + "audio/skill/jieyin1.mp3", + "audio/skill/jieyin2.mp3", + "audio/skill/jieyuan_less.mp3", + "audio/skill/jieyuan_more.mp3", + "audio/skill/jieyue_shan.mp3", + "audio/skill/jieyue_wuxie.mp3", + "audio/skill/jieyue1.mp3", + "audio/skill/jieyue2.mp3", + "audio/skill/jiezhong1.mp3", + "audio/skill/jiezhong2.mp3", + "audio/skill/jiezi1.mp3", + "audio/skill/jiezi2.mp3", + "audio/skill/jigong1.mp3", + "audio/skill/jigong2.mp3", + "audio/skill/jihun1.mp3", + "audio/skill/jihun2.mp3", + "audio/skill/jijiang1_liushan1.mp3", + "audio/skill/jijiang1_liushan2.mp3", + "audio/skill/jijiang1_ol_liushan1.mp3", + "audio/skill/jijiang1_ol_liushan2.mp3", + "audio/skill/jijiang1_re_liubei1.mp3", + "audio/skill/jijiang1_re_liubei2.mp3", + "audio/skill/jijiang1_re_liushan1.mp3", + "audio/skill/jijiang1_re_liushan2.mp3", + "audio/skill/jijiang11.mp3", + "audio/skill/jijiang12.mp3", + "audio/skill/jijiang2_liushan1.mp3", + "audio/skill/jijiang2_liushan2.mp3", + "audio/skill/jijiang21.mp3", + "audio/skill/jijiang22.mp3", + "audio/skill/jijing1.mp3", + "audio/skill/jijing2.mp3", + "audio/skill/jijiu_re_huatuo1.mp3", + "audio/skill/jijiu_re_huatuo2.mp3", + "audio/skill/jijiu1.mp3", + "audio/skill/jijiu2.mp3", + "audio/skill/jilei1.mp3", + "audio/skill/jilei2.mp3", + "audio/skill/jili1.mp3", + "audio/skill/jili2.mp3", + "audio/skill/jilue_fangzhu.mp3", + "audio/skill/jilue_fangzhu1.mp3", + "audio/skill/jilue_guicai.mp3", + "audio/skill/jilue_guicai1.mp3", + "audio/skill/jilue_jizhi.mp3", + "audio/skill/jilue_jizhi1.mp3", + "audio/skill/jilue_wansha.mp3", + "audio/skill/jilue_zhiheng.mp3", + "audio/skill/jilue_zhiheng1.mp3", + "audio/skill/jimeng1.mp3", + "audio/skill/jimeng2.mp3", + "audio/skill/jingce1.mp3", + "audio/skill/jingce2.mp3", + "audio/skill/jinghe1.mp3", + "audio/skill/jinghe2.mp3", + "audio/skill/jinglan1.mp3", + "audio/skill/jinglan2.mp3", + "audio/skill/jinglve1.mp3", + "audio/skill/jinglve2.mp3", + "audio/skill/jingong1.mp3", + "audio/skill/jingong2.mp3", + "audio/skill/jingzhong1.mp3", + "audio/skill/jingzhong2.mp3", + "audio/skill/jinhui1.mp3", + "audio/skill/jinhui2.mp3", + "audio/skill/jinjian1.mp3", + "audio/skill/jinjian2.mp3", + "audio/skill/jinjiu1.mp3", + "audio/skill/jinjiu2.mp3", + "audio/skill/jinqu1.mp3", + "audio/skill/jinqu2.mp3", + "audio/skill/jintao1.mp3", + "audio/skill/jintao2.mp3", + "audio/skill/jinzhi1.mp3", + "audio/skill/jinzhi2.mp3", + "audio/skill/jiqiao1.mp3", + "audio/skill/jiqiao2.mp3", + "audio/skill/jishe1.mp3", + "audio/skill/jishe2.mp3", + "audio/skill/jishi1.mp3", + "audio/skill/jishi2.mp3", + "audio/skill/jisi1.mp3", + "audio/skill/jisi2.mp3", + "audio/skill/jiuchi_re_dongzhuo1.mp3", + "audio/skill/jiuchi_re_dongzhuo2.mp3", + "audio/skill/jiuchi1.mp3", + "audio/skill/jiuchi2.mp3", + "audio/skill/jiufa1.mp3", + "audio/skill/jiufa2.mp3", + "audio/skill/jiushi11.mp3", + "audio/skill/jiushi12.mp3", + "audio/skill/jiushi21.mp3", + "audio/skill/jiushi22.mp3", + "audio/skill/jiushi31.mp3", + "audio/skill/jiushi32.mp3", + "audio/skill/jiuwei.mp3", + "audio/skill/jiuyuan1.mp3", + "audio/skill/jiuyuan2.mp3", + "audio/skill/jiwu1.mp3", + "audio/skill/jiwu2.mp3", + "audio/skill/jixi_gz_dengai1.mp3", + "audio/skill/jixi_gz_dengai2.mp3", + "audio/skill/jixi_ol_dengai1.mp3", + "audio/skill/jixi_ol_dengai2.mp3", + "audio/skill/jixi_re_dengai1.mp3", + "audio/skill/jixi_re_dengai2.mp3", + "audio/skill/jixi1.mp3", + "audio/skill/jixi2.mp3", + "audio/skill/jixian1.mp3", + "audio/skill/jixian2.mp3", + "audio/skill/jiyu1.mp3", + "audio/skill/jiyu2.mp3", + "audio/skill/jizhao1.mp3", + "audio/skill/jizhao2.mp3", + "audio/skill/jizhi_jianyong1.mp3", + "audio/skill/jizhi_jianyong2.mp3", + "audio/skill/jizhi1.mp3", + "audio/skill/jizhi2.mp3", + "audio/skill/jspdanqi1.mp3", + "audio/skill/jspdanqi2.mp3", + "audio/skill/juanjia1.mp3", + "audio/skill/juanjia2.mp3", + "audio/skill/jubao1.mp3", + "audio/skill/jubao2.mp3", + "audio/skill/juece_dc_liru1.mp3", + "audio/skill/juece_dc_liru2.mp3", + "audio/skill/juece1.mp3", + "audio/skill/juece2.mp3", + "audio/skill/juedi1.mp3", + "audio/skill/juedi2.mp3", + "audio/skill/juejing.mp3", + "audio/skill/jueman1.mp3", + "audio/skill/jueman2.mp3", + "audio/skill/jueqing1.mp3", + "audio/skill/jueqing2.mp3", + "audio/skill/juesheng1.mp3", + "audio/skill/juesheng2.mp3", + "audio/skill/juesi1.mp3", + "audio/skill/juesi2.mp3", + "audio/skill/juetao1.mp3", + "audio/skill/juetao2.mp3", + "audio/skill/juexiang_he1.mp3", + "audio/skill/juexiang_ji1.mp3", + "audio/skill/juexiang_lie1.mp3", + "audio/skill/juexiang_rou1.mp3", + "audio/skill/juexiang1.mp3", + "audio/skill/juexiang2.mp3", + "audio/skill/jueyong1.mp3", + "audio/skill/jueyong2.mp3", + "audio/skill/juezhi1.mp3", + "audio/skill/juezhi2.mp3", + "audio/skill/jugu1.mp3", + "audio/skill/jugu2.mp3", + "audio/skill/juguan1.mp3", + "audio/skill/juguan2.mp3", + "audio/skill/jujian1.mp3", + "audio/skill/jujian2.mp3", + "audio/skill/junbing1.mp3", + "audio/skill/junbing2.mp3", + "audio/skill/junxing1.mp3", + "audio/skill/junxing2.mp3", + "audio/skill/jushou.mp3", + "audio/skill/jushou1.mp3", + "audio/skill/jushou2.mp3", + "audio/skill/juxiang1_ol_zhurong1.mp3", + "audio/skill/juxiang1_ol_zhurong2.mp3", + "audio/skill/juxiang1_re_zhurong1.mp3", + "audio/skill/juxiang1_re_zhurong2.mp3", + "audio/skill/juxiang11.mp3", + "audio/skill/juxiang12.mp3", + "audio/skill/juyi1.mp3", + "audio/skill/juyi2.mp3", + "audio/skill/jyishi1.mp3", + "audio/skill/jyishi2.mp3", + "audio/skill/jyzongshi_re_jianyong1.mp3", + "audio/skill/jyzongshi_re_jianyong2.mp3", + "audio/skill/jyzongshi1.mp3", + "audio/skill/jyzongshi2.mp3", + "audio/skill/kaikang1.mp3", + "audio/skill/kaikang2.mp3", + "audio/skill/kanade_benzhan1.mp3", + "audio/skill/kanade_benzhan2.mp3", + "audio/skill/kanade_benzhan3.mp3", + "audio/skill/kanade_mapo1.mp3", + "audio/skill/kanade_mapo2.mp3", + "audio/skill/kangge1.mp3", + "audio/skill/kangge2.mp3", + "audio/skill/kanpo1.mp3", + "audio/skill/kanpo2.mp3", + "audio/skill/keji_re_lvmeng1.mp3", + "audio/skill/keji_re_lvmeng2.mp3", + "audio/skill/keji1.mp3", + "audio/skill/keji2.mp3", + "audio/skill/keshou1.mp3", + "audio/skill/keshou2.mp3", + "audio/skill/kongcheng_re_zhugeliang1.mp3", + "audio/skill/kongcheng_re_zhugeliang2.mp3", + "audio/skill/kongcheng11.mp3", + "audio/skill/kongcheng12.mp3", + "audio/skill/kongsheng1.mp3", + "audio/skill/kongsheng2.mp3", + "audio/skill/koulve1.mp3", + "audio/skill/koulve2.mp3", + "audio/skill/kousheng1.mp3", + "audio/skill/kousheng2.mp3", + "audio/skill/kuangbi1.mp3", + "audio/skill/kuangbi2.mp3", + "audio/skill/kuangcai1.mp3", + "audio/skill/kuangcai2.mp3", + "audio/skill/kuangfeng1.mp3", + "audio/skill/kuangfeng2.mp3", + "audio/skill/kuangfu1.mp3", + "audio/skill/kuangfu2.mp3", + "audio/skill/kuanggu_ol_weiyan1.mp3", + "audio/skill/kuanggu_ol_weiyan2.mp3", + "audio/skill/kuanggu_re_weiyan1.mp3", + "audio/skill/kuanggu_re_weiyan2.mp3", + "audio/skill/kuanggu1.mp3", + "audio/skill/kuanggu2.mp3", + "audio/skill/kuanshi1.mp3", + "audio/skill/kuanshi2.mp3", + "audio/skill/kuiji1.mp3", + "audio/skill/kuiji2.mp3", + "audio/skill/kuimang1.mp3", + "audio/skill/kuimang2.mp3", + "audio/skill/kuiwei1.mp3", + "audio/skill/kuiwei2.mp3", + "audio/skill/kunfen1.mp3", + "audio/skill/kunfen2.mp3", + "audio/skill/kurou1.mp3", + "audio/skill/kurou2.mp3", + "audio/skill/kuwu.mp3", + "audio/skill/laishou1.mp3", + "audio/skill/laishou2.mp3", + "audio/skill/laishou3.mp3", + "audio/skill/langmie1.mp3", + "audio/skill/langmie2.mp3", + "audio/skill/lanjiang1.mp3", + "audio/skill/lanjiang2.mp3", + "audio/skill/leiji1.mp3", + "audio/skill/leiji2.mp3", + "audio/skill/liandui1.mp3", + "audio/skill/liandui2.mp3", + "audio/skill/liangcaokuifa.mp3", + "audio/skill/liangfan1.mp3", + "audio/skill/liangfan2.mp3", + "audio/skill/liangjue1.mp3", + "audio/skill/liangjue2.mp3", + "audio/skill/liangjunxiangchi.mp3", + "audio/skill/liangyin1.mp3", + "audio/skill/liangyin2.mp3", + "audio/skill/liangying1.mp3", + "audio/skill/liangyuan1.mp3", + "audio/skill/liangyuan2.mp3", + "audio/skill/liangzhu1.mp3", + "audio/skill/liangzhu2.mp3", + "audio/skill/lianhuan1.mp3", + "audio/skill/lianhuan2.mp3", + "audio/skill/lianhuo1.mp3", + "audio/skill/lianhuo2.mp3", + "audio/skill/lianji.mp3", + "audio/skill/lianpo.mp3", + "audio/skill/lianpo1.mp3", + "audio/skill/lianpo2.mp3", + "audio/skill/lianying1.mp3", + "audio/skill/lianying2.mp3", + "audio/skill/lianzhou1.mp3", + "audio/skill/lianzhou2.mp3", + "audio/skill/lianzhu1.mp3", + "audio/skill/lianzhu2.mp3", + "audio/skill/lianzi1.mp3", + "audio/skill/lianzi2.mp3", + "audio/skill/liaoyi1.mp3", + "audio/skill/liaoyi2.mp3", + "audio/skill/liechi1.mp3", + "audio/skill/liechi2.mp3", + "audio/skill/liedan1.mp3", + "audio/skill/liedan2.mp3", + "audio/skill/liegong_ol_huangzhong1.mp3", + "audio/skill/liegong_ol_huangzhong2.mp3", + "audio/skill/liegong_re_huangzhong1.mp3", + "audio/skill/liegong_re_huangzhong2.mp3", + "audio/skill/liegong1.mp3", + "audio/skill/liegong2.mp3", + "audio/skill/liehou1.mp3", + "audio/skill/liehou2.mp3", + "audio/skill/liejie1.mp3", + "audio/skill/liejie2.mp3", + "audio/skill/lieren_ol_zhurong1.mp3", + "audio/skill/lieren_ol_zhurong2.mp3", + "audio/skill/lieren1.mp3", + "audio/skill/lieren2.mp3", + "audio/skill/liewei1.mp3", + "audio/skill/liewei2.mp3", + "audio/skill/lieyi1.mp3", + "audio/skill/lieyi2.mp3", + "audio/skill/liezhi1.mp3", + "audio/skill/liezhi2.mp3", + "audio/skill/lihun1.mp3", + "audio/skill/lihun2.mp3", + "audio/skill/lihuo_re_chengpu1.mp3", + "audio/skill/lihuo_re_chengpu2.mp3", + "audio/skill/lihuo1.mp3", + "audio/skill/lihuo2.mp3", + "audio/skill/liji1.mp3", + "audio/skill/liji2.mp3", + "audio/skill/lijian_re_diaochan1.mp3", + "audio/skill/lijian_re_diaochan2.mp3", + "audio/skill/lijian1.mp3", + "audio/skill/lijian2.mp3", + "audio/skill/lingbo1.mp3", + "audio/skill/lingbo2.mp3", + "audio/skill/lingce1.mp3", + "audio/skill/lingce2.mp3", + "audio/skill/linglong1.mp3", + "audio/skill/linglong2.mp3", + "audio/skill/lingren_jianxiong1.mp3", + "audio/skill/lingren_xingshang1.mp3", + "audio/skill/lirang1.mp3", + "audio/skill/lirang2.mp3", + "audio/skill/lisi1.mp3", + "audio/skill/lisi2.mp3", + "audio/skill/liubing1.mp3", + "audio/skill/liubing2.mp3", + "audio/skill/liuli_daxiaoqiao1.mp3", + "audio/skill/liuli_daxiaoqiao2.mp3", + "audio/skill/liuli_re_daqiao1.mp3", + "audio/skill/liuli_re_daqiao2.mp3", + "audio/skill/liuli1.mp3", + "audio/skill/liuli2.mp3", + "audio/skill/liunian1.mp3", + "audio/skill/liunian2.mp3", + "audio/skill/lixia1.mp3", + "audio/skill/lixia2.mp3", + "audio/skill/liyu1.mp3", + "audio/skill/liyu2.mp3", + "audio/skill/lizhan1.mp3", + "audio/skill/lizhan2.mp3", + "audio/skill/lkbushi1.mp3", + "audio/skill/lkbushi2.mp3", + "audio/skill/lkzhongzhuang1.mp3", + "audio/skill/lkzhongzhuang2.mp3", + "audio/skill/llqshenwei1.mp3", + "audio/skill/llqshenwei2.mp3", + "audio/skill/longdan_sha_re_zhaoyun1.mp3", + "audio/skill/longdan_sha_re_zhaoyun2.mp3", + "audio/skill/longdan_sha1.mp3", + "audio/skill/longdan_sha2.mp3", + "audio/skill/longdan_tongyuan.mp3", + "audio/skill/longhun1.mp3", + "audio/skill/longhun2.mp3", + "audio/skill/longhun3.mp3", + "audio/skill/longhun4.mp3", + "audio/skill/longyin1.mp3", + "audio/skill/longyin2.mp3", + "audio/skill/longyuan1.mp3", + "audio/skill/longyuan2.mp3", + "audio/skill/lskuizhu1.mp3", + "audio/skill/lskuizhu2.mp3", + "audio/skill/lslixun1.mp3", + "audio/skill/lslixun2.mp3", + "audio/skill/luanchou1.mp3", + "audio/skill/luanchou2.mp3", + "audio/skill/luanfeng1.mp3", + "audio/skill/luanfeng2.mp3", + "audio/skill/luanji1.mp3", + "audio/skill/luanji2.mp3", + "audio/skill/luanqun1.mp3", + "audio/skill/luanqun2.mp3", + "audio/skill/luanwu_re_jiaxu1.mp3", + "audio/skill/luanwu_re_jiaxu2.mp3", + "audio/skill/luanwu1.mp3", + "audio/skill/luanwu2.mp3", + "audio/skill/luanzhan1.mp3", + "audio/skill/luanzhan2.mp3", + "audio/skill/lulve1.mp3", + "audio/skill/lulve2.mp3", + "audio/skill/luochong1.mp3", + "audio/skill/luochong2.mp3", + "audio/skill/luoshen1.mp3", + "audio/skill/luoshen2.mp3", + "audio/skill/luoyi1.mp3", + "audio/skill/luoyi2.mp3", + "audio/skill/luoying_discard1.mp3", + "audio/skill/luoying_discard2.mp3", + "audio/skill/luoying_judge1.mp3", + "audio/skill/luoying_judge2.mp3", + "audio/skill/luoying1.mp3", + "audio/skill/luoying2.mp3", + "audio/skill/lvli1.mp3", + "audio/skill/lvli2.mp3", + "audio/skill/lxzhuixi1.mp3", + "audio/skill/lxzhuixi2.mp3", + "audio/skill/maihuo1.mp3", + "audio/skill/maihuo2.mp3", + "audio/skill/manji1.mp3", + "audio/skill/manji2.mp3", + "audio/skill/manjuan.mp3", + "audio/skill/mansi1.mp3", + "audio/skill/mansi2.mp3", + "audio/skill/manyi_mengyou1.mp3", + "audio/skill/manyi_mengyou2.mp3", + "audio/skill/manyi1.mp3", + "audio/skill/manyi2.mp3", + "audio/skill/mazui.mp3", + "audio/skill/mbaosi1.mp3", + "audio/skill/mbaosi2.mp3", + "audio/skill/mbdaoshu1.mp3", + "audio/skill/mbdaoshu2.mp3", + "audio/skill/mbdaoshu3.mp3", + "audio/skill/mbguli1.mp3", + "audio/skill/mbguli2.mp3", + "audio/skill/mbhuiyao1.mp3", + "audio/skill/mbhuiyao2.mp3", + "audio/skill/mbquesong1.mp3", + "audio/skill/mbquesong2.mp3", + "audio/skill/mbshihe1.mp3", + "audio/skill/mbshihe2.mp3", + "audio/skill/mbyilie1.mp3", + "audio/skill/mbyilie2.mp3", + "audio/skill/mbyilie3.mp3", + "audio/skill/mbzhenfu1.mp3", + "audio/skill/mbzhenfu2.mp3", + "audio/skill/meibu1.mp3", + "audio/skill/meibu2.mp3", + "audio/skill/meihun1.mp3", + "audio/skill/meihun2.mp3", + "audio/skill/mengjin1.mp3", + "audio/skill/mengjin2.mp3", + "audio/skill/mengqing1.mp3", + "audio/skill/mengqing2.mp3", + "audio/skill/mffengshi_sp_mifangfushiren1.mp3", + "audio/skill/mffengshi_sp_mifangfushiren2.mp3", + "audio/skill/mffengshi1.mp3", + "audio/skill/mffengshi2.mp3", + "audio/skill/miaojian1.mp3", + "audio/skill/miaojian2.mp3", + "audio/skill/miaoxian1.mp3", + "audio/skill/miaoxian2.mp3", + "audio/skill/mibei1.mp3", + "audio/skill/mibei2.mp3", + "audio/skill/midao1.mp3", + "audio/skill/midao2.mp3", + "audio/skill/midu1.mp3", + "audio/skill/midu2.mp3", + "audio/skill/mieji1.mp3", + "audio/skill/mieji2.mp3", + "audio/skill/miji_re_wangyi1.mp3", + "audio/skill/miji_re_wangyi2.mp3", + "audio/skill/miji1.mp3", + "audio/skill/miji2.mp3", + "audio/skill/mingce1.mp3", + "audio/skill/mingce2.mp3", + "audio/skill/mingcha1.mp3", + "audio/skill/mingcha2.mp3", + "audio/skill/mingfa1.mp3", + "audio/skill/mingfa2.mp3", + "audio/skill/mingjian1.mp3", + "audio/skill/mingjian2.mp3", + "audio/skill/mingjie1.mp3", + "audio/skill/mingluan1.mp3", + "audio/skill/mingluan2.mp3", + "audio/skill/mingshi1.mp3", + "audio/skill/mingshi2.mp3", + "audio/skill/mingzhe1.mp3", + "audio/skill/mingzhe2.mp3", + "audio/skill/minsi1.mp3", + "audio/skill/minsi2.mp3", + "audio/skill/mizhao1.mp3", + "audio/skill/mizhao2.mp3", + "audio/skill/mjchenshi1.mp3", + "audio/skill/mjchenshi2.mp3", + "audio/skill/mjdingyi1.mp3", + "audio/skill/mjdingyi2.mp3", + "audio/skill/mjmouzhi1.mp3", + "audio/skill/mjmouzhi2.mp3", + "audio/skill/mjweipo1.mp3", + "audio/skill/mjweipo2.mp3", + "audio/skill/mobiledanshou1.mp3", + "audio/skill/mobiledanshou2.mp3", + "audio/skill/mobilejingce1.mp3", + "audio/skill/mobilejingce2.mp3", + "audio/skill/mobilexingxue1.mp3", + "audio/skill/mobilexingxue2.mp3", + "audio/skill/mobileyanzhu1.mp3", + "audio/skill/mobileyanzhu2.mp3", + "audio/skill/mobilezhongyong1.mp3", + "audio/skill/mobilezhongyong2.mp3", + "audio/skill/monkey.mp3", + "audio/skill/moucheng1.mp3", + "audio/skill/moucheng2.mp3", + "audio/skill/moucuan1.mp3", + "audio/skill/moucuan2.mp3", + "audio/skill/moukui1.mp3", + "audio/skill/moukui2.mp3", + "audio/skill/mouli1.mp3", + "audio/skill/mouli2.mp3", + "audio/skill/mouni1.mp3", + "audio/skill/mouni2.mp3", + "audio/skill/mouzhi1.mp3", + "audio/skill/mouzhi2.mp3", + "audio/skill/mouzhu1.mp3", + "audio/skill/mouzhu2.mp3", + "audio/skill/mozhi1.mp3", + "audio/skill/mozhi2.mp3", + "audio/skill/mpbishi1.mp3", + "audio/skill/mpbishi2.mp3", + "audio/skill/mpjiusong1.mp3", + "audio/skill/mpjiusong2.mp3", + "audio/skill/mpmaotao1.mp3", + "audio/skill/mpmaotao2.mp3", + "audio/skill/mubing1.mp3", + "audio/skill/mubing2.mp3", + "audio/skill/mumu1.mp3", + "audio/skill/mumu2.mp3", + "audio/skill/muzhen1.mp3", + "audio/skill/muzhen2.mp3", + "audio/skill/naman1.mp3", + "audio/skill/naman2.mp3", + "audio/skill/naxiang1.mp3", + "audio/skill/naxiang2.mp3", + "audio/skill/naxue1.mp3", + "audio/skill/naxue2.mp3", + "audio/skill/neifa1.mp3", + "audio/skill/neifa2.mp3", + "audio/skill/new_jiangchi1.mp3", + "audio/skill/new_jiangchi2.mp3", + "audio/skill/new_reqingnang1.mp3", + "audio/skill/new_reqingnang2.mp3", + "audio/skill/new_reyaowu_sb_huaxiong1.mp3", + "audio/skill/new_reyaowu_sb_huaxiong2.mp3", + "audio/skill/new_reyaowu1.mp3", + "audio/skill/new_reyaowu2.mp3", + "audio/skill/niepan_re_pangtong1.mp3", + "audio/skill/niepan_re_pangtong2.mp3", + "audio/skill/niepan1.mp3", + "audio/skill/niepan2.mp3", + "audio/skill/nifu1.mp3", + "audio/skill/nifu2.mp3", + "audio/skill/niluan1.mp3", + "audio/skill/niluan2.mp3", + "audio/skill/noda_fengcheng1.mp3", + "audio/skill/noda_fengcheng2.mp3", + "audio/skill/noda_xunxin1.mp3", + "audio/skill/noda_xunxin2.mp3", + "audio/skill/ns_nsshimeng1.mp3", + "audio/skill/ns_nsshimeng2.mp3", + "audio/skill/nzry_binglve1.mp3", + "audio/skill/nzry_binglve2.mp3", + "audio/skill/nzry_chenglve1.mp3", + "audio/skill/nzry_chenglve2.mp3", + "audio/skill/nzry_cuike1.mp3", + "audio/skill/nzry_cuike2.mp3", + "audio/skill/nzry_cunmu1.mp3", + "audio/skill/nzry_cunmu2.mp3", + "audio/skill/nzry_dinghuo1.mp3", + "audio/skill/nzry_dinghuo2.mp3", + "audio/skill/nzry_feijun1.mp3", + "audio/skill/nzry_feijun2.mp3", + "audio/skill/nzry_huaiju1.mp3", + "audio/skill/nzry_huaiju2.mp3", + "audio/skill/nzry_jianxiang1.mp3", + "audio/skill/nzry_jianxiang2.mp3", + "audio/skill/nzry_jieying1.mp3", + "audio/skill/nzry_jieying2.mp3", + "audio/skill/nzry_junlve1.mp3", + "audio/skill/nzry_junlve2.mp3", + "audio/skill/nzry_juzhan_11.mp3", + "audio/skill/nzry_juzhan_12.mp3", + "audio/skill/nzry_kuizhu1.mp3", + "audio/skill/nzry_kuizhu2.mp3", + "audio/skill/nzry_lijun11.mp3", + "audio/skill/nzry_lijun12.mp3", + "audio/skill/nzry_longnu1.mp3", + "audio/skill/nzry_longnu2.mp3", + "audio/skill/nzry_mingren_1_sb_yl_luzhi1.mp3", + "audio/skill/nzry_mingren_1_sb_yl_luzhi2.mp3", + "audio/skill/nzry_mingren_11.mp3", + "audio/skill/nzry_mingren_12.mp3", + "audio/skill/nzry_shenshi_11.mp3", + "audio/skill/nzry_shenshi_12.mp3", + "audio/skill/nzry_shicai_21.mp3", + "audio/skill/nzry_shicai_22.mp3", + "audio/skill/nzry_yili1.mp3", + "audio/skill/nzry_yili2.mp3", + "audio/skill/nzry_zhenglun1.mp3", + "audio/skill/nzry_zhenglun2.mp3", + "audio/skill/nzry_zhenliang_11.mp3", + "audio/skill/nzry_zhenliang_12.mp3", + "audio/skill/nzry_zhizheng1.mp3", + "audio/skill/nzry_zhizheng2.mp3", + "audio/skill/ocongjian_tongyuan.mp3", + "audio/skill/ol_shenfen1.mp3", + "audio/skill/ol_shenfen2.mp3", + "audio/skill/ol_shichou1.mp3", + "audio/skill/ol_shichou2.mp3", + "audio/skill/ol_wuqian1.mp3", + "audio/skill/ol_wuqian2.mp3", + "audio/skill/olbaonue1.mp3", + "audio/skill/olbaonue2.mp3", + "audio/skill/olbeige1.mp3", + "audio/skill/olbeige2.mp3", + "audio/skill/olbihun1.mp3", + "audio/skill/olbihun2.mp3", + "audio/skill/olbixin1.mp3", + "audio/skill/olbixin2.mp3", + "audio/skill/olchanshuang1.mp3", + "audio/skill/olchanshuang2.mp3", + "audio/skill/olchenglie1.mp3", + "audio/skill/olchenglie2.mp3", + "audio/skill/olchenshuo1.mp3", + "audio/skill/olchenshuo2.mp3", + "audio/skill/olchongshen1.mp3", + "audio/skill/olchongshen2.mp3", + "audio/skill/olchuanwu1.mp3", + "audio/skill/olchuanwu2.mp3", + "audio/skill/olchuming1.mp3", + "audio/skill/olchuming2.mp3", + "audio/skill/olcuipo1.mp3", + "audio/skill/olcuipo2.mp3", + "audio/skill/old_fuhun1.mp3", + "audio/skill/old_fuhun2.mp3", + "audio/skill/old_guhuo1.mp3", + "audio/skill/old_guhuo2.mp3", + "audio/skill/oldaili1.mp3", + "audio/skill/oldaili2.mp3", + "audio/skill/oldianjun1.mp3", + "audio/skill/oldianjun2.mp3", + "audio/skill/oldimeng1.mp3", + "audio/skill/oldimeng2.mp3", + "audio/skill/oldingcuo1.mp3", + "audio/skill/oldingcuo2.mp3", + "audio/skill/oldmiji1.mp3", + "audio/skill/oldmiji2.mp3", + "audio/skill/oldongdao1.mp3", + "audio/skill/oldongdao2.mp3", + "audio/skill/oldqianxi1.mp3", + "audio/skill/oldqianxi2.mp3", + "audio/skill/olduanliang1.mp3", + "audio/skill/olduanliang2.mp3", + "audio/skill/oldzhenlie1.mp3", + "audio/skill/oldzhenlie2.mp3", + "audio/skill/olfangquan_shen_caopi1.mp3", + "audio/skill/olfangquan_shen_caopi2.mp3", + "audio/skill/olfangquan1.mp3", + "audio/skill/olfangquan2.mp3", + "audio/skill/olfeibai1.mp3", + "audio/skill/olfeibai2.mp3", + "audio/skill/olfengji1.mp3", + "audio/skill/olfengji2.mp3", + "audio/skill/olfengyan1.mp3", + "audio/skill/olfengyan2.mp3", + "audio/skill/olfengzi1.mp3", + "audio/skill/olfengzi2.mp3", + "audio/skill/olfudao1.mp3", + "audio/skill/olfudao2.mp3", + "audio/skill/olfushi1.mp3", + "audio/skill/olfushi2.mp3", + "audio/skill/olfusong1.mp3", + "audio/skill/olfusong2.mp3", + "audio/skill/olgangshu1.mp3", + "audio/skill/olgangshu2.mp3", + "audio/skill/olgongjie1.mp3", + "audio/skill/olgongjie2.mp3", + "audio/skill/olgoude1.mp3", + "audio/skill/olgoude2.mp3", + "audio/skill/olguangao1.mp3", + "audio/skill/olguangao2.mp3", + "audio/skill/olguzheng1.mp3", + "audio/skill/olguzheng2.mp3", + "audio/skill/olhaoshi1.mp3", + "audio/skill/olhaoshi2.mp3", + "audio/skill/olhongji1.mp3", + "audio/skill/olhongji2.mp3", + "audio/skill/olhuanfu1.mp3", + "audio/skill/olhuanfu2.mp3", + "audio/skill/olhuiqi1.mp3", + "audio/skill/olhuiqi2.mp3", + "audio/skill/olhuiyun1.mp3", + "audio/skill/olhuiyun2.mp3", + "audio/skill/olhunzi_re_sunyi1.mp3", + "audio/skill/olhunzi_re_sunyi2.mp3", + "audio/skill/olhunzi1.mp3", + "audio/skill/olhunzi2.mp3", + "audio/skill/oljianhe1.mp3", + "audio/skill/oljianhe2.mp3", + "audio/skill/oljianman1.mp3", + "audio/skill/oljianman2.mp3", + "audio/skill/oljianxuan1.mp3", + "audio/skill/oljianxuan2.mp3", + "audio/skill/oljieming1.mp3", + "audio/skill/oljieming2.mp3", + "audio/skill/oljiezi1.mp3", + "audio/skill/oljiezi2.mp3", + "audio/skill/oljiuchi1.mp3", + "audio/skill/oljiuchi2.mp3", + "audio/skill/oljizhan1.mp3", + "audio/skill/oljizhan2.mp3", + "audio/skill/oljuanxia1.mp3", + "audio/skill/oljuanxia2.mp3", + "audio/skill/olkangrui1.mp3", + "audio/skill/olkangrui2.mp3", + "audio/skill/olkenshang1.mp3", + "audio/skill/olkenshang2.mp3", + "audio/skill/olkuansai1.mp3", + "audio/skill/olkuansai2.mp3", + "audio/skill/ollangdao1.mp3", + "audio/skill/ollangdao2.mp3", + "audio/skill/olleijie1.mp3", + "audio/skill/olleijie2.mp3", + "audio/skill/olluanji_shen_caopi1.mp3", + "audio/skill/olluanji_shen_caopi2.mp3", + "audio/skill/olluanji1.mp3", + "audio/skill/olluanji2.mp3", + "audio/skill/olmiuyan1.mp3", + "audio/skill/olmiuyan2.mp3", + "audio/skill/olniepan1.mp3", + "audio/skill/olniepan2.mp3", + "audio/skill/olningwu1.mp3", + "audio/skill/olningwu2.mp3", + "audio/skill/olnishou1.mp3", + "audio/skill/olnishou2.mp3", + "audio/skill/olqiejian1.mp3", + "audio/skill/olqiejian2.mp3", + "audio/skill/olqingyi1.mp3", + "audio/skill/olqingyi2.mp3", + "audio/skill/olqingyuan1.mp3", + "audio/skill/olqingyuan2.mp3", + "audio/skill/olqisi1.mp3", + "audio/skill/olqisi2.mp3", + "audio/skill/olqushi1.mp3", + "audio/skill/olqushi2.mp3", + "audio/skill/olruoyu1.mp3", + "audio/skill/olruoyu2.mp3", + "audio/skill/olsaogu1.mp3", + "audio/skill/olsaogu2.mp3", + "audio/skill/olsbdouchan1.mp3", + "audio/skill/olsbdouchan2.mp3", + "audio/skill/olsbdulie1.mp3", + "audio/skill/olsbdulie2.mp3", + "audio/skill/olsbduoshou1.mp3", + "audio/skill/olsbduoshou2.mp3", + "audio/skill/olsbfumeng1.mp3", + "audio/skill/olsbfumeng2.mp3", + "audio/skill/olsbguidao1.mp3", + "audio/skill/olsbguidao2.mp3", + "audio/skill/olsbhetao_ol_sb_yuanshao_shadow1.mp3", + "audio/skill/olsbhetao_ol_sb_yuanshao_shadow2.mp3", + "audio/skill/olsbhetao_ol_sb_yuanshao_shadow3.mp3", + "audio/skill/olsbhetao1.mp3", + "audio/skill/olsbhetao2.mp3", + "audio/skill/olsbhetao3.mp3", + "audio/skill/olsbranji1.mp3", + "audio/skill/olsbranji2.mp3", + "audio/skill/olsbshenli_ol_sb_yuanshao_shadow1.mp3", + "audio/skill/olsbshenli_ol_sb_yuanshao_shadow2.mp3", + "audio/skill/olsbshenli_ol_sb_yuanshao_shadow3.mp3", + "audio/skill/olsbshenli1.mp3", + "audio/skill/olsbshenli2.mp3", + "audio/skill/olsbshenli3.mp3", + "audio/skill/olsbshishou_ol_sb_yuanshao_shadow1.mp3", + "audio/skill/olsbshishou_ol_sb_yuanshao_shadow2.mp3", + "audio/skill/olsbshishou_ol_sb_yuanshao_shadow3.mp3", + "audio/skill/olsbshishou1.mp3", + "audio/skill/olsbshishou2.mp3", + "audio/skill/olsbshishou3.mp3", + "audio/skill/olsbweilin1.mp3", + "audio/skill/olsbweilin2.mp3", + "audio/skill/olsbyufeng_ol_sb_yuanshao_shadow1.mp3", + "audio/skill/olsbyufeng1.mp3", + "audio/skill/olsbyufeng2.mp3", + "audio/skill/olsbzhuri1.mp3", + "audio/skill/olsbzhuri2.mp3", + "audio/skill/olshandao1.mp3", + "audio/skill/olshandao2.mp3", + "audio/skill/olshengong1.mp3", + "audio/skill/olshengong2.mp3", + "audio/skill/olshilu1.mp3", + "audio/skill/olshilu2.mp3", + "audio/skill/olshuangxiong1.mp3", + "audio/skill/olshuangxiong2.mp3", + "audio/skill/olsuji1.mp3", + "audio/skill/olsuji2.mp3", + "audio/skill/olsujian1.mp3", + "audio/skill/olsujian2.mp3", + "audio/skill/oltianhou_club.mp3", + "audio/skill/oltianhou_diamond.mp3", + "audio/skill/oltianhou_heart.mp3", + "audio/skill/oltianhou_spade.mp3", + "audio/skill/oltianhou1.mp3", + "audio/skill/oltianhou2.mp3", + "audio/skill/oltongduo1.mp3", + "audio/skill/oltongduo2.mp3", + "audio/skill/oltousui1.mp3", + "audio/skill/oltousui2.mp3", + "audio/skill/oltuntian1.mp3", + "audio/skill/oltuntian2.mp3", + "audio/skill/olweifu1.mp3", + "audio/skill/olweifu2.mp3", + "audio/skill/olweijie1.mp3", + "audio/skill/olweijie2.mp3", + "audio/skill/olxianbi1.mp3", + "audio/skill/olxianbi2.mp3", + "audio/skill/olxiangxv1.mp3", + "audio/skill/olxiangxv2.mp3", + "audio/skill/olxiangzuo1.mp3", + "audio/skill/olxiangzuo2.mp3", + "audio/skill/olxianlve1.mp3", + "audio/skill/olxianlve2.mp3", + "audio/skill/olxiaosi1.mp3", + "audio/skill/olxiaosi2.mp3", + "audio/skill/olxibing1.mp3", + "audio/skill/olxibing2.mp3", + "audio/skill/olxieju1.mp3", + "audio/skill/olxieju2.mp3", + "audio/skill/olximo1.mp3", + "audio/skill/olximo2.mp3", + "audio/skill/olximo3.mp3", + "audio/skill/olxinggu1.mp3", + "audio/skill/olxinggu2.mp3", + "audio/skill/olxiuhao1.mp3", + "audio/skill/olxiuhao2.mp3", + "audio/skill/olxueyi1.mp3", + "audio/skill/olxueyi2.mp3", + "audio/skill/olzaowang1.mp3", + "audio/skill/olzaowang2.mp3", + "audio/skill/olzaoxian1.mp3", + "audio/skill/olzaoxian2.mp3", + "audio/skill/olzenrun1.mp3", + "audio/skill/olzenrun2.mp3", + "audio/skill/olzeyue1.mp3", + "audio/skill/olzeyue2.mp3", + "audio/skill/olzhanjin1.mp3", + "audio/skill/olzhanjin2.mp3", + "audio/skill/olzhenying1.mp3", + "audio/skill/olzhenying2.mp3", + "audio/skill/olzhiba1.mp3", + "audio/skill/olzhiba2.mp3", + "audio/skill/olzhiji1.mp3", + "audio/skill/olzhiji2.mp3", + "audio/skill/olzhijian1.mp3", + "audio/skill/olzhijian2.mp3", + "audio/skill/olzhubi1.mp3", + "audio/skill/olzhubi2.mp3", + "audio/skill/olzhuyan1.mp3", + "audio/skill/olzhuyan2.mp3", + "audio/skill/paiyi_re_zhonghui1.mp3", + "audio/skill/paiyi_re_zhonghui2.mp3", + "audio/skill/paiyi1.mp3", + "audio/skill/paiyi2.mp3", + "audio/skill/paoxiao_guanzhang1.mp3", + "audio/skill/paoxiao_guanzhang2.mp3", + "audio/skill/paoxiao_re_guanzhang1.mp3", + "audio/skill/paoxiao_re_guanzhang2.mp3", + "audio/skill/paoxiao_re_zhangfei1.mp3", + "audio/skill/paoxiao_re_zhangfei2.mp3", + "audio/skill/paoxiao_xiahouba1.mp3", + "audio/skill/paoxiao_xiahouba2.mp3", + "audio/skill/paoxiao1.mp3", + "audio/skill/paoxiao2.mp3", + "audio/skill/pcaudio_fengchu_card.mp3", + "audio/skill/pcaudio_shuijing_card.mp3", + "audio/skill/pcaudio_wolong_card.mp3", + "audio/skill/pcaudio_xuanjian_card.mp3", + "audio/skill/pianchong1.mp3", + "audio/skill/pianchong2.mp3", + "audio/skill/pianyi1.mp3", + "audio/skill/pianyi2.mp3", + "audio/skill/piaoling1.mp3", + "audio/skill/piaoling2.mp3", + "audio/skill/piaoping1.mp3", + "audio/skill/piaoping2.mp3", + "audio/skill/pindi1.mp3", + "audio/skill/pindi2.mp3", + "audio/skill/pinghe1.mp3", + "audio/skill/pinghe2.mp3", + "audio/skill/pingjian1.mp3", + "audio/skill/pingjian2.mp3", + "audio/skill/pingkou1.mp3", + "audio/skill/pingkou2.mp3", + "audio/skill/pingxiang1.mp3", + "audio/skill/pingxiang2.mp3", + "audio/skill/pojun1.mp3", + "audio/skill/pojun2.mp3", + "audio/skill/polu1.mp3", + "audio/skill/polu2.mp3", + "audio/skill/poxiang1.mp3", + "audio/skill/poxiang2.mp3", + "audio/skill/pozhu1.mp3", + "audio/skill/pozhu2.mp3", + "audio/skill/pytianjiang1.mp3", + "audio/skill/pytianjiang2.mp3", + "audio/skill/pyzhuren1.mp3", + "audio/skill/pyzhuren2.mp3", + "audio/skill/qhzhangji1.mp3", + "audio/skill/qhzhangji2.mp3", + "audio/skill/qiangwu1.mp3", + "audio/skill/qiangwu2.mp3", + "audio/skill/qiangxi_boss_lvbu31.mp3", + "audio/skill/qiangxi_boss_lvbu32.mp3", + "audio/skill/qiangxi_ol_dianwei1.mp3", + "audio/skill/qiangxi_ol_dianwei2.mp3", + "audio/skill/qiangxi1.mp3", + "audio/skill/qiangxi2.mp3", + "audio/skill/qiangzhi_re_zhangsong1.mp3", + "audio/skill/qiangzhi_re_zhangsong2.mp3", + "audio/skill/qiangzhi1.mp3", + "audio/skill/qiangzhi2.mp3", + "audio/skill/qianhuan1.mp3", + "audio/skill/qianhuan2.mp3", + "audio/skill/qianlong1.mp3", + "audio/skill/qianlong2.mp3", + "audio/skill/qianmeng1.mp3", + "audio/skill/qianmeng2.mp3", + "audio/skill/qianxi1.mp3", + "audio/skill/qianxi2.mp3", + "audio/skill/qianxin1.mp3", + "audio/skill/qianxin2.mp3", + "audio/skill/qianxun1.mp3", + "audio/skill/qianxun2.mp3", + "audio/skill/qianya1.mp3", + "audio/skill/qianya2.mp3", + "audio/skill/qiaobian1.mp3", + "audio/skill/qiaobian2.mp3", + "audio/skill/qiaoli1.mp3", + "audio/skill/qiaoli2.mp3", + "audio/skill/qiaomeng1.mp3", + "audio/skill/qiaomeng2.mp3", + "audio/skill/qiaoshi1.mp3", + "audio/skill/qiaoshi2.mp3", + "audio/skill/qiaoshui1.mp3", + "audio/skill/qiaoshui2.mp3", + "audio/skill/qiaoyan1.mp3", + "audio/skill/qiaoyan2.mp3", + "audio/skill/qibaodao2.mp3", + "audio/skill/qibie1.mp3", + "audio/skill/qibie2.mp3", + "audio/skill/qice_clan_xunyou1.mp3", + "audio/skill/qice_clan_xunyou2.mp3", + "audio/skill/qice1.mp3", + "audio/skill/qice2.mp3", + "audio/skill/qieting1.mp3", + "audio/skill/qieting2.mp3", + "audio/skill/qiexie1.mp3", + "audio/skill/qiexie2.mp3", + "audio/skill/qigong1.mp3", + "audio/skill/qigong2.mp3", + "audio/skill/qilin_skill.mp3", + "audio/skill/qiluan21.mp3", + "audio/skill/qiluan22.mp3", + "audio/skill/qimei1.mp3", + "audio/skill/qimei2.mp3", + "audio/skill/qimou1.mp3", + "audio/skill/qimou2.mp3", + "audio/skill/qinbao1.mp3", + "audio/skill/qinbao2.mp3", + "audio/skill/qingbei1.mp3", + "audio/skill/qingbei2.mp3", + "audio/skill/qingcheng1.mp3", + "audio/skill/qingcheng2.mp3", + "audio/skill/qinggang_skill.mp3", + "audio/skill/qingguo_sb_zhenji1.mp3", + "audio/skill/qingguo_sb_zhenji2.mp3", + "audio/skill/qingguo1.mp3", + "audio/skill/qingguo2.mp3", + "audio/skill/qingjian1.mp3", + "audio/skill/qingjian2.mp3", + "audio/skill/qingjiao1.mp3", + "audio/skill/qingjiao2.mp3", + "audio/skill/qingjue1.mp3", + "audio/skill/qingjue2.mp3", + "audio/skill/qingleng1.mp3", + "audio/skill/qingleng2.mp3", + "audio/skill/qingliang1.mp3", + "audio/skill/qingliang2.mp3", + "audio/skill/qinglong_skill.mp3", + "audio/skill/qingman1.mp3", + "audio/skill/qingman2.mp3", + "audio/skill/qingnang1.mp3", + "audio/skill/qingnang2.mp3", + "audio/skill/qingtan1.mp3", + "audio/skill/qingtan2.mp3", + "audio/skill/qinguo_lose1.mp3", + "audio/skill/qinguo_lose2.mp3", + "audio/skill/qinguo_use1.mp3", + "audio/skill/qinguo_use2.mp3", + "audio/skill/qingxi1.mp3", + "audio/skill/qingxi2.mp3", + "audio/skill/qingxian1.mp3", + "audio/skill/qingxian2.mp3", + "audio/skill/qingyi1.mp3", + "audio/skill/qingyi2.mp3", + "audio/skill/qingyin1.mp3", + "audio/skill/qingyin2.mp3", + "audio/skill/qingyu1.mp3", + "audio/skill/qingyu2.mp3", + "audio/skill/qingyu3.mp3", + "audio/skill/qingzhong1.mp3", + "audio/skill/qingzhong2.mp3", + "audio/skill/qinqing1.mp3", + "audio/skill/qinqing2.mp3", + "audio/skill/qinwang11.mp3", + "audio/skill/qinwang12.mp3", + "audio/skill/qinwang21.mp3", + "audio/skill/qinwang22.mp3", + "audio/skill/qinxue1.mp3", + "audio/skill/qinxue2.mp3", + "audio/skill/qinyin1.mp3", + "audio/skill/qinyin2.mp3", + "audio/skill/qinzheng1.mp3", + "audio/skill/qinzheng2.mp3", + "audio/skill/qiongshou1.mp3", + "audio/skill/qiongshou2.mp3", + "audio/skill/qirang1.mp3", + "audio/skill/qirang2.mp3", + "audio/skill/qiuan1.mp3", + "audio/skill/qiuan2.mp3", + "audio/skill/qiuyuan1.mp3", + "audio/skill/qiuyuan2.mp3", + "audio/skill/qiwu.mp3", + "audio/skill/qixi_re_ganning1.mp3", + "audio/skill/qixi_re_ganning2.mp3", + "audio/skill/qixi_re_heqi1.mp3", + "audio/skill/qixi_re_heqi2.mp3", + "audio/skill/qixi1.mp3", + "audio/skill/qixi2.mp3", + "audio/skill/qixing1.mp3", + "audio/skill/qixing2.mp3", + "audio/skill/qizhi1.mp3", + "audio/skill/qizhi2.mp3", + "audio/skill/qljsuiren1.mp3", + "audio/skill/qljsuiren2.mp3", + "audio/skill/quanbian1.mp3", + "audio/skill/quanbian2.mp3", + "audio/skill/quanfeng1.mp3", + "audio/skill/quanfeng2.mp3", + "audio/skill/quanji1.mp3", + "audio/skill/quanji2.mp3", + "audio/skill/quanjin1.mp3", + "audio/skill/quanjin2.mp3", + "audio/skill/quanjiu1.mp3", + "audio/skill/quanjiu2.mp3", + "audio/skill/quhu_ol_xunyu1.mp3", + "audio/skill/quhu_ol_xunyu2.mp3", + "audio/skill/quhu_re_xunyu1.mp3", + "audio/skill/quhu_re_xunyu2.mp3", + "audio/skill/quhu1.mp3", + "audio/skill/quhu2.mp3", + "audio/skill/quji1.mp3", + "audio/skill/quji2.mp3", + "audio/skill/quxi1.mp3", + "audio/skill/quxi2.mp3", + "audio/skill/rangjie1.mp3", + "audio/skill/rangjie2.mp3", + "audio/skill/ranshang1.mp3", + "audio/skill/ranshang2.mp3", + "audio/skill/ranshang21.mp3", + "audio/skill/ranshang22.mp3", + "audio/skill/reandong1.mp3", + "audio/skill/reandong2.mp3", + "audio/skill/reanguo1.mp3", + "audio/skill/reanguo2.mp3", + "audio/skill/reanjian1.mp3", + "audio/skill/reanjian2.mp3", + "audio/skill/reanxu1.mp3", + "audio/skill/reanxu2.mp3", + "audio/skill/rebaobian1.mp3", + "audio/skill/rebaobian2.mp3", + "audio/skill/rebingyi1.mp3", + "audio/skill/rebingyi2.mp3", + "audio/skill/rebiyue1.mp3", + "audio/skill/rebiyue2.mp3", + "audio/skill/rebizhuan1.mp3", + "audio/skill/rebizhuan2.mp3", + "audio/skill/recangchu1.mp3", + "audio/skill/recangchu2.mp3", + "audio/skill/rechanhui1.mp3", + "audio/skill/rechanhui2.mp3", + "audio/skill/rechanyuan1.mp3", + "audio/skill/rechanyuan2.mp3", + "audio/skill/rechengxiang1.mp3", + "audio/skill/rechengxiang2.mp3", + "audio/skill/rechunlao1.mp3", + "audio/skill/rechunlao2.mp3", + "audio/skill/redanxin1.mp3", + "audio/skill/redanxin2.mp3", + "audio/skill/redaoji1.mp3", + "audio/skill/redaoji2.mp3", + "audio/skill/redingpin1.mp3", + "audio/skill/redingpin2.mp3", + "audio/skill/reduodao1.mp3", + "audio/skill/reduodao2.mp3", + "audio/skill/reenyuan1.mp3", + "audio/skill/reenyuan2.mp3", + "audio/skill/refaen_dc_chenqun1.mp3", + "audio/skill/refaen_dc_chenqun2.mp3", + "audio/skill/refaen1.mp3", + "audio/skill/refaen2.mp3", + "audio/skill/refangquan1.mp3", + "audio/skill/refangquan2.mp3", + "audio/skill/refangzhu1.mp3", + "audio/skill/refangzhu2.mp3", + "audio/skill/refanjian1.mp3", + "audio/skill/refanjian2.mp3", + "audio/skill/refankui1.mp3", + "audio/skill/refankui2.mp3", + "audio/skill/refenglve1.mp3", + "audio/skill/refenglve2.mp3", + "audio/skill/refenli1.mp3", + "audio/skill/refenli2.mp3", + "audio/skill/refenyin_wufan1.mp3", + "audio/skill/refenyin_wufan2.mp3", + "audio/skill/refenyin1.mp3", + "audio/skill/refenyin2.mp3", + "audio/skill/refuli1.mp3", + "audio/skill/refuli2.mp3", + "audio/skill/refuman1.mp3", + "audio/skill/refuman2.mp3", + "audio/skill/refuyuan1.mp3", + "audio/skill/refuyuan2.mp3", + "audio/skill/reganglie1.mp3", + "audio/skill/reganglie2.mp3", + "audio/skill/reganlu1.mp3", + "audio/skill/reganlu2.mp3", + "audio/skill/regongji1.mp3", + "audio/skill/regongji2.mp3", + "audio/skill/reguhuo1.mp3", + "audio/skill/reguhuo2.mp3", + "audio/skill/reguicai1.mp3", + "audio/skill/reguicai2.mp3", + "audio/skill/reguose1.mp3", + "audio/skill/reguose2.mp3", + "audio/skill/rehongyan1.mp3", + "audio/skill/rehongyan2.mp3", + "audio/skill/rehuaiyi1.mp3", + "audio/skill/rehuaiyi2.mp3", + "audio/skill/rehuashen1.mp3", + "audio/skill/rehuashen2.mp3", + "audio/skill/rehunzi1.mp3", + "audio/skill/rehunzi2.mp3", + "audio/skill/rehuoji_ol_pangtong1.mp3", + "audio/skill/rehuoji_ol_pangtong2.mp3", + "audio/skill/rehuoji_ol_sp_zhugeliang1.mp3", + "audio/skill/rehuoji_ol_sp_zhugeliang2.mp3", + "audio/skill/rehuoji1.mp3", + "audio/skill/rehuoji2.mp3", + "audio/skill/rehuoshui1.mp3", + "audio/skill/rehuoshui2.mp3", + "audio/skill/rejianchu1.mp3", + "audio/skill/rejianchu2.mp3", + "audio/skill/rejiangchi1.mp3", + "audio/skill/rejiangchi2.mp3", + "audio/skill/rejianxiong_shen_caopi1.mp3", + "audio/skill/rejianxiong_shen_caopi2.mp3", + "audio/skill/rejianxiong1.mp3", + "audio/skill/rejianxiong2.mp3", + "audio/skill/rejianyan1.mp3", + "audio/skill/rejianyan2.mp3", + "audio/skill/rejiaojin1.mp3", + "audio/skill/rejiaojin2.mp3", + "audio/skill/rejiaozhao1.mp3", + "audio/skill/rejiaozhao2.mp3", + "audio/skill/rejieming1.mp3", + "audio/skill/rejieming2.mp3", + "audio/skill/rejieyin1.mp3", + "audio/skill/rejieyin2.mp3", + "audio/skill/rejieyue1.mp3", + "audio/skill/rejieyue2.mp3", + "audio/skill/rejigong1.mp3", + "audio/skill/rejigong2.mp3", + "audio/skill/rejinjiu1.mp3", + "audio/skill/rejinjiu2.mp3", + "audio/skill/rejiqiao1.mp3", + "audio/skill/rejiqiao2.mp3", + "audio/skill/rejiushi1.mp3", + "audio/skill/rejiushi2.mp3", + "audio/skill/rejiuyuan1.mp3", + "audio/skill/rejiuyuan2.mp3", + "audio/skill/rejixu1.mp3", + "audio/skill/rejixu2.mp3", + "audio/skill/rejizhi_lukang1.mp3", + "audio/skill/rejizhi_lukang2.mp3", + "audio/skill/rejizhi1.mp3", + "audio/skill/rejizhi2.mp3", + "audio/skill/rejuece1.mp3", + "audio/skill/rejuece2.mp3", + "audio/skill/rejueqing1.mp3", + "audio/skill/rejueqing2.mp3", + "audio/skill/rejunxing1.mp3", + "audio/skill/rejunxing2.mp3", + "audio/skill/rekanpo_ol_pangtong1.mp3", + "audio/skill/rekanpo_ol_pangtong2.mp3", + "audio/skill/rekanpo_ol_sp_zhugeliang1.mp3", + "audio/skill/rekanpo_ol_sp_zhugeliang2.mp3", + "audio/skill/rekanpo1.mp3", + "audio/skill/rekanpo2.mp3", + "audio/skill/rekuangbi1.mp3", + "audio/skill/rekuangbi2.mp3", + "audio/skill/rekuangcai1.mp3", + "audio/skill/rekuangcai2.mp3", + "audio/skill/rekurou1.mp3", + "audio/skill/rekurou2.mp3", + "audio/skill/releiji1.mp3", + "audio/skill/releiji2.mp3", + "audio/skill/reliangying1.mp3", + "audio/skill/reliangying2.mp3", + "audio/skill/relianying1.mp3", + "audio/skill/relianying2.mp3", + "audio/skill/relieren1.mp3", + "audio/skill/relieren2.mp3", + "audio/skill/relihuo1.mp3", + "audio/skill/relihuo2.mp3", + "audio/skill/relinglong1.mp3", + "audio/skill/relinglong2.mp3", + "audio/skill/relonghun1.mp3", + "audio/skill/relonghun2.mp3", + "audio/skill/relongyin1.mp3", + "audio/skill/relongyin2.mp3", + "audio/skill/reluanji1.mp3", + "audio/skill/reluanji2.mp3", + "audio/skill/reluoshen1.mp3", + "audio/skill/reluoshen2.mp3", + "audio/skill/reluoyi1.mp3", + "audio/skill/reluoyi2.mp3", + "audio/skill/reluoying_dc_caozhi1.mp3", + "audio/skill/reluoying_dc_caozhi2.mp3", + "audio/skill/reluoying1.mp3", + "audio/skill/reluoying2.mp3", + "audio/skill/remieji1.mp3", + "audio/skill/remieji2.mp3", + "audio/skill/remingce1.mp3", + "audio/skill/remingce2.mp3", + "audio/skill/rende1.mp3", + "audio/skill/rende2.mp3", + "audio/skill/renjie.mp3", + "audio/skill/renjie2.mp3", + "audio/skill/renjie21.mp3", + "audio/skill/renjie22.mp3", + "audio/skill/renshe1.mp3", + "audio/skill/renshe2.mp3", + "audio/skill/renshi1.mp3", + "audio/skill/renshi2.mp3", + "audio/skill/renwang_skill.mp3", + "audio/skill/renxin_re_caochong1.mp3", + "audio/skill/renxin_re_caochong2.mp3", + "audio/skill/renxin1.mp3", + "audio/skill/renxin2.mp3", + "audio/skill/renzheng1.mp3", + "audio/skill/renzheng2.mp3", + "audio/skill/repaoxiao1.mp3", + "audio/skill/repaoxiao2.mp3", + "audio/skill/repindi1.mp3", + "audio/skill/repindi2.mp3", + "audio/skill/repingkou1.mp3", + "audio/skill/repingkou2.mp3", + "audio/skill/repojun1.mp3", + "audio/skill/repojun2.mp3", + "audio/skill/repolu1.mp3", + "audio/skill/reqiangxi1.mp3", + "audio/skill/reqiangxi2.mp3", + "audio/skill/reqianxi1.mp3", + "audio/skill/reqianxi2.mp3", + "audio/skill/reqianxun1.mp3", + "audio/skill/reqianxun2.mp3", + "audio/skill/reqiaobian1.mp3", + "audio/skill/reqiaobian2.mp3", + "audio/skill/reqiaoshi1.mp3", + "audio/skill/reqiaoshi2.mp3", + "audio/skill/reqiaoshui1.mp3", + "audio/skill/reqiaoshui2.mp3", + "audio/skill/reqice1.mp3", + "audio/skill/reqice2.mp3", + "audio/skill/reqieting1.mp3", + "audio/skill/reqieting2.mp3", + "audio/skill/reqimou1.mp3", + "audio/skill/reqimou2.mp3", + "audio/skill/reqingcheng1.mp3", + "audio/skill/reqingcheng2.mp3", + "audio/skill/reqingguo1.mp3", + "audio/skill/reqingguo2.mp3", + "audio/skill/reqingxi1.mp3", + "audio/skill/reqingxi2.mp3", + "audio/skill/reqinwang1.mp3", + "audio/skill/reqinwang2.mp3", + "audio/skill/reqiuyuan1.mp3", + "audio/skill/reqiuyuan2.mp3", + "audio/skill/requanji1.mp3", + "audio/skill/requanji2.mp3", + "audio/skill/rerende_gz_jun_liubei1.mp3", + "audio/skill/rerende_gz_jun_liubei2.mp3", + "audio/skill/rerende_shen_caopi1.mp3", + "audio/skill/rerende_shen_caopi2.mp3", + "audio/skill/rerende1.mp3", + "audio/skill/rerende2.mp3", + "audio/skill/resanyao1.mp3", + "audio/skill/resanyao2.mp3", + "audio/skill/reshangshi1.mp3", + "audio/skill/reshangshi2.mp3", + "audio/skill/reshejian1.mp3", + "audio/skill/reshejian2.mp3", + "audio/skill/reshenduan1.mp3", + "audio/skill/reshenduan2.mp3", + "audio/skill/reshenxing1.mp3", + "audio/skill/reshenxing2.mp3", + "audio/skill/reshishou1.mp3", + "audio/skill/reshishou2.mp3", + "audio/skill/residi1.mp3", + "audio/skill/residi2.mp3", + "audio/skill/retieji_boss_lvbu31.mp3", + "audio/skill/retieji_boss_lvbu32.mp3", + "audio/skill/retieji1.mp3", + "audio/skill/retieji2.mp3", + "audio/skill/retishen1.mp3", + "audio/skill/retishen2.mp3", + "audio/skill/retongbo1.mp3", + "audio/skill/retongbo2.mp3", + "audio/skill/retuntian1.mp3", + "audio/skill/retuntian2.mp3", + "audio/skill/retuxi1.mp3", + "audio/skill/retuxi2.mp3", + "audio/skill/rewangzu1.mp3", + "audio/skill/rewangzu2.mp3", + "audio/skill/reweimu1.mp3", + "audio/skill/reweimu2.mp3", + "audio/skill/rewurong1.mp3", + "audio/skill/rewurong2.mp3", + "audio/skill/rexiantu1.mp3", + "audio/skill/rexiantu2.mp3", + "audio/skill/rexianzhen1.mp3", + "audio/skill/rexianzhen2.mp3", + "audio/skill/rexianzhou1.mp3", + "audio/skill/rexianzhou2.mp3", + "audio/skill/rexingshang1.mp3", + "audio/skill/rexingshang2.mp3", + "audio/skill/rexingsheng1.mp3", + "audio/skill/rexingsheng2.mp3", + "audio/skill/rexingxue1.mp3", + "audio/skill/rexingxue2.mp3", + "audio/skill/rexinsheng1.mp3", + "audio/skill/rexinsheng2.mp3", + "audio/skill/rexuanhuo1.mp3", + "audio/skill/rexuanhuo2.mp3", + "audio/skill/reyajiao1.mp3", + "audio/skill/reyajiao2.mp3", + "audio/skill/reyanyu1.mp3", + "audio/skill/reyanyu2.mp3", + "audio/skill/reyanzhu1.mp3", + "audio/skill/reyanzhu2.mp3", + "audio/skill/reyicong_dc_gongsunzan.mp3", + "audio/skill/reyicong_dc_gongsunzan1.mp3", + "audio/skill/reyicong1.mp3", + "audio/skill/reyicong2.mp3", + "audio/skill/reyiji1.mp3", + "audio/skill/reyiji2.mp3", + "audio/skill/reyingshi1.mp3", + "audio/skill/reyingshi2.mp3", + "audio/skill/reyingshui1.mp3", + "audio/skill/reyingshui2.mp3", + "audio/skill/reyingzi_gexuan1.mp3", + "audio/skill/reyingzi_heqi1.mp3", + "audio/skill/reyingzi_heqi2.mp3", + "audio/skill/reyingzi_re_heqi1.mp3", + "audio/skill/reyingzi_re_heqi2.mp3", + "audio/skill/reyingzi_re_sunben1.mp3", + "audio/skill/reyingzi_re_sunben2.mp3", + "audio/skill/reyingzi_re_sunce1.mp3", + "audio/skill/reyingzi_re_sunce2.mp3", + "audio/skill/reyingzi_re_sunyi1.mp3", + "audio/skill/reyingzi_sunce1.mp3", + "audio/skill/reyingzi_sunce2.mp3", + "audio/skill/reyingzi1.mp3", + "audio/skill/reyingzi2.mp3", + "audio/skill/reyonglve1.mp3", + "audio/skill/reyonglve2.mp3", + "audio/skill/rezaiqi1.mp3", + "audio/skill/rezaiqi2.mp3", + "audio/skill/rezhanjue1.mp3", + "audio/skill/rezhanjue2.mp3", + "audio/skill/rezhiheng_shen_caopi1.mp3", + "audio/skill/rezhiheng_shen_caopi2.mp3", + "audio/skill/rezhiheng1.mp3", + "audio/skill/rezhiheng2.mp3", + "audio/skill/rezhijian1.mp3", + "audio/skill/rezhijian2.mp3", + "audio/skill/rezhiyu1.mp3", + "audio/skill/rezhiyu2.mp3", + "audio/skill/rezhongyong1.mp3", + "audio/skill/rezhongyong2.mp3", + "audio/skill/rezhuhai1.mp3", + "audio/skill/rezhuhai2.mp3", + "audio/skill/rezhuikong1.mp3", + "audio/skill/rezhuikong2.mp3", + "audio/skill/rezongshi1.mp3", + "audio/skill/rezongshi2.mp3", + "audio/skill/rezongxuan1.mp3", + "audio/skill/rezongxuan2.mp3", + "audio/skill/rongbei1.mp3", + "audio/skill/rongbei2.mp3", + "audio/skill/roulin_ol_dongzhuo1.mp3", + "audio/skill/roulin_ol_dongzhuo2.mp3", + "audio/skill/roulin_re_dongzhuo1.mp3", + "audio/skill/roulin_re_dongzhuo2.mp3", + "audio/skill/roulin1.mp3", + "audio/skill/roulin2.mp3", + "audio/skill/ruilve1.mp3", + "audio/skill/ruilve2.mp3", + "audio/skill/ruoyu_re_liushan1.mp3", + "audio/skill/ruoyu_re_liushan2.mp3", + "audio/skill/ruoyu1.mp3", + "audio/skill/ruoyu2.mp3", + "audio/skill/rw_bagua_skill.mp3", + "audio/skill/rw_baiyin_skill.mp3", + "audio/skill/rw_renwang_skill.mp3", + "audio/skill/rw_tengjia1.mp3", + "audio/skill/rw_tengjia2.mp3", + "audio/skill/rw_zhuge_skill.mp3", + "audio/skill/sanchen1.mp3", + "audio/skill/sanchen2.mp3", + "audio/skill/sangu1.mp3", + "audio/skill/sangu2.mp3", + "audio/skill/sanjian_skill.mp3", + "audio/skill/sanku1.mp3", + "audio/skill/sanku2.mp3", + "audio/skill/sanshou1.mp3", + "audio/skill/sanshou2.mp3", + "audio/skill/sanyao1.mp3", + "audio/skill/sanyao2.mp3", + "audio/skill/saodi1.mp3", + "audio/skill/saodi2.mp3", + "audio/skill/saya_powei1.mp3", + "audio/skill/saya_powei2.mp3", + "audio/skill/saya_shouji1.mp3", + "audio/skill/saya_shouji2.mp3", + "audio/skill/sbaiyin.mp3", + "audio/skill/sbaiyin1.mp3", + "audio/skill/sbaiyin2.mp3", + "audio/skill/sbanguo1.mp3", + "audio/skill/sbanguo2.mp3", + "audio/skill/sbanguo3.mp3", + "audio/skill/sbbenxi1.mp3", + "audio/skill/sbbenxi2.mp3", + "audio/skill/sbbenxi3.mp3", + "audio/skill/sbbiyue1.mp3", + "audio/skill/sbbiyue2.mp3", + "audio/skill/sbduanliang_false.mp3", + "audio/skill/sbduanliang_true1.mp3", + "audio/skill/sbduanliang_true2.mp3", + "audio/skill/sbduanliang1.mp3", + "audio/skill/sbdujiang1.mp3", + "audio/skill/sbdujiang2.mp3", + "audio/skill/sbduojing1.mp3", + "audio/skill/sbduojing2.mp3", + "audio/skill/sbenyuan1.mp3", + "audio/skill/sbenyuan2.mp3", + "audio/skill/sbfangzhu1.mp3", + "audio/skill/sbfangzhu2.mp3", + "audio/skill/sbfanjian1.mp3", + "audio/skill/sbfanjian2.mp3", + "audio/skill/sbfenwei1.mp3", + "audio/skill/sbfenwei2.mp3", + "audio/skill/sbguanxing1.mp3", + "audio/skill/sbguanxing2.mp3", + "audio/skill/sbguidao1.mp3", + "audio/skill/sbguidao2.mp3", + "audio/skill/sbguose1.mp3", + "audio/skill/sbguose2.mp3", + "audio/skill/sbhuangtian1.mp3", + "audio/skill/sbhuangtian2.mp3", + "audio/skill/sbhujia1.mp3", + "audio/skill/sbhujia2.mp3", + "audio/skill/sbhunzi1.mp3", + "audio/skill/sbhunzi2.mp3", + "audio/skill/sbhuoji1.mp3", + "audio/skill/sbhuoji2.mp3", + "audio/skill/sbhuoji3.mp3", + "audio/skill/sbhuoshou1.mp3", + "audio/skill/sbhuoshou2.mp3", + "audio/skill/sbjiang1.mp3", + "audio/skill/sbjiang2.mp3", + "audio/skill/sbjianxiong1.mp3", + "audio/skill/sbjianxiong2.mp3", + "audio/skill/sbjieming1.mp3", + "audio/skill/sbjieming2.mp3", + "audio/skill/sbjiewei1.mp3", + "audio/skill/sbjiewei2.mp3", + "audio/skill/sbjieyin1.mp3", + "audio/skill/sbjieyin2.mp3", + "audio/skill/sbjieyue1.mp3", + "audio/skill/sbjieyue2.mp3", + "audio/skill/sbjieyue3.mp3", + "audio/skill/sbjieyue4.mp3", + "audio/skill/sbjijiang1.mp3", + "audio/skill/sbjijiang2.mp3", + "audio/skill/sbjiuyuan1.mp3", + "audio/skill/sbjiuyuan2.mp3", + "audio/skill/sbjizhi1.mp3", + "audio/skill/sbjizhi2.mp3", + "audio/skill/sbjizhu1.mp3", + "audio/skill/sbjizhu2.mp3", + "audio/skill/sbjizhu3.mp3", + "audio/skill/sbjushou1.mp3", + "audio/skill/sbjushou2.mp3", + "audio/skill/sbjushou3.mp3", + "audio/skill/sbjuxiang1.mp3", + "audio/skill/sbjuxiang2.mp3", + "audio/skill/sbkanpo1.mp3", + "audio/skill/sbkanpo2.mp3", + "audio/skill/sbkeji1.mp3", + "audio/skill/sbkeji2.mp3", + "audio/skill/sbkongcheng1.mp3", + "audio/skill/sbkongcheng2.mp3", + "audio/skill/sbkurou1.mp3", + "audio/skill/sbkurou2.mp3", + "audio/skill/sbleiji1.mp3", + "audio/skill/sbleiji2.mp3", + "audio/skill/sbliangzhu1.mp3", + "audio/skill/sbliangzhu2.mp3", + "audio/skill/sblianhuan1.mp3", + "audio/skill/sblianhuan2.mp3", + "audio/skill/sbliegong1.mp3", + "audio/skill/sbliegong2.mp3", + "audio/skill/sblieren1.mp3", + "audio/skill/sblieren2.mp3", + "audio/skill/sblijian1.mp3", + "audio/skill/sblijian2.mp3", + "audio/skill/sbliuli1.mp3", + "audio/skill/sbliuli2.mp3", + "audio/skill/sblongdan1.mp3", + "audio/skill/sblongdan2.mp3", + "audio/skill/sbluanji1.mp3", + "audio/skill/sbluanji2.mp3", + "audio/skill/sbluoshen1.mp3", + "audio/skill/sbluoshen2.mp3", + "audio/skill/sbmingce1.mp3", + "audio/skill/sbmingce2.mp3", + "audio/skill/sbniepan1.mp3", + "audio/skill/sbniepan2.mp3", + "audio/skill/sbpaoxiao1.mp3", + "audio/skill/sbpaoxiao2.mp3", + "audio/skill/sbqiaobian1.mp3", + "audio/skill/sbqiaobian2.mp3", + "audio/skill/sbqiaoshi1.mp3", + "audio/skill/sbqiaoshi2.mp3", + "audio/skill/sbqicai1.mp3", + "audio/skill/sbqicai2.mp3", + "audio/skill/sbqingzheng1.mp3", + "audio/skill/sbqingzheng2.mp3", + "audio/skill/sbqixi1.mp3", + "audio/skill/sbqixi2.mp3", + "audio/skill/sbquhu1.mp3", + "audio/skill/sbquhu2.mp3", + "audio/skill/sbrende1.mp3", + "audio/skill/sbrende2.mp3", + "audio/skill/sbrende3.mp3", + "audio/skill/sbshipo1.mp3", + "audio/skill/sbshipo2.mp3", + "audio/skill/sbsongwei1.mp3", + "audio/skill/sbsongwei2.mp3", + "audio/skill/sbtianxiang1.mp3", + "audio/skill/sbtianxiang2.mp3", + "audio/skill/sbtiaoxin1.mp3", + "audio/skill/sbtiaoxin2.mp3", + "audio/skill/sbtieji_false.mp3", + "audio/skill/sbtieji_true1.mp3", + "audio/skill/sbtieji_true2.mp3", + "audio/skill/sbtieji1.mp3", + "audio/skill/sbtongye1.mp3", + "audio/skill/sbtongye2.mp3", + "audio/skill/sbwusheng1.mp3", + "audio/skill/sbwusheng2.mp3", + "audio/skill/sbwusheng3.mp3", + "audio/skill/sbxiaoji1.mp3", + "audio/skill/sbxiaoji2.mp3", + "audio/skill/sbxiayuan1.mp3", + "audio/skill/sbxiayuan2.mp3", + "audio/skill/sbxieji1.mp3", + "audio/skill/sbxieji2.mp3", + "audio/skill/sbxieji3.mp3", + "audio/skill/sbxingshang1.mp3", + "audio/skill/sbxingshang2.mp3", + "audio/skill/sbxuanhuo1.mp3", + "audio/skill/sbxuanhuo2.mp3", + "audio/skill/sbxueyi1.mp3", + "audio/skill/sbxueyi2.mp3", + "audio/skill/sbyangwei1.mp3", + "audio/skill/sbyangwei2.mp3", + "audio/skill/sbyanyu1.mp3", + "audio/skill/sbyanyu2.mp3", + "audio/skill/sbyaoming1.mp3", + "audio/skill/sbyaoming2.mp3", + "audio/skill/sbyijue1.mp3", + "audio/skill/sbyijue2.mp3", + "audio/skill/sbyingzi_sb_sunce1.mp3", + "audio/skill/sbyingzi_sb_sunce2.mp3", + "audio/skill/sbyingzi1.mp3", + "audio/skill/sbyingzi2.mp3", + "audio/skill/sbzaiqi1.mp3", + "audio/skill/sbzaiqi2.mp3", + "audio/skill/sbzhangwu1.mp3", + "audio/skill/sbzhangwu2.mp3", + "audio/skill/sbzhaxiang1.mp3", + "audio/skill/sbzhaxiang2.mp3", + "audio/skill/sbzhenliang1.mp3", + "audio/skill/sbzhenliang2.mp3", + "audio/skill/sbzhiba1.mp3", + "audio/skill/sbzhiba2.mp3", + "audio/skill/sbzhichi1.mp3", + "audio/skill/sbzhichi2.mp3", + "audio/skill/sbzhiheng1.mp3", + "audio/skill/sbzhiheng2.mp3", + "audio/skill/sbzhiji1.mp3", + "audio/skill/sbzhiji2.mp3", + "audio/skill/sbzishou1.mp3", + "audio/skill/sbzishou2.mp3", + "audio/skill/sbzongshi1.mp3", + "audio/skill/sbzongshi2.mp3", + "audio/skill/scfuhai1.mp3", + "audio/skill/scfuhai2.mp3", + "audio/skill/scs_bilan_enter.mp3", + "audio/skill/scs_duangui_enter.mp3", + "audio/skill/scs_gaowang_enter.mp3", + "audio/skill/scs_guosheng_enter.mp3", + "audio/skill/scs_hankui_enter.mp3", + "audio/skill/scs_lisong_enter.mp3", + "audio/skill/scs_sunzhang_enter.mp3", + "audio/skill/scs_xiayun_enter.mp3", + "audio/skill/scs_zhangrang_enter.mp3", + "audio/skill/scs_zhaozhong_enter.mp3", + "audio/skill/scsanruo1.mp3", + "audio/skill/scschihe1.mp3", + "audio/skill/scschiyan1.mp3", + "audio/skill/scskuiji1.mp3", + "audio/skill/scsniqu1.mp3", + "audio/skill/scspicai1.mp3", + "audio/skill/scstaoluan1.mp3", + "audio/skill/scsxiaolu1.mp3", + "audio/skill/scsyaozhuo1.mp3", + "audio/skill/scszimou1.mp3", + "audio/skill/sghuishi1.mp3", + "audio/skill/sghuishi2.mp3", + "audio/skill/sgrenwang1.mp3", + "audio/skill/sgrenwang2.mp3", + "audio/skill/shameng1.mp3", + "audio/skill/shameng2.mp3", + "audio/skill/shanduan1.mp3", + "audio/skill/shanduan2.mp3", + "audio/skill/shangshi1.mp3", + "audio/skill/shangshi2.mp3", + "audio/skill/shangshix1.mp3", + "audio/skill/shangshix2.mp3", + "audio/skill/shangyi1.mp3", + "audio/skill/shangyi2.mp3", + "audio/skill/shanjia1.mp3", + "audio/skill/shanjia2.mp3", + "audio/skill/shanli1.mp3", + "audio/skill/shanli2.mp3", + "audio/skill/shanshen1.mp3", + "audio/skill/shanshen2.mp3", + "audio/skill/shanxi1.mp3", + "audio/skill/shanxi2.mp3", + "audio/skill/shanxie1.mp3", + "audio/skill/shanxie2.mp3", + "audio/skill/shanzhuan1.mp3", + "audio/skill/shanzhuan2.mp3", + "audio/skill/shebian1.mp3", + "audio/skill/shebian2.mp3", + "audio/skill/shefu1.mp3", + "audio/skill/shefu2.mp3", + "audio/skill/shejian1.mp3", + "audio/skill/shejian2.mp3", + "audio/skill/shelie1.mp3", + "audio/skill/shelie2.mp3", + "audio/skill/shencai1.mp3", + "audio/skill/shencai2.mp3", + "audio/skill/shenduan1.mp3", + "audio/skill/shenduan2.mp3", + "audio/skill/shenfen1.mp3", + "audio/skill/shenfen2.mp3", + "audio/skill/shenfu1.mp3", + "audio/skill/shenfu2.mp3", + "audio/skill/shengxi_feiyi1.mp3", + "audio/skill/shengxi_feiyi2.mp3", + "audio/skill/shengxi1.mp3", + "audio/skill/shengxi2.mp3", + "audio/skill/shenji1.mp3", + "audio/skill/shenji2.mp3", + "audio/skill/shenju1.mp3", + "audio/skill/shenju2.mp3", + "audio/skill/shenpin1.mp3", + "audio/skill/shenpin2.mp3", + "audio/skill/shenqu1.mp3", + "audio/skill/shenqu2.mp3", + "audio/skill/shensu1_ol_xiahouyuan1.mp3", + "audio/skill/shensu1_ol_xiahouyuan2.mp3", + "audio/skill/shensu1_re_xiahouyuan1.mp3", + "audio/skill/shensu1_re_xiahouyuan2.mp3", + "audio/skill/shensu1_xiahouba1.mp3", + "audio/skill/shensu1_xiahouba2.mp3", + "audio/skill/shensu11.mp3", + "audio/skill/shensu12.mp3", + "audio/skill/shensu21.mp3", + "audio/skill/shensu22.mp3", + "audio/skill/shenwei1.mp3", + "audio/skill/shenwei2.mp3", + "audio/skill/shenxian1.mp3", + "audio/skill/shenxian2.mp3", + "audio/skill/shenxing1.mp3", + "audio/skill/shenxing2.mp3", + "audio/skill/shenzhi1.mp3", + "audio/skill/shenzhi2.mp3", + "audio/skill/shenzhu1.mp3", + "audio/skill/shenzhu2.mp3", + "audio/skill/sheyan1.mp3", + "audio/skill/sheyan2.mp3", + "audio/skill/sheyi1.mp3", + "audio/skill/sheyi2.mp3", + "audio/skill/shezang1.mp3", + "audio/skill/shezang2.mp3", + "audio/skill/shhlianhua1.mp3", + "audio/skill/shhlianhua2.mp3", + "audio/skill/shibei_xin_jushou1.mp3", + "audio/skill/shibei_xin_jushou2.mp3", + "audio/skill/shibei1.mp3", + "audio/skill/shibei2.mp3", + "audio/skill/shichou1.mp3", + "audio/skill/shichou2.mp3", + "audio/skill/shiduo1.mp3", + "audio/skill/shiduo2.mp3", + "audio/skill/shifei_re_guotufengji1.mp3", + "audio/skill/shifei_re_guotufengji2.mp3", + "audio/skill/shifei1.mp3", + "audio/skill/shifei2.mp3", + "audio/skill/shiina_feiyan1.mp3", + "audio/skill/shiina_qingshen1.mp3", + "audio/skill/shiina_retieji1.mp3", + "audio/skill/shiki_omusubi1.mp3", + "audio/skill/shiki_omusubi2.mp3", + "audio/skill/shiming1.mp3", + "audio/skill/shiming2.mp3", + "audio/skill/shiorimiyuki_banyin1.mp3", + "audio/skill/shiorimiyuki_banyin2.mp3", + "audio/skill/shiorimiyuki_tingxian1.mp3", + "audio/skill/shiorimiyuki_tingxian2.mp3", + "audio/skill/shiren1.mp3", + "audio/skill/shiren2.mp3", + "audio/skill/shishengshibai.mp3", + "audio/skill/shixin1.mp3", + "audio/skill/shixin2.mp3", + "audio/skill/shiyong1.mp3", + "audio/skill/shiyong2.mp3", + "audio/skill/shiyong3.mp3", + "audio/skill/shiyuan1.mp3", + "audio/skill/shiyuan2.mp3", + "audio/skill/shizhan1.mp3", + "audio/skill/shizhan2.mp3", + "audio/skill/shoucheng1.mp3", + "audio/skill/shoucheng2.mp3", + "audio/skill/shoufa1.mp3", + "audio/skill/shoufa2.mp3", + "audio/skill/shouli1.mp3", + "audio/skill/shouli2.mp3", + "audio/skill/shoulijian.mp3", + "audio/skill/shouxi1.mp3", + "audio/skill/shouxi2.mp3", + "audio/skill/shouye1.mp3", + "audio/skill/shouye2.mp3", + "audio/skill/shuaiyan1.mp3", + "audio/skill/shuaiyan2.mp3", + "audio/skill/shuangren1.mp3", + "audio/skill/shuangren2.mp3", + "audio/skill/shuangxiong_re_yanwen1.mp3", + "audio/skill/shuangxiong_re_yanwen2.mp3", + "audio/skill/shuangxiong1.mp3", + "audio/skill/shuangxiong2.mp3", + "audio/skill/shuchen1.mp3", + "audio/skill/shuchen2.mp3", + "audio/skill/shuimeng1.mp3", + "audio/skill/shuimeng2.mp3", + "audio/skill/shuishi1.mp3", + "audio/skill/shuishi2.mp3", + "audio/skill/shuliang1.mp3", + "audio/skill/shuliang2.mp3", + "audio/skill/shunshi1.mp3", + "audio/skill/shunshi2.mp3", + "audio/skill/shuojian1.mp3", + "audio/skill/shuojian2.mp3", + "audio/skill/shushen1.mp3", + "audio/skill/shushen2.mp3", + "audio/skill/sibian1.mp3", + "audio/skill/sibian2.mp3", + "audio/skill/sidi.mp3", + "audio/skill/sidi1.mp3", + "audio/skill/sidi2.mp3", + "audio/skill/sijian1.mp3", + "audio/skill/sijian2.mp3", + "audio/skill/sijun1.mp3", + "audio/skill/sijun2.mp3", + "audio/skill/sishu1.mp3", + "audio/skill/sishu2.mp3", + "audio/skill/smyyingshi1.mp3", + "audio/skill/smyyingshi2.mp3", + "audio/skill/songci1.mp3", + "audio/skill/songci2.mp3", + "audio/skill/songshu1.mp3", + "audio/skill/songshu2.mp3", + "audio/skill/songwei_re_caopi1.mp3", + "audio/skill/songwei_re_caopi2.mp3", + "audio/skill/songwei2_re_caopi1.mp3", + "audio/skill/songwei2_re_caopi2.mp3", + "audio/skill/songwei21.mp3", + "audio/skill/songwei22.mp3", + "audio/skill/souying1.mp3", + "audio/skill/souying2.mp3", + "audio/skill/spchijie1.mp3", + "audio/skill/spchijie2.mp3", + "audio/skill/spcunsi1.mp3", + "audio/skill/spcunsi2.mp3", + "audio/skill/spdaizui1.mp3", + "audio/skill/spdaizui2.mp3", + "audio/skill/spdaming1.mp3", + "audio/skill/spdaming2.mp3", + "audio/skill/spdaming3.mp3", + "audio/skill/spdaoshu1.mp3", + "audio/skill/spdaoshu2.mp3", + "audio/skill/spdaoshu3.mp3", + "audio/skill/spdengli1.mp3", + "audio/skill/spdengli2.mp3", + "audio/skill/spdiancai1.mp3", + "audio/skill/spdiancai2.mp3", + "audio/skill/spdiaodu1.mp3", + "audio/skill/spdiaodu2.mp3", + "audio/skill/spdifei1.mp3", + "audio/skill/spdifei2.mp3", + "audio/skill/spell2131_1.mp3", + "audio/skill/spell2131_2.mp3", + "audio/skill/spfangzong1.mp3", + "audio/skill/spfangzong2.mp3", + "audio/skill/spfenming1.mp3", + "audio/skill/spfenming2.mp3", + "audio/skill/spguixiu1.mp3", + "audio/skill/spguixiu2.mp3", + "audio/skill/spjianyi1.mp3", + "audio/skill/spjianyi2.mp3", + "audio/skill/spjiedao1.mp3", + "audio/skill/spjiedao2.mp3", + "audio/skill/spjincui1.mp3", + "audio/skill/spjincui2.mp3", + "audio/skill/spjungong1.mp3", + "audio/skill/spjungong2.mp3", + "audio/skill/splirang1.mp3", + "audio/skill/splirang2.mp3", + "audio/skill/splveying1.mp3", + "audio/skill/splveying2.mp3", + "audio/skill/spmanwang1.mp3", + "audio/skill/spmanwang2.mp3", + "audio/skill/spmiewu1.mp3", + "audio/skill/spmiewu2.mp3", + "audio/skill/spmingshi1.mp3", + "audio/skill/spmingshi2.mp3", + "audio/skill/spmingxuan1.mp3", + "audio/skill/spmingxuan2.mp3", + "audio/skill/spolzhouxuan1.mp3", + "audio/skill/spolzhouxuan2.mp3", + "audio/skill/sppanqin1.mp3", + "audio/skill/sppanqin2.mp3", + "audio/skill/spqiai1.mp3", + "audio/skill/spqiai2.mp3", + "audio/skill/spqishe1.mp3", + "audio/skill/spqishe2.mp3", + "audio/skill/spsanchen1.mp3", + "audio/skill/spsanchen2.mp3", + "audio/skill/spshangyi1.mp3", + "audio/skill/spshangyi2.mp3", + "audio/skill/spshanxi1.mp3", + "audio/skill/spshanxi2.mp3", + "audio/skill/spshicai1.mp3", + "audio/skill/spshicai2.mp3", + "audio/skill/spshidi1.mp3", + "audio/skill/spshidi2.mp3", + "audio/skill/spshiji1.mp3", + "audio/skill/spshiji2.mp3", + "audio/skill/spsongshu1.mp3", + "audio/skill/spsongshu2.mp3", + "audio/skill/sptaoluan1.mp3", + "audio/skill/sptaoluan2.mp3", + "audio/skill/sptunjiang1.mp3", + "audio/skill/sptunjiang2.mp3", + "audio/skill/spwanwei1.mp3", + "audio/skill/spwanwei2.mp3", + "audio/skill/spweiwu1.mp3", + "audio/skill/spweiwu2.mp3", + "audio/skill/spwenji1.mp3", + "audio/skill/spwenji2.mp3", + "audio/skill/spwuku1.mp3", + "audio/skill/spwuku2.mp3", + "audio/skill/spxianchou1.mp3", + "audio/skill/spxianchou2.mp3", + "audio/skill/spxiangzhen1.mp3", + "audio/skill/spxiangzhen2.mp3", + "audio/skill/spxiaoni1.mp3", + "audio/skill/spxiaoni2.mp3", + "audio/skill/spxizhan1.mp3", + "audio/skill/spxizhan2.mp3", + "audio/skill/spxizhan3.mp3", + "audio/skill/spxizhan4.mp3", + "audio/skill/spyajun1.mp3", + "audio/skill/spyajun2.mp3", + "audio/skill/spyanji1.mp3", + "audio/skill/spyanji2.mp3", + "audio/skill/spyanji3.mp3", + "audio/skill/spyanjiao1.mp3", + "audio/skill/spyanjiao2.mp3", + "audio/skill/spyilie1.mp3", + "audio/skill/spyilie2.mp3", + "audio/skill/spyingwu1.mp3", + "audio/skill/spyingwu2.mp3", + "audio/skill/spyinju1.mp3", + "audio/skill/spyinju2.mp3", + "audio/skill/spyishi1.mp3", + "audio/skill/spyishi2.mp3", + "audio/skill/spyuejian1.mp3", + "audio/skill/spyuejian2.mp3", + "audio/skill/spzhengjun1.mp3", + "audio/skill/spzhengjun2.mp3", + "audio/skill/spzhengjun3.mp3", + "audio/skill/spzhenting1.mp3", + "audio/skill/spzhenting2.mp3", + "audio/skill/spzhenwei1.mp3", + "audio/skill/spzhenwei2.mp3", + "audio/skill/spzhuilie1.mp3", + "audio/skill/spzhuilie2.mp3", + "audio/skill/spzundi1.mp3", + "audio/skill/spzundi2.mp3", + "audio/skill/staraoshi1.mp3", + "audio/skill/staraoshi2.mp3", + "audio/skill/starcanxi1.mp3", + "audio/skill/starcanxi2.mp3", + "audio/skill/starhaoshou1.mp3", + "audio/skill/starhaoshou2.mp3", + "audio/skill/starjiaowang1.mp3", + "audio/skill/starjiaowang2.mp3", + "audio/skill/starlifeng1.mp3", + "audio/skill/starlifeng2.mp3", + "audio/skill/starpizhi1.mp3", + "audio/skill/starpizhi2.mp3", + "audio/skill/starsujun1.mp3", + "audio/skill/starsujun2.mp3", + "audio/skill/starweilin1.mp3", + "audio/skill/starweilin2.mp3", + "audio/skill/starxiaoyan1.mp3", + "audio/skill/starxiaoyan2.mp3", + "audio/skill/starzhangrong1.mp3", + "audio/skill/starzhangrong2.mp3", + "audio/skill/starzhonggu1.mp3", + "audio/skill/starzhonggu2.mp3", + "audio/skill/starzongshi1.mp3", + "audio/skill/starzongshi2.mp3", + "audio/skill/stianyi1.mp3", + "audio/skill/stianyi2.mp3", + "audio/skill/suishi1.mp3", + "audio/skill/suishi2.mp3", + "audio/skill/suizheng1.mp3", + "audio/skill/suizheng2.mp3", + "audio/skill/suoliang1.mp3", + "audio/skill/suoliang2.mp3", + "audio/skill/sushou1.mp3", + "audio/skill/sushou2.mp3", + "audio/skill/suzi1.mp3", + "audio/skill/suzi2.mp3", + "audio/skill/syjiqiao1.mp3", + "audio/skill/syjiqiao2.mp3", + "audio/skill/syxiongyi1.mp3", + "audio/skill/syxiongyi2.mp3", + "audio/skill/tairan1.mp3", + "audio/skill/tairan2.mp3", + "audio/skill/tamo1.mp3", + "audio/skill/tamo2.mp3", + "audio/skill/taoluan1.mp3", + "audio/skill/taoluan2.mp3", + "audio/skill/taomie1.mp3", + "audio/skill/taomie2.mp3", + "audio/skill/taomie3.mp3", + "audio/skill/taoxi1.mp3", + "audio/skill/taoxi2.mp3", + "audio/skill/taoyin1.mp3", + "audio/skill/taoyin2.mp3", + "audio/skill/tashui1.mp3", + "audio/skill/tashui2.mp3", + "audio/skill/tengjia1.mp3", + "audio/skill/tengjia2.mp3", + "audio/skill/tianbian1.mp3", + "audio/skill/tianbian2.mp3", + "audio/skill/tiandao.mp3", + "audio/skill/tiandu_re_guojia1.mp3", + "audio/skill/tiandu_re_guojia2.mp3", + "audio/skill/tiandu_xizhicai1.mp3", + "audio/skill/tiandu_xizhicai2.mp3", + "audio/skill/tiandu1.mp3", + "audio/skill/tiandu2.mp3", + "audio/skill/tianfu1.mp3", + "audio/skill/tianfu2.mp3", + "audio/skill/tianjie1.mp3", + "audio/skill/tianjie2.mp3", + "audio/skill/tianming1.mp3", + "audio/skill/tianming2.mp3", + "audio/skill/tianren1.mp3", + "audio/skill/tianren2.mp3", + "audio/skill/tianshu1.mp3", + "audio/skill/tianshu2.mp3", + "audio/skill/tiansuan1.mp3", + "audio/skill/tiansuan2.mp3", + "audio/skill/tianxiang_daxiaoqiao1.mp3", + "audio/skill/tianxiang_daxiaoqiao2.mp3", + "audio/skill/tianxiang_ol_xiaoqiao1.mp3", + "audio/skill/tianxiang_ol_xiaoqiao2.mp3", + "audio/skill/tianxiang_re_xiaoqiao1.mp3", + "audio/skill/tianxiang_re_xiaoqiao2.mp3", + "audio/skill/tianxiang1.mp3", + "audio/skill/tianxiang2.mp3", + "audio/skill/tianxing1.mp3", + "audio/skill/tianxing2.mp3", + "audio/skill/tianyi_re_taishici1.mp3", + "audio/skill/tianyi_re_taishici2.mp3", + "audio/skill/tianyi1.mp3", + "audio/skill/tianyi2.mp3", + "audio/skill/tianyin1.mp3", + "audio/skill/tianyin2.mp3", + "audio/skill/tianyun1.mp3", + "audio/skill/tianyun2.mp3", + "audio/skill/tianze1.mp3", + "audio/skill/tianze2.mp3", + "audio/skill/tianzuo1.mp3", + "audio/skill/tianzuo2.mp3", + "audio/skill/tiaoxin_gz_jiangwei1.mp3", + "audio/skill/tiaoxin_gz_jiangwei2.mp3", + "audio/skill/tiaoxin_ol_jiangwei1.mp3", + "audio/skill/tiaoxin_ol_jiangwei2.mp3", + "audio/skill/tiaoxin_re_jiangwei1.mp3", + "audio/skill/tiaoxin_re_jiangwei2.mp3", + "audio/skill/tiaoxin_sp_jiangwei1.mp3", + "audio/skill/tiaoxin_sp_jiangwei2.mp3", + "audio/skill/tiaoxin_xiahouba1.mp3", + "audio/skill/tiaoxin_xiahouba2.mp3", + "audio/skill/tiaoxin1.mp3", + "audio/skill/tiaoxin2.mp3", + "audio/skill/tieji1.mp3", + "audio/skill/tieji2.mp3", + "audio/skill/tiqi1.mp3", + "audio/skill/tiqi2.mp3", + "audio/skill/tongbo1.mp3", + "audio/skill/tongbo2.mp3", + "audio/skill/tongduo1.mp3", + "audio/skill/tongduo2.mp3", + "audio/skill/tongji1.mp3", + "audio/skill/tongji2.mp3", + "audio/skill/tongli1.mp3", + "audio/skill/tongli2.mp3", + "audio/skill/tongqu1.mp3", + "audio/skill/tongqu2.mp3", + "audio/skill/tongwei1.mp3", + "audio/skill/tongwei2.mp3", + "audio/skill/tongxie1.mp3", + "audio/skill/tongxie2.mp3", + "audio/skill/tongyuan1.mp3", + "audio/skill/tongyuan2.mp3", + "audio/skill/tspowei1.mp3", + "audio/skill/tspowei2.mp3", + "audio/skill/tspowei3.mp3", + "audio/skill/tsumugi_mugyu1.mp3", + "audio/skill/tsumugi_mugyu2.mp3", + "audio/skill/tsumugi_mugyu3.mp3", + "audio/skill/tsumugi_mugyu4.mp3", + "audio/skill/tsumugi_mugyu5.mp3", + "audio/skill/tuifeng1.mp3", + "audio/skill/tuifeng2.mp3", + "audio/skill/tuishi1.mp3", + "audio/skill/tuishi2.mp3", + "audio/skill/tuiyan1.mp3", + "audio/skill/tuiyan2.mp3", + "audio/skill/tunchu1.mp3", + "audio/skill/tunchu2.mp3", + "audio/skill/tuntian_gz_dengai1.mp3", + "audio/skill/tuntian_gz_dengai2.mp3", + "audio/skill/tuntian1.mp3", + "audio/skill/tuntian2.mp3", + "audio/skill/tuogu1.mp3", + "audio/skill/tuogu2.mp3", + "audio/skill/tuoxian.mp3", + "audio/skill/tuoxian2.mp3", + "audio/skill/tuxi1.mp3", + "audio/skill/tuxi2.mp3", + "audio/skill/tuxing1.mp3", + "audio/skill/tuxing2.mp3", + "audio/skill/twbingde1.mp3", + "audio/skill/twbingde2.mp3", + "audio/skill/twbudao1.mp3", + "audio/skill/twbudao2.mp3", + "audio/skill/twchaofeng1.mp3", + "audio/skill/twchaofeng2.mp3", + "audio/skill/twchayi1.mp3", + "audio/skill/twchengxi1.mp3", + "audio/skill/twchengxi2.mp3", + "audio/skill/twchongqi1.mp3", + "audio/skill/twchongqi2.mp3", + "audio/skill/twchuanshu1.mp3", + "audio/skill/twchuanshu2.mp3", + "audio/skill/twchungang1.mp3", + "audio/skill/twchungang2.mp3", + "audio/skill/twdanfa1.mp3", + "audio/skill/twdanfa2.mp3", + "audio/skill/twdanlie1.mp3", + "audio/skill/twdanlie2.mp3", + "audio/skill/twdianyi1.mp3", + "audio/skill/twdianyi2.mp3", + "audio/skill/twdingzhen1.mp3", + "audio/skill/twdingzhen2.mp3", + "audio/skill/twduoren1.mp3", + "audio/skill/twduoren2.mp3", + "audio/skill/twfeifu1.mp3", + "audio/skill/twfeifu2.mp3", + "audio/skill/twfengji1.mp3", + "audio/skill/twfengji2.mp3", + "audio/skill/twfenwang1.mp3", + "audio/skill/twfenwang2.mp3", + "audio/skill/twfenwu1.mp3", + "audio/skill/twfenwu2.mp3", + "audio/skill/twfucuan1.mp3", + "audio/skill/twfucuan2.mp3", + "audio/skill/twfujian1.mp3", + "audio/skill/twfujian2.mp3", + "audio/skill/twfupan1.mp3", + "audio/skill/twfupan2.mp3", + "audio/skill/twfupan3.mp3", + "audio/skill/twfuzuan1.mp3", + "audio/skill/twfuzuan2.mp3", + "audio/skill/twgezhi1.mp3", + "audio/skill/twgezhi2.mp3", + "audio/skill/twgongge1.mp3", + "audio/skill/twgongge2.mp3", + "audio/skill/twgongge3.mp3", + "audio/skill/twhanyu1.mp3", + "audio/skill/twhanyu2.mp3", + "audio/skill/twhuiyuan1.mp3", + "audio/skill/twhuiyuan2.mp3", + "audio/skill/twhuzhong1.mp3", + "audio/skill/twhuzhong2.mp3", + "audio/skill/twjiange1.mp3", + "audio/skill/twjiange2.mp3", + "audio/skill/twjianming1.mp3", + "audio/skill/twjianming2.mp3", + "audio/skill/twjianwei1.mp3", + "audio/skill/twjianwei2.mp3", + "audio/skill/twjiaohua1.mp3", + "audio/skill/twjiaohua2.mp3", + "audio/skill/twjichou1.mp3", + "audio/skill/twjichou2.mp3", + "audio/skill/twjiekuang1.mp3", + "audio/skill/twjiekuang2.mp3", + "audio/skill/twjieyu1.mp3", + "audio/skill/twjieyu2.mp3", + "audio/skill/twjijiang1.mp3", + "audio/skill/twjijiang2.mp3", + "audio/skill/twjilun1.mp3", + "audio/skill/twjilun2.mp3", + "audio/skill/twjingce1.mp3", + "audio/skill/twjingce2.mp3", + "audio/skill/twjuchen1.mp3", + "audio/skill/twjuchen2.mp3", + "audio/skill/twjuezhu1.mp3", + "audio/skill/twjuezhu2.mp3", + "audio/skill/twjuntun1.mp3", + "audio/skill/twjuntun2.mp3", + "audio/skill/twkaiji1.mp3", + "audio/skill/twkaiji2.mp3", + "audio/skill/twkaizeng1.mp3", + "audio/skill/twkaizeng2.mp3", + "audio/skill/twkujian1.mp3", + "audio/skill/twkujian2.mp3", + "audio/skill/twkujian3.mp3", + "audio/skill/twkunsi1.mp3", + "audio/skill/twkunsi2.mp3", + "audio/skill/twlanjiang.mp3", + "audio/skill/twliexi1.mp3", + "audio/skill/twliexi2.mp3", + "audio/skill/twlijian1.mp3", + "audio/skill/twlijian2.mp3", + "audio/skill/twlingbao1.mp3", + "audio/skill/twlingbao2.mp3", + "audio/skill/twlingfa1.mp3", + "audio/skill/twlingfa2.mp3", + "audio/skill/twluanlve1.mp3", + "audio/skill/twluanlve2.mp3", + "audio/skill/twluannian1.mp3", + "audio/skill/twluannian2.mp3", + "audio/skill/twlvren1.mp3", + "audio/skill/twlvren2.mp3", + "audio/skill/twmiaolve1.mp3", + "audio/skill/twmiaolve2.mp3", + "audio/skill/twmutao1.mp3", + "audio/skill/twmutao2.mp3", + "audio/skill/twmuyue1.mp3", + "audio/skill/twneirao1.mp3", + "audio/skill/twneirao2.mp3", + "audio/skill/twqingkou1.mp3", + "audio/skill/twqingkou2.mp3", + "audio/skill/twqingren1.mp3", + "audio/skill/twqingren2.mp3", + "audio/skill/twqingtao1.mp3", + "audio/skill/twqingtao2.mp3", + "audio/skill/twqiongji1.mp3", + "audio/skill/twqiongji2.mp3", + "audio/skill/twquanqian1.mp3", + "audio/skill/twquanqian2.mp3", + "audio/skill/twrenchou1.mp3", + "audio/skill/twrenchou2.mp3", + "audio/skill/twrouke1.mp3", + "audio/skill/twrouke2.mp3", + "audio/skill/twruilian1.mp3", + "audio/skill/twruilian2.mp3", + "audio/skill/twshanghe1.mp3", + "audio/skill/twshanghe2.mp3", + "audio/skill/twshenyi1.mp3", + "audio/skill/twshenyi2.mp3", + "audio/skill/twshepan1.mp3", + "audio/skill/twshepan2.mp3", + "audio/skill/twshexhong1.mp3", + "audio/skill/twshexhong2.mp3", + "audio/skill/twshezhong1.mp3", + "audio/skill/twshezhong2.mp3", + "audio/skill/twshigong1.mp3", + "audio/skill/twshigong2.mp3", + "audio/skill/twshoushou1.mp3", + "audio/skill/twshoushou2.mp3", + "audio/skill/twsidai1.mp3", + "audio/skill/twsidai2.mp3", + "audio/skill/twsidao1.mp3", + "audio/skill/twsidao2.mp3", + "audio/skill/twsuizheng1.mp3", + "audio/skill/twsuizheng2.mp3", + "audio/skill/twsuizheng3.mp3", + "audio/skill/twtanfeng1.mp3", + "audio/skill/twtanfeng2.mp3", + "audio/skill/twtiaoxin1.mp3", + "audio/skill/twtiaoxin2.mp3", + "audio/skill/twtuidao1.mp3", + "audio/skill/twtuidao2.mp3", + "audio/skill/twwuhun1.mp3", + "audio/skill/twwuhun2.mp3", + "audio/skill/twxiafeng1.mp3", + "audio/skill/twxiafeng2.mp3", + "audio/skill/twxianfeng1.mp3", + "audio/skill/twxianfeng2.mp3", + "audio/skill/twxiawang1.mp3", + "audio/skill/twxiawang2.mp3", + "audio/skill/twxiawei1.mp3", + "audio/skill/twxiawei2.mp3", + "audio/skill/twxinghan1.mp3", + "audio/skill/twxinghan2.mp3", + "audio/skill/twxingzhui1.mp3", + "audio/skill/twxingzhui2.mp3", + "audio/skill/twxiongjun1.mp3", + "audio/skill/twxiongjun2.mp3", + "audio/skill/twxiongxi1.mp3", + "audio/skill/twxiongxi2.mp3", + "audio/skill/twxiongzheng1.mp3", + "audio/skill/twxiongzheng2.mp3", + "audio/skill/twxuechang1.mp3", + "audio/skill/twxuechang2.mp3", + "audio/skill/twyangming1.mp3", + "audio/skill/twyangming2.mp3", + "audio/skill/twyangshi1.mp3", + "audio/skill/twyangshi2.mp3", + "audio/skill/twyanshi1.mp3", + "audio/skill/twyanshi2.mp3", + "audio/skill/twyanshi3.mp3", + "audio/skill/twyiju1.mp3", + "audio/skill/twyiju2.mp3", + "audio/skill/twyimou1.mp3", + "audio/skill/twyimou2.mp3", + "audio/skill/twyingji1.mp3", + "audio/skill/twyingji2.mp3", + "audio/skill/twyingjia1.mp3", + "audio/skill/twyingjia2.mp3", + "audio/skill/twyouye1.mp3", + "audio/skill/twyouye2.mp3", + "audio/skill/twyujue1.mp3", + "audio/skill/twyujue2.mp3", + "audio/skill/twyulong1.mp3", + "audio/skill/twyulong2.mp3", + "audio/skill/twzhangwu1.mp3", + "audio/skill/twzhangwu2.mp3", + "audio/skill/twzhengjian1.mp3", + "audio/skill/twzhengjian2.mp3", + "audio/skill/twzhenhu1.mp3", + "audio/skill/twzhenhu2.mp3", + "audio/skill/twzhenxi1.mp3", + "audio/skill/twzhenxi2.mp3", + "audio/skill/twzhian1.mp3", + "audio/skill/twzhian2.mp3", + "audio/skill/twzhiji1.mp3", + "audio/skill/twzhiji2.mp3", + "audio/skill/twzhiqu1.mp3", + "audio/skill/twzhiqu2.mp3", + "audio/skill/twzhongchi1.mp3", + "audio/skill/twzhongchi2.mp3", + "audio/skill/twzhuidu1.mp3", + "audio/skill/twzhuidu2.mp3", + "audio/skill/vtbguisha1.mp3", + "audio/skill/vtbleyu1.mp3", + "audio/skill/vtbmeiniang1.mp3", + "audio/skill/vtbshanwu1.mp3", + "audio/skill/vtbshuli1.mp3", + "audio/skill/vtbtaoyan1.mp3", + "audio/skill/vtbxianli1.mp3", + "audio/skill/vtbyanli1.mp3", + "audio/skill/vtbyaoli1.mp3", + "audio/skill/vtbyuanli1.mp3", + "audio/skill/waishi1.mp3", + "audio/skill/waishi2.mp3", + "audio/skill/wanggui1.mp3", + "audio/skill/wanggui2.mp3", + "audio/skill/wangjing1.mp3", + "audio/skill/wangjing2.mp3", + "audio/skill/wangong1.mp3", + "audio/skill/wangong2.mp3", + "audio/skill/wangxi1.mp3", + "audio/skill/wangxi2.mp3", + "audio/skill/wangzun1.mp3", + "audio/skill/wangzun2.mp3", + "audio/skill/wanlan1.mp3", + "audio/skill/wanlan2.mp3", + "audio/skill/wanrong1.mp3", + "audio/skill/wanrong2.mp3", + "audio/skill/wansha_boss_lvbu31.mp3", + "audio/skill/wansha_boss_lvbu32.mp3", + "audio/skill/wansha_re_jiaxu1.mp3", + "audio/skill/wansha_re_jiaxu2.mp3", + "audio/skill/wansha_shen_simayi1.mp3", + "audio/skill/wansha_shen_simayi2.mp3", + "audio/skill/wansha1.mp3", + "audio/skill/wansha2.mp3", + "audio/skill/wanwei1.mp3", + "audio/skill/wanwei2.mp3", + "audio/skill/wanyi1.mp3", + "audio/skill/wanyi2.mp3", + "audio/skill/weicheng1.mp3", + "audio/skill/weicheng2.mp3", + "audio/skill/weidi1.mp3", + "audio/skill/weidi2.mp3", + "audio/skill/weifeng1.mp3", + "audio/skill/weifeng2.mp3", + "audio/skill/weijing1.mp3", + "audio/skill/weijing2.mp3", + "audio/skill/weikui1.mp3", + "audio/skill/weikui2.mp3", + "audio/skill/weilie1.mp3", + "audio/skill/weilie2.mp3", + "audio/skill/weimeng1.mp3", + "audio/skill/weimeng2.mp3", + "audio/skill/weimu1.mp3", + "audio/skill/weimu2.mp3", + "audio/skill/weipo1.mp3", + "audio/skill/weipo2.mp3", + "audio/skill/weishu1.mp3", + "audio/skill/weishu2.mp3", + "audio/skill/weiyi1.mp3", + "audio/skill/weiyi2.mp3", + "audio/skill/weizhong1.mp3", + "audio/skill/weizhong2.mp3", + "audio/skill/wendao1.mp3", + "audio/skill/wendao2.mp3", + "audio/skill/wengua1.mp3", + "audio/skill/wengua2.mp3", + "audio/skill/wfyuyan1.mp3", + "audio/skill/wfyuyan2.mp3", + "audio/skill/wlcuorui1.mp3", + "audio/skill/wlcuorui2.mp3", + "audio/skill/wufei1.mp3", + "audio/skill/wufei2.mp3", + "audio/skill/wuhun21.mp3", + "audio/skill/wuhun22.mp3", + "audio/skill/wuji1.mp3", + "audio/skill/wuji2.mp3", + "audio/skill/wulie1.mp3", + "audio/skill/wulie2.mp3", + "audio/skill/wuling1.mp3", + "audio/skill/wuling2.mp3", + "audio/skill/wumou1.mp3", + "audio/skill/wumou2.mp3", + "audio/skill/wuniang1.mp3", + "audio/skill/wuniang2.mp3", + "audio/skill/wuqian1.mp3", + "audio/skill/wuqian2.mp3", + "audio/skill/wuqin1.mp3", + "audio/skill/wuqin2.mp3", + "audio/skill/wurong1.mp3", + "audio/skill/wurong2.mp3", + "audio/skill/wushen1.mp3", + "audio/skill/wushen2.mp3", + "audio/skill/wusheng_dc_jsp_guanyu1.mp3", + "audio/skill/wusheng_dc_jsp_guanyu2.mp3", + "audio/skill/wusheng_guansuo1.mp3", + "audio/skill/wusheng_guansuo2.mp3", + "audio/skill/wusheng_guanzhang1.mp3", + "audio/skill/wusheng_guanzhang2.mp3", + "audio/skill/wusheng_jsp_guanyu1.mp3", + "audio/skill/wusheng_jsp_guanyu2.mp3", + "audio/skill/wusheng_re_guanyu1.mp3", + "audio/skill/wusheng_re_guanyu2.mp3", + "audio/skill/wusheng_re_guanzhang1.mp3", + "audio/skill/wusheng_re_guanzhang2.mp3", + "audio/skill/wusheng1.mp3", + "audio/skill/wusheng2.mp3", + "audio/skill/wushuang_lvlingqi1.mp3", + "audio/skill/wushuang_lvlingqi2.mp3", + "audio/skill/wushuang_re_lvbu1.mp3", + "audio/skill/wushuang_re_lvbu2.mp3", + "audio/skill/wushuang_shen_lvbu1.mp3", + "audio/skill/wushuang_shen_lvbu2.mp3", + "audio/skill/wushuang_wechat_lvbu1.mp3", + "audio/skill/wushuang_wechat_lvbu2.mp3", + "audio/skill/wushuang1.mp3", + "audio/skill/wushuang11.mp3", + "audio/skill/wushuang12.mp3", + "audio/skill/wushuang2.mp3", + "audio/skill/wushuang21.mp3", + "audio/skill/wushuang22.mp3", + "audio/skill/wuxin1.mp3", + "audio/skill/wuxin2.mp3", + "audio/skill/wuyan1.mp3", + "audio/skill/wuyan2.mp3", + "audio/skill/wuyuan1.mp3", + "audio/skill/wuyuan2.mp3", + "audio/skill/wylianji1.mp3", + "audio/skill/wylianji2.mp3", + "audio/skill/xhzhiyan1.mp3", + "audio/skill/xhzhiyan2.mp3", + "audio/skill/xianfu1.mp3", + "audio/skill/xianfu2.mp3", + "audio/skill/xianfu3.mp3", + "audio/skill/xianfu4.mp3", + "audio/skill/xianfu5.mp3", + "audio/skill/xianfu6.mp3", + "audio/skill/xianghai1.mp3", + "audio/skill/xianghai2.mp3", + "audio/skill/xiangle_ol_liushan1.mp3", + "audio/skill/xiangle_ol_liushan2.mp3", + "audio/skill/xiangle_re_liushan1.mp3", + "audio/skill/xiangle_re_liushan2.mp3", + "audio/skill/xiangle1.mp3", + "audio/skill/xiangle2.mp3", + "audio/skill/xiangshu1.mp3", + "audio/skill/xiangshu2.mp3", + "audio/skill/xianjing1.mp3", + "audio/skill/xianjing2.mp3", + "audio/skill/xianshuai1.mp3", + "audio/skill/xianshuai2.mp3", + "audio/skill/xiansi_re_liufeng1.mp3", + "audio/skill/xiansi_re_liufeng2.mp3", + "audio/skill/xiansi1.mp3", + "audio/skill/xiansi2.mp3", + "audio/skill/xiansi21.mp3", + "audio/skill/xiansi22.mp3", + "audio/skill/xiantu1.mp3", + "audio/skill/xiantu2.mp3", + "audio/skill/xianwan1.mp3", + "audio/skill/xianwan2.mp3", + "audio/skill/xianwang1.mp3", + "audio/skill/xianwang2.mp3", + "audio/skill/xianwei1.mp3", + "audio/skill/xianwei2.mp3", + "audio/skill/xianzhen1.mp3", + "audio/skill/xianzhen2.mp3", + "audio/skill/xianzhou_xin_caifuren1.mp3", + "audio/skill/xianzhou_xin_caifuren2.mp3", + "audio/skill/xianzhou1.mp3", + "audio/skill/xianzhou2.mp3", + "audio/skill/xianzhu1.mp3", + "audio/skill/xianzhu2.mp3", + "audio/skill/xiaoguo1.mp3", + "audio/skill/xiaoguo2.mp3", + "audio/skill/xiaoji_re_sunshangxiang1.mp3", + "audio/skill/xiaoji_re_sunshangxiang2.mp3", + "audio/skill/xiaoji_sp_sunshangxiang1.mp3", + "audio/skill/xiaoji_sp_sunshangxiang2.mp3", + "audio/skill/xiaoji1.mp3", + "audio/skill/xiaoji2.mp3", + "audio/skill/xiaoni1.mp3", + "audio/skill/xiaoni2.mp3", + "audio/skill/xiaowu1.mp3", + "audio/skill/xiaowu2.mp3", + "audio/skill/xiaoxi_hansui1.mp3", + "audio/skill/xiaoxi_hansui2.mp3", + "audio/skill/xiaoxi_machao1.mp3", + "audio/skill/xiaoxi_machao2.mp3", + "audio/skill/xiaoxi_pangde1.mp3", + "audio/skill/xiaoxi_pangde2.mp3", + "audio/skill/xiashu1.mp3", + "audio/skill/xiashu2.mp3", + "audio/skill/xibing1.mp3", + "audio/skill/xibing2.mp3", + "audio/skill/xiechan1.mp3", + "audio/skill/xiechan2.mp3", + "audio/skill/xiecui1.mp3", + "audio/skill/xiecui2.mp3", + "audio/skill/xiemu1.mp3", + "audio/skill/xiemu2.mp3", + "audio/skill/xijue_tuxi1.mp3", + "audio/skill/xijue_tuxi2.mp3", + "audio/skill/xijue_xiaoguo1.mp3", + "audio/skill/xijue_xiaoguo2.mp3", + "audio/skill/xijue1.mp3", + "audio/skill/xijue2.mp3", + "audio/skill/xinanjian1.mp3", + "audio/skill/xinanjian2.mp3", + "audio/skill/xinbenxi1.mp3", + "audio/skill/xinbenxi2.mp3", + "audio/skill/xinbuyi1.mp3", + "audio/skill/xinbuyi2.mp3", + "audio/skill/xindanshou1.mp3", + "audio/skill/xindanshou2.mp3", + "audio/skill/xinduodao1.mp3", + "audio/skill/xinduodao2.mp3", + "audio/skill/xinenyuan1.mp3", + "audio/skill/xinenyuan2.mp3", + "audio/skill/xinfencheng_re_liru1.mp3", + "audio/skill/xinfencheng_re_liru2.mp3", + "audio/skill/xinfencheng1.mp3", + "audio/skill/xinfencheng2.mp3", + "audio/skill/xinfu_andong1.mp3", + "audio/skill/xinfu_andong2.mp3", + "audio/skill/xinfu_bijing1.mp3", + "audio/skill/xinfu_bijing2.mp3", + "audio/skill/xinfu_chenghao1.mp3", + "audio/skill/xinfu_chenghao2.mp3", + "audio/skill/xinfu_daigong1.mp3", + "audio/skill/xinfu_daigong2.mp3", + "audio/skill/xinfu_denglou1.mp3", + "audio/skill/xinfu_denglou2.mp3", + "audio/skill/xinfu_dianhu1.mp3", + "audio/skill/xinfu_dianhu2.mp3", + "audio/skill/xinfu_dianhua1.mp3", + "audio/skill/xinfu_dianhua2.mp3", + "audio/skill/xinfu_duanfa1.mp3", + "audio/skill/xinfu_duanfa2.mp3", + "audio/skill/xinfu_falu1.mp3", + "audio/skill/xinfu_falu2.mp3", + "audio/skill/xinfu_fangtong1.mp3", + "audio/skill/xinfu_fangtong2.mp3", + "audio/skill/xinfu_fuhai1.mp3", + "audio/skill/xinfu_fuhai2.mp3", + "audio/skill/xinfu_fujian1.mp3", + "audio/skill/xinfu_fujian2.mp3", + "audio/skill/xinfu_fuyin1.mp3", + "audio/skill/xinfu_fuyin2.mp3", + "audio/skill/xinfu_gongqing_gz_panjun1.mp3", + "audio/skill/xinfu_gongqing_gz_panjun2.mp3", + "audio/skill/xinfu_gongqing1.mp3", + "audio/skill/xinfu_gongqing2.mp3", + "audio/skill/xinfu_guanchao1.mp3", + "audio/skill/xinfu_guanchao2.mp3", + "audio/skill/xinfu_guanwei1.mp3", + "audio/skill/xinfu_guanwei2.mp3", + "audio/skill/xinfu_guhuo2.mp3", + "audio/skill/xinfu_guolun1.mp3", + "audio/skill/xinfu_guolun2.mp3", + "audio/skill/xinfu_jianji1.mp3", + "audio/skill/xinfu_jianji2.mp3", + "audio/skill/xinfu_jianjie1.mp3", + "audio/skill/xinfu_jianjie2.mp3", + "audio/skill/xinfu_jianjie3.mp3", + "audio/skill/xinfu_jijie1.mp3", + "audio/skill/xinfu_jijie2.mp3", + "audio/skill/xinfu_jijun1.mp3", + "audio/skill/xinfu_jijun2.mp3", + "audio/skill/xinfu_jingxie1.mp3", + "audio/skill/xinfu_jingxie2.mp3", + "audio/skill/xinfu_jixu1.mp3", + "audio/skill/xinfu_jixu2.mp3", + "audio/skill/xinfu_jiyuan1.mp3", + "audio/skill/xinfu_jiyuan2.mp3", + "audio/skill/xinfu_kannan1.mp3", + "audio/skill/xinfu_kannan2.mp3", + "audio/skill/xinfu_langxi1.mp3", + "audio/skill/xinfu_langxi2.mp3", + "audio/skill/xinfu_lianpian1.mp3", + "audio/skill/xinfu_lianpian2.mp3", + "audio/skill/xinfu_limu1.mp3", + "audio/skill/xinfu_limu2.mp3", + "audio/skill/xinfu_lingren1.mp3", + "audio/skill/xinfu_lingren2.mp3", + "audio/skill/xinfu_longyuan1.mp3", + "audio/skill/xinfu_longyuan2.mp3", + "audio/skill/xinfu_lveming1.mp3", + "audio/skill/xinfu_lveming2.mp3", + "audio/skill/xinfu_pingcai.mp3", + "audio/skill/xinfu_qiai1.mp3", + "audio/skill/xinfu_qiai2.mp3", + "audio/skill/xinfu_qianchong1.mp3", + "audio/skill/xinfu_qianchong2.mp3", + "audio/skill/xinfu_qianchong3.mp3", + "audio/skill/xinfu_qianxin1.mp3", + "audio/skill/xinfu_qianxin2.mp3", + "audio/skill/xinfu_qiaosi1.mp3", + "audio/skill/xinfu_qiaosi2.mp3", + "audio/skill/xinfu_sanwen1.mp3", + "audio/skill/xinfu_sanwen2.mp3", + "audio/skill/xinfu_shajue1.mp3", + "audio/skill/xinfu_shajue2.mp3", + "audio/skill/xinfu_shangjian1.mp3", + "audio/skill/xinfu_shangjian2.mp3", + "audio/skill/xinfu_sidao1.mp3", + "audio/skill/xinfu_sidao2.mp3", + "audio/skill/xinfu_songsang1.mp3", + "audio/skill/xinfu_songsang2.mp3", + "audio/skill/xinfu_tanbei1.mp3", + "audio/skill/xinfu_tanbei2.mp3", + "audio/skill/xinfu_tunan1.mp3", + "audio/skill/xinfu_tunan2.mp3", + "audio/skill/xinfu_tunjun1.mp3", + "audio/skill/xinfu_tunjun2.mp3", + "audio/skill/xinfu_tushe1.mp3", + "audio/skill/xinfu_tushe2.mp3", + "audio/skill/xinfu_weilu1.mp3", + "audio/skill/xinfu_weilu2.mp3", + "audio/skill/xinfu_wuniang1.mp3", + "audio/skill/xinfu_wuniang2.mp3", + "audio/skill/xinfu_xingluan1.mp3", + "audio/skill/xinfu_xingluan2.mp3", + "audio/skill/xinfu_xingzhao.mp3", + "audio/skill/xinfu_xingzhao2.mp3", + "audio/skill/xinfu_xionghuo1.mp3", + "audio/skill/xinfu_xionghuo2.mp3", + "audio/skill/xinfu_xunxian1.mp3", + "audio/skill/xinfu_xunxian2.mp3", + "audio/skill/xinfu_xushen1.mp3", + "audio/skill/xinfu_xushen2.mp3", + "audio/skill/xinfu_yingshi1.mp3", + "audio/skill/xinfu_yingshi2.mp3", + "audio/skill/xinfu_yinshi1.mp3", + "audio/skill/xinfu_yinshi2.mp3", + "audio/skill/xinfu_yisuan1.mp3", + "audio/skill/xinfu_yisuan2.mp3", + "audio/skill/xinfu_youdi1.mp3", + "audio/skill/xinfu_youdi2.mp3", + "audio/skill/xinfu_zengdao1.mp3", + "audio/skill/xinfu_zengdao2.mp3", + "audio/skill/xinfu_zhanji1.mp3", + "audio/skill/xinfu_zhanji2.mp3", + "audio/skill/xinfu_zhaoxin1.mp3", + "audio/skill/xinfu_zhaoxin2.mp3", + "audio/skill/xinfu_zhennan1.mp3", + "audio/skill/xinfu_zhennan2.mp3", + "audio/skill/xinfu_zhenxing1.mp3", + "audio/skill/xinfu_zhenxing2.mp3", + "audio/skill/xinfu_zhenyi1.mp3", + "audio/skill/xinfu_zhenyi2.mp3", + "audio/skill/xinfu_zuilun1.mp3", + "audio/skill/xinfu_zuilun2.mp3", + "audio/skill/xinfuli1.mp3", + "audio/skill/xinfuli2.mp3", + "audio/skill/xinganlu1.mp3", + "audio/skill/xinganlu2.mp3", + "audio/skill/xingbu1.mp3", + "audio/skill/xingbu2.mp3", + "audio/skill/xingchong1.mp3", + "audio/skill/xingchong2.mp3", + "audio/skill/xinghan1.mp3", + "audio/skill/xinghan2.mp3", + "audio/skill/xingongji1.mp3", + "audio/skill/xingongji2.mp3", + "audio/skill/xingqi1.mp3", + "audio/skill/xingqi2.mp3", + "audio/skill/xingshang1.mp3", + "audio/skill/xingshang2.mp3", + "audio/skill/xingshen1.mp3", + "audio/skill/xingshen2.mp3", + "audio/skill/xingshuai1.mp3", + "audio/skill/xingshuai2.mp3", + "audio/skill/xingtu1.mp3", + "audio/skill/xingtu2.mp3", + "audio/skill/xinguidao1.mp3", + "audio/skill/xinguidao2.mp3", + "audio/skill/xinguixiu1.mp3", + "audio/skill/xinguixiu2.mp3", + "audio/skill/xingwu1.mp3", + "audio/skill/xingwu2.mp3", + "audio/skill/xingxue1.mp3", + "audio/skill/xingxue2.mp3", + "audio/skill/xingzuo1.mp3", + "audio/skill/xingzuo2.mp3", + "audio/skill/xinhuangtian2_re_zhangjiao1.mp3", + "audio/skill/xinhuangtian2_re_zhangjiao2.mp3", + "audio/skill/xinjiangchi1.mp3", + "audio/skill/xinjiangchi2.mp3", + "audio/skill/xinjianying1.mp3", + "audio/skill/xinjianying2.mp3", + "audio/skill/xinjiaojin1.mp3", + "audio/skill/xinjiaojin2.mp3", + "audio/skill/xinjiefan1.mp3", + "audio/skill/xinjiefan2.mp3", + "audio/skill/xinjiewei1.mp3", + "audio/skill/xinjiewei2.mp3", + "audio/skill/xinjingce1.mp3", + "audio/skill/xinjingce2.mp3", + "audio/skill/xinjuece1.mp3", + "audio/skill/xinjuece2.mp3", + "audio/skill/xinjuejing1.mp3", + "audio/skill/xinjuejing2.mp3", + "audio/skill/xinjujian1.mp3", + "audio/skill/xinjujian2.mp3", + "audio/skill/xinjushou1.mp3", + "audio/skill/xinjushou2.mp3", + "audio/skill/xinjyzongshi1.mp3", + "audio/skill/xinjyzongshi2.mp3", + "audio/skill/xinkuangfu1.mp3", + "audio/skill/xinkuangfu2.mp3", + "audio/skill/xinleiji1.mp3", + "audio/skill/xinleiji2.mp3", + "audio/skill/xinlianhuan_ol_pangtong1.mp3", + "audio/skill/xinlianhuan_ol_pangtong2.mp3", + "audio/skill/xinlianhuan1.mp3", + "audio/skill/xinlianhuan2.mp3", + "audio/skill/xinmieji1.mp3", + "audio/skill/xinmieji2.mp3", + "audio/skill/xinniluan1.mp3", + "audio/skill/xinniluan2.mp3", + "audio/skill/xinpaiyi1.mp3", + "audio/skill/xinpaiyi2.mp3", + "audio/skill/xinpingkou1.mp3", + "audio/skill/xinpingkou2.mp3", + "audio/skill/xinpojun1.mp3", + "audio/skill/xinpojun2.mp3", + "audio/skill/xinqiaoshui1.mp3", + "audio/skill/xinqiaoshui2.mp3", + "audio/skill/xinqieting1.mp3", + "audio/skill/xinqieting2.mp3", + "audio/skill/xinqingxi1.mp3", + "audio/skill/xinqingxi2.mp3", + "audio/skill/xinqiuyuan1.mp3", + "audio/skill/xinqiuyuan2.mp3", + "audio/skill/xinquanji1.mp3", + "audio/skill/xinquanji2.mp3", + "audio/skill/xinrende1.mp3", + "audio/skill/xinrende2.mp3", + "audio/skill/xinsheng1.mp3", + "audio/skill/xinsheng2.mp3", + "audio/skill/xinshenxing1.mp3", + "audio/skill/xinshenxing2.mp3", + "audio/skill/xintan1.mp3", + "audio/skill/xintan2.mp3", + "audio/skill/xinwurong1.mp3", + "audio/skill/xinwurong2.mp3", + "audio/skill/xinwurong3.mp3", + "audio/skill/xinwusheng1.mp3", + "audio/skill/xinwusheng2.mp3", + "audio/skill/xinwuyan1.mp3", + "audio/skill/xinwuyan2.mp3", + "audio/skill/xinxuanhuo1.mp3", + "audio/skill/xinxuanhuo2.mp3", + "audio/skill/xinyaoming1.mp3", + "audio/skill/xinyaoming2.mp3", + "audio/skill/xinzenhui1.mp3", + "audio/skill/xinzenhui2.mp3", + "audio/skill/xinzhan1.mp3", + "audio/skill/xinzhan2.mp3", + "audio/skill/xinzhenjun1.mp3", + "audio/skill/xinzhenjun2.mp3", + "audio/skill/xinzhiyan1.mp3", + "audio/skill/xinzhiyan2.mp3", + "audio/skill/xinzhuikong1.mp3", + "audio/skill/xinzhuikong2.mp3", + "audio/skill/xinzili1.mp3", + "audio/skill/xinzili2.mp3", + "audio/skill/xinzongxuan1.mp3", + "audio/skill/xinzongxuan2.mp3", + "audio/skill/xiongmang1.mp3", + "audio/skill/xiongmang2.mp3", + "audio/skill/xiongrao1.mp3", + "audio/skill/xiongrao2.mp3", + "audio/skill/xiongshu1.mp3", + "audio/skill/xiongshu2.mp3", + "audio/skill/xiongsuan1.mp3", + "audio/skill/xiongsuan2.mp3", + "audio/skill/xiongyi1.mp3", + "audio/skill/xiongyi2.mp3", + "audio/skill/xiongzhi1.mp3", + "audio/skill/xiongzhi2.mp3", + "audio/skill/xiuluo1.mp3", + "audio/skill/xiuluo2.mp3", + "audio/skill/xiusheng1.mp3", + "audio/skill/xiusheng2.mp3", + "audio/skill/xixiu1.mp3", + "audio/skill/xixiu2.mp3", + "audio/skill/xiyan1.mp3", + "audio/skill/xiyan2.mp3", + "audio/skill/xiying1.mp3", + "audio/skill/xiying2.mp3", + "audio/skill/xizhen1.mp3", + "audio/skill/xizhen2.mp3", + "audio/skill/xjshijian1.mp3", + "audio/skill/xjshijian2.mp3", + "audio/skill/xpchijie1.mp3", + "audio/skill/xpchijie2.mp3", + "audio/skill/xsqianxin1.mp3", + "audio/skill/xsqianxin2.mp3", + "audio/skill/xuanbei1.mp3", + "audio/skill/xuanbei2.mp3", + "audio/skill/xuancun1.mp3", + "audio/skill/xuancun2.mp3", + "audio/skill/xuanfeng_boss_lvbu31.mp3", + "audio/skill/xuanfeng_boss_lvbu32.mp3", + "audio/skill/xuanfeng_re_heqi1.mp3", + "audio/skill/xuanfeng_re_heqi2.mp3", + "audio/skill/xuanfeng_re_lingtong1.mp3", + "audio/skill/xuanfeng_re_lingtong2.mp3", + "audio/skill/xuanfeng_xin_lingtong1.mp3", + "audio/skill/xuanfeng_xin_lingtong2.mp3", + "audio/skill/xuanfeng1.mp3", + "audio/skill/xuanfeng2.mp3", + "audio/skill/xuanhuo1.mp3", + "audio/skill/xuanhuo2.mp3", + "audio/skill/xuanlve1.mp3", + "audio/skill/xuanlve2.mp3", + "audio/skill/xuanmu1.mp3", + "audio/skill/xuanmu2.mp3", + "audio/skill/xueji1.mp3", + "audio/skill/xueji2.mp3", + "audio/skill/xuelunyang.mp3", + "audio/skill/xuewei1.mp3", + "audio/skill/xuewei2.mp3", + "audio/skill/xueyi1.mp3", + "audio/skill/xueyi2.mp3", + "audio/skill/xuezhao1.mp3", + "audio/skill/xuezhao2.mp3", + "audio/skill/xunde1.mp3", + "audio/skill/xunde2.mp3", + "audio/skill/xunli1.mp3", + "audio/skill/xunli2.mp3", + "audio/skill/xunshi1.mp3", + "audio/skill/xunshi2.mp3", + "audio/skill/xunxun1.mp3", + "audio/skill/xunxun2.mp3", + "audio/skill/xunyi1.mp3", + "audio/skill/xunyi2.mp3", + "audio/skill/xunzhi1.mp3", + "audio/skill/xunzhi2.mp3", + "audio/skill/xushen1.mp3", + "audio/skill/xushen2.mp3", + "audio/skill/xutuhuanjin.mp3", + "audio/skill/xuxie1.mp3", + "audio/skill/xuxie2.mp3", + "audio/skill/xz_xunxun1.mp3", + "audio/skill/xz_xunxun2.mp3", + "audio/skill/yachai1.mp3", + "audio/skill/yachai2.mp3", + "audio/skill/yaner1.mp3", + "audio/skill/yaner2.mp3", + "audio/skill/yangjie1.mp3", + "audio/skill/yangjie2.mp3", + "audio/skill/yangkuang1.mp3", + "audio/skill/yangkuang2.mp3", + "audio/skill/yangzhong1.mp3", + "audio/skill/yangzhong2.mp3", + "audio/skill/yanhuo1.mp3", + "audio/skill/yanhuo2.mp3", + "audio/skill/yanjiao1.mp3", + "audio/skill/yanjiao2.mp3", + "audio/skill/yanru1.mp3", + "audio/skill/yanru2.mp3", + "audio/skill/yanxi1.mp3", + "audio/skill/yanxi2.mp3", + "audio/skill/yanxiao1.mp3", + "audio/skill/yanxiao2.mp3", + "audio/skill/yanyu1.mp3", + "audio/skill/yanyu2.mp3", + "audio/skill/yanzheng1.mp3", + "audio/skill/yanzheng2.mp3", + "audio/skill/yanzhu1.mp3", + "audio/skill/yanzhu2.mp3", + "audio/skill/yaoming1.mp3", + "audio/skill/yaoming2.mp3", + "audio/skill/yaopei1.mp3", + "audio/skill/yaopei2.mp3", + "audio/skill/yaowu1.mp3", + "audio/skill/yaowu2.mp3", + "audio/skill/yashi1.mp3", + "audio/skill/yashi2.mp3", + "audio/skill/yawang1.mp3", + "audio/skill/yawang2.mp3", + "audio/skill/ybzhuiji1.mp3", + "audio/skill/ybzhuiji2.mp3", + "audio/skill/yechou1.mp3", + "audio/skill/yechou2.mp3", + "audio/skill/yeyan1.mp3", + "audio/skill/yeyan2.mp3", + "audio/skill/yeyan3.mp3", + "audio/skill/yicheng1.mp3", + "audio/skill/yicheng2.mp3", + "audio/skill/yichong1.mp3", + "audio/skill/yichong2.mp3", + "audio/skill/yicong1.mp3", + "audio/skill/yicong2.mp3", + "audio/skill/yidian1.mp3", + "audio/skill/yidian2.mp3", + "audio/skill/yidu1.mp3", + "audio/skill/yidu2.mp3", + "audio/skill/yifa1.mp3", + "audio/skill/yifa2.mp3", + "audio/skill/yigui1.mp3", + "audio/skill/yigui2.mp3", + "audio/skill/yiji1.mp3", + "audio/skill/yiji2.mp3", + "audio/skill/yijiao1.mp3", + "audio/skill/yijiao2.mp3", + "audio/skill/yijie1.mp3", + "audio/skill/yijie2.mp3", + "audio/skill/yijin1.mp3", + "audio/skill/yijin2.mp3", + "audio/skill/yijin3.mp3", + "audio/skill/yijue1.mp3", + "audio/skill/yijue2.mp3", + "audio/skill/yilie1.mp3", + "audio/skill/yilie2.mp3", + "audio/skill/yimie1.mp3", + "audio/skill/yimie2.mp3", + "audio/skill/yinbing1.mp3", + "audio/skill/yinbing2.mp3", + "audio/skill/yingba1.mp3", + "audio/skill/yingba2.mp3", + "audio/skill/yingbin1.mp3", + "audio/skill/yingbin2.mp3", + "audio/skill/yingbing1.mp3", + "audio/skill/yingbing2.mp3", + "audio/skill/yingfeng1.mp3", + "audio/skill/yingfeng2.mp3", + "audio/skill/yinghun_ol_sunjian1.mp3", + "audio/skill/yinghun_ol_sunjian2.mp3", + "audio/skill/yinghun_re_sunben1.mp3", + "audio/skill/yinghun_re_sunben2.mp3", + "audio/skill/yinghun_re_sunce1.mp3", + "audio/skill/yinghun_re_sunce2.mp3", + "audio/skill/yinghun_re_sunjian1.mp3", + "audio/skill/yinghun_re_sunjian2.mp3", + "audio/skill/yinghun_sb_sunce1.mp3", + "audio/skill/yinghun_sb_sunce2.mp3", + "audio/skill/yinghun_sunce1.mp3", + "audio/skill/yinghun_sunce2.mp3", + "audio/skill/yinghun_sunjian1.mp3", + "audio/skill/yinghun_sunjian2.mp3", + "audio/skill/yinghun1.mp3", + "audio/skill/yinghun2.mp3", + "audio/skill/yingyang1.mp3", + "audio/skill/yingyang2.mp3", + "audio/skill/yingyuan1.mp3", + "audio/skill/yingyuan2.mp3", + "audio/skill/yingzi1.mp3", + "audio/skill/yingzi2.mp3", + "audio/skill/yinju1.mp3", + "audio/skill/yinju2.mp3", + "audio/skill/yinlang1.mp3", + "audio/skill/yinlang2.mp3", + "audio/skill/yinli1.mp3", + "audio/skill/yinli2.mp3", + "audio/skill/yinyi1.mp3", + "audio/skill/yinyi2.mp3", + "audio/skill/yirang_re_taoqian1.mp3", + "audio/skill/yirang_re_taoqian2.mp3", + "audio/skill/yirang1.mp3", + "audio/skill/yirang2.mp3", + "audio/skill/yise1.mp3", + "audio/skill/yise2.mp3", + "audio/skill/yishe1.mp3", + "audio/skill/yishe2.mp3", + "audio/skill/yitian.mp3", + "audio/skill/yixiang_re_taoqian1.mp3", + "audio/skill/yixiang_re_taoqian2.mp3", + "audio/skill/yixiang1.mp3", + "audio/skill/yixiang2.mp3", + "audio/skill/yiyong1.mp3", + "audio/skill/yiyong2.mp3", + "audio/skill/yizan_respond_shan1.mp3", + "audio/skill/yizan_respond_shan2.mp3", + "audio/skill/yizhao1.mp3", + "audio/skill/yizhao2.mp3", + "audio/skill/yizheng1.mp3", + "audio/skill/yizheng2.mp3", + "audio/skill/yizhi1.mp3", + "audio/skill/yizhi2.mp3", + "audio/skill/yizhong1.mp3", + "audio/skill/yizhong2.mp3", + "audio/skill/yizhu1.mp3", + "audio/skill/yizhu2.mp3", + "audio/skill/yizu1.mp3", + "audio/skill/yizu2.mp3", + "audio/skill/yongdi_xinping1.mp3", + "audio/skill/yongdi_xinping2.mp3", + "audio/skill/yongdi1.mp3", + "audio/skill/yongdi2.mp3", + "audio/skill/yongjin_xin_lingtong1.mp3", + "audio/skill/yongjin_xin_lingtong2.mp3", + "audio/skill/yongjin1.mp3", + "audio/skill/yongjin2.mp3", + "audio/skill/yongjue1.mp3", + "audio/skill/yongjue2.mp3", + "audio/skill/yonglve1.mp3", + "audio/skill/yonglve2.mp3", + "audio/skill/yongsi1.mp3", + "audio/skill/yongsi2.mp3", + "audio/skill/youdi1.mp3", + "audio/skill/youdi2.mp3", + "audio/skill/youlong1.mp3", + "audio/skill/youlong2.mp3", + "audio/skill/youxu1.mp3", + "audio/skill/youxu2.mp3", + "audio/skill/youyan1.mp3", + "audio/skill/youyan2.mp3", + "audio/skill/youyi1.mp3", + "audio/skill/youyi2.mp3", + "audio/skill/yuanchou1.mp3", + "audio/skill/yuanchou2.mp3", + "audio/skill/yuanhu1.mp3", + "audio/skill/yuanhu2.mp3", + "audio/skill/yuanhu3.mp3", + "audio/skill/yuanlve1.mp3", + "audio/skill/yuanlve2.mp3", + "audio/skill/yuanqing1.mp3", + "audio/skill/yuanqing2.mp3", + "audio/skill/yuanyu1.mp3", + "audio/skill/yuanyu2.mp3", + "audio/skill/yuanzi1.mp3", + "audio/skill/yuanzi2.mp3", + "audio/skill/yuce_re_manchong1.mp3", + "audio/skill/yuce_re_manchong2.mp3", + "audio/skill/yuce1.mp3", + "audio/skill/yuce2.mp3", + "audio/skill/yuehun1.mp3", + "audio/skill/yuehun2.mp3", + "audio/skill/yuejian1.mp3", + "audio/skill/yuejian2.mp3", + "audio/skill/yufeng1.mp3", + "audio/skill/yufeng2.mp3", + "audio/skill/yuheng1.mp3", + "audio/skill/yuheng2.mp3", + "audio/skill/yuhua1.mp3", + "audio/skill/yuhua2.mp3", + "audio/skill/yui_jiang1.mp3", + "audio/skill/yui_jiang2.mp3", + "audio/skill/yui_lieyin1.mp3", + "audio/skill/yui_lieyin2.mp3", + "audio/skill/yui_takaramono1.mp3", + "audio/skill/yui_takaramono2.mp3", + "audio/skill/yujue1.mp3", + "audio/skill/yujue2.mp3", + "audio/skill/yuqi1.mp3", + "audio/skill/yuqi2.mp3", + "audio/skill/yuri_wangxi1.mp3", + "audio/skill/yuri_wangxi2.mp3", + "audio/skill/yuri_xingdong_gain1.mp3", + "audio/skill/yuri_xingdong_gain2.mp3", + "audio/skill/yuri_xingdong1.mp3", + "audio/skill/yuri_xingdong2.mp3", + "audio/skill/yuri_xingdong3.mp3", + "audio/skill/yusui1.mp3", + "audio/skill/yusui2.mp3", + "audio/skill/yuxiang.mp3", + "audio/skill/yuxu1.mp3", + "audio/skill/yuxu2.mp3", + "audio/skill/yuyan1.mp3", + "audio/skill/yuyan2.mp3", + "audio/skill/yuyun1.mp3", + "audio/skill/yuyun2.mp3", + "audio/skill/yuzhang1.mp3", + "audio/skill/yuzhang2.mp3", + "audio/skill/zaiqi1.mp3", + "audio/skill/zaiqi2.mp3", + "audio/skill/zaoli1.mp3", + "audio/skill/zaoli2.mp3", + "audio/skill/zaoxian_re_dengai1.mp3", + "audio/skill/zaoxian_re_dengai2.mp3", + "audio/skill/zaoxian1.mp3", + "audio/skill/zaoxian2.mp3", + "audio/skill/zaoyun1.mp3", + "audio/skill/zaoyun2.mp3", + "audio/skill/zengou1.mp3", + "audio/skill/zengou2.mp3", + "audio/skill/zfengshi1.mp3", + "audio/skill/zfengshi2.mp3", + "audio/skill/zhafu1.mp3", + "audio/skill/zhafu2.mp3", + "audio/skill/zhangba_skill.mp3", + "audio/skill/zhangming1.mp3", + "audio/skill/zhangming2.mp3", + "audio/skill/zhangu1.mp3", + "audio/skill/zhangu2.mp3", + "audio/skill/zhangwu1.mp3", + "audio/skill/zhangwu2.mp3", + "audio/skill/zhanjue1.mp3", + "audio/skill/zhanjue2.mp3", + "audio/skill/zhanshen1.mp3", + "audio/skill/zhanshen2.mp3", + "audio/skill/zhanwan1.mp3", + "audio/skill/zhanwan2.mp3", + "audio/skill/zhanyanliangzhuwenchou.mp3", + "audio/skill/zhanyi1.mp3", + "audio/skill/zhanyi2.mp3", + "audio/skill/zhanyuan1.mp3", + "audio/skill/zhanyuan2.mp3", + "audio/skill/zhaofu1.mp3", + "audio/skill/zhaofu2.mp3", + "audio/skill/zhaohan1.mp3", + "audio/skill/zhaohan2.mp3", + "audio/skill/zhaohuo_re_taoqian1.mp3", + "audio/skill/zhaohuo_re_taoqian2.mp3", + "audio/skill/zhaohuo1.mp3", + "audio/skill/zhaohuo2.mp3", + "audio/skill/zhaolie1.mp3", + "audio/skill/zhaolie2.mp3", + "audio/skill/zhaoran1.mp3", + "audio/skill/zhaoran2.mp3", + "audio/skill/zhaosong1.mp3", + "audio/skill/zhaosong2.mp3", + "audio/skill/zhaotao1.mp3", + "audio/skill/zhaotao2.mp3", + "audio/skill/zhaxiang1.mp3", + "audio/skill/zhaxiang2.mp3", + "audio/skill/zhefu1.mp3", + "audio/skill/zhefu2.mp3", + "audio/skill/zhendu1.mp3", + "audio/skill/zhendu2.mp3", + "audio/skill/zhengbi1.mp3", + "audio/skill/zhengbi2.mp3", + "audio/skill/zhengding1.mp3", + "audio/skill/zhengding2.mp3", + "audio/skill/zhenge1.mp3", + "audio/skill/zhenge2.mp3", + "audio/skill/zhengjian1.mp3", + "audio/skill/zhengjian2.mp3", + "audio/skill/zhengjing_boom.mp3", + "audio/skill/zhengjing_click.mp3", + "audio/skill/zhengjing_finish.mp3", + "audio/skill/zhengjing_guanju.mp3", + "audio/skill/zhengjing1.mp3", + "audio/skill/zhengjing2.mp3", + "audio/skill/zhengnan1.mp3", + "audio/skill/zhengnan2.mp3", + "audio/skill/zhengqing1.mp3", + "audio/skill/zhengqing2.mp3", + "audio/skill/zhenlie_re_wangyi1.mp3", + "audio/skill/zhenlie_re_wangyi2.mp3", + "audio/skill/zhenlie1.mp3", + "audio/skill/zhenlie2.mp3", + "audio/skill/zhenshan1.mp3", + "audio/skill/zhenshan2.mp3", + "audio/skill/zhente1.mp3", + "audio/skill/zhente2.mp3", + "audio/skill/zhenwei_re_wenpin1.mp3", + "audio/skill/zhenwei_re_wenpin2.mp3", + "audio/skill/zhenwei1.mp3", + "audio/skill/zhenwei2.mp3", + "audio/skill/zhiba2_re_sunben1.mp3", + "audio/skill/zhiba2_re_sunben2.mp3", + "audio/skill/zhiba21.mp3", + "audio/skill/zhiba22.mp3", + "audio/skill/zhibian1.mp3", + "audio/skill/zhibian2.mp3", + "audio/skill/zhichi_re_chengong1.mp3", + "audio/skill/zhichi_re_chengong2.mp3", + "audio/skill/zhichi1.mp3", + "audio/skill/zhichi2.mp3", + "audio/skill/zhidao1.mp3", + "audio/skill/zhidao2.mp3", + "audio/skill/zhige1.mp3", + "audio/skill/zhige2.mp3", + "audio/skill/zhiheng_gz_jun_sunquan1.mp3", + "audio/skill/zhiheng_gz_jun_sunquan2.mp3", + "audio/skill/zhiheng1.mp3", + "audio/skill/zhiheng2.mp3", + "audio/skill/zhiji_re_jiangwei1.mp3", + "audio/skill/zhiji_re_jiangwei2.mp3", + "audio/skill/zhiji1.mp3", + "audio/skill/zhiji2.mp3", + "audio/skill/zhijian1.mp3", + "audio/skill/zhijian2.mp3", + "audio/skill/zhilve1.mp3", + "audio/skill/zhilve2.mp3", + "audio/skill/zhiman_guansuo1.mp3", + "audio/skill/zhiman_guansuo2.mp3", + "audio/skill/zhiman_re_masu1.mp3", + "audio/skill/zhiman_re_masu2.mp3", + "audio/skill/zhiman1.mp3", + "audio/skill/zhiman2.mp3", + "audio/skill/zhimeng1.mp3", + "audio/skill/zhimeng2.mp3", + "audio/skill/zhiming1.mp3", + "audio/skill/zhiming2.mp3", + "audio/skill/zhiren1.mp3", + "audio/skill/zhiren2.mp3", + "audio/skill/zhiri1.mp3", + "audio/skill/zhiri2.mp3", + "audio/skill/zhishi1.mp3", + "audio/skill/zhishi2.mp3", + "audio/skill/zhiwei1.mp3", + "audio/skill/zhiwei2.mp3", + "audio/skill/zhiyan_gexuan1.mp3", + "audio/skill/zhiyan_re_yufan1.mp3", + "audio/skill/zhiyan_re_yufan2.mp3", + "audio/skill/zhiyan_xin_yufan1.mp3", + "audio/skill/zhiyan_xin_yufan2.mp3", + "audio/skill/zhiyan1.mp3", + "audio/skill/zhiyan2.mp3", + "audio/skill/zhiyi1.mp3", + "audio/skill/zhiyi2.mp3", + "audio/skill/zhiyu1.mp3", + "audio/skill/zhiyu2.mp3", + "audio/skill/zhongjian1.mp3", + "audio/skill/zhongjian2.mp3", + "audio/skill/zhongjie1.mp3", + "audio/skill/zhongjie2.mp3", + "audio/skill/zhongyi1.mp3", + "audio/skill/zhongyi2.mp3", + "audio/skill/zhongyong1.mp3", + "audio/skill/zhongyong2.mp3", + "audio/skill/zhongyun1.mp3", + "audio/skill/zhongyun2.mp3", + "audio/skill/zhongzuo1.mp3", + "audio/skill/zhongzuo2.mp3", + "audio/skill/zhoufu1.mp3", + "audio/skill/zhoufu2.mp3", + "audio/skill/zhoulin1.mp3", + "audio/skill/zhoulin2.mp3", + "audio/skill/zhouxian1.mp3", + "audio/skill/zhouxian2.mp3", + "audio/skill/zhouxuan1.mp3", + "audio/skill/zhouxuan2.mp3", + "audio/skill/zhuandui1.mp3", + "audio/skill/zhuandui2.mp3", + "audio/skill/zhuangdan1.mp3", + "audio/skill/zhuangdan2.mp3", + "audio/skill/zhuangpo1.mp3", + "audio/skill/zhuangpo2.mp3", + "audio/skill/zhuangrong1.mp3", + "audio/skill/zhuangrong2.mp3", + "audio/skill/zhuangshu1.mp3", + "audio/skill/zhuangshu2.mp3", + "audio/skill/zhuge_skill.mp3", + "audio/skill/zhuhai_gz_re_xushu1.mp3", + "audio/skill/zhuhai_gz_re_xushu2.mp3", + "audio/skill/zhuhai1.mp3", + "audio/skill/zhuhai2.mp3", + "audio/skill/zhuide1.mp3", + "audio/skill/zhuide2.mp3", + "audio/skill/zhuihuan1.mp3", + "audio/skill/zhuihuan2.mp3", + "audio/skill/zhuikong1.mp3", + "audio/skill/zhuikong2.mp3", + "audio/skill/zhuitao1.mp3", + "audio/skill/zhuitao2.mp3", + "audio/skill/zhuiyi_re_bulianshi1.mp3", + "audio/skill/zhuiyi_re_bulianshi2.mp3", + "audio/skill/zhuiyi1.mp3", + "audio/skill/zhuiyi2.mp3", + "audio/skill/zhujian1.mp3", + "audio/skill/zhujian2.mp3", + "audio/skill/zhukou1.mp3", + "audio/skill/zhukou2.mp3", + "audio/skill/zhuning1.mp3", + "audio/skill/zhuning2.mp3", + "audio/skill/zhuosheng1.mp3", + "audio/skill/zhuosheng2.mp3", + "audio/skill/zhuque_skill.mp3", + "audio/skill/zhushi1.mp3", + "audio/skill/zhushi2.mp3", + "audio/skill/zhuwei1.mp3", + "audio/skill/zhuwei2.mp3", + "audio/skill/zifu1.mp3", + "audio/skill/zifu2.mp3", + "audio/skill/zili_re_zhonghui1.mp3", + "audio/skill/zili_re_zhonghui2.mp3", + "audio/skill/zili1.mp3", + "audio/skill/zili2.mp3", + "audio/skill/ziliang1.mp3", + "audio/skill/ziliang2.mp3", + "audio/skill/ziqu1.mp3", + "audio/skill/ziqu2.mp3", + "audio/skill/zishou_re_liubiao1.mp3", + "audio/skill/zishou_re_liubiao2.mp3", + "audio/skill/zishou1.mp3", + "audio/skill/zishou2.mp3", + "audio/skill/zishu1.mp3", + "audio/skill/zishu2.mp3", + "audio/skill/ziyuan1.mp3", + "audio/skill/ziyuan2.mp3", + "audio/skill/zjjuxiang1.mp3", + "audio/skill/zjjuxiang2.mp3", + "audio/skill/zlhuji1.mp3", + "audio/skill/zlhuji2.mp3", + "audio/skill/zlshoufu1.mp3", + "audio/skill/zlshoufu2.mp3", + "audio/skill/zniaoxiang1.mp3", + "audio/skill/zniaoxiang2.mp3", + "audio/skill/zongfan1.mp3", + "audio/skill/zongfan2.mp3", + "audio/skill/zonghuo.mp3", + "audio/skill/zongkui_tw_beimihu1.mp3", + "audio/skill/zongkui_tw_beimihu2.mp3", + "audio/skill/zongkui1.mp3", + "audio/skill/zongkui2.mp3", + "audio/skill/zongshi1.mp3", + "audio/skill/zongshi2.mp3", + "audio/skill/zongxuan1.mp3", + "audio/skill/zongxuan2.mp3", + "audio/skill/zongzuo1.mp3", + "audio/skill/zongzuo2.mp3", + "audio/skill/zuici1.mp3", + "audio/skill/zuici2.mp3", + "audio/skill/zuixiang.mp3", + "audio/skill/zunwei1.mp3", + "audio/skill/zunwei2.mp3", + "audio/skill/zuoding_re_zhongyao1.mp3", + "audio/skill/zuoding_re_zhongyao2.mp3", + "audio/skill/zuoding1.mp3", + "audio/skill/zuoding2.mp3", + "audio/skill/zuoxing1.mp3", + "audio/skill/zuoxing2.mp3", + "audio/skill/zyqiao1.mp3", + "audio/skill/zyqiao2.mp3", + /*skill audio end*/ + + /*voice begin*/ + "audio/voice/male/0.mp3", + "audio/voice/male/1.mp3", + "audio/voice/male/2.mp3", + "audio/voice/male/3.mp3", + "audio/voice/male/4.mp3", + "audio/voice/male/5.mp3", + "audio/voice/male/6.mp3", + "audio/voice/male/7.mp3", + "audio/voice/male/8.mp3", + "audio/voice/male/9.mp3", + "audio/voice/male/10.mp3", + "audio/voice/male/11.mp3", + "audio/voice/male/12.mp3", + "audio/voice/male/13.mp3", + "audio/voice/male/14.mp3", + "audio/voice/male/15.mp3", + "audio/voice/male/16.mp3", + "audio/voice/male/17.mp3", + "audio/voice/male/18.mp3", + "audio/voice/male/19.mp3", + "audio/voice/male/20.mp3", + "audio/voice/male/21.mp3", + "audio/voice/male/22.mp3", + "audio/voice/female/0.mp3", + "audio/voice/female/1.mp3", + "audio/voice/female/2.mp3", + "audio/voice/female/3.mp3", + "audio/voice/female/4.mp3", + "audio/voice/female/5.mp3", + "audio/voice/female/6.mp3", + "audio/voice/female/7.mp3", + "audio/voice/female/8.mp3", + "audio/voice/female/9.mp3", + "audio/voice/female/10.mp3", + "audio/voice/female/11.mp3", + "audio/voice/female/12.mp3", + "audio/voice/female/13.mp3", + "audio/voice/female/14.mp3", + "audio/voice/female/15.mp3", + "audio/voice/female/16.mp3", + "audio/voice/female/17.mp3", + "audio/voice/female/18.mp3", + "audio/voice/female/19.mp3", + "audio/voice/female/20.mp3", + "audio/voice/female/21.mp3", + "audio/voice/female/22.mp3", + /*voice end*/ + /*audio end*/ + + "font/huangcao.woff2", + "font/shousha.woff2", + "font/xiaozhuan.woff2", + "font/xingkai.woff2", + "font/xinwei.woff2", + "font/yuanli.woff2", + + /*background image begin*/ + "image/background/beipan_bg.jpg", + "image/background/heaven_bg.jpg", + "image/background/huangtian_bg.jpg", + "image/background/key_bg.jpg", + "image/background/kyoani_bg.jpg", + "image/background/lanting_bg.jpg", + "image/background/lingju_bg.jpg", + "image/background/noname_bg.jpg", + "image/background/ol_bg.jpg", + "image/background/oltianhou_club_bg.jpg", + "image/background/oltianhou_diamond_bg.jpg", + "image/background/oltianhou_heart_bg.jpg", + "image/background/oltianhou_spade_bg.jpg", + "image/background/planetarian_bg.jpg", + "image/background/sanying_bg.jpg", + "image/background/september_bg.jpg", + "image/background/shengshi_bg.jpg", + "image/background/taoyuan_bg.jpg", + "image/background/wangshi_bg.jpg", + "image/background/wuming_bg.jpg", + "image/background/xiaowu_bg.jpg", + "image/background/xinsha_bg.jpg", + "image/background/xiongxin_bg.jpg", + "image/background/yinxiang_bg.jpg", + "image/background/zhanhuo_bg.jpg", + "image/background/zhanyun_bg.jpg", + "image/background/zhulin_bg.jpg", + /*background image end*/ + + /*card image begin*/ + "image/card/bagua.png", + "image/card/baihupifeng.png", + "image/card/baishouzhihu.png", + "image/card/baiyidujiang.png", + "image/card/baiyin.png", + "image/card/bingliang.png", + "image/card/binglinchengxia.png", + "image/card/binglinchengxiax.png", + "image/card/bingpotong.png", + "image/card/bintieshuangji.png", + "image/card/cangchizhibi.png", + "image/card/caochuan.png", + "image/card/caochuanjiejian.png", + "image/card/caomu.png", + "image/card/caoyao.png", + "image/card/cardtempname_bg.png", + "image/card/changandajian_equip1.png", + "image/card/charge.png", + "image/card/cheliji_feilunzhanyu.png", + "image/card/cheliji_sichengliangyu.png", + "image/card/cheliji_tiejixuanyu.png", + "image/card/chenghuodajie.png", + "image/card/chenhuodajie.png", + "image/card/chiling.png", + "image/card/chilongya.png", + "image/card/chitu.png", + "image/card/chiyuxi.png", + "image/card/chuansongmen.png", + "image/card/chunbing.png", + "image/card/chuqibuyi.png", + "image/card/cisha.png", + "image/card/cixiong.png", + "image/card/cooperation_damage.png", + "image/card/dagongche.png", + "image/card/daihuofenglun.png", + "image/card/dawan.png", + "image/card/db_atk1.jpg", + "image/card/db_atk1_出阵迎战.jpg", + "image/card/db_atk1_反抗.jpg", + "image/card/db_atk1_固守城池.jpg", + "image/card/db_atk2.jpg", + "image/card/db_atk2_拱卫中军.jpg", + "image/card/db_atk2_归顺.jpg", + "image/card/db_atk2_突出重围.jpg", + "image/card/db_def1.jpg", + "image/card/db_def1_围城断粮.jpg", + "image/card/db_def1_镇压.jpg", + "image/card/db_def1_直取敌营.jpg", + "image/card/db_def2.jpg", + "image/card/db_def2_安抚.jpg", + "image/card/db_def2_擂鼓进军.jpg", + "image/card/db_def2_扰阵疲敌.jpg", + "image/card/diaobingqianjiang.png", + "image/card/diaohulishan.png", + "image/card/dilu.png", + "image/card/dinglanyemingzhu.png", + "image/card/dinvxuanshuang.png", + "image/card/diqi.png", + "image/card/donghuangzhong.png", + "image/card/dongzhuxianji.png", + "image/card/du.png", + "image/card/duanjian.png", + "image/card/dunpaigedang.png", + "image/card/dz_mantianguohai.png", + "image/card/expandedSlots.png", + "image/card/fangtian.png", + "image/card/feibiao.png", + "image/card/feilongduofeng.png", + "image/card/fengchu_card.png", + "image/card/fengxueren.png", + "image/card/fengyinzhidan.png", + "image/card/fudichouxin.png", + "image/card/fulei.png", + "image/card/fuxiqin.png", + "image/card/geanguanhuo.png", + "image/card/gongshoujianbei.png", + "image/card/gouhunluo.png", + "image/card/group_jin.png", + "image/card/group_key.png", + "image/card/group_qun.png", + "image/card/group_shen.png", + "image/card/group_shu.png", + "image/card/group_unknown.png", + "image/card/group_wei.png", + "image/card/group_western.png", + "image/card/group_wu.png", + "image/card/group_ye.png", + "image/card/guaguliaodu.png", + "image/card/guangshatianyi.png", + "image/card/guanshi.png", + "image/card/guding.png", + "image/card/gudonggeng.png", + "image/card/guilingzhitao.png", + "image/card/guisheqi.png", + "image/card/guiyanfadao.png", + "image/card/guiyoujie.png", + "image/card/guohe.png", + "image/card/gw_aerdeyin.jpg", + "image/card/gw_ansha.jpg", + "image/card/gw_aozuzhilei.jpg", + "image/card/gw_baishuang.jpg", + "image/card/gw_baobaoshu.jpg", + "image/card/gw_baoxueyaoshui.jpg", + "image/card/gw_birinongwu.jpg", + "image/card/gw_butianshu.jpg", + "image/card/gw_chongci.jpg", + "image/card/gw_ciguhanshuang.jpg", + "image/card/gw_dieyi.png", + "image/card/gw_dudayuanshuai1.jpg", + "image/card/gw_dudayuanshuai2.jpg", + "image/card/gw_fuyuan.jpg", + "image/card/gw_ganhan.jpg", + "image/card/gw_guaiwuchaoxue.jpg", + "image/card/gw_huangjiashenpan.jpg", + "image/card/gw_hudiewu.jpg", + "image/card/gw_kunenfayin.jpg", + "image/card/gw_lang.jpg", + "image/card/gw_leizhoushu.jpg", + "image/card/gw_niuquzhijing.jpg", + "image/card/gw_nuhaifengbao.jpg", + "image/card/gw_poxiao.jpg", + "image/card/gw_qinpendayu.jpg", + "image/card/gw_shanbengshu.jpg", + "image/card/gw_shizizhaohuan.jpg", + "image/card/gw_tongdi.jpg", + "image/card/gw_tunshi.jpg", + "image/card/gw_wenyi.jpg", + "image/card/gw_wuyao.jpg", + "image/card/gw_xianzumaijiu.jpg", + "image/card/gw_xinsheng.jpg", + "image/card/gw_yanziyaoshui.jpg", + "image/card/gw_yigeniyin.jpg", + "image/card/gw_youer.jpg", + "image/card/gw_zhihuanjun.jpg", + "image/card/gw_zhongmozhizhan.jpg", + "image/card/gw_zhuoshao.jpg", + "image/card/gw_zirankuizeng.jpg", + "image/card/gw_zuihouyuanwang.jpg", + "image/card/gw_zumoshoukao.jpg", + "image/card/gx_chongyingshenfu.png", + "image/card/gx_lingbaoxianhu.png", + "image/card/gx_taijifuchen.png", + "image/card/gz_guguoanbang.png", + "image/card/gz_haolingtianxia.png", + "image/card/gz_kefuzhongyuan.png", + "image/card/gz_wenheluanwu.png", + "image/card/hanbing.png", + "image/card/handcard.png", + "image/card/haotianta.png", + "image/card/heiguangkai.png", + "image/card/heilonglinpian.png", + "image/card/hina_shenji.png", + "image/card/hongshui.png", + "image/card/hsbaowu_cangbaotu.jpg", + "image/card/hsbaowu_huangjinyuanhou.jpg", + "image/card/hsdusu_huangxuecao.jpg", + "image/card/hsdusu_huoyanhua.jpg", + "image/card/hsdusu_kuyecao.jpg", + "image/card/hsdusu_shinancao.jpg", + "image/card/hsdusu_xueji.jpg", + "image/card/hsfashu_anyingjingxiang.jpg", + "image/card/hsfashu_buwendingyibian.jpg", + "image/card/hsjixie_zhadan.jpg", + "image/card/hslingjian_jinjilengdong.jpg", + "image/card/hslingjian_shengxiuhaojiao.jpg", + "image/card/hslingjian_shijianhuisu.jpg", + "image/card/hslingjian_xingtigaizao.jpg", + "image/card/hslingjian_xuanfengzhiren.jpg", + "image/card/hslingjian_yinmilichang.jpg", + "image/card/hslingjian_zhongxinghujia.jpg", + "image/card/hsmengjing_feicuiyoulong.jpg", + "image/card/hsmengjing_huanxiaojiemei.jpg", + "image/card/hsmengjing_mengjing.jpg", + "image/card/hsmengjing_mengye.jpg", + "image/card/hsmengjing_suxing.jpg", + "image/card/hsqingyu_feibiao.jpg", + "image/card/hsqingyu_hufu.jpg", + "image/card/hsqingyu_shandian.jpg", + "image/card/hsqingyu_zhanfang.jpg", + "image/card/hsqingyu_zhao.jpg", + "image/card/hsqizhou_feng.jpg", + "image/card/hsqizhou_huo.jpg", + "image/card/hsqizhou_shui.jpg", + "image/card/hsqizhou_tu.jpg", + "image/card/hsshenqi_kongbusangzhong.jpg", + "image/card/hsshenqi_morijingxiang.jpg", + "image/card/hsshenqi_nengliangzhiguang.jpg", + "image/card/hstianqi_dalian.jpg", + "image/card/hstianqi_nazigelin.jpg", + "image/card/hstianqi_shali.jpg", + "image/card/hstianqi_suolasi.jpg", + "image/card/hsyaoshui.jpg", + "image/card/hszuzhou_guhuo.jpg", + "image/card/hszuzhou_nvwudeganguo.jpg", + "image/card/hszuzhou_nvwudepingguo.jpg", + "image/card/hszuzhou_nvwudexuetu.jpg", + "image/card/hszuzhou_wushushike.jpg", + "image/card/hualiu.png", + "image/card/huanglinzhicong.png", + "image/card/huanpodan.png", + "image/card/hufu.png", + "image/card/huimiezhichui.png", + "image/card/huogong.png", + "image/card/huoshan.png", + "image/card/huoshaolianying.png", + "image/card/huxinjing.png", + "image/card/identity_commoner.jpg", + "image/card/identity_enemy.jpg", + "image/card/identity_fan.jpg", + "image/card/identity_friend.jpg", + "image/card/identity_nei.jpg", + "image/card/identity_zhong.jpg", + "image/card/identity_zhu.jpg", + "image/card/jiedao.png", + "image/card/jiejia.png", + "image/card/jiguanfeng.png", + "image/card/jiguanshu.png", + "image/card/jiguantong.png", + "image/card/jiguanyaoshu.png", + "image/card/jiguanyuan.png", + "image/card/jihuocard.png", + "image/card/jinchan.png", + "image/card/jingfanma.png", + "image/card/jingleishan.png", + "image/card/jinhe.png", + "image/card/jinlianzhu.png", + "image/card/jintuiziru.png", + "image/card/jiu.png", + "image/card/jiuwei.png", + "image/card/jiwangkailai.png", + "image/card/juedou.png", + "image/card/jueying.png", + "image/card/kaihua.png", + "image/card/kamome_suitcase.png", + "image/card/kano_paibingbuzhen.png", + "image/card/kongdongyin.png", + "image/card/kunlunjingc.png", + "image/card/kuwu.png", + "image/card/langeguaiyi.png", + "image/card/lanyinjia.png", + "image/card/lebu.png", + "image/card/lianjunshengyan.png", + "image/card/lianyaohu.png", + "image/card/linghunzhihuo.png", + "image/card/lingjiandai.png", + "image/card/liufengsan.png", + "image/card/liulongcanjia.png", + "image/card/liutouge.png", + "image/card/liuxiaxianniang.png", + "image/card/liuxinghuoyu.png", + "image/card/liyutang.png", + "image/card/longxugou.png", + "image/card/lukai_club.png", + "image/card/lukai_diamond.png", + "image/card/lukai_heart.png", + "image/card/lukai_spade.png", + "image/card/lulitongxin.png", + "image/card/luojingxiashi.png", + "image/card/luyugeng.png", + "image/card/ly_piliche.png", + "image/card/mapodoufu.png", + "image/card/mianju.png", + "image/card/mianlijinzhen.png", + "image/card/miki_binoculars.png", + "image/card/miki_hydrogladiator.png", + "image/card/mingguangkai.png", + "image/card/minguangkai.png", + "image/card/mizhilianou.png", + "image/card/molicha.png", + "image/card/monkey.png", + "image/card/mtg_bingheyaosai.jpg", + "image/card/mtg_cangbaohaiwan.jpg", + "image/card/mtg_duzhao.jpg", + "image/card/mtg_feixu.jpg", + "image/card/mtg_haidao.jpg", + "image/card/mtg_lindixiliu.jpg", + "image/card/mtg_linzhongjianta.jpg", + "image/card/mtg_longlushanfeng.jpg", + "image/card/mtg_shamolvzhou.jpg", + "image/card/mtg_shuimomuxue.jpg", + "image/card/mtg_yixialan.jpg", + "image/card/mtg_youlin.jpg", + "image/card/mujiaren.png", + "image/card/muniu.png", + "image/card/muniu_small.png", + "image/card/mutoumianju.png", + "image/card/nanman.png", + "image/card/numa.png", + "image/card/nvwashi.png", + "image/card/nvzhuang.png", + "image/card/pangufu.png", + "image/card/pantao.png", + "image/card/pss_paper.png", + "image/card/pss_scissor.png", + "image/card/pss_stone.png", + "image/card/pyzhuren_club.png", + "image/card/pyzhuren_diamond.png", + "image/card/pyzhuren_heart.png", + "image/card/pyzhuren_shandian.png", + "image/card/pyzhuren_spade.png", + "image/card/qiankunbiao.png", + "image/card/qiankundai.png", + "image/card/qiaosi_card1.png", + "image/card/qiaosi_card2.png", + "image/card/qiaosi_card3.png", + "image/card/qiaosi_card4.png", + "image/card/qiaosi_card5.png", + "image/card/qiaosi_card6.png", + "image/card/qibaodao.png", + "image/card/qijia.png", + "image/card/qilin.png", + "image/card/qinggang.png", + "image/card/qinglianxindeng.png", + "image/card/qinglong.png", + "image/card/qinglonglingzhu.png", + "image/card/qinglongzhigui.png", + "image/card/qingtuan.png", + "image/card/qixingbaodao.png", + "image/card/qizhengxiangsheng.png", + "image/card/renwang.png", + "image/card/rewrite_bagua.png", + "image/card/rewrite_baiyin.png", + "image/card/rewrite_lanyinjia.png", + "image/card/rewrite_renwang.png", + "image/card/rewrite_tengjia.png", + "image/card/rewrite_zhuge.png", + "image/card/ruyijingubang.png", + "image/card/sadengjinhuan.png", + "image/card/sanjian.png", + "image/card/sanlve.png", + "image/card/serafuku.png", + "image/card/sex_double.png", + "image/card/sex_female.png", + "image/card/sex_male.png", + "image/card/sex_male_castrated.png", + "image/card/sex_none.png", + "image/card/sex_unknown.png", + "image/card/sha.png", + "image/card/shan.png", + "image/card/shandian.png", + "image/card/shandianjian.png", + "image/card/shatang.png", + "image/card/shencaojie.png", + "image/card/shenenshu.png", + "image/card/shengdong.png", + "image/card/shenhuofeiya.png", + "image/card/shenmiguo.png", + "image/card/shennongding.png", + "image/card/shentoumianju.png", + "image/card/shezhanqunru.png", + "image/card/shield.png", + "image/card/shihuawuqi.png", + "image/card/shihuifen.png", + "image/card/shijieshu.png", + "image/card/shoulijian.png", + "image/card/shuchui.png", + "image/card/shuijing_card.png", + "image/card/shuiyanqijun.png", + "image/card/shuiyanqijunx.png", + "image/card/shujinsan.png", + "image/card/shunshou.png", + "image/card/sifeizhenmian.png", + "image/card/sizhaojian.png", + "image/card/suijiyingbian.png", + "image/card/suolianjia.png", + "image/card/taigongyinfu.png", + "image/card/taipingyaoshu.png", + "image/card/tanhuadong.png", + "image/card/tanshezhiren.png", + "image/card/tao.png", + "image/card/taoyuan.png", + "image/card/tengjia.png", + "image/card/tianjitu.png", + "image/card/tianxianjiu.png", + "image/card/tiaojiyanmei.png", + "image/card/tiesuo.png", + "image/card/tiesuo_mark.png", + "image/card/tongque.png", + "image/card/toulianghuanzhu.png", + "image/card/toushiche.png", + "image/card/tuhunsha.png", + "image/card/tuixinzhifu.png", + "image/card/tunliang.png", + "image/card/tuteng1.jpg", + "image/card/tuteng2.jpg", + "image/card/tuteng3.jpg", + "image/card/tuteng4.jpg", + "image/card/tuteng5.jpg", + "image/card/tuteng6.jpg", + "image/card/tuteng7.jpg", + "image/card/tuteng8.jpg", + "image/card/wangmeizhike.png", + "image/card/wanjian.png", + "image/card/wenhuangsan.png", + "image/card/wolong_card.png", + "image/card/wufengjian.png", + "image/card/wugu.png", + "image/card/wuliu.png", + "image/card/wutiesuolian.png", + "image/card/wuxie.png", + "image/card/wuxinghelingshan.png", + "image/card/wuxingpan.png", + "image/card/wuzhong.png", + "image/card/wy_meirenji.png", + "image/card/wy_xiaolicangdao.png", + "image/card/xiajiao.png", + "image/card/xianluhui.png", + "image/card/xiaolicangdao.png", + "image/card/xiayuncailing.png", + "image/card/xietianzi.png", + "image/card/xinge.png", + "image/card/xingjiegoutong.png", + "image/card/xingjunyan.png", + "image/card/xionghuangjiu.png", + "image/card/xixueguizhihuan.png", + "image/card/xuanjian_card.png", + "image/card/xuanwuzhihuang.png", + "image/card/xuanyuanjian.png", + "image/card/xuejibingbao.png", + "image/card/xuelunyang.png", + "image/card/xumou_jsrg.jpg", + "image/card/yajiaoqiang.png", + "image/card/yangpijuan.png", + "image/card/yanjiadan_club.png", + "image/card/yanjiadan_diamond.png", + "image/card/yanjiadan_heart.png", + "image/card/yanjiadan_spade.png", + "image/card/yanxiao_card.jpg", + "image/card/yexingyi.png", + "image/card/yihuajiemu.png", + "image/card/yinfengjia.png", + "image/card/yinfengyi.png", + "image/card/ying.png", + "image/card/yinyueqiang.png", + "image/card/yitianjian.png", + "image/card/yiyi.png", + "image/card/yonglv.png", + "image/card/youdishenru.png", + "image/card/yougeng.png", + "image/card/yuanbaorou.png", + "image/card/yuanjiao.png", + "image/card/yuanjun.png", + "image/card/yuansuhuimie.png", + "image/card/yuchandui.png", + "image/card/yuchangen.png", + "image/card/yuchankan.png", + "image/card/yuchankun.png", + "image/card/yuchanli.png", + "image/card/yuchanqian.png", + "image/card/yuchanxun.png", + "image/card/yuchanzhen.png", + "image/card/yufulu.png", + "image/card/yuheng.png", + "image/card/yunvyuanshen.png", + "image/card/yuruyi.png", + "image/card/yuxi.png", + "image/card/zengbin.png", + "image/card/zhadan.png", + "image/card/zhangba.png", + "image/card/zhanxiang.png", + "image/card/zhaogujing.png", + "image/card/zhaomingdan.png", + "image/card/zhaoshu.png", + "image/card/zheji.png", + "image/card/zhibi.png", + "image/card/zhiliaobo.png", + "image/card/zhiluxiaohu.png", + "image/card/zhuahuang.png", + "image/card/zhuangshu_basic.png", + "image/card/zhuangshu_equip.png", + "image/card/zhuangshu_trick.png", + "image/card/zhufangshenshi.png", + "image/card/zhuge.png", + "image/card/zhujinqiyuan.png", + "image/card/zhulu_card.png", + "image/card/zhungangshuo.png", + "image/card/zhuque.png", + "image/card/zhuquezhizhang.png", + "image/card/zixin.png", + "image/card/ziyangdan.png", + "image/card/zong.png", + /*card image end*/ + + /*character image begin*/ + "image/character/ahuinan.jpg", + "image/character/bailingyun.jpg", + "image/character/baiwuchang.jpg", + "image/character/baosanniang.jpg", + "image/character/baoxin.jpg", + "image/character/beimihu.jpg", + "image/character/bianfuren.jpg", + "image/character/bianxi.jpg", + "image/character/boss_zhaoyun.jpg", + "image/character/bulianshi.jpg", + "image/character/buzhi.jpg", + "image/character/caifuren.jpg", + "image/character/caimaozhangyun.jpg", + "image/character/caiwenji.jpg", + "image/character/caiyang.jpg", + "image/character/caiyong.jpg", + "image/character/caizhenji.jpg", + "image/character/caoang.jpg", + "image/character/caoanmin.jpg", + "image/character/caobuxing.jpg", + "image/character/caocao.jpg", + "image/character/caochong.jpg", + "image/character/caochun.jpg", + "image/character/caohong.jpg", + "image/character/caohua.jpg", + "image/character/caojie.jpg", + "image/character/caojinyu.jpg", + "image/character/caomao.jpg", + "image/character/caopi.jpg", + "image/character/caoren.jpg", + "image/character/caorui.jpg", + "image/character/caoshuang.jpg", + "image/character/caosong.jpg", + "image/character/caoxi.jpg", + "image/character/caoxian.jpg", + "image/character/caoxiancaohua.jpg", + "image/character/caoxing.jpg", + "image/character/caoxiu.jpg", + "image/character/caoyi.jpg", + "image/character/caoying.jpg", + "image/character/caoyu.jpg", + "image/character/caozhang.jpg", + "image/character/caozhen.jpg", + "image/character/caozhi.jpg", + "image/character/cenhun.jpg", + "image/character/cheliji.jpg", + "image/character/chendao.jpg", + "image/character/chendeng.jpg", + "image/character/chendong.jpg", + "image/character/chengbing.jpg", + "image/character/chengjichengcui.jpg", + "image/character/chengong.jpg", + "image/character/chengpu.jpg", + "image/character/chengui.jpg", + "image/character/chengyu.jpg", + "image/character/chenjiao.jpg", + "image/character/chenlin.jpg", + "image/character/chenqun.jpg", + "image/character/chenshi.jpg", + "image/character/chentai.jpg", + "image/character/chunyuqiong.jpg", + "image/character/clan_hanrong.jpg", + "image/character/clan_hanshao.jpg", + "image/character/clan_wanghun.jpg", + "image/character/clan_wangling.jpg", + "image/character/clan_wanglun.jpg", + "image/character/clan_wangyun.jpg", + "image/character/clan_wuban.jpg", + "image/character/clan_wukuang.jpg", + "image/character/clan_wuqiao.jpg", + "image/character/clan_wuxian.jpg", + "image/character/clan_xuncai.jpg", + "image/character/clan_xuncan.jpg", + "image/character/clan_xunchen.jpg", + "image/character/clan_xunshu.jpg", + "image/character/clan_xunyou.jpg", + "image/character/clan_zhonghui.jpg", + "image/character/clan_zhongyan.jpg", + "image/character/clan_zhongyu.jpg", + "image/character/cuimao.jpg", + "image/character/cuiyan.jpg", + "image/character/daqiao.jpg", + "image/character/daxiaoqiao.jpg", + "image/character/db_key_hina.jpg", + "image/character/db_key_liyingxia.jpg", + "image/character/db_wenyang.jpg", + "image/character/dc_bulianshi.jpg", + "image/character/dc_caiyang.jpg", + "image/character/dc_caocao.jpg", + "image/character/dc_caoshuang.jpg", + "image/character/dc_caozhi.jpg", + "image/character/dc_chenqun.jpg", + "image/character/dc_daxiaoqiao.jpg", + "image/character/dc_dongzhao.jpg", + "image/character/dc_duyu.jpg", + "image/character/dc_fuwan.jpg", + "image/character/dc_ganfuren.jpg", + "image/character/dc_gaolan.jpg", + "image/character/dc_gongsunzan.jpg", + "image/character/dc_guansuo.jpg", + "image/character/dc_huangchengyan.jpg", + "image/character/dc_huanghao.jpg", + "image/character/dc_huangquan.jpg", + "image/character/dc_huangzu.jpg", + "image/character/dc_huban.jpg", + "image/character/dc_hujinding.jpg", + "image/character/dc_huojun.jpg", + "image/character/dc_jiachong.jpg", + "image/character/dc_jiben.jpg", + "image/character/dc_jikang.jpg", + "image/character/dc_jiling.jpg", + "image/character/dc_jsp_guanyu.jpg", + "image/character/dc_kongrong.jpg", + "image/character/dc_liru.jpg", + "image/character/dc_liuba.jpg", + "image/character/dc_liubei.jpg", + "image/character/dc_liuli.jpg", + "image/character/dc_liuye.jpg", + "image/character/dc_liuyu.jpg", + "image/character/dc_luotong.jpg", + "image/character/dc_lvkuanglvxiang.jpg", + "image/character/dc_mengda.jpg", + "image/character/dc_mifuren.jpg", + "image/character/dc_ruiji.jpg", + "image/character/dc_sb_lusu.jpg", + "image/character/dc_sb_simayi.jpg", + "image/character/dc_sb_simayi_shadow.jpg", + "image/character/dc_sb_zhouyu.jpg", + "image/character/dc_shixie.jpg", + "image/character/dc_simashi.jpg", + "image/character/dc_sp_jiaxu.jpg", + "image/character/dc_sp_machao.jpg", + "image/character/dc_sunce.jpg", + "image/character/dc_sunchen.jpg", + "image/character/dc_sunhanhua.jpg", + "image/character/dc_sunquan.jpg", + "image/character/dc_sunru.jpg", + "image/character/dc_sunziliufang.jpg", + "image/character/dc_tengfanglan.jpg", + "image/character/dc_wangchang.jpg", + "image/character/dc_wangjun.jpg", + "image/character/dc_wangling.jpg", + "image/character/dc_wangyun.jpg", + "image/character/dc_wuban.jpg", + "image/character/dc_xiahouba.jpg", + "image/character/dc_xujing.jpg", + "image/character/dc_xushu.jpg", + "image/character/dc_yangbiao.jpg", + "image/character/dc_yanghu.jpg", + "image/character/dc_yuejiu.jpg", + "image/character/dc_zhangmancheng.jpg", + "image/character/dc_zhaotongzhaoguang.jpg", + "image/character/dc_zhaoxiang.jpg", + "image/character/dc_zhaoyǎn.jpg", + "image/character/dc_zhaoyun.jpg", + "image/character/dc_zhouxuān.jpg", + "image/character/dc_zhuling.jpg", + "image/character/ddd_baosanniang.jpg", + "image/character/ddd_caomao.jpg", + "image/character/ddd_caoshuang.jpg", + "image/character/ddd_dingfeng.jpg", + "image/character/ddd_guanning.jpg", + "image/character/ddd_handang.jpg", + "image/character/ddd_jianshuo.jpg", + "image/character/ddd_kebineng.jpg", + "image/character/ddd_liangxi.jpg", + "image/character/ddd_lie.jpg", + "image/character/ddd_liuba.jpg", + "image/character/ddd_liuhong.jpg", + "image/character/ddd_liuye.jpg", + "image/character/ddd_sunliang.jpg", + "image/character/ddd_wangkanglvkai.jpg", + "image/character/ddd_wuzhi.jpg", + "image/character/ddd_xiahouxuan.jpg", + "image/character/ddd_xianglang.jpg", + "image/character/ddd_xinxianying.jpg", + "image/character/ddd_xuelingyun.jpg", + "image/character/ddd_xujing.jpg", + "image/character/ddd_yujin.jpg", + "image/character/ddd_zhangkai.jpg", + "image/character/ddd_zhaoang.jpg", + "image/character/ddd_zhenji.jpg", + "image/character/ddd_zhouchu.jpg", + "image/character/default_silhouette_female.jpg", + "image/character/default_silhouette_male.jpg", + "image/character/dengai.jpg", + "image/character/dengzhi.jpg", + "image/character/dengzhong.jpg", + "image/character/dianwei.jpg", + "image/character/diaochan.jpg", + "image/character/dingfeng.jpg", + "image/character/dingshangwan.jpg", + "image/character/dingyuan.jpg", + "image/character/diy_caiwenji.jpg", + "image/character/diy_feishi.jpg", + "image/character/diy_hanlong.jpg", + "image/character/diy_huangzhong.jpg", + "image/character/diy_liufu.jpg", + "image/character/diy_liuyan.jpg", + "image/character/diy_liuzan.jpg", + "image/character/diy_lukang.jpg", + "image/character/diy_menghuo.jpg", + "image/character/diy_tianyu.jpg", + "image/character/diy_weiyan.jpg", + "image/character/diy_wenyang.jpg", + "image/character/diy_xizhenxihong.jpg", + "image/character/diy_xuhuang.jpg", + "image/character/diy_yangyi.jpg", + "image/character/diy_yuji.jpg", + "image/character/diy_zaozhirenjun.jpg", + "image/character/diy_zhenji.jpg", + "image/character/diy_zhouyu.jpg", + "image/character/dongbai.jpg", + "image/character/dongcheng.jpg", + "image/character/dongguiren.jpg", + "image/character/dongtuna.jpg", + "image/character/dongwan.jpg", + "image/character/dongxie.jpg", + "image/character/dongyun.jpg", + "image/character/dongzhao.jpg", + "image/character/dongzhuo.jpg", + "image/character/duanjiong.jpg", + "image/character/duanqiaoxiao.jpg", + "image/character/duanwei.jpg", + "image/character/dufuren.jpg", + "image/character/duji.jpg", + "image/character/dukui.jpg", + "image/character/duosidawang.jpg", + "image/character/duxi.jpg", + "image/character/duyu.jpg", + "image/character/fanchou.jpg", + "image/character/fanjiangzhangda.jpg", + "image/character/fanyufeng.jpg", + "image/character/fazheng.jpg", + "image/character/feiyao.jpg", + "image/character/feiyi.jpg", + "image/character/fengfang.jpg", + "image/character/fengfangnv.jpg", + "image/character/fengxi.jpg", + "image/character/fuhuanghou.jpg", + "image/character/fuqian.jpg", + "image/character/furong.jpg", + "image/character/furongfuqian.jpg", + "image/character/fuwan.jpg", + "image/character/ganfuren.jpg", + "image/character/ganfurenmifuren.jpg", + "image/character/ganning.jpg", + "image/character/gaogan.jpg", + "image/character/gaolan.jpg", + "image/character/gaoshun.jpg", + "image/character/gaoxiang.jpg", + "image/character/gexuan.jpg", + "image/character/gjqt_aruan.jpg", + "image/character/gjqt_bailitusu.jpg", + "image/character/gjqt_beiluo.jpg", + "image/character/gjqt_cenying.jpg", + "image/character/gjqt_chuqi.jpg", + "image/character/gjqt_fanglansheng.jpg", + "image/character/gjqt_fengqingxue.jpg", + "image/character/gjqt_hongyu.jpg", + "image/character/gjqt_ouyangshaogong.jpg", + "image/character/gjqt_wenrenyu.jpg", + "image/character/gjqt_xiangling.jpg", + "image/character/gjqt_xiayize.jpg", + "image/character/gjqt_xieyi.jpg", + "image/character/gjqt_xunfang.jpg", + "image/character/gjqt_yanjiaxieyi.jpg", + "image/character/gjqt_yinqianshang.jpg", + "image/character/gjqt_yuewuyi.jpg", + "image/character/gjqt_yunwuyue.jpg", + "image/character/gongsundu.jpg", + "image/character/gongsunkang.jpg", + "image/character/gongsunyuan.jpg", + "image/character/gongsunzan.jpg", + "image/character/guanhai.jpg", + "image/character/guanlu.jpg", + "image/character/guanning.jpg", + "image/character/guānning.jpg", + "image/character/guanping.jpg", + "image/character/guanqiujian.jpg", + "image/character/guansuo.jpg", + "image/character/guanxingzhangbao.jpg", + "image/character/guanyinping.jpg", + "image/character/guanyu.jpg", + "image/character/guanzhang.jpg", + "image/character/guohuai.jpg", + "image/character/guohuanghou.jpg", + "image/character/guojia.jpg", + "image/character/guosi.jpg", + "image/character/guotu.jpg", + "image/character/guotufengji.jpg", + "image/character/guozhao.jpg", + "image/character/guyong.jpg", + "image/character/gw_aigeleisi.jpg", + "image/character/gw_aimin.jpg", + "image/character/gw_airuiting.jpg", + "image/character/gw_aisinie.jpg", + "image/character/gw_aokeweisite.jpg", + "image/character/gw_bierna.jpg", + "image/character/gw_bulanwang.jpg", + "image/character/gw_dagong.jpg", + "image/character/gw_diandian.jpg", + "image/character/gw_enxier.jpg", + "image/character/gw_falanxisika.jpg", + "image/character/gw_feilafanruide.jpg", + "image/character/gw_fenghuang.jpg", + "image/character/gw_fuertaisite.jpg", + "image/character/gw_fulisi.jpg", + "image/character/gw_gaier.jpg", + "image/character/gw_haizhiyezhu.jpg", + "image/character/gw_haluo.jpg", + "image/character/gw_hanmuduoer.jpg", + "image/character/gw_hengsaite.jpg", + "image/character/gw_huoge.jpg", + "image/character/gw_jieluote.jpg", + "image/character/gw_kaerweite.jpg", + "image/character/gw_kairuisi.jpg", + "image/character/gw_kanbi.jpg", + "image/character/gw_kaxier.jpg", + "image/character/gw_kuite.jpg", + "image/character/gw_laduoweide.jpg", + "image/character/gw_lanbote.jpg", + "image/character/gw_laomaotou.jpg", + "image/character/gw_laomaotou2.jpg", + "image/character/gw_linjing.jpg", + "image/character/gw_luobo.jpg", + "image/character/gw_luoqi.jpg", + "image/character/gw_meizi.jpg", + "image/character/gw_mieren.jpg", + "image/character/gw_nitelila.jpg", + "image/character/gw_nvyemo.jpg", + "image/character/gw_oudimu.jpg", + "image/character/gw_puxila.jpg", + "image/character/gw_qigaiwang.jpg", + "image/character/gw_sanhanya.jpg", + "image/character/gw_saqiya.jpg", + "image/character/gw_saqiya1.jpg", + "image/character/gw_saqiya2.jpg", + "image/character/gw_shanhu.jpg", + "image/character/gw_shasixiwusi.jpg", + "image/character/gw_telisi.jpg", + "image/character/gw_xigedelifa.jpg", + "image/character/gw_xili.jpg", + "image/character/gw_yenaifa.jpg", + "image/character/gw_yioufeisi.jpg", + "image/character/gw_yioufeisisp.jpg", + "image/character/gw_yisilinni.jpg", + "image/character/gw_zhangyujushou.jpg", + "image/character/gw_zhuoertan.jpg", + "image/character/gz_caohong.jpg", + "image/character/gz_caopi.jpg", + "image/character/gz_chengong.jpg", + "image/character/gz_dengai.jpg", + "image/character/gz_dengzhi.jpg", + "image/character/gz_dianwei.jpg", + "image/character/gz_diaochan.jpg", + "image/character/gz_dingfeng.jpg", + "image/character/gz_fazheng.jpg", + "image/character/gz_fengxi.jpg", + "image/character/gz_ganfuren.jpg", + "image/character/gz_gongsunyuan.jpg", + "image/character/gz_guanyu.jpg", + "image/character/gz_guohuai.jpg", + "image/character/gz_guojia.jpg", + "image/character/gz_hetaihou.jpg", + "image/character/gz_huangyueying.jpg", + "image/character/gz_huangzhong.jpg", + "image/character/gz_huangzu.jpg", + "image/character/gz_jiangwei.jpg", + "image/character/gz_jiaxu.jpg", + "image/character/gz_lingtong.jpg", + "image/character/gz_liuba.jpg", + "image/character/gz_liuqi.jpg", + "image/character/gz_lukang.jpg", + "image/character/gz_luxun.jpg", + "image/character/gz_lvbu.jpg", + "image/character/gz_lvlingqi.jpg", + "image/character/gz_madai.jpg", + "image/character/gz_masu.jpg", + "image/character/gz_miheng.jpg", + "image/character/gz_panfeng.jpg", + "image/character/gz_panjun.jpg", + "image/character/gz_pengyang.jpg", + "image/character/gz_re_xushu.jpg", + "image/character/gz_re_yuanshao.jpg", + "image/character/gz_shamoke.jpg", + "image/character/gz_shixie.jpg", + "image/character/gz_simazhao.jpg", + "image/character/gz_sp_zhugeliang.jpg", + "image/character/gz_sunce.jpg", + "image/character/gz_sunjian.jpg", + "image/character/gz_sunshangxiang.jpg", + "image/character/gz_tangzi.jpg", + "image/character/gz_wangping.jpg", + "image/character/gz_wenqin.jpg", + "image/character/gz_wuguotai.jpg", + "image/character/gz_wujing.jpg", + "image/character/gz_xf_sufei.jpg", + "image/character/gz_xiahouba.jpg", + "image/character/gz_xiahouyuan.jpg", + "image/character/gz_xiaoqiao.jpg", + "image/character/gz_xunyou.jpg", + "image/character/gz_xusheng.jpg", + "image/character/gz_xuyou.jpg", + "image/character/gz_yanbaihu.jpg", + "image/character/gz_yangwan.jpg", + "image/character/gz_yuanshu.jpg", + "image/character/gz_yuejin.jpg", + "image/character/gz_yuji.jpg", + "image/character/gz_yujin.jpg", + "image/character/gz_zhanglu.jpg", + "image/character/gz_zhangxiu.jpg", + "image/character/gz_zhenji.jpg", + "image/character/gz_zhonghui.jpg", + "image/character/gz_zhouyu.jpg", + "image/character/gz_zhugeke.jpg", + "image/character/gz_zhugeliang.jpg", + "image/character/gz_zhuling.jpg", + "image/character/gz_zuoci.jpg", + "image/character/hanba.jpg", + "image/character/handang.jpg", + "image/character/hanfu.jpg", + "image/character/hanhaoshihuan.jpg", + "image/character/hanlong.jpg", + "image/character/hanmeng.jpg", + "image/character/hansui.jpg", + "image/character/haomeng.jpg", + "image/character/haopu.jpg", + "image/character/haozhao.jpg", + "image/character/heiwuchang.jpg", + "image/character/hejin.jpg", + "image/character/heqi.jpg", + "image/character/hetaihou.jpg", + "image/character/heyan.jpg", + "image/character/hhzz_kanade.jpg", + "image/character/hhzz_shiona.jpg", + "image/character/hhzz_takaramono1.jpg", + "image/character/hhzz_takaramono2.jpg", + "image/character/hidden_image.jpg", + "image/character/hs_aedwin.jpg", + "image/character/hs_aerfusi.jpg", + "image/character/hs_aiqinvyao.jpg", + "image/character/hs_alakir.jpg", + "image/character/hs_alextrasza.jpg", + "image/character/hs_alleria.jpg", + "image/character/hs_amala.jpg", + "image/character/hs_anduin.jpg", + "image/character/hs_anomalus.jpg", + "image/character/hs_antonidas.jpg", + "image/character/hs_ashamoer.jpg", + "image/character/hs_aya.jpg", + "image/character/hs_baiguyoulong.jpg", + "image/character/hs_bannabusi.jpg", + "image/character/hs_barnes.jpg", + "image/character/hs_bchillmaw.jpg", + "image/character/hs_bilanyoulong.jpg", + "image/character/hs_bingshuangnvwang.jpg", + "image/character/hs_blingtron.jpg", + "image/character/hs_bolvar.jpg", + "image/character/hs_brann.jpg", + "image/character/hs_duyaxinshi.jpg", + "image/character/hs_enzoth.jpg", + "image/character/hs_fachaotuteng.jpg", + "image/character/hs_fandral.jpg", + "image/character/hs_fengjianhuanfengzhe.jpg", + "image/character/hs_fenjie.jpg", + "image/character/hs_finley.jpg", + "image/character/hs_fuding.jpg", + "image/character/hs_guldan.jpg", + "image/character/hs_hajiasha.jpg", + "image/character/hs_hallazeal.jpg", + "image/character/hs_heifengqishi.jpg", + "image/character/hs_hemite.jpg", + "image/character/hs_hudunren.jpg", + "image/character/hs_huolituteng.jpg", + "image/character/hs_huzhixiannv.jpg", + "image/character/hs_jaina.jpg", + "image/character/hs_jgarrosh.jpg", + "image/character/hs_jiawodun.jpg", + "image/character/hs_jiaziruila.jpg", + "image/character/hs_jinglinglong.jpg", + "image/character/hs_kaituozhe.jpg", + "image/character/hs_kalimosi.jpg", + "image/character/hs_kazhakusi.jpg", + "image/character/hs_kchromaggus.jpg", + "image/character/hs_kcthun.jpg", + "image/character/hs_khadgar.jpg", + "image/character/hs_lafamu.jpg", + "image/character/hs_laila.jpg", + "image/character/hs_laxiao.jpg", + "image/character/hs_lazi.jpg", + "image/character/hs_liadrin.jpg", + "image/character/hs_loatheb.jpg", + "image/character/hs_lreno.jpg", + "image/character/hs_lrexxar.jpg", + "image/character/hs_lrhonin.jpg", + "image/character/hs_magni.jpg", + "image/character/hs_malfurion.jpg", + "image/character/hs_malorne.jpg", + "image/character/hs_malygos.jpg", + "image/character/hs_manyututeng.jpg", + "image/character/hs_medivh.jpg", + "image/character/hs_mijiaojisi.jpg", + "image/character/hs_mojinbaozi.jpg", + "image/character/hs_morgl.jpg", + "image/character/hs_nate.jpg", + "image/character/hs_neptulon.jpg", + "image/character/hs_nozdormu.jpg", + "image/character/hs_nuogefu.jpg", + "image/character/hs_pengpeng.jpg", + "image/character/hs_pyros.jpg", + "image/character/hs_pyros1.jpg", + "image/character/hs_pyros2.jpg", + "image/character/hs_ronghejuren.jpg", + "image/character/hs_ruanniguai.jpg", + "image/character/hs_sainaliusi.jpg", + "image/character/hs_sapphiron.jpg", + "image/character/hs_selajin.jpg", + "image/character/hs_selajin2.jpg", + "image/character/hs_shaku.jpg", + "image/character/hs_shanlingjuren.jpg", + "image/character/hs_shifazhe.jpg", + "image/character/hs_shirencao.jpg", + "image/character/hs_shizugui.jpg", + "image/character/hs_shuiwenxuejia.jpg", + "image/character/hs_siwangxianzhi.jpg", + "image/character/hs_siwangzhiyi.jpg", + "image/character/hs_sthrall.jpg", + "image/character/hs_taisi.jpg", + "image/character/hs_tanghangu.jpg", + "image/character/hs_tgolem.jpg", + "image/character/hs_totemic.jpg", + "image/character/hs_trueheart.jpg", + "image/character/hs_tuoqi.jpg", + "image/character/hs_tyrande.jpg", + "image/character/hs_waleera.jpg", + "image/character/hs_walian.jpg", + "image/character/hs_wolazi.jpg", + "image/character/hs_wujiyuansu.jpg", + "image/character/hs_wuther.jpg", + "image/character/hs_wuyaowang.jpg", + "image/character/hs_wvelen.jpg", + "image/character/hs_xialikeer.jpg", + "image/character/hs_xiangyaqishi.jpg", + "image/character/hs_xsylvanas.jpg", + "image/character/hs_xuanzhuanjijia.jpg", + "image/character/hs_xuefashi.jpg", + "image/character/hs_xukongzhiying.jpg", + "image/character/hs_yangyanwageli.jpg", + "image/character/hs_yashaji.jpg", + "image/character/hs_yelinchulong.jpg", + "image/character/hs_yelinlonghou.jpg", + "image/character/hs_yelise.jpg", + "image/character/hs_yinggencao.jpg", + "image/character/hs_yngvar.jpg", + "image/character/hs_yogg.jpg", + "image/character/hs_ysera.jpg", + "image/character/hs_yuhuozhe.jpg", + "image/character/hs_zhanzhenggushu.jpg", + "image/character/hs_zhihuanhua.jpg", + "image/character/hs_zhishigushu.jpg", + "image/character/hs_zhouzhuo.jpg", + "image/character/huaman.jpg", + "image/character/huanfan.jpg", + "image/character/huangchengyan.jpg", + "image/character/huangfusong.jpg", + "image/character/huanggai.jpg", + "image/character/huanghao.jpg", + "image/character/huangjinleishi.jpg", + "image/character/huangyueying.jpg", + "image/character/huangzhong.jpg", + "image/character/huangzu.jpg", + "image/character/huatuo.jpg", + "image/character/huaxin.jpg", + "image/character/huaxiong.jpg", + "image/character/huban.jpg", + "image/character/hucheer.jpg", + "image/character/hujinding.jpg", + "image/character/huojun.jpg", + "image/character/huzhao.jpg", + "image/character/jiachong.jpg", + "image/character/jiakui.jpg", + "image/character/jiangfei.jpg", + "image/character/jianggan.jpg", + "image/character/jiangqing.jpg", + "image/character/jiangwei.jpg", + "image/character/jianyong.jpg", + "image/character/jiaxu.jpg", + "image/character/jikang.jpg", + "image/character/jiling.jpg", + "image/character/jin_guohuai.jpg", + "image/character/jin_jiachong.jpg", + "image/character/jin_simashi.jpg", + "image/character/jin_simayi.jpg", + "image/character/jin_simazhao.jpg", + "image/character/jin_wangyuanji.jpg", + "image/character/jin_xiahouhui.jpg", + "image/character/jin_yanghu.jpg", + "image/character/jin_yanghuiyu.jpg", + "image/character/jin_zhangchunhua.jpg", + "image/character/jin_zhouchu.jpg", + "image/character/jsp_caoren.jpg", + "image/character/jsp_guanyu.jpg", + "image/character/jsp_huangyueying.jpg", + "image/character/jsp_liubei.jpg", + "image/character/jsp_zhaoyun.jpg", + "image/character/jsrg_caocao.jpg", + "image/character/jsrg_caofang.jpg", + "image/character/jsrg_chendeng.jpg", + "image/character/jsrg_chunyuqiong.jpg", + "image/character/jsrg_dongbai.jpg", + "image/character/jsrg_fanjiangzhangda.jpg", + "image/character/jsrg_gaoxiang.jpg", + "image/character/jsrg_guanyu.jpg", + "image/character/jsrg_guojia.jpg", + "image/character/jsrg_guoxun.jpg", + "image/character/jsrg_guozhao.jpg", + "image/character/jsrg_hansui.jpg", + "image/character/jsrg_hejin.jpg", + "image/character/jsrg_huangfusong.jpg", + "image/character/jsrg_huangzhong.jpg", + "image/character/jsrg_jiangwei.jpg", + "image/character/jsrg_kongrong.jpg", + "image/character/jsrg_liubei.jpg", + "image/character/jsrg_liuhong.jpg", + "image/character/jsrg_liuyan.jpg", + "image/character/jsrg_liuyong.jpg", + "image/character/jsrg_lougui.jpg", + "image/character/jsrg_luxun.jpg", + "image/character/jsrg_lvbu.jpg", + "image/character/jsrg_machao.jpg", + "image/character/jsrg_nanhualaoxian.jpg", + "image/character/jsrg_pangtong.jpg", + "image/character/jsrg_qiaoxuan.jpg", + "image/character/jsrg_simayi.jpg", + "image/character/jsrg_sunce.jpg", + "image/character/jsrg_sunjian.jpg", + "image/character/jsrg_sunjun.jpg", + "image/character/jsrg_sunlubansunluyu.jpg", + "image/character/jsrg_sunshangxiang.jpg", + "image/character/jsrg_wangyun.jpg", + "image/character/jsrg_weiwenzhugezhi.jpg", + "image/character/jsrg_xiahouen.jpg", + "image/character/jsrg_xiahourong.jpg", + "image/character/jsrg_xugong.jpg", + "image/character/jsrg_xushao.jpg", + "image/character/jsrg_xuyou.jpg", + "image/character/jsrg_yangbiao.jpg", + "image/character/jsrg_zhangchu.jpg", + "image/character/jsrg_zhangfei.jpg", + "image/character/jsrg_zhanghe.jpg", + "image/character/jsrg_zhangliao.jpg", + "image/character/jsrg_zhangren.jpg", + "image/character/jsrg_zhangxuan.jpg", + "image/character/jsrg_zhaoyun.jpg", + "image/character/jsrg_zhenji.jpg", + "image/character/jsrg_zhugeliang.jpg", + "image/character/jsrg_zhujun.jpg", + "image/character/jsrg_zoushi.jpg", + "image/character/jun_caocao.jpg", + "image/character/jun_liubei.jpg", + "image/character/jun_sunquan.jpg", + "image/character/jun_zhangjiao.jpg", + "image/character/junk_duanwei.jpg", + "image/character/junk_guanyu.jpg", + "image/character/junk_huangyueying.jpg", + "image/character/junk_lidian.jpg", + "image/character/junk_liubei.jpg", + "image/character/junk_simayi.jpg", + "image/character/junk_sunquan.jpg", + "image/character/junk_xuyou.jpg", + "image/character/junk_zhangjiao.jpg", + "image/character/junk_zhangrang.jpg", + "image/character/kaisa.jpg", + "image/character/kanze.jpg", + "image/character/kebineng.jpg", + "image/character/key_abyusa.jpg", + "image/character/key_akane.jpg", + "image/character/key_akiko.jpg", + "image/character/key_ao.jpg", + "image/character/key_asara.jpg", + "image/character/key_ayato.jpg", + "image/character/key_chihaya.jpg", + "image/character/key_doruji.jpg", + "image/character/key_erika.jpg", + "image/character/key_fuuko.jpg", + "image/character/key_godan.jpg", + "image/character/key_harukakanata.jpg", + "image/character/key_haruko.jpg", + "image/character/key_hina.jpg", + "image/character/key_hinata.jpg", + "image/character/key_hiroto.jpg", + "image/character/key_hisako.jpg", + "image/character/key_inari.jpg", + "image/character/key_iriya.jpg", + "image/character/key_iwasawa.jpg", + "image/character/key_jojiro.jpg", + "image/character/key_kagari.jpg", + "image/character/key_kamome.jpg", + "image/character/key_kano.jpg", + "image/character/key_kaori.jpg", + "image/character/key_kengo.jpg", + "image/character/key_kiyu.jpg", + "image/character/key_komari.jpg", + "image/character/key_kotarou.jpg", + "image/character/key_kotomi.jpg", + "image/character/key_kotori.jpg", + "image/character/key_kud.jpg", + "image/character/key_kyoko.jpg", + "image/character/key_kyou.jpg", + "image/character/key_kyouko.jpg", + "image/character/key_kyousuke.jpg", + "image/character/key_lucia.jpg", + "image/character/key_masato.jpg", + "image/character/key_mia.jpg", + "image/character/key_michiru.jpg", + "image/character/key_midori.jpg", + "image/character/key_miki.jpg", + "image/character/key_minagi.jpg", + "image/character/key_mio.jpg", + "image/character/key_misa.jpg", + "image/character/key_misuzu.jpg", + "image/character/key_nagisa.jpg", + "image/character/key_nao.jpg", + "image/character/key_noda.jpg", + "image/character/key_rei.jpg", + "image/character/key_riki.jpg", + "image/character/key_rin.jpg", + "image/character/key_rumi.jpg", + "image/character/key_ryoichi.jpg", + "image/character/key_sakuya.jpg", + "image/character/key_sasami.jpg", + "image/character/key_satomi.jpg", + "image/character/key_saya.jpg", + "image/character/key_seira.jpg", + "image/character/key_shiina.jpg", + "image/character/key_shiki.jpg", + "image/character/key_shiori.jpg", + "image/character/key_shiorimiyuki.jpg", + "image/character/key_shiroha.jpg", + "image/character/key_shizuku.jpg", + "image/character/key_shizuru.jpg", + "image/character/key_sunohara.jpg", + "image/character/key_tenzen.jpg", + "image/character/key_tomoya.jpg", + "image/character/key_tomoyo.jpg", + "image/character/key_tsumugi.jpg", + "image/character/key_umi.jpg", + "image/character/key_ushio.jpg", + "image/character/key_yoshino.jpg", + "image/character/key_youta.jpg", + "image/character/key_yui.jpg", + "image/character/key_yuiko.jpg", + "image/character/key_yukine.jpg", + "image/character/key_yukito.jpg", + "image/character/key_yuri.jpg", + "image/character/key_yusa.jpg", + "image/character/key_yuu.jpg", + "image/character/key_yuuki.jpg", + "image/character/key_yuzuru.jpg", + "image/character/kongrong.jpg", + "image/character/kuailiangkuaiyue.jpg", + "image/character/kuaiqi.jpg", + "image/character/laimin.jpg", + "image/character/laiyinger.jpg", + "image/character/le_shen_jiaxu.jpg", + "image/character/leibo.jpg", + "image/character/leitong.jpg", + "image/character/liangxing.jpg", + "image/character/liaohua.jpg", + "image/character/libai.jpg", + "image/character/licaiwei.jpg", + "image/character/lifeng.jpg", + "image/character/lijue.jpg", + "image/character/lingcao.jpg", + "image/character/lingju.jpg", + "image/character/lingtong.jpg", + "image/character/liqueguosi.jpg", + "image/character/liru.jpg", + "image/character/lisu.jpg", + "image/character/litong.jpg", + "image/character/liuba.jpg", + "image/character/liubei.jpg", + "image/character/liubian.jpg", + "image/character/liubiao.jpg", + "image/character/liuchen.jpg", + "image/character/liucheng.jpg", + "image/character/liuchongluojun.jpg", + "image/character/liufeng.jpg", + "image/character/liuhong.jpg", + "image/character/liuhui.jpg", + "image/character/liupan.jpg", + "image/character/liupi.jpg", + "image/character/liuqi.jpg", + "image/character/liushan.jpg", + "image/character/liuxie.jpg", + "image/character/liuyan.jpg", + "image/character/liuyao.jpg", + "image/character/liuye.jpg", + "image/character/liuyong.jpg", + "image/character/liuyu.jpg", + "image/character/liuzan.jpg", + "image/character/liuzhang.jpg", + "image/character/liwan.jpg", + "image/character/liwei.jpg", + "image/character/liyan.jpg", + "image/character/liyi.jpg", + "image/character/liyixiejing.jpg", + "image/character/longwang.jpg", + "image/character/longyufei.jpg", + "image/character/luji.jpg", + "image/character/lukai.jpg", + "image/character/lukang.jpg", + "image/character/luotong.jpg", + "image/character/luoxian.jpg", + "image/character/lushi.jpg", + "image/character/luxun.jpg", + "image/character/luyi.jpg", + "image/character/luyusheng.jpg", + "image/character/luzhi.jpg", + "image/character/lvboshe.jpg", + "image/character/lvbu.jpg", + "image/character/lvdai.jpg", + "image/character/lvfan.jpg", + "image/character/lvkai.jpg", + "image/character/lvkuanglvxiang.jpg", + "image/character/lvlingqi.jpg", + "image/character/lvmeng.jpg", + "image/character/lvqian.jpg", + "image/character/machao.jpg", + "image/character/macheng.jpg", + "image/character/madai.jpg", + "image/character/majun.jpg", + "image/character/maliang.jpg", + "image/character/malingli.jpg", + "image/character/mamian.jpg", + "image/character/mamidi.jpg", + "image/character/manchong.jpg", + "image/character/mangyachang.jpg", + "image/character/masu.jpg", + "image/character/mateng.jpg", + "image/character/maxiumatie.jpg", + "image/character/mayuanyi.jpg", + "image/character/mayunlu.jpg", + "image/character/mazhong.jpg", + "image/character/mb_chengui.jpg", + "image/character/mb_huban.jpg", + "image/character/mb_sunluyu.jpg", + "image/character/mb_xianglang.jpg", + "image/character/mengda.jpg", + "image/character/menghuo.jpg", + "image/character/mengjie.jpg", + "image/character/mengyou.jpg", + "image/character/mifangfushiren.jpg", + "image/character/mifuren.jpg", + "image/character/miheng.jpg", + "image/character/mizhu.jpg", + "image/character/mp_liuling.jpg", + "image/character/mtg_ayeni.jpg", + "image/character/mtg_jiding.jpg", + "image/character/mtg_jiesi.jpg", + "image/character/mtg_lilianna.jpg", + "image/character/mtg_nisha.jpg", + "image/character/mtg_qianzhuo.jpg", + "image/character/muludawang.jpg", + "image/character/mushun.jpg", + "image/character/nanhualaoxian.jpg", + "image/character/nashime.jpg", + "image/character/new_caoren.jpg", + "image/character/nezha.jpg", + "image/character/nianshou.jpg", + "image/character/niufu.jpg", + "image/character/niujin.jpg", + "image/character/niutou.jpg", + "image/character/noname.jpg", + "image/character/noname_machao.png", + "image/character/noname_sunce.png", + "image/character/ns_caimao.jpg", + "image/character/ns_caoanmin.jpg", + "image/character/ns_caocao.jpg", + "image/character/ns_caocaosp.jpg", + "image/character/ns_caoshuang.jpg", + "image/character/ns_chendao.jpg", + "image/character/ns_chengpu.jpg", + "image/character/ns_chentai.jpg", + "image/character/ns_duangui.jpg", + "image/character/ns_duji.jpg", + "image/character/ns_fanchou.jpg", + "image/character/ns_guanlu.jpg", + "image/character/ns_huamulan.jpg", + "image/character/ns_huangchengyan.jpg", + "image/character/ns_huangwudie.jpg", + "image/character/ns_huangzu.jpg", + "image/character/ns_jiaxu.jpg", + "image/character/ns_jinke.jpg", + "image/character/ns_lijue.jpg", + "image/character/ns_limi.jpg", + "image/character/ns_lisu.jpg", + "image/character/ns_liuzhang.jpg", + "image/character/ns_luyusheng.jpg", + "image/character/ns_lvmeng.jpg", + "image/character/ns_lvzhi.jpg", + "image/character/ns_masu.jpg", + "image/character/ns_mengyou.jpg", + "image/character/ns_nanhua.jpg", + "image/character/ns_nanhua_left.jpg", + "image/character/ns_nanhua_right.jpg", + "image/character/ns_ruanji.jpg", + "image/character/ns_shenpei.jpg", + "image/character/ns_simazhao.jpg", + "image/character/ns_sunchensunjun.jpg", + "image/character/ns_sundeng.jpg", + "image/character/ns_sunjian.jpg", + "image/character/ns_sunyi.jpg", + "image/character/ns_wangyue.jpg", + "image/character/ns_wangyun.jpg", + "image/character/ns_wenchou.jpg", + "image/character/ns_xinnanhua.jpg", + "image/character/ns_xinxianying.jpg", + "image/character/ns_yanghu.jpg", + "image/character/ns_yangyi.jpg", + "image/character/ns_yanliang.jpg", + "image/character/ns_yuanxi.jpg", + "image/character/ns_yuji.jpg", + "image/character/ns_yujisp.jpg", + "image/character/ns_zanghong.jpg", + "image/character/ns_zhangbao.jpg", + "image/character/ns_zhangji.jpg", + "image/character/ns_zhangning.jpg", + "image/character/ns_zhangwei.jpg", + "image/character/ns_zhangxiu.jpg", + "image/character/ns_zhonglimu.jpg", + "image/character/ns_zhugeliang.jpg", + "image/character/ns_zuoci.jpg", + "image/character/ol_bianfuren.jpg", + "image/character/ol_caiwenji.jpg", + "image/character/ol_caozhang.jpg", + "image/character/ol_chendeng.jpg", + "image/character/ol_chengpu.jpg", + "image/character/ol_dengai.jpg", + "image/character/ol_dengzhi.jpg", + "image/character/ol_dianwei.jpg", + "image/character/ol_dingshangwan.jpg", + "image/character/ol_dingyuan.jpg", + "image/character/ol_dongzhao.jpg", + "image/character/ol_dongzhuo.jpg", + "image/character/ol_feiyi.jpg", + "image/character/ol_furong.jpg", + "image/character/ol_gaoshun.jpg", + "image/character/ol_guohuai.jpg", + "image/character/ol_huangzhong.jpg", + "image/character/ol_huaxin.jpg", + "image/character/ol_huaxiong.jpg", + "image/character/ol_huban.jpg", + "image/character/ol_hujinding.jpg", + "image/character/ol_jiangwei.jpg", + "image/character/ol_jianyong.jpg", + "image/character/ol_lingtong.jpg", + "image/character/ol_lisu.jpg", + "image/character/ol_liuba.jpg", + "image/character/ol_liushan.jpg", + "image/character/ol_liuyu.jpg", + "image/character/ol_liwan.jpg", + "image/character/ol_lukai.jpg", + "image/character/ol_lusu.jpg", + "image/character/ol_luyusheng.jpg", + "image/character/ol_maliang.jpg", + "image/character/ol_mengda.jpg", + "image/character/ol_pangde.jpg", + "image/character/ol_pangtong.jpg", + "image/character/ol_pengyang.jpg", + "image/character/ol_puyuan.jpg", + "image/character/ol_qianzhao.jpg", + "image/character/ol_sb_guanyu.jpg", + "image/character/ol_sb_jiangwei.jpg", + "image/character/ol_sb_taishici.jpg", + "image/character/ol_sb_yuanshao.jpg", + "image/character/ol_sb_yuanshao_shadow.jpg", + "image/character/ol_sp_zhugeliang.jpg", + "image/character/ol_sunjian.jpg", + "image/character/ol_wanglang.jpg", + "image/character/ol_wangrong.jpg", + "image/character/ol_weiyan.jpg", + "image/character/ol_wenqin.jpg", + "image/character/ol_xiahouyuan.jpg", + "image/character/ol_xiaoqiao.jpg", + "image/character/ol_xinxianying.jpg", + "image/character/ol_xuhuang.jpg", + "image/character/ol_xunyu.jpg", + "image/character/ol_yangyi.jpg", + "image/character/ol_yanwen.jpg", + "image/character/ol_yuanshao.jpg", + "image/character/ol_yuanshu.jpg", + "image/character/ol_yufan.jpg", + "image/character/ol_yujin.jpg", + "image/character/ol_zhangchangpu.jpg", + "image/character/ol_zhangliao.jpg", + "image/character/ol_zhangrang.jpg", + "image/character/ol_zhangyì.jpg", + "image/character/ol_zhangzhang.jpg", + "image/character/ol_zhouqun.jpg", + "image/character/ol_zhujun.jpg", + "image/character/ol_zhuling.jpg", + "image/character/ol_zhurong.jpg", + "image/character/old_bulianshi.jpg", + "image/character/old_caocao.jpg", + "image/character/old_caochong.jpg", + "image/character/old_caochun.jpg", + "image/character/old_caoren.jpg", + "image/character/old_caorui.jpg", + "image/character/old_caoxiu.jpg", + "image/character/old_caozhen.jpg", + "image/character/old_chendao.jpg", + "image/character/old_chenqun.jpg", + "image/character/old_dingfeng.jpg", + "image/character/old_fuhuanghou.jpg", + "image/character/old_gaoshun.jpg", + "image/character/old_guanqiujian.jpg", + "image/character/old_guanyinping.jpg", + "image/character/old_guanyu.jpg", + "image/character/old_guanzhang.jpg", + "image/character/old_handang.jpg", + "image/character/old_huangfusong.jpg", + "image/character/old_huanghao.jpg", + "image/character/old_huatuo.jpg", + "image/character/old_huaxiong.jpg", + "image/character/old_jiakui.jpg", + "image/character/old_lingju.jpg", + "image/character/old_lingtong.jpg", + "image/character/old_liubiao.jpg", + "image/character/old_liuzan.jpg", + "image/character/old_liyan.jpg", + "image/character/old_machao.jpg", + "image/character/old_madai.jpg", + "image/character/old_majun.jpg", + "image/character/old_maliang.jpg", + "image/character/old_quancong.jpg", + "image/character/old_re_lidian.jpg", + "image/character/old_shen_zhaoyun.jpg", + "image/character/old_shixie.jpg", + "image/character/old_wanglang.jpg", + "image/character/old_wangyi.jpg", + "image/character/old_wangyun.jpg", + "image/character/old_xiaoqiao.jpg", + "image/character/old_xusheng.jpg", + "image/character/old_yangyan.jpg", + "image/character/old_yangzhi.jpg", + "image/character/old_yuanshu.jpg", + "image/character/old_zhangfei.jpg", + "image/character/old_zhangxingcai.jpg", + "image/character/old_zhaoyun.jpg", + "image/character/old_zhonghui.jpg", + "image/character/old_zhoutai.jpg", + "image/character/old_zhugezhan.jpg", + "image/character/old_zhuhuan.jpg", + "image/character/old_zhuran.jpg", + "image/character/old_zhuzhi.jpg", + "image/character/oldre_liubiao.jpg", + "image/character/ow_ana.jpg", + "image/character/ow_banzang.jpg", + "image/character/ow_baolei.jpg", + "image/character/ow_chanyata.jpg", + "image/character/ow_dva.jpg", + "image/character/ow_falaozhiying.jpg", + "image/character/ow_heibaihe.jpg", + "image/character/ow_heiying.jpg", + "image/character/ow_kuangshu.jpg", + "image/character/ow_laiyinhate.jpg", + "image/character/ow_liekong.jpg", + "image/character/ow_luba.jpg", + "image/character/ow_luxiao.jpg", + "image/character/ow_maikelei.jpg", + "image/character/ow_mei.jpg", + "image/character/ow_orisa.jpg", + "image/character/ow_shibing.jpg", + "image/character/ow_sishen.jpg", + "image/character/ow_tianshi.jpg", + "image/character/ow_tuobiang.jpg", + "image/character/ow_wensidun.jpg", + "image/character/ow_yuanshi.jpg", + "image/character/ow_zhaliya.jpg", + "image/character/ow_zhixuzhiguang.jpg", + "image/character/pal_anu.jpg", + "image/character/pal_changqing.jpg", + "image/character/pal_hanlingsha.jpg", + "image/character/pal_jiangcheng.jpg", + "image/character/pal_jiangyunfan.jpg", + "image/character/pal_jingtian.jpg", + "image/character/pal_jushifang.jpg", + "image/character/pal_leiyuange.jpg", + "image/character/pal_linyueru.jpg", + "image/character/pal_liumengli.jpg", + "image/character/pal_lixiaoyao.jpg", + "image/character/pal_longkui.jpg", + "image/character/pal_longkuigui.jpg", + "image/character/pal_longyou.jpg", + "image/character/pal_luozhaoyan.jpg", + "image/character/pal_mingxiu.jpg", + "image/character/pal_muchanglan.jpg", + "image/character/pal_murongziying.jpg", + "image/character/pal_nangonghuang.jpg", + "image/character/pal_shenqishuang.jpg", + "image/character/pal_sumei.jpg", + "image/character/pal_tangyurou.jpg", + "image/character/pal_wangpengxu.jpg", + "image/character/pal_wangxiaohu.jpg", + "image/character/pal_wenhui.jpg", + "image/character/pal_xia.jpg", + "image/character/pal_xiahoujinxuan.jpg", + "image/character/pal_xianqing.jpg", + "image/character/pal_xiaoman.jpg", + "image/character/pal_xingxuan.jpg", + "image/character/pal_xuanxiao.jpg", + "image/character/pal_xuejian.jpg", + "image/character/pal_yuejinzhao.jpg", + "image/character/pal_yueqi.jpg", + "image/character/pal_yuntianhe.jpg", + "image/character/pal_zhaoliner.jpg", + "image/character/pal_zixuan.jpg", + "image/character/panfeng.jpg", + "image/character/pangde.jpg", + "image/character/pangdegong.jpg", + "image/character/panghui.jpg", + "image/character/pangshanmin.jpg", + "image/character/pangtong.jpg", + "image/character/panjun.jpg", + "image/character/panshu.jpg", + "image/character/panzhangmazhong.jpg", + "image/character/pe_mengda.jpg", + "image/character/pe_sunchen.jpg", + "image/character/pe_wangyun.jpg", + "image/character/pe_wenqin.jpg", + "image/character/pe_zhonghui.jpg", + "image/character/peixiu.jpg", + "image/character/peiyuanshao.jpg", + "image/character/pengyang.jpg", + "image/character/pk_sp_duyu.jpg", + "image/character/prp_zhugeliang.jpg", + "image/character/ps_caopi.jpg", + "image/character/ps_caozhi.jpg", + "image/character/ps_guanyu.jpg", + "image/character/ps_jiaxu.jpg", + "image/character/ps_jin_simayi.jpg", + "image/character/ps_lvbu.jpg", + "image/character/ps_machao.jpg", + "image/character/ps_shen_machao.jpg", + "image/character/ps_simayi.jpg", + "image/character/ps_zhugeliang.jpg", + "image/character/ps1059_guojia.jpg", + "image/character/ps1062_zhouyu.jpg", + "image/character/ps2063_zhaoyun.jpg", + "image/character/ps2066_zhugeliang.jpg", + "image/character/ps2067_zhaoyun.jpg", + "image/character/ps2068_simayi.jpg", + "image/character/ps2070_guojia.jpg", + "image/character/ps2080_zhouyu.jpg", + "image/character/pujing.jpg", + "image/character/puyuan.jpg", + "image/character/qianzhao.jpg", + "image/character/qiaogong.jpg", + "image/character/qiaorui.jpg", + "image/character/qiaozhou.jpg", + "image/character/qinghegongzhu.jpg", + "image/character/qinlang.jpg", + "image/character/qinmi.jpg", + "image/character/qinyilu.jpg", + "image/character/qiuliju.jpg", + "image/character/quancong.jpg", + "image/character/quanhuijie.jpg", + "image/character/quhuang.jpg", + "image/character/quyi.jpg", + "image/character/re_baosanniang.jpg", + "image/character/re_bulianshi.jpg", + "image/character/re_caifuren.jpg", + "image/character/re_caiwenji.jpg", + "image/character/re_caiyong.jpg", + "image/character/re_caocao.jpg", + "image/character/re_caochong.jpg", + "image/character/re_caopi.jpg", + "image/character/re_caorui.jpg", + "image/character/re_caoxiu.jpg", + "image/character/re_caozhang.jpg", + "image/character/re_caozhen.jpg", + "image/character/re_caozhi.jpg", + "image/character/re_chendeng.jpg", + "image/character/re_chengong.jpg", + "image/character/re_chengpu.jpg", + "image/character/re_chenqun.jpg", + "image/character/re_chunyuqiong.jpg", + "image/character/re_daqiao.jpg", + "image/character/re_dengai.jpg", + "image/character/re_dengzhi.jpg", + "image/character/re_dianwei.jpg", + "image/character/re_diaochan.jpg", + "image/character/re_dongbai.jpg", + "image/character/re_dongcheng.jpg", + "image/character/re_dongzhuo.jpg", + "image/character/re_duji.jpg", + "image/character/re_fazheng.jpg", + "image/character/re_fengfangnv.jpg", + "image/character/re_fuhuanghou.jpg", + "image/character/re_ganning.jpg", + "image/character/re_gaoshun.jpg", + "image/character/re_gongsunyuan.jpg", + "image/character/re_gongsunzan.jpg", + "image/character/re_guanping.jpg", + "image/character/re_guanqiujian.jpg", + "image/character/re_guanyu.jpg", + "image/character/re_guanzhang.jpg", + "image/character/re_guohuai.jpg", + "image/character/re_guohuanghou.jpg", + "image/character/re_guojia.jpg", + "image/character/re_guotufengji.jpg", + "image/character/re_guyong.jpg", + "image/character/re_handang.jpg", + "image/character/re_hanhaoshihuan.jpg", + "image/character/re_hansui.jpg", + "image/character/re_hejin.jpg", + "image/character/re_heqi.jpg", + "image/character/re_huanggai.jpg", + "image/character/re_huangyueying.jpg", + "image/character/re_huangzhong.jpg", + "image/character/re_huatuo.jpg", + "image/character/re_huaxiong.jpg", + "image/character/re_hucheer.jpg", + "image/character/re_jiangwei.jpg", + "image/character/re_jianyong.jpg", + "image/character/re_jiaxu.jpg", + "image/character/re_jikang.jpg", + "image/character/re_jsp_huangyueying.jpg", + "image/character/re_jsp_pangtong.jpg", + "image/character/re_jushou.jpg", + "image/character/re_kanze.jpg", + "image/character/re_liaohua.jpg", + "image/character/re_lidian.jpg", + "image/character/re_lingtong.jpg", + "image/character/re_liru.jpg", + "image/character/re_liubei.jpg", + "image/character/re_liubiao.jpg", + "image/character/re_liuchen.jpg", + "image/character/re_liufeng.jpg", + "image/character/re_liushan.jpg", + "image/character/re_liuzan.jpg", + "image/character/re_lusu.jpg", + "image/character/re_luxun.jpg", + "image/character/re_lvbu.jpg", + "image/character/re_lvmeng.jpg", + "image/character/re_machao.jpg", + "image/character/re_madai.jpg", + "image/character/re_maliang.jpg", + "image/character/re_manchong.jpg", + "image/character/re_masu.jpg", + "image/character/re_mazhong.jpg", + "image/character/re_menghuo.jpg", + "image/character/re_miheng.jpg", + "image/character/re_nanhualaoxian.jpg", + "image/character/re_niujin.jpg", + "image/character/re_panfeng.jpg", + "image/character/re_pangde.jpg", + "image/character/re_pangdegong.jpg", + "image/character/re_pangtong.jpg", + "image/character/re_panshu.jpg", + "image/character/re_panzhangmazhong.jpg", + "image/character/re_quancong.jpg", + "image/character/re_quyi.jpg", + "image/character/re_simayi.jpg", + "image/character/re_sp_taishici.jpg", + "image/character/re_sp_zhugeliang.jpg", + "image/character/re_sunben.jpg", + "image/character/re_sunce.jpg", + "image/character/re_sundeng.jpg", + "image/character/re_sunjian.jpg", + "image/character/re_sunluban.jpg", + "image/character/re_sunluyu.jpg", + "image/character/re_sunquan.jpg", + "image/character/re_sunshangxiang.jpg", + "image/character/re_sunxiu.jpg", + "image/character/re_sunyi.jpg", + "image/character/re_taishici.jpg", + "image/character/re_taoqian.jpg", + "image/character/re_wangyi.jpg", + "image/character/re_wangyun.jpg", + "image/character/re_weiwenzhugezhi.jpg", + "image/character/re_weiyan.jpg", + "image/character/re_wenpin.jpg", + "image/character/re_wuguotai.jpg", + "image/character/re_wuyi.jpg", + "image/character/re_xiahoudun.jpg", + "image/character/re_xiahoushi.jpg", + "image/character/re_xiahouyuan.jpg", + "image/character/re_xiaoqiao.jpg", + "image/character/re_xinxianying.jpg", + "image/character/re_xugong.jpg", + "image/character/re_xuhuang.jpg", + "image/character/re_xunchen.jpg", + "image/character/re_xunyou.jpg", + "image/character/re_xunyu.jpg", + "image/character/re_xusheng.jpg", + "image/character/re_xushu.jpg", + "image/character/re_xuzhu.jpg", + "image/character/re_yanwen.jpg", + "image/character/re_yuanshao.jpg", + "image/character/re_yuanshu.jpg", + "image/character/re_yufan.jpg", + "image/character/re_yuji.jpg", + "image/character/re_yujin.jpg", + "image/character/re_zhangbao.jpg", + "image/character/re_zhangchunhua.jpg", + "image/character/re_zhangfei.jpg", + "image/character/re_zhanggong.jpg", + "image/character/re_zhanghe.jpg", + "image/character/re_zhangjiao.jpg", + "image/character/re_zhangliang.jpg", + "image/character/re_zhangliao.jpg", + "image/character/re_zhangsong.jpg", + "image/character/re_zhangyi.jpg", + "image/character/re_zhangzhang.jpg", + "image/character/re_zhaoyun.jpg", + "image/character/re_zhenji.jpg", + "image/character/re_zhonghui.jpg", + "image/character/re_zhongyao.jpg", + "image/character/re_zhoucang.jpg", + "image/character/re_zhouyu.jpg", + "image/character/re_zhugeliang.jpg", + "image/character/re_zhuhuan.jpg", + "image/character/re_zhuran.jpg", + "image/character/re_zhurong.jpg", + "image/character/re_zhuzhi.jpg", + "image/character/re_zoushi.jpg", + "image/character/re_zuoci.jpg", + "image/character/ruanhui.jpg", + "image/character/ruanji.jpg", + "image/character/ruanyu.jpg", + "image/character/ruiji.jpg", + "image/character/sb_caocao.jpg", + "image/character/sb_caopi.jpg", + "image/character/sb_caoren.jpg", + "image/character/sb_chengong.jpg", + "image/character/sb_daqiao.jpg", + "image/character/sb_diaochan.jpg", + "image/character/sb_fazheng.jpg", + "image/character/sb_ganning.jpg", + "image/character/sb_guanyu.jpg", + "image/character/sb_huanggai.jpg", + "image/character/sb_huangyueying.jpg", + "image/character/sb_huangzhong.jpg", + "image/character/sb_huaxiong.jpg", + "image/character/sb_jiangwei.jpg", + "image/character/sb_liubei.jpg", + "image/character/sb_liubiao.jpg", + "image/character/sb_lvmeng.jpg", + "image/character/sb_machao.jpg", + "image/character/sb_menghuo.jpg", + "image/character/sb_pangtong.jpg", + "image/character/sb_sp_zhugeliang.jpg", + "image/character/sb_sunce.jpg", + "image/character/sb_sunquan.jpg", + "image/character/sb_sunshangxiang.jpg", + "image/character/sb_xiahoushi.jpg", + "image/character/sb_xiaoqiao.jpg", + "image/character/sb_xuhuang.jpg", + "image/character/sb_yl_luzhi.jpg", + "image/character/sb_yuanshao.jpg", + "image/character/sb_yujin.jpg", + "image/character/sb_zhangfei.jpg", + "image/character/sb_zhanghe.jpg", + "image/character/sb_zhangjiao.jpg", + "image/character/sb_zhaoyun.jpg", + "image/character/sb_zhenji.jpg", + "image/character/sb_zhouyu.jpg", + "image/character/sb_zhugeliang.jpg", + "image/character/sb_zhurong.jpg", + "image/character/scs_bilan.jpg", + "image/character/scs_bilan_dead.jpg", + "image/character/scs_duangui.jpg", + "image/character/scs_duangui_dead.jpg", + "image/character/scs_gaowang.jpg", + "image/character/scs_gaowang_dead.jpg", + "image/character/scs_guosheng.jpg", + "image/character/scs_guosheng_dead.jpg", + "image/character/scs_hankui.jpg", + "image/character/scs_hankui_dead.jpg", + "image/character/scs_lisong.jpg", + "image/character/scs_lisong_dead.jpg", + "image/character/scs_sunzhang.jpg", + "image/character/scs_sunzhang_dead.jpg", + "image/character/scs_xiayun.jpg", + "image/character/scs_xiayun_dead.jpg", + "image/character/scs_zhangrang.jpg", + "image/character/scs_zhangrang_dead.jpg", + "image/character/scs_zhaozhong.jpg", + "image/character/scs_zhaozhong_dead.jpg", + "image/character/shamoke.jpg", + "image/character/shen_caocao.jpg", + "image/character/shen_caopi.jpg", + "image/character/shen_dengai.jpg", + "image/character/shen_dianwei.jpg", + "image/character/shen_diaochan.jpg", + "image/character/shen_ganning.jpg", + "image/character/shen_guanyu.jpg", + "image/character/shen_guojia.jpg", + "image/character/shen_huatuo.jpg", + "image/character/shen_jiangwei.jpg", + "image/character/shen_jiaxu.jpg", + "image/character/shen_liubei.jpg", + "image/character/shen_luxun.jpg", + "image/character/shen_lvbu.jpg", + "image/character/shen_lvmeng.jpg", + "image/character/shen_machao.jpg", + "image/character/shen_simayi.jpg", + "image/character/shen_sunce.jpg", + "image/character/shen_sunquan.jpg", + "image/character/shen_taishici.jpg", + "image/character/shen_xunyu.jpg", + "image/character/shen_xuzhu.jpg", + "image/character/shen_zhangfei.jpg", + "image/character/shen_zhangjiao.jpg", + "image/character/shen_zhangliao.jpg", + "image/character/shen_zhaoyun.jpg", + "image/character/shen_zhenji.jpg", + "image/character/shen_zhouyu.jpg", + "image/character/shen_zhugeliang.jpg", + "image/character/shenpei.jpg", + "image/character/shibao.jpg", + "image/character/shibing1.jpg", + "image/character/shibing2.jpg", + "image/character/shichangshi.jpg", + "image/character/shichangshi_dead.jpg", + "image/character/shixie.jpg", + "image/character/shiyi.jpg", + "image/character/simafu.jpg", + "image/character/simahui.jpg", + "image/character/simalang.jpg", + "image/character/simashi.jpg", + "image/character/simayi.jpg", + "image/character/simazhao.jpg", + "image/character/simazhou.jpg", + "image/character/sp_bianfuren.jpg", + "image/character/sp_caiwenji.jpg", + "image/character/sp_caoren.jpg", + "image/character/sp_caosong.jpg", + "image/character/sp_chendong.jpg", + "image/character/sp_chenzhen.jpg", + "image/character/sp_cuiyan.jpg", + "image/character/sp_daqiao.jpg", + "image/character/sp_diaochan.jpg", + "image/character/sp_dongzhuo.jpg", + "image/character/sp_duyu.jpg", + "image/character/sp_fuhuanghou.jpg", + "image/character/sp_fuwan.jpg", + "image/character/sp_ganning.jpg", + "image/character/sp_gaolan.jpg", + "image/character/sp_gongsunzan.jpg", + "image/character/sp_huaman.jpg", + "image/character/sp_huangfusong.jpg", + "image/character/sp_huaxin.jpg", + "image/character/sp_jianggan.jpg", + "image/character/sp_jiangqing.jpg", + "image/character/sp_jiangwan.jpg", + "image/character/sp_jiangwei.jpg", + "image/character/sp_jiaxu.jpg", + "image/character/sp_jiben.jpg", + "image/character/sp_key_kanade.jpg", + "image/character/sp_key_yuri.jpg", + "image/character/sp_kongrong.jpg", + "image/character/sp_liubei.jpg", + "image/character/sp_liuqi.jpg", + "image/character/sp_liuxie.jpg", + "image/character/sp_lvfan.jpg", + "image/character/sp_lvmeng.jpg", + "image/character/sp_machao.jpg", + "image/character/sp_maojie.jpg", + "image/character/sp_menghuo.jpg", + "image/character/sp_mifangfushiren.jpg", + "image/character/sp_mifuren.jpg", + "image/character/sp_mushun.jpg", + "image/character/sp_ol_zhanghe.jpg", + "image/character/sp_pangde.jpg", + "image/character/sp_pangtong.jpg", + "image/character/sp_pengyang.jpg", + "image/character/sp_shenpei.jpg", + "image/character/sp_simazhao.jpg", + "image/character/sp_sufei.jpg", + "image/character/sp_sunshangxiang.jpg", + "image/character/sp_sunshao.jpg", + "image/character/sp_taishici.jpg", + "image/character/sp_wangcan.jpg", + "image/character/sp_wangshuang.jpg", + "image/character/sp_wangyuanji.jpg", + "image/character/sp_xiahoudun.jpg", + "image/character/sp_xiahoushi.jpg", + "image/character/sp_xinpi.jpg", + "image/character/sp_xinxianying.jpg", + "image/character/sp_xujing.jpg", + "image/character/sp_xunchen.jpg", + "image/character/sp_xuyou.jpg", + "image/character/sp_yanghu.jpg", + "image/character/sp_yangwan.jpg", + "image/character/sp_zhangchangpu.jpg", + "image/character/sp_zhangfei.jpg", + "image/character/sp_zhanghe.jpg", + "image/character/sp_zhangjiao.jpg", + "image/character/sp_zhangliao.jpg", + "image/character/sp_zhangwen.jpg", + "image/character/sp_zhaoyun.jpg", + "image/character/sp_zhugeliang.jpg", + "image/character/sp_zhujun.jpg", + "image/character/sp_zongyu.jpg", + "image/character/star_caoren.jpg", + "image/character/star_dongzhuo.jpg", + "image/character/star_yuanshao.jpg", + "image/character/star_yuanshu.jpg", + "image/character/star_zhangchunhua.jpg", + "image/character/std_panfeng.jpg", + "image/character/sunce.jpg", + "image/character/sunchen.jpg", + "image/character/sundeng.jpg", + "image/character/sunhanhua.jpg", + "image/character/sunhao.jpg", + "image/character/sunhong.jpg", + "image/character/sunhuan.jpg", + "image/character/sunjian.jpg", + "image/character/sunlang.jpg", + "image/character/sunli.jpg", + "image/character/sunliang.jpg", + "image/character/sunlingluan.jpg", + "image/character/sunluban.jpg", + "image/character/sunluyu.jpg", + "image/character/sunqian.jpg", + "image/character/sunquan.jpg", + "image/character/sunru.jpg", + "image/character/sunshangxiang.jpg", + "image/character/sunshao.jpg", + "image/character/sunwukong.jpg", + "image/character/sunxiu.jpg", + "image/character/sunyang.jpg", + "image/character/sunyi.jpg", + "image/character/sunyu.jpg", + "image/character/sunziliufang.jpg", + "image/character/swd_anka.jpg", + "image/character/swd_chenfu.jpg", + "image/character/swd_chengyaojin.jpg", + "image/character/swd_chenjingchou.jpg", + "image/character/swd_cheyun.jpg", + "image/character/swd_chunyuheng.jpg", + "image/character/swd_duanmeng.jpg", + "image/character/swd_duguningke.jpg", + "image/character/swd_duopeng.jpg", + "image/character/swd_fengtianling.jpg", + "image/character/swd_fengyu.jpg", + "image/character/swd_fu.jpg", + "image/character/swd_fuyan.jpg", + "image/character/swd_guyue.jpg", + "image/character/swd_haidapang.jpg", + "image/character/swd_hanlong.jpg", + "image/character/swd_hanluo.jpg", + "image/character/swd_hengai.jpg", + "image/character/swd_huanglei.jpg", + "image/character/swd_huanyuanzhi.jpg", + "image/character/swd_huiyan.jpg", + "image/character/swd_hupo.jpg", + "image/character/swd_huyue.jpg", + "image/character/swd_huzhongxian.jpg", + "image/character/swd_jialanduo.jpg", + "image/character/swd_jiangwu.jpg", + "image/character/swd_jiangziya.jpg", + "image/character/swd_jiliang.jpg", + "image/character/swd_jipeng.jpg", + "image/character/swd_jiting.jpg", + "image/character/swd_jiuyou.jpg", + "image/character/swd_kama.jpg", + "image/character/swd_kangnalishi.jpg", + "image/character/swd_kendi.jpg", + "image/character/swd_lanmoshen.jpg", + "image/character/swd_lanyin.jpg", + "image/character/swd_lilian.jpg", + "image/character/swd_linyue.jpg", + "image/character/swd_luchengxuan.jpg", + "image/character/swd_maixing.jpg", + "image/character/swd_miles.jpg", + "image/character/swd_moye.jpg", + "image/character/swd_murongshi.jpg", + "image/character/swd_muyue.jpg", + "image/character/swd_muyun.jpg", + "image/character/swd_nicole.jpg", + "image/character/swd_qi.jpg", + "image/character/swd_qiner.jpg", + "image/character/swd_qinshubao.jpg", + "image/character/swd_quxian.jpg", + "image/character/swd_rongshuang.jpg", + "image/character/swd_septem.jpg", + "image/character/swd_shangzhang.jpg", + "image/character/swd_shanxiaoxiao.jpg", + "image/character/swd_shaowei.jpg", + "image/character/swd_shuijing.jpg", + "image/character/swd_shuwaner.jpg", + "image/character/swd_sikongyu.jpg", + "image/character/swd_situqiang.jpg", + "image/character/swd_tuobayuer.jpg", + "image/character/swd_tuwei.jpg", + "image/character/swd_wangsiyue.jpg", + "image/character/swd_weida.jpg", + "image/character/swd_wushi.jpg", + "image/character/swd_xiaohuanglong.jpg", + "image/character/swd_xiarou.jpg", + "image/character/swd_xiyan.jpg", + "image/character/swd_xuanyuanjiantong.jpg", + "image/character/swd_xuanyuanjianxian.jpg", + "image/character/swd_yeyaxi.jpg", + "image/character/swd_youzhao.jpg", + "image/character/swd_yuchiyanhong.jpg", + "image/character/swd_yuli.jpg", + "image/character/swd_yunhu.jpg", + "image/character/swd_yuwentuo.jpg", + "image/character/swd_yuxiaoxue.jpg", + "image/character/swd_zhanggao.jpg", + "image/character/swd_zhaoyun.jpg", + "image/character/swd_zhiyin.jpg", + "image/character/swd_zhuoshanzhu.jpg", + "image/character/swd_zidashu.jpg", + "image/character/swd_ziqiao.jpg", + "image/character/tadun.jpg", + "image/character/taishici.jpg", + "image/character/tangji.jpg", + "image/character/tangzi.jpg", + "image/character/taoqian.jpg", + "image/character/taoshen.jpg", + "image/character/tengfanglan.jpg", + "image/character/tenggongzhu.jpg", + "image/character/tengyin.jpg", + "image/character/tianchou.jpg", + "image/character/tianfeng.jpg", + "image/character/tianshangyi.jpg", + "image/character/tianyu.jpg", + "image/character/tongyuan.jpg", + "image/character/tw_baoxin.jpg", + "image/character/tw_beimihu.jpg", + "image/character/tw_bianfuren.jpg", + "image/character/tw_bingyuan.jpg", + "image/character/tw_caoang.jpg", + "image/character/tw_caocao.jpg", + "image/character/tw_caohong.jpg", + "image/character/tw_caoxiu.jpg", + "image/character/tw_caozhao.jpg", + "image/character/tw_chendong.jpg", + "image/character/tw_chengpu.jpg", + "image/character/tw_chenzhen.jpg", + "image/character/tw_daxiaoqiao.jpg", + "image/character/tw_dengzhi.jpg", + "image/character/tw_dingfeng.jpg", + "image/character/tw_dongzhao.jpg", + "image/character/tw_fanchou.jpg", + "image/character/tw_feiyi.jpg", + "image/character/tw_fengxí.jpg", + "image/character/tw_furong.jpg", + "image/character/tw_fuwan.jpg", + "image/character/tw_gexuan.jpg", + "image/character/tw_gongsunfan.jpg", + "image/character/tw_guanqiujian.jpg", + "image/character/tw_guohuai.jpg", + "image/character/tw_guyong.jpg", + "image/character/tw_handang.jpg", + "image/character/tw_haomeng.jpg", + "image/character/tw_hejin.jpg", + "image/character/tw_hucheer.jpg", + "image/character/tw_huchuquan.jpg", + "image/character/tw_huojun.jpg", + "image/character/tw_jiangji.jpg", + "image/character/tw_jiangqing.jpg", + "image/character/tw_jianshuo.jpg", + "image/character/tw_jiling.jpg", + "image/character/tw_liufuren.jpg", + "image/character/tw_liuhong.jpg", + "image/character/tw_liuzhang.jpg", + "image/character/tw_liwei.jpg", + "image/character/tw_madai.jpg", + "image/character/tw_maliang.jpg", + "image/character/tw_mateng.jpg", + "image/character/tw_mayunlu.jpg", + "image/character/tw_menghuo.jpg", + "image/character/tw_niufudongxie.jpg", + "image/character/tw_niujin.jpg", + "image/character/tw_ol_sunjian.jpg", + "image/character/tw_puyangxing.jpg", + "image/character/tw_qiaogong.jpg", + "image/character/tw_qiaorui.jpg", + "image/character/tw_re_caohong.jpg", + "image/character/tw_re_fazheng.jpg", + "image/character/tw_shen_guanyu.jpg", + "image/character/tw_shen_lvmeng.jpg", + "image/character/tw_sunyi.jpg", + "image/character/tw_tianyu.jpg", + "image/character/tw_wangcan.jpg", + "image/character/tw_wangchang.jpg", + "image/character/tw_wangling.jpg", + "image/character/tw_weixu.jpg", + "image/character/tw_wujing.jpg", + "image/character/tw_xiahouba.jpg", + "image/character/tw_xiahouen.jpg", + "image/character/tw_xiahoushang.jpg", + "image/character/tw_xuezong.jpg", + "image/character/tw_xujing.jpg", + "image/character/tw_xunchen.jpg", + "image/character/tw_yangang.jpg", + "image/character/tw_yangyi.jpg", + "image/character/tw_yanxiang.jpg", + "image/character/tw_yl_luzhi.jpg", + "image/character/tw_yufuluo.jpg", + "image/character/tw_yujin.jpg", + "image/character/tw_zangba.jpg", + "image/character/tw_zhangfei.jpg", + "image/character/tw_zhanghong.jpg", + "image/character/tw_zhangji.jpg", + "image/character/tw_zhangmancheng.jpg", + "image/character/tw_zhangnan.jpg", + "image/character/tw_zhangning.jpg", + "image/character/tw_zhangzhao.jpg", + "image/character/tw_zhaoxiang.jpg", + "image/character/tw_zhouchu.jpg", + "image/character/tw_zhugeguo.jpg", + "image/character/tw_zongyu.jpg", + "image/character/tw_zumao.jpg", + "image/character/vtb_xiaojiu.jpg", + "image/character/vtb_xiaole.jpg", + "image/character/vtb_xiaosha.jpg", + "image/character/vtb_xiaoshan.jpg", + "image/character/vtb_xiaotao.jpg", + "image/character/wangcan.jpg", + "image/character/wangfuzhaolei.jpg", + "image/character/wangguan.jpg", + "image/character/wangji.jpg", + "image/character/wangjun.jpg", + "image/character/wanglang.jpg", + "image/character/wanglie.jpg", + "image/character/wangling.jpg", + "image/character/wangping.jpg", + "image/character/wangrong.jpg", + "image/character/wangshuang.jpg", + "image/character/wangtao.jpg", + "image/character/wangwei.jpg", + "image/character/wangxiang.jpg", + "image/character/wangyan.jpg", + "image/character/wangyi.jpg", + "image/character/wangyuanji.jpg", + "image/character/wangyue.jpg", + "image/character/wangyun.jpg", + "image/character/wanniangongzhu.jpg", + "image/character/weiguan.jpg", + "image/character/weiwenzhugezhi.jpg", + "image/character/weiyan.jpg", + "image/character/weizi.jpg", + "image/character/wenpin.jpg", + "image/character/wenqin.jpg", + "image/character/wenyang.jpg", + "image/character/wolongfengchu.jpg", + "image/character/wu_luxun.jpg", + "image/character/wu_zhugeliang.jpg", + "image/character/wu_zhutiexiong.jpg", + "image/character/wuanguo.jpg", + "image/character/wuban.jpg", + "image/character/wufan.jpg", + "image/character/wuguotai.jpg", + "image/character/wujing.jpg", + "image/character/wulan.jpg", + "image/character/wutugu.jpg", + "image/character/wuxian.jpg", + "image/character/wuyan.jpg", + "image/character/wuyi.jpg", + "image/character/xf_huangquan.jpg", + "image/character/xf_sufei.jpg", + "image/character/xf_tangzi.jpg", + "image/character/xf_yiji.jpg", + "image/character/xia_dianwei.jpg", + "image/character/xia_liubei.jpg", + "image/character/xia_liyàn.jpg", + "image/character/xia_lusu.jpg", + "image/character/xia_tongyuan.jpg", + "image/character/xia_wangyue.jpg", + "image/character/xia_xiahoudun.jpg", + "image/character/xia_xiahousone.jpg", + "image/character/xia_xiahouzie.jpg", + "image/character/xia_xushu.jpg", + "image/character/xia_zhangwei.jpg", + "image/character/xia_zhaoe.jpg", + "image/character/xiahouba.jpg", + "image/character/xiahoudun.jpg", + "image/character/xiahoujie.jpg", + "image/character/xiahoulingnv.jpg", + "image/character/xiahoumao.jpg", + "image/character/xiahoushi.jpg", + "image/character/xiahouxuan.jpg", + "image/character/xiahouyuan.jpg", + "image/character/xiangchong.jpg", + "image/character/xianglang.jpg", + "image/character/xiaoqiao.jpg", + "image/character/xiaoyuehankehan.jpg", + "image/character/xielingyu.jpg", + "image/character/xin_baosanniang.jpg", + "image/character/xin_caifuren.jpg", + "image/character/xin_caoxiu.jpg", + "image/character/xin_caozhang.jpg", + "image/character/xin_caozhen.jpg", + "image/character/xin_chengpu.jpg", + "image/character/xin_fazheng.jpg", + "image/character/xin_fuhuanghou.jpg", + "image/character/xin_gaoshun.jpg", + "image/character/xin_gongsunzan.jpg", + "image/character/xin_guohuai.jpg", + "image/character/xin_guozhao.jpg", + "image/character/xin_guyong.jpg", + "image/character/xin_handang.jpg", + "image/character/xin_hansui.jpg", + "image/character/xin_jianyong.jpg", + "image/character/xin_jushou.jpg", + "image/character/xin_liaohua.jpg", + "image/character/xin_lingtong.jpg", + "image/character/xin_liru.jpg", + "image/character/xin_liubiao.jpg", + "image/character/xin_mamidi.jpg", + "image/character/xin_masu.jpg", + "image/character/xin_panzhangmazhong.jpg", + "image/character/xin_quancong.jpg", + "image/character/xin_sunliang.jpg", + "image/character/xin_sunluban.jpg", + "image/character/xin_sunxiu.jpg", + "image/character/xin_wuguotai.jpg", + "image/character/xin_wuyi.jpg", + "image/character/xin_xiahoudun.jpg", + "image/character/xin_xusheng.jpg", + "image/character/xin_xushu.jpg", + "image/character/xin_yuanshao.jpg", + "image/character/xin_yufan.jpg", + "image/character/xin_yuji.jpg", + "image/character/xin_yujin.jpg", + "image/character/xin_zhangfei.jpg", + "image/character/xin_zhangyi.jpg", + "image/character/xin_zhonghui.jpg", + "image/character/xin_zhoucang.jpg", + "image/character/xin_zhoutai.jpg", + "image/character/xin_zhuhuan.jpg", + "image/character/xin_zhuran.jpg", + "image/character/xin_zhuzhi.jpg", + "image/character/xinchang.jpg", + "image/character/xingdaorong.jpg", + "image/character/xinpi.jpg", + "image/character/xinping.jpg", + "image/character/xinxianying.jpg", + "image/character/xizheng.jpg", + "image/character/xizhicai.jpg", + "image/character/xuangongzhu.jpg", + "image/character/xuelingyun.jpg", + "image/character/xuezong.jpg", + "image/character/xugong.jpg", + "image/character/xuhuang.jpg", + "image/character/xujing.jpg", + "image/character/xunchen.jpg", + "image/character/xunyou.jpg", + "image/character/xunyu.jpg", + "image/character/xurong.jpg", + "image/character/xushao.jpg", + "image/character/xusheng.jpg", + "image/character/xushi.jpg", + "image/character/xushu.jpg", + "image/character/xuyou.jpg", + "image/character/xuzhu.jpg", + "image/character/yanbaihu.jpg", + "image/character/yanfuren.jpg", + "image/character/yangbiao.jpg", + "image/character/yangfu.jpg", + "image/character/yanghong.jpg", + "image/character/yanghuiyu.jpg", + "image/character/yangwan.jpg", + "image/character/yangxiu.jpg", + "image/character/yangyan.jpg", + "image/character/yangyi.jpg", + "image/character/yangzhi.jpg", + "image/character/yanjun.jpg", + "image/character/yanpu.jpg", + "image/character/yanrou.jpg", + "image/character/yanwen.jpg", + "image/character/yanxiang.jpg", + "image/character/yanyan.jpg", + "image/character/yeshiwen.jpg", + "image/character/yinfuren.jpg", + "image/character/yj_caoang.jpg", + "image/character/yj_caocao.jpg", + "image/character/yj_caohong.jpg", + "image/character/yj_dongzhuo.jpg", + "image/character/yj_ganning.jpg", + "image/character/yj_huangzhong.jpg", + "image/character/yj_jiaxu.jpg", + "image/character/yj_jushou.jpg", + "image/character/yj_liru.jpg", + "image/character/yj_qiaozhou.jpg", + "image/character/yj_sufei.jpg", + "image/character/yj_weiyan.jpg", + "image/character/yj_xuhuang.jpg", + "image/character/yj_xuyou.jpg", + "image/character/yj_zhangfei.jpg", + "image/character/yj_zhanghe.jpg", + "image/character/yj_zhangliao.jpg", + "image/character/yj_zhenji.jpg", + "image/character/yj_zhoubuyi.jpg", + "image/character/yl_luzhi.jpg", + "image/character/yl_yuanshu.jpg", + "image/character/yongjian_ganning.jpg", + "image/character/yuanhuan.jpg", + "image/character/yuanji.jpg", + "image/character/yuanshu.jpg", + "image/character/yuantanyuanshang.jpg", + "image/character/yuantanyuanxiyuanshang.jpg", + "image/character/yue_caiwenji.jpg", + "image/character/yue_daqiao.jpg", + "image/character/yue_xiaoqiao.jpg", + "image/character/yue_zhoufei.jpg", + "image/character/yuechen.jpg", + "image/character/yuejin.jpg", + "image/character/yuejiu.jpg", + "image/character/yufan.jpg", + "image/character/yuji.jpg", + "image/character/yujin.jpg", + "image/character/yujin_yujin.jpg", + "image/character/yxs_aijiyanhou.jpg", + "image/character/yxs_baosi.jpg", + "image/character/yxs_bole.jpg", + "image/character/yxs_caocao.jpg", + "image/character/yxs_chengjisihan.jpg", + "image/character/yxs_chengyaojin.jpg", + "image/character/yxs_diaochan.jpg", + "image/character/yxs_direnjie.jpg", + "image/character/yxs_fuermosi.jpg", + "image/character/yxs_goujian.jpg", + "image/character/yxs_guiguzi.jpg", + "image/character/yxs_handingdun.jpg", + "image/character/yxs_huamulan.jpg", + "image/character/yxs_jinke.jpg", + "image/character/yxs_kaisa.jpg", + "image/character/yxs_lanlinwang.jpg", + "image/character/yxs_libai.jpg", + "image/character/yxs_lishimin.jpg", + "image/character/yxs_luban.jpg", + "image/character/yxs_luobinhan.jpg", + "image/character/yxs_luocheng.jpg", + "image/character/yxs_luzhishen.jpg", + "image/character/yxs_lvzhi.jpg", + "image/character/yxs_meixi.jpg", + "image/character/yxs_mingchenghuanghou.jpg", + "image/character/yxs_mozi.jpg", + "image/character/yxs_nandinggeer.jpg", + "image/character/yxs_napolun.jpg", + "image/character/yxs_qinqiong.jpg", + "image/character/yxs_sunwu.jpg", + "image/character/yxs_tangbohu.jpg", + "image/character/yxs_wangzhaojun.jpg", + "image/character/yxs_weizhongxian.jpg", + "image/character/yxs_wuzetian.jpg", + "image/character/yxs_xiangyu.jpg", + "image/character/yxs_xiaoqiao.jpg", + "image/character/yxs_yangguang.jpg", + "image/character/yxs_yangyuhuan.jpg", + "image/character/yxs_yingzheng.jpg", + "image/character/yxs_yuefei.jpg", + "image/character/yxs_yujix.jpg", + "image/character/yxs_zhangsanfeng.jpg", + "image/character/yxs_zhaoyong.jpg", + "image/character/yxs_zhuyuanzhang.jpg", + "image/character/zangba.jpg", + "image/character/zerong.jpg", + "image/character/zhangbao.jpg", + "image/character/zhangchangpu.jpg", + "image/character/zhangchu.jpg", + "image/character/zhangchunhua.jpg", + "image/character/zhangfei.jpg", + "image/character/zhangfen.jpg", + "image/character/zhanggong.jpg", + "image/character/zhanghe.jpg", + "image/character/zhangheng.jpg", + "image/character/zhanghu.jpg", + "image/character/zhanghua.jpg", + "image/character/zhanghuyuechen.jpg", + "image/character/zhangji.jpg", + "image/character/zhangjiao.jpg", + "image/character/zhangjinyun.jpg", + "image/character/zhangkai.jpg", + "image/character/zhangliang.jpg", + "image/character/zhangliao.jpg", + "image/character/zhangling.jpg", + "image/character/zhanglu.jpg", + "image/character/zhangmiao.jpg", + "image/character/zhangning.jpg", + "image/character/zhangqiying.jpg", + "image/character/zhangrang.jpg", + "image/character/zhangren.jpg", + "image/character/zhangshiping.jpg", + "image/character/zhangsong.jpg", + "image/character/zhangwen.jpg", + "image/character/zhangxingcai.jpg", + "image/character/zhangxiu.jpg", + "image/character/zhangxuan.jpg", + "image/character/zhangxun.jpg", + "image/character/zhangyan.jpg", + "image/character/zhangyao.jpg", + "image/character/zhangyi.jpg", + "image/character/zhangyì.jpg", + "image/character/zhangzhang.jpg", + "image/character/zhangzhi.jpg", + "image/character/zhangzhongjing.jpg", + "image/character/zhaoang.jpg", + "image/character/zhaotongzhaoguang.jpg", + "image/character/zhaoxiang.jpg", + "image/character/zhaoyan.jpg", + "image/character/zhaoyǎn.jpg", + "image/character/zhaoyun.jpg", + "image/character/zhaozhi.jpg", + "image/character/zhaozhong.jpg", + "image/character/zhenghun.jpg", + "image/character/zhengxuan.jpg", + "image/character/zhenji.jpg", + "image/character/zhonghui.jpg", + "image/character/zhongyan.jpg", + "image/character/zhongyao.jpg", + "image/character/zhoubuyi.jpg", + "image/character/zhoucang.jpg", + "image/character/zhouchu.jpg", + "image/character/zhoufang.jpg", + "image/character/zhoufei.jpg", + "image/character/zhouqun.jpg", + "image/character/zhoushan.jpg", + "image/character/zhoutai.jpg", + "image/character/zhouyi.jpg", + "image/character/zhouyu.jpg", + "image/character/zhugedan.jpg", + "image/character/zhugeguo.jpg", + "image/character/zhugejin.jpg", + "image/character/zhugeke.jpg", + "image/character/zhugeliang.jpg", + "image/character/zhugemengxue.jpg", + "image/character/zhugeruoxue.jpg", + "image/character/zhugeshang.jpg", + "image/character/zhugezhan.jpg", + "image/character/zhuhuan.jpg", + "image/character/zhujianping.jpg", + "image/character/zhujun.jpg", + "image/character/zhuling.jpg", + "image/character/zhuran.jpg", + "image/character/zhurong.jpg", + "image/character/zhutiexiong.jpg", + "image/character/zhuzhi.jpg", + "image/character/zongyu.jpg", + "image/character/zoushi.jpg", + "image/character/zumao.jpg", + "image/character/zuoci.jpg", + "image/character/zuofen.jpg", + /*character image end*/ + + "image/emotion/shibing_emotion/1.gif", + "image/emotion/shibing_emotion/2.gif", + "image/emotion/shibing_emotion/3.gif", + "image/emotion/shibing_emotion/4.gif", + "image/emotion/shibing_emotion/5.gif", + "image/emotion/shibing_emotion/6.gif", + "image/emotion/shibing_emotion/7.gif", + "image/emotion/shibing_emotion/8.gif", + "image/emotion/shibing_emotion/9.gif", + "image/emotion/shibing_emotion/10.gif", + "image/emotion/shibing_emotion/11.gif", + "image/emotion/shibing_emotion/12.gif", + "image/emotion/shibing_emotion/13.gif", + "image/emotion/shibing_emotion/14.gif", + "image/emotion/shibing_emotion/15.gif", + "image/emotion/guojia_emotion/1.gif", + "image/emotion/guojia_emotion/2.gif", + "image/emotion/guojia_emotion/3.gif", + "image/emotion/guojia_emotion/4.gif", + "image/emotion/guojia_emotion/5.gif", + "image/emotion/guojia_emotion/6.gif", + "image/emotion/guojia_emotion/7.gif", + "image/emotion/guojia_emotion/8.gif", + "image/emotion/guojia_emotion/9.gif", + "image/emotion/guojia_emotion/10.gif", + "image/emotion/guojia_emotion/11.gif", + "image/emotion/guojia_emotion/12.gif", + "image/emotion/guojia_emotion/13.gif", + "image/emotion/guojia_emotion/14.gif", + "image/emotion/guojia_emotion/15.gif", + "image/emotion/guojia_emotion/16.gif", + "image/emotion/guojia_emotion/17.gif", + "image/emotion/guojia_emotion/18.gif", + "image/emotion/guojia_emotion/19.gif", + "image/emotion/guojia_emotion/20.gif", + "image/emotion/zhenji_emotion/1.gif", + "image/emotion/zhenji_emotion/2.gif", + "image/emotion/zhenji_emotion/3.gif", + "image/emotion/zhenji_emotion/4.gif", + "image/emotion/zhenji_emotion/5.gif", + "image/emotion/zhenji_emotion/6.gif", + "image/emotion/zhenji_emotion/7.gif", + "image/emotion/zhenji_emotion/8.gif", + "image/emotion/zhenji_emotion/9.gif", + "image/emotion/zhenji_emotion/10.gif", + "image/emotion/zhenji_emotion/11.gif", + "image/emotion/zhenji_emotion/12.gif", + "image/emotion/zhenji_emotion/13.gif", + "image/emotion/zhenji_emotion/14.gif", + "image/emotion/zhenji_emotion/15.gif", + "image/emotion/zhenji_emotion/16.gif", + "image/emotion/zhenji_emotion/17.gif", + "image/emotion/zhenji_emotion/18.gif", + "image/emotion/zhenji_emotion/19.gif", + "image/emotion/zhenji_emotion/20.gif", + "image/emotion/xiaojiu_emotion/1.gif", + "image/emotion/xiaojiu_emotion/2.gif", + "image/emotion/xiaojiu_emotion/3.gif", + "image/emotion/xiaojiu_emotion/4.gif", + "image/emotion/xiaojiu_emotion/5.gif", + "image/emotion/xiaojiu_emotion/6.gif", + "image/emotion/xiaojiu_emotion/7.gif", + "image/emotion/xiaojiu_emotion/8.gif", + "image/emotion/xiaojiu_emotion/9.gif", + "image/emotion/xiaojiu_emotion/10.gif", + "image/emotion/xiaojiu_emotion/11.gif", + "image/emotion/xiaojiu_emotion/12.gif", + "image/emotion/xiaojiu_emotion/13.gif", + "image/emotion/xiaojiu_emotion/14.gif", + "image/emotion/xiaojiu_emotion/15.gif", + "image/emotion/xiaojiu_emotion/16.gif", + "image/emotion/xiaojiu_emotion/17.gif", + "image/emotion/xiaojiu_emotion/18.gif", + "image/emotion/xiaojiu_emotion/19.gif", + "image/emotion/xiaojiu_emotion/20.gif", + "image/emotion/xiaokuo_emotion/1.gif", + "image/emotion/xiaokuo_emotion/2.gif", + "image/emotion/xiaokuo_emotion/3.gif", + "image/emotion/xiaokuo_emotion/4.gif", + "image/emotion/xiaokuo_emotion/5.gif", + "image/emotion/xiaokuo_emotion/6.gif", + "image/emotion/xiaokuo_emotion/7.gif", + "image/emotion/xiaokuo_emotion/8.gif", + "image/emotion/xiaosha_emotion/1.gif", + "image/emotion/xiaosha_emotion/2.gif", + "image/emotion/xiaosha_emotion/3.gif", + "image/emotion/xiaosha_emotion/4.gif", + "image/emotion/xiaosha_emotion/5.gif", + "image/emotion/xiaosha_emotion/6.gif", + "image/emotion/xiaosha_emotion/7.gif", + "image/emotion/xiaosha_emotion/8.gif", + "image/emotion/xiaosha_emotion/9.gif", + "image/emotion/xiaosha_emotion/10.gif", + "image/emotion/xiaosha_emotion/11.gif", + "image/emotion/xiaosha_emotion/12.gif", + "image/emotion/xiaosha_emotion/13.gif", + "image/emotion/xiaosha_emotion/14.gif", + "image/emotion/xiaosha_emotion/15.gif", + "image/emotion/xiaosha_emotion/16.gif", + "image/emotion/xiaosha_emotion/17.gif", + "image/emotion/xiaosha_emotion/18.gif", + "image/emotion/xiaosha_emotion/19.gif", + "image/emotion/xiaosha_emotion/20.gif", + "image/emotion/xiaotao_emotion/1.gif", + "image/emotion/xiaotao_emotion/2.gif", + "image/emotion/xiaotao_emotion/3.gif", + "image/emotion/xiaotao_emotion/4.gif", + "image/emotion/xiaotao_emotion/5.gif", + "image/emotion/xiaotao_emotion/6.gif", + "image/emotion/xiaotao_emotion/7.gif", + "image/emotion/xiaotao_emotion/8.gif", + "image/emotion/xiaotao_emotion/9.gif", + "image/emotion/xiaotao_emotion/10.gif", + "image/emotion/xiaotao_emotion/11.gif", + "image/emotion/xiaotao_emotion/12.gif", + "image/emotion/xiaotao_emotion/13.gif", + "image/emotion/xiaotao_emotion/14.gif", + "image/emotion/xiaotao_emotion/15.gif", + "image/emotion/xiaotao_emotion/16.gif", + "image/emotion/xiaotao_emotion/17.gif", + "image/emotion/xiaotao_emotion/18.gif", + "image/emotion/xiaotao_emotion/19.gif", + "image/emotion/xiaotao_emotion/20.gif", + "image/emotion/xiaowu_emotion/1.gif", + "image/emotion/xiaowu_emotion/2.gif", + "image/emotion/xiaowu_emotion/3.gif", + "image/emotion/xiaowu_emotion/4.gif", + "image/emotion/xiaowu_emotion/5.gif", + "image/emotion/xiaowu_emotion/6.gif", + "image/emotion/xiaowu_emotion/7.gif", + "image/emotion/xiaowu_emotion/8.gif", + "image/emotion/xiaowu_emotion/9.gif", + "image/emotion/xiaowu_emotion/10.gif", + "image/emotion/xiaowu_emotion/11.gif", + "image/emotion/xiaowu_emotion/12.gif", + "image/emotion/xiaowu_emotion/13.gif", + "image/emotion/xiaowu_emotion/14.gif", + "image/emotion/throw_emotion/egg1.png", + "image/emotion/throw_emotion/egg2.png", + "image/emotion/throw_emotion/flower1.png", + "image/emotion/throw_emotion/flower2.png", + "image/emotion/throw_emotion/shoe1.png", + "image/emotion/throw_emotion/shoe2.png", + "image/emotion/throw_emotion/jiasuo1.png", + "image/emotion/throw_emotion/jiasuo2.png", + "image/emotion/throw_emotion/wine1.png", + "image/emotion/throw_emotion/wine2.png", + "image/emotion/throw_emotion/yuxisx1.png", + "image/emotion/throw_emotion/yuxisx2.png", + + "image/mode/boss/card/chixueqingfeng.png", + "image/mode/boss/card/chiyanzhenhunqin.png", + "image/mode/boss/card/guilongzhanyuedao.png", + "image/mode/boss/card/guofengyupao.png", + "image/mode/boss/card/honghuangzhili.png", + "image/mode/boss/card/hongmianbaihuapao.png", + "image/mode/boss/card/juechenjinge.png", + "image/mode/boss/card/linglongshimandai.png", + "image/mode/boss/card/qimenbagua.png", + "image/mode/boss/card/sadouchengbing.png", + "image/mode/boss/card/shufazijinguan.png", + "image/mode/boss/card/wushuangfangtianji.png", + "image/mode/boss/card/xiuluolianyuji.png", + "image/mode/boss/card/xuwangzhimian.png", + "image/mode/boss/card/yihuajiemu.png", + "image/mode/boss/card/qicaishenlu.png", + "image/mode/boss/card/longfenghemingjian.png", + "image/mode/boss/card/boss_mengpohuihun.png", + "image/mode/boss/card/gubuzifeng.png", + "image/mode/boss/card/jinwuluorigong.png", + "image/mode/boss/card/lingsheji.png", + "image/mode/boss/card/shanrangzhaoshu.png", + "image/mode/boss/card/xingtianpojunfu.png", + "image/mode/boss/card/niaobaidaowenha.png", + + "image/mode/boss/character/boss_baihu.jpg", + "image/mode/boss/character/boss_baimangshilian.jpg", + "image/mode/boss/character/boss_baiwuchang.jpg", + "image/mode/boss/character/boss_bianchengwang.jpg", + "image/mode/boss/character/boss_bifang.jpg", + "image/mode/boss/character/boss_caiwenji.jpg", + "image/mode/boss/character/boss_caocao.jpg", + "image/mode/boss/character/boss_chi.jpg", + "image/mode/boss/character/boss_chiyanshilian.jpg", + "image/mode/boss/character/boss_chujiangwang.jpg", + "image/mode/boss/character/boss_diaochan.jpg", + "image/mode/boss/character/boss_dizangwang.jpg", + "image/mode/boss/character/boss_dongzhuo.jpg", + "image/mode/boss/character/boss_dushiwang.jpg", + "image/mode/boss/character/boss_guojia.jpg", + "image/mode/boss/character/boss_heiwuchang.jpg", + "image/mode/boss/character/boss_huangyueying.jpg", + "image/mode/boss/character/boss_huatuo.jpg", + "image/mode/boss/character/boss_hundun.jpg", + "image/mode/boss/character/boss_huoshenzhurong.jpg", + "image/mode/boss/character/boss_jinshenrushou.jpg", + "image/mode/boss/character/boss_liang.jpg", + "image/mode/boss/character/boss_liubei.jpg", + "image/mode/boss/character/boss_luocha.jpg", + "image/mode/boss/character/boss_luxun.jpg", + "image/mode/boss/character/boss_lvbu1.jpg", + "image/mode/boss/character/boss_lvbu2.jpg", + "image/mode/boss/character/boss_lvbu3.jpg", + "image/mode/boss/character/boss_mamian.jpg", + "image/mode/boss/character/boss_mengpo.jpg", + "image/mode/boss/character/boss_mingxingzhu.jpg", + "image/mode/boss/character/boss_mo.jpg", + "image/mode/boss/character/boss_mushengoumang.jpg", + "image/mode/boss/character/boss_nianshou.jpg", + "image/mode/boss/character/boss_nianshou_baonu.jpg", + "image/mode/boss/character/boss_nianshou_heti.jpg", + "image/mode/boss/character/boss_nianshou_jingjue.jpg", + "image/mode/boss/character/boss_nianshou_renxing.jpg", + "image/mode/boss/character/boss_nianshou_ruizhi.jpg", + "image/mode/boss/character/boss_niutou.jpg", + "image/mode/boss/character/boss_pangtong.jpg", + "image/mode/boss/character/boss_pingdengwang.jpg", + "image/mode/boss/character/boss_qinglong.jpg", + "image/mode/boss/character/boss_qingmushilian.jpg", + "image/mode/boss/character/boss_qinguangwang.jpg", + "image/mode/boss/character/boss_qiongqi.jpg", + "image/mode/boss/character/boss_satan.jpg", + "image/mode/boss/character/boss_shaohao.jpg", + "image/mode/boss/character/boss_shuijing.jpg", + "image/mode/boss/character/boss_shuishengonggong.jpg", + "image/mode/boss/character/boss_shuishenxuanming.jpg", + "image/mode/boss/character/boss_shujing.jpg", + "image/mode/boss/character/boss_songdiwang.jpg", + "image/mode/boss/character/boss_sunshangxiang.jpg", + "image/mode/boss/character/boss_taihao.jpg", + "image/mode/boss/character/boss_taishanwang.jpg", + "image/mode/boss/character/boss_taotie.jpg", + "image/mode/boss/character/boss_taowu.jpg", + "image/mode/boss/character/boss_wang.jpg", + "image/mode/boss/character/boss_wuguanwang.jpg", + "image/mode/boss/character/boss_xiangliu.jpg", + "image/mode/boss/character/boss_xuanlinshilian.jpg", + "image/mode/boss/character/boss_xuanwu.jpg", + "image/mode/boss/character/boss_yandi.jpg", + "image/mode/boss/character/boss_yanling.jpg", + "image/mode/boss/character/boss_yanluowang.jpg", + "image/mode/boss/character/boss_yecha.jpg", + "image/mode/boss/character/boss_yingzhao.jpg", + "image/mode/boss/character/boss_yuji.jpg", + "image/mode/boss/character/boss_zhangchunhua.jpg", + "image/mode/boss/character/boss_zhangjiao.jpg", + "image/mode/boss/character/boss_zhenji.jpg", + "image/mode/boss/character/boss_zhouyu.jpg", + "image/mode/boss/character/boss_zhuanlunwang.jpg", + "image/mode/boss/character/boss_zhuanxu.jpg", + "image/mode/boss/character/boss_zhugeliang.jpg", + "image/mode/boss/character/boss_zhuoguiquxie.jpg", + "image/mode/boss/character/boss_zhuque.jpg", + "image/mode/boss/character/boss_zhuyan.jpg", + "image/mode/boss/character/boss_zhuyin.jpg", + "image/mode/boss/character/boss_zuoci.jpg", + + "image/mode/chess/card/chess_chuzhang.png", + "image/mode/chess/card/chess_shezhang.png", + "image/mode/chess/character/chess_beimingjukun.jpg", + "image/mode/chess/character/chess_caocao.jpg", + "image/mode/chess/character/chess_diaochan.jpg", + "image/mode/chess/character/chess_dongzhuo.jpg", + "image/mode/chess/character/chess_huangzhong.jpg", + "image/mode/chess/character/chess_huatuo.jpg", + "image/mode/chess/character/chess_jinchidiao.jpg", + "image/mode/chess/character/chess_sunshangxiang.jpg", + "image/mode/chess/character/chess_taishici.jpg", + "image/mode/chess/character/chess_wuzhaojinlong.jpg", + "image/mode/chess/character/chess_xingtian.jpg", + "image/mode/chess/character/chess_zhangliao.jpg", + "image/mode/chess/character/leader_caocao.jpg", + "image/mode/chess/character/leader_liubei.jpg", + "image/mode/chess/character/leader_sunquan.jpg", + "image/mode/chess/character/leader_yuri.jpg", + "image/mode/chess/difficulty/leader_easy.jpg", + "image/mode/chess/difficulty/leader_hard.jpg", + "image/mode/chess/difficulty/leader_medium.jpg", + "image/mode/stone/card/spell_ansezhadan.jpg", + "image/mode/stone/card/spell_anyingkuangluan.jpg", + "image/mode/stone/card/spell_anyinglieyan.jpg", + "image/mode/stone/card/spell_anyingxingtai.jpg", + "image/mode/stone/card/spell_anzhongpohuai.jpg", + "image/mode/stone/card/spell_aoshufeidan.jpg", + "image/mode/stone/card/spell_aoshuzhihui.jpg", + "image/mode/stone/card/spell_baofengxue.jpg", + "image/mode/stone/card/spell_beici.jpg", + "image/mode/stone/card/spell_bianxingshu.jpg", + "image/mode/stone/card/spell_bingdong.jpg", + "image/mode/stone/card/spell_binghuan.jpg", + "image/mode/stone/card/spell_canying.jpg", + "image/mode/stone/card/spell_chazhuangshandian.jpg", + "image/mode/stone/card/spell_chenmo.jpg", + "image/mode/stone/card/spell_chirehuoba.jpg", + "image/mode/stone/card/spell_chongfeng.jpg", + "image/mode/stone/card/spell_cigu.jpg", + "image/mode/stone/card/spell_cisha.jpg", + "image/mode/stone/card/spell_conglinzhihun.jpg", + "image/mode/stone/card/spell_daoshan.jpg", + "image/mode/stone/card/spell_diyulieyan.jpg", + "image/mode/stone/card/spell_dubiao.jpg", + "image/mode/stone/card/spell_dunpaimengji.jpg", + "image/mode/stone/card/spell_duochongsheji.jpg", + "image/mode/stone/card/spell_emozhinu.jpg", + "image/mode/stone/card/spell_emozhixin.jpg", + "image/mode/stone/card/spell_enzeshu.jpg", + "image/mode/stone/card/spell_fengnu.jpg", + "image/mode/stone/card/spell_fengxian.jpg", + "image/mode/stone/card/spell_fennu.jpg", + "image/mode/stone/card/spell_fennuzhichui.jpg", + "image/mode/stone/card/spell_fuchoudaji.jpg", + "image/mode/stone/card/spell_fuchouzhinu.jpg", + "image/mode/stone/card/spell_fugen.jpg", + "image/mode/stone/card/spell_fushishu.jpg", + "image/mode/stone/card/spell_guanmenfanggou.jpg", + "image/mode/stone/card/spell_hanbingjian.jpg", + "image/mode/stone/card/spell_hanbingpingzhang.jpg", + "image/mode/stone/card/spell_heiandiyu.jpg", + "image/mode/stone/card/spell_heianqiyue.jpg", + "image/mode/stone/card/spell_hengsao.jpg", + "image/mode/stone/card/spell_huoqiushu.jpg", + "image/mode/stone/card/spell_huotigenxu.jpg", + "image/mode/stone/card/spell_jianrenluanwu.jpg", + "image/mode/stone/card/spell_jingshenkongzhi.jpg", + "image/mode/stone/card/spell_jingxiang.jpg", + "image/mode/stone/card/spell_jinyingduijue.jpg", + "image/mode/stone/card/spell_jipao.jpg", + "image/mode/stone/card/spell_juemingluandou.jpg", + "image/mode/stone/card/spell_kongxinshu.jpg", + "image/mode/stone/card/spell_kuaisusheji.jpg", + "image/mode/stone/card/spell_kuaisuzhiliao.jpg", + "image/mode/stone/card/spell_kuangbao.jpg", + "image/mode/stone/card/spell_laojiuhuoba.jpg", + "image/mode/stone/card/spell_lianhuanbaolie.jpg", + "image/mode/stone/card/spell_lierenyinji.jpg", + "image/mode/stone/card/spell_lieyanfengbao.jpg", + "image/mode/stone/card/spell_liliangdaijia.jpg", + "image/mode/stone/card/spell_liliangzhufu.jpg", + "image/mode/stone/card/spell_linghunhongxi.jpg", + "image/mode/stone/card/spell_maizang.jpg", + "image/mode/stone/card/spell_mengun.jpg", + "image/mode/stone/card/spell_modaoyou.jpg", + "image/mode/stone/card/spell_morizaihuo.jpg", + "image/mode/stone/card/spell_naluzhiguang.jpg", + "image/mode/stone/card/spell_niuquxukong.jpg", + "image/mode/stone/card/spell_nuhuozhongshao.jpg", + "image/mode/stone/card/spell_nuxi.jpg", + "image/mode/stone/card/spell_piaoqie.jpg", + "image/mode/stone/card/spell_qiangfengsheji.jpg", + "image/mode/stone/card/spell_rongyanbaolie.jpg", + "image/mode/stone/card/spell_sanghunzhao.jpg", + "image/mode/stone/card/spell_shalumingling.jpg", + "image/mode/stone/card/spell_shandianfengbao.jpg", + "image/mode/stone/card/spell_shengerpingdeng.jpg", + "image/mode/stone/card/spell_shengguangzhadan.jpg", + "image/mode/stone/card/spell_shengliaoshu.jpg", + "image/mode/stone/card/spell_shenpan.jpg", + "image/mode/stone/card/spell_shenshengfennu.jpg", + "image/mode/stone/card/spell_shenshengxinxing.jpg", + "image/mode/stone/card/spell_shihuawuqi.jpg", + "image/mode/stone/card/spell_shixue.jpg", + "image/mode/stone/card/spell_sijidaifa.jpg", + "image/mode/stone/card/spell_siwangchanrao.jpg", + "image/mode/stone/card/spell_tanxianmao.jpg", + "image/mode/stone/card/spell_tianjiangzhuqun.jpg", + "image/mode/stone/card/spell_wangzhezhufu.jpg", + "image/mode/stone/card/spell_weijisifu.jpg", + "image/mode/stone/card/spell_wuyashenxiang.jpg", + "image/mode/stone/card/spell_xianzuzhaohuan.jpg", + "image/mode/stone/card/spell_xianzuzhihun.jpg", + "image/mode/stone/card/spell_xianzuzhiliao.jpg", + "image/mode/stone/card/spell_xianzuzhishi.jpg", + "image/mode/stone/card/spell_xiaoguibaopo.jpg", + "image/mode/stone/card/spell_xiaoshi.jpg", + "image/mode/stone/card/spell_xingchenzhuiluo.jpg", + "image/mode/stone/card/spell_xinlinghanbao.jpg", + "image/mode/stone/card/spell_xinlingshijie.jpg", + "image/mode/stone/card/spell_xishengqiyue.jpg", + "image/mode/stone/card/spell_xuanfengzhan.jpg", + "image/mode/stone/card/spell_yanbaoshu.jpg", + "image/mode/stone/card/spell_yanmie.jpg", + "image/mode/stone/card/spell_yaoshu.jpg", + "image/mode/stone/card/spell_yemanpaoxiao.jpg", + "image/mode/stone/card/spell_yexingchengzhang.jpg", + "image/mode/stone/card/spell_yexinglanghun.jpg", + "image/mode/stone/card/spell_yingyongdaji.jpg", + "image/mode/stone/card/spell_yongshizhufu.jpg", + "image/mode/stone/card/spell_zhandounuhuo.jpg", + "image/mode/stone/card/spell_zhansha.jpg", + "image/mode/stone/card/spell_zhaohuanchongwu.jpg", + "image/mode/stone/card/spell_zhengqianghaosheng.jpg", + "image/mode/stone/card/spell_zhenyanshu.jpg", + "image/mode/stone/card/spell_zhihuizhufu.jpg", + "image/mode/stone/card/spell_zhiliaoshui.jpg", + "image/mode/stone/card/spell_zhiliaozhichu.jpg", + "image/mode/stone/card/spell_zhiliaozhihuan.jpg", + "image/mode/stone/card/spell_zhongnian.jpg", + "image/mode/stone/card/spell_zhuizongshu.jpg", + "image/mode/stone/card/spell_zhumo.jpg", + "image/mode/stone/card/spell_zidanshangtang.jpg", + "image/mode/stone/card/spell_ziranzhili.jpg", + "image/mode/stone/card/spell_ziyang.jpg", + "image/mode/stone/card/spell_zuozhandongyuan.jpg", + "image/mode/stone/card/spell_zuzhou.jpg", + "image/mode/stone/career/druid.png", + "image/mode/stone/career/hunter.png", + "image/mode/stone/career/knight.png", + "image/mode/stone/career/mage.png", + "image/mode/stone/career/paladin.png", + "image/mode/stone/career/priest.png", + "image/mode/stone/career/rogue.png", + "image/mode/stone/career/shaman.png", + "image/mode/stone/career/warlock.png", + "image/mode/stone/career/warrior.png", + "image/mode/stone/character/stone_aidewen.jpg", + "image/mode/stone/character/stone_aihaozhihun.jpg", + "image/mode/stone/character/stone_alaikesita.jpg", + "image/mode/stone/character/stone_andongni.jpg", + "image/mode/stone/character/stone_anyingzisi.jpg", + "image/mode/stone/character/stone_aolajier.jpg", + "image/mode/stone/character/stone_aomishouwei.jpg", + "image/mode/stone/character/stone_aoshushi.jpg", + "image/mode/stone/character/stone_baohuzhishu.jpg", + "image/mode/stone/character/stone_baoqishi.jpg", + "image/mode/stone/character/stone_baoweizhe.jpg", + "image/mode/stone/character/stone_beijunmushi.jpg", + "image/mode/stone/character/stone_caoyuanshi.jpg", + "image/mode/stone/character/stone_chidunshinv.jpg", + "image/mode/stone/character/stone_chidunweishi.jpg", + "image/mode/stone/character/stone_chilundashi.jpg", + "image/mode/stone/character/stone_cike.jpg", + "image/mode/stone/character/stone_conglinshouwei.jpg", + "image/mode/stone/character/stone_conglinxiaoshou.jpg", + "image/mode/stone/character/stone_damoshatuo.jpg", + "image/mode/stone/character/stone_daomufeizei.jpg", + "image/mode/stone/character/stone_dijieshicong.jpg", + "image/mode/stone/character/stone_diyuhuo.jpg", + "image/mode/stone/character/stone_diyuhuox.jpg", + "image/mode/stone/character/stone_duyanhaidao.jpg", + "image/mode/stone/character/stone_fachao.jpg", + "image/mode/stone/character/stone_falifulong.jpg", + "image/mode/stone/character/stone_famingjia.jpg", + "image/mode/stone/character/stone_faqishi.jpg", + "image/mode/stone/character/stone_fatiaozhuru.jpg", + "image/mode/stone/character/stone_fennuxiaoji.jpg", + "image/mode/stone/character/stone_fuding.jpg", + "image/mode/stone/character/stone_fuhuokaijia.jpg", + "image/mode/stone/character/stone_fukongmoyan.jpg", + "image/mode/stone/character/stone_gangtiewushi.jpg", + "image/mode/stone/character/stone_geluomashi.jpg", + "image/mode/stone/character/stone_guangmingquan.jpg", + "image/mode/stone/character/stone_guangyaozhizi.jpg", + "image/mode/stone/character/stone_guanliyuan.jpg", + "image/mode/stone/character/stone_guiqishi.jpg", + "image/mode/stone/character/stone_haidao.jpg", + "image/mode/stone/character/stone_haidaotoumu.jpg", + "image/mode/stone/character/stone_hanguangzhizhe.jpg", + "image/mode/stone/character/stone_heianjiaotu.jpg", + "image/mode/stone/character/stone_heishitanfan.jpg", + "image/mode/stone/character/stone_heitieairen.jpg", + "image/mode/stone/character/stone_heiyaoyaoshou.jpg", + "image/mode/stone/character/stone_honglongyongshi.jpg", + "image/mode/stone/character/stone_huangjialeixiang.jpg", + "image/mode/stone/character/stone_huangyeqishi.jpg", + "image/mode/stone/character/stone_hudunren.jpg", + "image/mode/stone/character/stone_huofu.jpg", + "image/mode/stone/character/stone_huoli.jpg", + "image/mode/stone/character/stone_huoqiangshou.jpg", + "image/mode/stone/character/stone_huoshanxiemu.jpg", + "image/mode/stone/character/stone_huoshe.jpg", + "image/mode/stone/character/stone_huoyanweishi.jpg", + "image/mode/stone/character/stone_huoyao.jpg", + "image/mode/stone/character/stone_huoyuansu.jpg", + "image/mode/stone/character/stone_jialakesi.jpg", + "image/mode/stone/character/stone_jialakesix.jpg", + "image/mode/stone/character/stone_jiangong.jpg", + "image/mode/stone/character/stone_jiewangzhu.jpg", + "image/mode/stone/character/stone_jingxiang.jpg", + "image/mode/stone/character/stone_jingyingweishi.jpg", + "image/mode/stone/character/stone_jujishou.jpg", + "image/mode/stone/character/stone_junxuguan.jpg", + "image/mode/stone/character/stone_juxingchanchu.jpg", + "image/mode/stone/character/stone_kaodalalong.jpg", + "image/mode/stone/character/stone_kelushi.jpg", + "image/mode/stone/character/stone_kongjuzhanma.jpg", + "image/mode/stone/character/stone_kuangyedoushi.jpg", + "image/mode/stone/character/stone_kuangzhanshi.jpg", + "image/mode/stone/character/stone_kutongsiseng.jpg", + "image/mode/stone/character/stone_langren.jpg", + "image/mode/stone/character/stone_lansaizhanshi.jpg", + "image/mode/stone/character/stone_leiouke.jpg", + "image/mode/stone/character/stone_liebao.jpg", + "image/mode/stone/character/stone_liegou.jpg", + "image/mode/stone/character/stone_liewangshouwei.jpg", + "image/mode/stone/character/stone_lieyanxiaogui.jpg", + "image/mode/stone/character/stone_lifaji.jpg", + "image/mode/stone/character/stone_lindishuyao.jpg", + "image/mode/stone/character/stone_linghunjisi.jpg", + "image/mode/stone/character/stone_longmianjiaoguan.jpg", + "image/mode/stone/character/stone_longwangpeiou.jpg", + "image/mode/stone/character/stone_mafengzhuru.jpg", + "image/mode/stone/character/stone_maligousi.jpg", + "image/mode/stone/character/stone_meimo.jpg", + "image/mode/stone/character/stone_mengmaren.jpg", + "image/mode/stone/character/stone_mianyang.jpg", + "image/mode/stone/character/stone_mingguangjisi.jpg", + "image/mode/stone/character/stone_misha.jpg", + "image/mode/stone/character/stone_morishouwei.jpg", + "image/mode/stone/character/stone_muguangchulong.jpg", + "image/mode/stone/character/stone_muyangren.jpg", + "image/mode/stone/character/stone_nianqingjisi.jpg", + "image/mode/stone/character/stone_nuoziduomu.jpg", + "image/mode/stone/character/stone_peilianshi.jpg", + "image/mode/stone/character/stone_qiezei.jpg", + "image/mode/stone/character/stone_qingwa.jpg", + "image/mode/stone/character/stone_renyaqishi.jpg", + "image/mode/stone/character/stone_sainaliusi.jpg", + "image/mode/stone/character/stone_senlinlang.jpg", + "image/mode/stone/character/stone_shachuisaman.jpg", + "image/mode/stone/character/stone_shalinxingzhe.jpg", + "image/mode/stone/character/stone_shengdianzhishi.jpg", + "image/mode/stone/character/stone_shengguanghuwei.jpg", + "image/mode/stone/character/stone_shengjiachong.jpg", + "image/mode/stone/character/stone_shenmiqishou.jpg", + "image/mode/stone/character/stone_shenshengyongshi.jpg", + "image/mode/stone/character/stone_shifazhe.jpg", + "image/mode/stone/character/stone_shihualong.jpg", + "image/mode/stone/character/stone_shishigui.jpg", + "image/mode/stone/character/stone_shixiangweishi.jpg", + "image/mode/stone/character/stone_shuiyuansu.jpg", + "image/mode/stone/character/stone_shumiao.jpg", + "image/mode/stone/character/stone_shuren.jpg", + "image/mode/stone/character/stone_shurenx.jpg", + "image/mode/stone/character/stone_shurenxx.jpg", + "image/mode/stone/character/stone_siwangzhiyi.jpg", + "image/mode/stone/character/stone_suoxiaojishi.jpg", + "image/mode/stone/character/stone_tegong.jpg", + "image/mode/stone/character/stone_tongkunvwang.jpg", + "image/mode/stone/character/stone_tujiu.jpg", + "image/mode/stone/character/stone_tuteng1.jpg", + "image/mode/stone/character/stone_tuteng2.jpg", + "image/mode/stone/character/stone_tuteng3.jpg", + "image/mode/stone/character/stone_tuteng4.jpg", + "image/mode/stone/character/stone_tutengshi.jpg", + "image/mode/stone/character/stone_tutengyongshi.jpg", + "image/mode/stone/character/stone_tuyuansu.jpg", + "image/mode/stone/character/stone_wanshiyuansu.jpg", + "image/mode/stone/character/stone_weilun.jpg", + "image/mode/stone/character/stone_wujiyuansu.jpg", + "image/mode/stone/character/stone_wushixuetu.jpg", + "image/mode/stone/character/stone_wuyi.jpg", + "image/mode/stone/character/stone_xiaogui.jpg", + "image/mode/stone/character/stone_xiaoguishouling.jpg", + "image/mode/stone/character/stone_xiaojingling.jpg", + "image/mode/stone/character/stone_xinbing.jpg", + "image/mode/stone/character/stone_xiushuihaidao.jpg", + "image/mode/stone/character/stone_xuefanzhanshi.jpg", + "image/mode/stone/character/stone_xuejuren.jpg", + "image/mode/stone/character/stone_xukongkongmo.jpg", + "image/mode/stone/character/stone_xukongxingzhe.jpg", + "image/mode/stone/character/stone_xulingwushi.jpg", + "image/mode/stone/character/stone_xunmashi.jpg", + "image/mode/stone/character/stone_xunmenglong.jpg", + "image/mode/stone/character/stone_xunshoushi.jpg", + "image/mode/stone/character/stone_yanjingshe.jpg", + "image/mode/stone/character/stone_yanshushi.jpg", + "image/mode/stone/character/stone_yaosaishouwei.jpg", + "image/mode/stone/character/stone_yingxiongzhihun.jpg", + "image/mode/stone/character/stone_yisela.jpg", + "image/mode/stone/character/stone_youlinglang.jpg", + "image/mode/stone/character/stone_yuanguanying.jpg", + "image/mode/stone/character/stone_yuanhou.jpg", + "image/mode/stone/character/stone_yurenqishi.jpg", + "image/mode/stone/character/stone_zhaohuanzhe.jpg", + "image/mode/stone/character/stone_zhifuzhe.jpg", + "image/mode/stone/character/stone_zhihuiguan.jpg", + "image/mode/stone/character/stone_zhiyuzhe.jpg", + "image/mode/stone/character/stone_zhongshi.jpg", + "image/mode/stone/character/stone_zhucangzhe.jpg", + "image/mode/stone/character/stone_zhujiashi.jpg", + "image/mode/stone/character/stone_zhumo.jpg", + "image/mode/stone/character/stone_zongxiong.jpg", + "image/mode/stone/character/stone_zousishangfan.jpg", + "image/mode/tafang/character/tafang_mech_dubiaoxianjing.jpg", + "image/mode/tafang/character/tafang_mech_gongchengche.jpg", + "image/mode/tafang/character/tafang_mech_guangmingquan.jpg", + "image/mode/tafang/character/tafang_mech_jiguanren.jpg", + "image/mode/tafang/character/tafang_mech_jiqishi.jpg", + "image/mode/tafang/character/tafang_mech_mutong.jpg", + "image/mode/tafang/character/tafang_mech_nengliangqiu.jpg", + "image/mode/tafang/character/tafang_mech_shanggukanshou.jpg", + "image/mode/tafang/character/tafang_mech_shenmidiaoxiang.jpg", + "image/mode/tafang/character/tafang_mech_shenpanxianjing.jpg", + "image/mode/tafang/character/tafang_mech_shiyuansu.jpg", + "image/mode/tafang/character/tafang_mech_toushiche.jpg", + "image/mode/tafang/character/tafang_mech_tutengzhen.jpg", + "image/mode/tafang/character/tafang_mech_weixingxianjing.jpg", + "image/mode/tafang/character/tafang_mech_wuyashenxiang.jpg", + "image/mode/versus/character/boss_chiyuzhuque.jpg", + "image/mode/versus/character/boss_duanyuzhongda.jpg", + "image/mode/versus/character/boss_fudibian.jpg", + "image/mode/versus/character/boss_gongshenyueying.jpg", + "image/mode/versus/character/boss_jiarenzidan.jpg", + "image/mode/versus/character/boss_jileibaihu.jpg", + "image/mode/versus/character/boss_juechenmiaocai.jpg", + "image/mode/versus/character/boss_liedixuande.jpg", + "image/mode/versus/character/boss_lieshiyazi.jpg", + "image/mode/versus/character/boss_lingjiaxuanwu.jpg", + "image/mode/versus/character/boss_qiaokuijunyi.jpg", + "image/mode/versus/character/boss_shihuosuanni.jpg", + "image/mode/versus/character/boss_tianhoukongming.jpg", + "image/mode/versus/character/boss_tuntianchiwen.jpg", + "image/mode/versus/character/boss_yuhuoshiyuan.jpg", + "image/mode/versus/character/boss_yunpingqinglong.jpg", + "image/mode/versus/character/boss_baijiwenyuan.jpg", + "image/mode/versus/character/boss_fuweizilong.jpg", + "image/mode/versus/character/boss_kumuyuanrang.jpg", + "image/mode/versus/character/boss_yihanyunchang.jpg", + "image/mode/versus/character/liuqi.jpg", + "image/mode/versus/character/tangzi.jpg", + + /*splash image begin*/ + "image/splash/style1.jpg", + "image/splash/style2.jpg", + "image/splash/style1/boss.jpg", + "image/splash/style1/brawl.jpg", + "image/splash/style1/chess.jpg", + "image/splash/style1/connect.jpg", + "image/splash/style1/doudizhu.jpg", + "image/splash/style1/guozhan.jpg", + "image/splash/style1/identity.jpg", + "image/splash/style1/single.jpg", + "image/splash/style1/stone.jpg", + "image/splash/style1/tafang.jpg", + "image/splash/style1/versus.jpg", + "image/splash/style2/boss.jpg", + "image/splash/style2/brawl.jpg", + "image/splash/style2/chess.jpg", + "image/splash/style2/connect.jpg", + "image/splash/style2/doudizhu.jpg", + "image/splash/style2/guozhan.jpg", + "image/splash/style2/identity.jpg", + "image/splash/style2/single.jpg", + "image/splash/style2/stone.jpg", + "image/splash/style2/tafang.jpg", + "image/splash/style2/versus.jpg", + /*splash image end*/ + + "theme/music/grid.png", + "theme/music/wood.png", + "theme/music/wood3.png", + "theme/simple/card.png", + "theme/simple/card2.png", + "theme/simple/grid.png", + "theme/simple/unknown.png", + "theme/simple/wood.png", + "theme/simple/wood3.png", + "theme/style/card/image/border_bronze.jpg", + "theme/style/card/image/border_gold.jpg", + "theme/style/card/image/border_map.jpg", + "theme/style/card/image/border_silver.jpg", + "theme/style/card/image/border_wood.jpg", + "theme/style/card/image/new.png", + "theme/style/card/image/ol.png", + "theme/style/cardback/image/feicheng.png", + "theme/style/cardback/image/feicheng2.png", + "theme/style/cardback/image/liusha.png", + "theme/style/cardback/image/liusha2.png", + "theme/style/cardback/image/new.png", + "theme/style/cardback/image/new2.png", + "theme/style/cardback/image/official.png", + "theme/style/cardback/image/official2.png", + "theme/style/cardback/image/ol.png", + "theme/style/cardback/image/ol2.png", + "theme/style/hp/image/emotion1.png", + "theme/style/hp/image/emotion2.png", + "theme/style/hp/image/emotion3.png", + "theme/style/hp/image/emotion4.png", + "theme/style/hp/image/glass1.png", + "theme/style/hp/image/glass2.png", + "theme/style/hp/image/glass3.png", + "theme/style/hp/image/glass4.png", + "theme/style/hp/image/official1.png", + "theme/style/hp/image/official2.png", + "theme/style/hp/image/official3.png", + "theme/style/hp/image/official4.png", + "theme/style/hp/image/ol1.png", + "theme/style/hp/image/ol2.png", + "theme/style/hp/image/ol3.png", + "theme/style/hp/image/ol4.png", + "theme/style/hp/image/round1.png", + "theme/style/hp/image/round2.png", + "theme/style/hp/image/round3.png", + "theme/style/hp/image/round4.png", + "theme/style/player/bronze1.png", + "theme/style/player/bronze2.png", + "theme/style/player/bronze3.png", + "theme/style/player/bronze_d1.png", + "theme/style/player/bronze_d2.png", + "theme/style/player/gold1.png", + "theme/style/player/gold2.png", + "theme/style/player/gold3.png", + "theme/style/player/gold_d1.png", + "theme/style/player/gold_d2.png", + "theme/style/player/silver1.png", + "theme/style/player/silver2.png", + "theme/style/player/silver3.png", + "theme/style/player/silver_d1.png", + "theme/style/player/silver_d2.png", + "theme/woodden/grid.png", + "theme/woodden/wood.jpg", + "theme/woodden/wood.png", + "theme/woodden/wood2.jpg", + "theme/woodden/wood2.png", +]; +window.noname_skin_list = {}; diff --git a/game/canUse.ts b/game/canUse.ts index 4f3678080..13e08568d 100644 --- a/game/canUse.ts +++ b/game/canUse.ts @@ -1,4 +1,4 @@ // apk每次安装后第一次启动加载Service Worker会失败 // 所以每次导入这个ts判断是否会成功,失败的话重启一次 -export const text: string = 'ts文件导入成功'; \ No newline at end of file +export const text: string = "ts文件导入成功"; diff --git a/game/codemirror.js b/game/codemirror.js index c25437c24..82ac6d5c1 100644 --- a/game/codemirror.js +++ b/game/codemirror.js @@ -1,10458 +1,10458 @@ - -function getDocumentZoom() { - //一般body的缩放是xy同步的 - var transform = getComputedStyle(document.body).transform; - // @ts-ignore - if (transform == 'none') transform = 1; - // @ts-ignore - else transform = +transform.slice(7, -1).split(',')[0]; - return +transform; -} - -// BROWSER SNIFFING - -// Kludges for bugs and behavior differences that can't be feature -// detected are enabled based on userAgent etc sniffing. -var userAgent = navigator.userAgent; -var platform = navigator.platform; - -var gecko = /gecko\/\d/i.test(userAgent); -var ie_upto10 = /MSIE \d/.test(userAgent); -var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); -var ie = ie_upto10 || ie_11up; -// @ts-ignore -var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); -var webkit = /WebKit\//.test(userAgent); -var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); -var chrome = /Chrome\//.test(userAgent); -var presto = /Opera\//.test(userAgent); -var safari = /Apple Computer/.test(navigator.vendor); -var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); -var phantom = /PhantomJS/.test(userAgent); - -var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); -// This is woefully incomplete. Suggestions for alternative methods welcome. -var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); -var mac = ios || /Mac/.test(platform); -var chromeOS = /\bCrOS\b/.test(userAgent); -var windows = /win/i.test(platform); - -var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/); -// @ts-ignore -if (presto_version) presto_version = Number(presto_version[1]); -// @ts-ignore -if (presto_version && presto_version >= 15) { presto = false; webkit = true; } -// Some browsers use the wrong event properties to signal cmd/ctrl on OS X -// @ts-ignore -var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); -var captureRightClick = gecko || (ie && ie_version >= 9); - -// Optimize some code when these features are not used. -var sawReadOnlySpans = false, sawCollapsedSpans = false; - -// EDITOR CONSTRUCTOR - -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - -// This is CodeMirror (http://codemirror.net), a code editor -// implemented in JavaScript on top of the browser's DOM. -// -// You can find some technical background for some of the code below -// at http://marijnhaverbeke.nl/blog/#cm-internals . - -/** - * @type { typeof import('codemirror/index') } - */ -// @ts-ignore -var CodeMirror = (function () { - - // A CodeMirror instance represents an editor. This is the object - // that user code is usually dealing with. - - function CodeMirror(place, options) { - if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); - - this.options = options = options ? copyObj(options) : {}; - // Determine effective options based on given values and defaults. - copyObj(defaults, options, false); - setGuttersForLineNumbers(options); - - var doc = options.value; - if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator); - this.doc = doc; - - var input = new CodeMirror.inputStyles[options.inputStyle](this); - var display = this.display = new Display(place, doc, input); - display.wrapper.CodeMirror = this; - updateGutters(this); - themeChanged(this); - if (options.lineWrapping) - this.display.wrapper.className += " CodeMirror-wrap"; - if (options.autofocus && !mobile) display.input.focus(); - initScrollbars(this); - - this.state = { - keyMaps: [], // stores maps added by addKeyMap - overlays: [], // highlighting overlays, as added by addOverlay - modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info - overwrite: false, - delayingBlurEvent: false, - focused: false, - suppressEdits: false, // used to disable editing during key handlers when in readOnly mode - pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll - selectingText: false, - draggingText: false, - highlight: new Delayed(), // stores highlight worker timeout - keySeq: null, // Unfinished key sequence - specialChars: null - }; - - var cm = this; - - // Override magic textarea content restore that IE sometimes does - // on our hidden textarea on reload - if (ie && ie_version < 11) setTimeout(function () { cm.display.input.reset(true); }, 20); - - registerEventHandlers(this); - ensureGlobalHandlers(); - - startOperation(this); - this.curOp.forceUpdate = true; - attachDoc(this, doc); - - if ((options.autofocus && !mobile) || cm.hasFocus()) - setTimeout(bind(onFocus, this), 20); - else - onBlur(this); - - for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) - optionHandlers[opt](this, options[opt], Init); - maybeUpdateLineNumberWidth(this); - if (options.finishInit) options.finishInit(this); - for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); - endOperation(this); - // Suppress optimizelegibility in Webkit, since it breaks text - // measuring on line wrapping boundaries. - if (webkit && options.lineWrapping && - getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") - display.lineDiv.style.textRendering = "auto"; - } - - // DISPLAY CONSTRUCTOR - - // The display handles the DOM integration, both for input reading - // and content drawing. It holds references to DOM nodes and - // display-related state. - - function Display(place, doc, input) { - var d = this; - this.input = input; - - // Covers bottom-right square when both scrollbars are present. - d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); - d.scrollbarFiller.setAttribute("cm-not-content", "true"); - // Covers bottom of gutter when coverGutterNextToScrollbar is on - // and h scrollbar is present. - d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); - d.gutterFiller.setAttribute("cm-not-content", "true"); - // Will contain the actual code, positioned to cover the viewport. - d.lineDiv = elt("div", null, "CodeMirror-code"); - // Elements are added to these to represent selection and cursors. - d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); - d.cursorDiv = elt("div", null, "CodeMirror-cursors"); - // A visibility: hidden element used to find the size of things. - d.measure = elt("div", null, "CodeMirror-measure"); - // When lines outside of the viewport are measured, they are drawn in this. - d.lineMeasure = elt("div", null, "CodeMirror-measure"); - // Wraps everything that needs to exist inside the vertically-padded coordinate system - d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], - null, "position: relative; outline: none"); - // Moved around its parent to cover visible view. - d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); - // Set to the height of the document, allowing scrolling. - d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); - d.sizerWidth = null; - // Behavior of elts with overflow: auto and padding is - // inconsistent across browsers. This is used to ensure the - // scrollable area is big enough. - d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); - // Will contain the gutters, if any. - d.gutters = elt("div", null, "CodeMirror-gutters"); - d.lineGutter = null; - // Actual scrollable element. - d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); - d.scroller.setAttribute("tabIndex", "-1"); - // The element in which the editor lives. - d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); - - // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) - if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } - if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; - - if (place) { - if (place.appendChild) place.appendChild(d.wrapper); - else place(d.wrapper); - } - - // Current rendered range (may be bigger than the view window). - d.viewFrom = d.viewTo = doc.first; - d.reportedViewFrom = d.reportedViewTo = doc.first; - // Information about the rendered lines. - d.view = []; - d.renderedView = null; - // Holds info about a single rendered line when it was rendered - // for measurement, while not in view. - d.externalMeasured = null; - // Empty space (in pixels) above the view - d.viewOffset = 0; - d.lastWrapHeight = d.lastWrapWidth = 0; - d.updateLineNumbers = null; - - d.nativeBarWidth = d.barHeight = d.barWidth = 0; - d.scrollbarsClipped = false; - - // Used to only resize the line number gutter when necessary (when - // the amount of lines crosses a boundary that makes its width change) - d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; - // Set to true when a non-horizontal-scrolling line widget is - // added. As an optimization, line widget aligning is skipped when - // this is false. - d.alignWidgets = false; - - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; - - // Tracks the maximum line length so that the horizontal scrollbar - // can be kept static when scrolling. - d.maxLine = null; - d.maxLineLength = 0; - d.maxLineChanged = false; - - // Used for measuring wheel scrolling granularity - d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; - - // True when shift is held down. - d.shift = false; - - // Used to track whether anything happened since the context menu - // was opened. - d.selForContextMenu = null; - - d.activeTouch = null; - - input.init(d); - } - - // STATE UPDATES - - // Used to get the editor into a consistent state again when options change. - - function loadMode(cm) { - cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); - resetModeState(cm); - } - - function resetModeState(cm) { - cm.doc.iter(function (line) { - if (line.stateAfter) line.stateAfter = null; - if (line.styles) line.styles = null; - }); - cm.doc.frontier = cm.doc.first; - startWorker(cm, 100); - cm.state.modeGen++; - if (cm.curOp) regChange(cm); - } - - function wrappingChanged(cm) { - if (cm.options.lineWrapping) { - addClass(cm.display.wrapper, "CodeMirror-wrap"); - cm.display.sizer.style.minWidth = ""; - cm.display.sizerWidth = null; - } else { - rmClass(cm.display.wrapper, "CodeMirror-wrap"); - findMaxLine(cm); - } - estimateLineHeights(cm); - regChange(cm); - clearCaches(cm); - setTimeout(function () { updateScrollbars(cm); }, 100); - } - - // Returns a function that estimates the height of a line, to use as - // first approximation until the line becomes visible (and is thus - // properly measurable). - function estimateHeight(cm) { - var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; - var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); - return function (line) { - if (lineIsHidden(cm.doc, line)) return 0; - - var widgetsHeight = 0; - if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { - if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; - } - - if (wrapping) - return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; - else - return widgetsHeight + th; - }; - } - - function estimateLineHeights(cm) { - var doc = cm.doc, est = estimateHeight(cm); - doc.iter(function (line) { - var estHeight = est(line); - if (estHeight != line.height) updateLineHeight(line, estHeight); - }); - } - - function themeChanged(cm) { - cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + - cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); - clearCaches(cm); - } - - function guttersChanged(cm) { - updateGutters(cm); - regChange(cm); - setTimeout(function () { alignHorizontally(cm); }, 20); - } - - // Rebuild the gutter elements, ensure the margin to the left of the - // code matches their width. - function updateGutters(cm) { - var gutters = cm.display.gutters, specs = cm.options.gutters; - removeChildren(gutters); - for (var i = 0; i < specs.length; ++i) { - var gutterClass = specs[i]; - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); - if (gutterClass == "CodeMirror-linenumbers") { - cm.display.lineGutter = gElt; - gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; - } - } - gutters.style.display = i ? "" : "none"; - updateGutterSpace(cm); - } - - function updateGutterSpace(cm) { - var width = cm.display.gutters.offsetWidth; - cm.display.sizer.style.marginLeft = width + "px"; - } - - // Compute the character length of a line, taking into account - // collapsed ranges (see markText) that might hide parts, and join - // other lines onto it. - function lineLength(line) { - if (line.height == 0) return 0; - var len = line.text.length, merged, cur = line; - while (merged = collapsedSpanAtStart(cur)) { - var found = merged.find(0, true); - cur = found.from.line; - len += found.from.ch - found.to.ch; - } - cur = line; - while (merged = collapsedSpanAtEnd(cur)) { - var found = merged.find(0, true); - len -= cur.text.length - found.from.ch; - cur = found.to.line; - len += cur.text.length - found.to.ch; - } - return len; - } - - // Find the longest line in the document. - function findMaxLine(cm) { - var d = cm.display, doc = cm.doc; - d.maxLine = getLine(doc, doc.first); - d.maxLineLength = lineLength(d.maxLine); - d.maxLineChanged = true; - doc.iter(function (line) { - var len = lineLength(line); - if (len > d.maxLineLength) { - d.maxLineLength = len; - d.maxLine = line; - } - }); - } - - // Make sure the gutters options contains the element - // "CodeMirror-linenumbers" when the lineNumbers option is true. - function setGuttersForLineNumbers(options) { - var found = indexOf(options.gutters, "CodeMirror-linenumbers"); - if (found == -1 && options.lineNumbers) { - options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); - } else if (found > -1 && !options.lineNumbers) { - options.gutters = options.gutters.slice(0); - options.gutters.splice(found, 1); - } - } - - // SCROLLBARS - - // Prepare DOM reads needed to update the scrollbars. Done in one - // shot to minimize update/measure roundtrips. - function measureForScrollbars(cm) { - var d = cm.display, gutterW = d.gutters.offsetWidth; - var docH = Math.round(cm.doc.height + paddingVert(cm.display)); - return { - clientHeight: d.scroller.clientHeight, - viewHeight: d.wrapper.clientHeight, - scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, - viewWidth: d.wrapper.clientWidth, - barLeft: cm.options.fixedGutter ? gutterW : 0, - docHeight: docH, - scrollHeight: docH + scrollGap(cm) + d.barHeight, - nativeBarWidth: d.nativeBarWidth, - gutterWidth: gutterW - }; - } - - function NativeScrollbars(place, scroll, cm) { - this.cm = cm; - var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); - var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); - place(vert); place(horiz); - - on(vert, "scroll", function () { - if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); - }); - on(horiz, "scroll", function () { - if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); - }); - - this.checkedZeroWidth = false; - // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). - if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; - } - - NativeScrollbars.prototype = copyObj({ - update: function (measure) { - var needsH = measure.scrollWidth > measure.clientWidth + 1; - var needsV = measure.scrollHeight > measure.clientHeight + 1; - var sWidth = measure.nativeBarWidth; - - if (needsV) { - this.vert.style.display = "block"; - this.vert.style.bottom = needsH ? sWidth + "px" : "0"; - var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); - // A bug in IE8 can cause this value to be negative, so guard it. - this.vert.firstChild.style.height = - Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; - } else { - this.vert.style.display = ""; - this.vert.firstChild.style.height = "0"; - } - - if (needsH) { - this.horiz.style.display = "block"; - this.horiz.style.right = needsV ? sWidth + "px" : "0"; - this.horiz.style.left = measure.barLeft + "px"; - var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); - this.horiz.firstChild.style.width = - (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; - } else { - this.horiz.style.display = ""; - this.horiz.firstChild.style.width = "0"; - } - - if (!this.checkedZeroWidth && measure.clientHeight > 0) { - if (sWidth == 0) this.zeroWidthHack(); - this.checkedZeroWidth = true; - } - - return { right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0 }; - }, - setScrollLeft: function (pos) { - if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; - if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz); - }, - setScrollTop: function (pos) { - if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; - if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert); - }, - zeroWidthHack: function () { - var w = mac && !mac_geMountainLion ? "12px" : "18px"; - this.horiz.style.height = this.vert.style.width = w; - this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; - this.disableHoriz = new Delayed; - this.disableVert = new Delayed; - }, - enableZeroWidthBar: function (bar, delay) { - bar.style.pointerEvents = "auto"; - function maybeDisable() { - // To find out whether the scrollbar is still visible, we - // check whether the element under the pixel in the bottom - // left corner of the scrollbar box is the scrollbar box - // itself (when the bar is still visible) or its filler child - // (when the bar is hidden). If it is still visible, we keep - // it enabled, if it's hidden, we disable pointer events. - var box = bar.getBoundingClientRect(); - var elt = document.elementFromPoint(box.left + 1, box.bottom - 1); - if (elt != bar) bar.style.pointerEvents = "none"; - else delay.set(1000, maybeDisable); - } - delay.set(1000, maybeDisable); - }, - clear: function () { - var parent = this.horiz.parentNode; - parent.removeChild(this.horiz); - parent.removeChild(this.vert); - } - }, NativeScrollbars.prototype); - - function NullScrollbars() { } - - NullScrollbars.prototype = copyObj({ - update: function () { return { bottom: 0, right: 0 }; }, - setScrollLeft: function () { }, - setScrollTop: function () { }, - clear: function () { } - }, NullScrollbars.prototype); - - CodeMirror.scrollbarModel = { "native": NativeScrollbars, "null": NullScrollbars }; - - function initScrollbars(cm) { - if (cm.display.scrollbars) { - cm.display.scrollbars.clear(); - if (cm.display.scrollbars.addClass) - rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); - } - - cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function (node) { - cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); - // Prevent clicks in the scrollbars from killing focus - on(node, "mousedown", function () { - if (cm.state.focused) setTimeout(function () { cm.display.input.focus(); }, 0); - }); - node.setAttribute("cm-not-content", "true"); - }, function (pos, axis) { - if (axis == "horizontal") setScrollLeft(cm, pos); - else setScrollTop(cm, pos); - }, cm); - if (cm.display.scrollbars.addClass) - addClass(cm.display.wrapper, cm.display.scrollbars.addClass); - } - - function updateScrollbars(cm, measure) { - if (!measure) measure = measureForScrollbars(cm); - var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; - updateScrollbarsInner(cm, measure); - for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { - if (startWidth != cm.display.barWidth && cm.options.lineWrapping) - updateHeightsInViewport(cm); - updateScrollbarsInner(cm, measureForScrollbars(cm)); - startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; - } - } - - // Re-synchronize the fake scrollbars with the actual size of the - // content. - function updateScrollbarsInner(cm, measure) { - var d = cm.display; - var sizes = d.scrollbars.update(measure); - - d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; - d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; - d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" - - if (sizes.right && sizes.bottom) { - d.scrollbarFiller.style.display = "block"; - d.scrollbarFiller.style.height = sizes.bottom + "px"; - d.scrollbarFiller.style.width = sizes.right + "px"; - } else d.scrollbarFiller.style.display = ""; - if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { - d.gutterFiller.style.display = "block"; - d.gutterFiller.style.height = sizes.bottom + "px"; - d.gutterFiller.style.width = measure.gutterWidth + "px"; - } else d.gutterFiller.style.display = ""; - } - - // Compute the lines that are visible in a given viewport (defaults - // the the current scroll position). viewport may contain top, - // height, and ensure (see op.scrollToPos) properties. - function visibleLines(display, doc, viewport) { - var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; - top = Math.floor(top - paddingTop(display)); - var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; - - var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); - // Ensure is a {from: {line, ch}, to: {line, ch}} object, and - // forces those lines into the viewport (if possible). - if (viewport && viewport.ensure) { - var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; - if (ensureFrom < from) { - from = ensureFrom; - to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); - } else if (Math.min(ensureTo, doc.lastLine()) >= to) { - from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); - to = ensureTo; - } - } - return { from: from, to: Math.max(to, from + 1) }; - } - - // LINE NUMBERS - - // Re-align line numbers and gutter marks to compensate for - // horizontal scrolling. - function alignHorizontally(cm) { - var display = cm.display, view = display.view; - if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; - var gutterW = display.gutters.offsetWidth, left = comp + "px"; - for (var i = 0; i < view.length; i++) if (!view[i].hidden) { - if (cm.options.fixedGutter && view[i].gutter) - view[i].gutter.style.left = left; - var align = view[i].alignable; - if (align) for (var j = 0; j < align.length; j++) - align[j].style.left = left; - } - if (cm.options.fixedGutter) - display.gutters.style.left = (comp + gutterW) + "px"; - } - - // Used to ensure that the line number gutter is still the right - // size for the current document size. Returns true when an update - // is needed. - function maybeUpdateLineNumberWidth(cm) { - if (!cm.options.lineNumbers) return false; - var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; - var documentZoom = getDocumentZoom(); - if (last.length != display.lineNumChars) { - var test = display.measure.appendChild(elt("div", [elt("div", last)], - "CodeMirror-linenumber CodeMirror-gutter-elt")); - var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; - display.lineGutter.style.width = ""; - display.lineNumInnerWidth = (Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1) /* / documentZoom */; - display.lineNumWidth = (display.lineNumInnerWidth + padding) /* / documentZoom */; - display.lineNumChars = (display.lineNumInnerWidth ? last.length : -1) /* / documentZoom */; - display.lineGutter.style.width = display.lineNumWidth + "px"; - updateGutterSpace(cm); - return true; - } - return false; - } - - function lineNumberFor(options, i) { - return String(options.lineNumberFormatter(i + options.firstLineNumber)); - } - - // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, - // but using getBoundingClientRect to get a sub-pixel-accurate - // result. - function compensateForHScroll(display) { - return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; - } - - // DISPLAY DRAWING - - function DisplayUpdate(cm, viewport, force) { - var display = cm.display; - - this.viewport = viewport; - // Store some values that we'll need later (but don't want to force a relayout for) - this.visible = visibleLines(display, cm.doc, viewport); - this.editorIsHidden = !display.wrapper.offsetWidth; - this.wrapperHeight = display.wrapper.clientHeight; - this.wrapperWidth = display.wrapper.clientWidth; - this.oldDisplayWidth = displayWidth(cm); - this.force = force; - this.dims = getDimensions(cm); - this.events = []; - } - - DisplayUpdate.prototype.signal = function (emitter, type) { - if (hasHandler(emitter, type)) - this.events.push(arguments); - }; - DisplayUpdate.prototype.finish = function () { - for (var i = 0; i < this.events.length; i++) - signal.apply(null, this.events[i]); - }; - - function maybeClipScrollbars(cm) { - var display = cm.display; - if (!display.scrollbarsClipped && display.scroller.offsetWidth) { - display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; - display.heightForcer.style.height = scrollGap(cm) + "px"; - display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; - display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; - display.scrollbarsClipped = true; - } - } - - // Does the actual updating of the line display. Bails out - // (returning false) when there is nothing to be done and forced is - // false. - function updateDisplayIfNeeded(cm, update) { - var display = cm.display, doc = cm.doc; - - if (update.editorIsHidden) { - resetView(cm); - return false; - } - - // Bail out if the visible area is already rendered and nothing changed. - if (!update.force && - update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && - display.renderedView == display.view && countDirtyView(cm) == 0) - return false; - - if (maybeUpdateLineNumberWidth(cm)) { - resetView(cm); - update.dims = getDimensions(cm); - } - - // Compute a suitable new viewport (from & to) - var end = doc.first + doc.size; - var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); - var to = Math.min(end, update.visible.to + cm.options.viewportMargin); - if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); - if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); - if (sawCollapsedSpans) { - from = visualLineNo(cm.doc, from); - to = visualLineEndNo(cm.doc, to); - } - - var different = from != display.viewFrom || to != display.viewTo || - display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; - adjustView(cm, from, to); - - display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); - // Position the mover div to align with the current scroll position - cm.display.mover.style.top = display.viewOffset + "px"; - - var toUpdate = countDirtyView(cm); - if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && - (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) - return false; - - // For big changes, we hide the enclosing element during the - // update, since that speeds up the operations on most browsers. - var focused = activeElt(); - if (toUpdate > 4) display.lineDiv.style.display = "none"; - patchDisplay(cm, display.updateLineNumbers, update.dims); - if (toUpdate > 4) display.lineDiv.style.display = ""; - display.renderedView = display.view; - // There might have been a widget with a focused element that got - // hidden or updated, if so re-focus it. - if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); - - // Prevent selection and cursors from interfering with the scroll - // width and height. - removeChildren(display.cursorDiv); - removeChildren(display.selectionDiv); - display.gutters.style.height = display.sizer.style.minHeight = 0; - - if (different) { - display.lastWrapHeight = update.wrapperHeight; - display.lastWrapWidth = update.wrapperWidth; - startWorker(cm, 400); - } - - display.updateLineNumbers = null; - - return true; - } - - function postUpdateDisplay(cm, update) { - var viewport = update.viewport; - - for (var first = true; ; first = false) { - if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { - // Clip forced viewport to actual scrollable area. - if (viewport && viewport.top != null) - viewport = { top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top) }; - // Updated line heights might result in the drawn area not - // actually covering the viewport. Keep looping until it does. - update.visible = visibleLines(cm.display, cm.doc, viewport); - if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) - break; - } - if (!updateDisplayIfNeeded(cm, update)) break; - updateHeightsInViewport(cm); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - updateScrollbars(cm, barMeasure); - setDocumentHeight(cm, barMeasure); - } - - update.signal(cm, "update", cm); - if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { - update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); - cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; - } - } - - function updateDisplaySimple(cm, viewport) { - var update = new DisplayUpdate(cm, viewport); - if (updateDisplayIfNeeded(cm, update)) { - updateHeightsInViewport(cm); - postUpdateDisplay(cm, update); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - updateScrollbars(cm, barMeasure); - setDocumentHeight(cm, barMeasure); - update.finish(); - } - } - - function setDocumentHeight(cm, measure) { - var documentZoom = getDocumentZoom(); - cm.display.sizer.style.minHeight = measure.docHeight / documentZoom + "px"; - cm.display.heightForcer.style.top = measure.docHeight / documentZoom + "px"; - cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) / documentZoom + "px"; - } - - // Read the actual heights of the rendered lines, and update their - // stored heights to match. - function updateHeightsInViewport(cm) { - var display = cm.display; - var prevBottom = display.lineDiv.offsetTop; - for (var i = 0; i < display.view.length; i++) { - var cur = display.view[i], height; - if (cur.hidden) continue; - if (ie && ie_version < 8) { - var bot = cur.node.offsetTop + cur.node.offsetHeight; - height = bot - prevBottom; - prevBottom = bot; - } else { - var box = cur.node.getBoundingClientRect(); - height = box.bottom - box.top; - } - var diff = cur.line.height - height; - if (height < 2) height = textHeight(display); - if (diff > .001 || diff < -.001) { - updateLineHeight(cur.line, height); - updateWidgetHeight(cur.line); - if (cur.rest) for (var j = 0; j < cur.rest.length; j++) - updateWidgetHeight(cur.rest[j]); - } - } - } - - // Read and store the height of line widgets associated with the - // given line. - function updateWidgetHeight(line) { - if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) - line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; - } - - // Do a bulk-read of the DOM positions and sizes needed to draw the - // view, so that we don't interleave reading and writing to the DOM. - function getDimensions(cm) { - var d = cm.display, left = {}, width = {}; - var gutterLeft = d.gutters.clientLeft; - for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { - left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; - width[cm.options.gutters[i]] = n.clientWidth; - } - return { - fixedPos: compensateForHScroll(d), - gutterTotalWidth: d.gutters.offsetWidth, - gutterLeft: left, - gutterWidth: width, - wrapperWidth: d.wrapper.clientWidth - }; - } - - // Sync the actual display DOM structure with display.view, removing - // nodes for lines that are no longer in view, and creating the ones - // that are not there yet, and updating the ones that are out of - // date. - function patchDisplay(cm, updateNumbersFrom, dims) { - var display = cm.display, lineNumbers = cm.options.lineNumbers; - var container = display.lineDiv, cur = container.firstChild; - - function rm(node) { - var next = node.nextSibling; - // Works around a throw-scroll bug in OS X Webkit - if (webkit && mac && cm.display.currentWheelTarget == node) - node.style.display = "none"; - else - node.parentNode.removeChild(node); - return next; - } - - var view = display.view, lineN = display.viewFrom; - // Loop over the elements in the view, syncing cur (the DOM nodes - // in display.lineDiv) with the view as we go. - for (var i = 0; i < view.length; i++) { - var lineView = view[i]; - if (lineView.hidden) { - } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet - var node = buildLineElement(cm, lineView, lineN, dims); - container.insertBefore(node, cur); - } else { // Already drawn - while (cur != lineView.node) cur = rm(cur); - var updateNumber = lineNumbers && updateNumbersFrom != null && - updateNumbersFrom <= lineN && lineView.lineNumber; - if (lineView.changes) { - if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; - updateLineForChanges(cm, lineView, lineN, dims); - } - if (updateNumber) { - removeChildren(lineView.lineNumber); - lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); - } - cur = lineView.node.nextSibling; - } - lineN += lineView.size; - } - while (cur) cur = rm(cur); - } - - // When an aspect of a line changes, a string is added to - // lineView.changes. This updates the relevant part of the line's - // DOM structure. - function updateLineForChanges(cm, lineView, lineN, dims) { - for (var j = 0; j < lineView.changes.length; j++) { - var type = lineView.changes[j]; - if (type == "text") updateLineText(cm, lineView); - else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); - else if (type == "class") updateLineClasses(lineView); - else if (type == "widget") updateLineWidgets(cm, lineView, dims); - } - lineView.changes = null; - } - - // Lines with gutter elements, widgets or a background class need to - // be wrapped, and have the extra elements added to the wrapper div - function ensureLineWrapped(lineView) { - if (lineView.node == lineView.text) { - lineView.node = elt("div", null, null, "position: relative"); - if (lineView.text.parentNode) - lineView.text.parentNode.replaceChild(lineView.node, lineView.text); - lineView.node.appendChild(lineView.text); - if (ie && ie_version < 8) lineView.node.style.zIndex = 2; - } - return lineView.node; - } - - function updateLineBackground(lineView) { - var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; - if (cls) cls += " CodeMirror-linebackground"; - if (lineView.background) { - if (cls) lineView.background.className = cls; - else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } - } else if (cls) { - var wrap = ensureLineWrapped(lineView); - lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); - } - } - - // Wrapper around buildLineContent which will reuse the structure - // in display.externalMeasured when possible. - function getLineContent(cm, lineView) { - var ext = cm.display.externalMeasured; - if (ext && ext.line == lineView.line) { - cm.display.externalMeasured = null; - lineView.measure = ext.measure; - return ext.built; - } - return buildLineContent(cm, lineView); - } - - // Redraw the line's text. Interacts with the background and text - // classes because the mode may output tokens that influence these - // classes. - function updateLineText(cm, lineView) { - var cls = lineView.text.className; - var built = getLineContent(cm, lineView); - if (lineView.text == lineView.node) lineView.node = built.pre; - lineView.text.parentNode.replaceChild(built.pre, lineView.text); - lineView.text = built.pre; - if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { - lineView.bgClass = built.bgClass; - lineView.textClass = built.textClass; - updateLineClasses(lineView); - } else if (cls) { - lineView.text.className = cls; - } - } - - function updateLineClasses(lineView) { - updateLineBackground(lineView); - if (lineView.line.wrapClass) - ensureLineWrapped(lineView).className = lineView.line.wrapClass; - else if (lineView.node != lineView.text) - lineView.node.className = ""; - var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; - lineView.text.className = textClass || ""; - } - - function updateLineGutter(cm, lineView, lineN, dims) { - if (lineView.gutter) { - lineView.node.removeChild(lineView.gutter); - lineView.gutter = null; - } - if (lineView.gutterBackground) { - lineView.node.removeChild(lineView.gutterBackground); - lineView.gutterBackground = null; - } - if (lineView.line.gutterClass) { - var wrap = ensureLineWrapped(lineView); - lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, - "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + - "px; width: " + dims.gutterTotalWidth + "px"); - wrap.insertBefore(lineView.gutterBackground, lineView.text); - } - var markers = lineView.line.gutterMarkers; - if (cm.options.lineNumbers || markers) { - var wrap = ensureLineWrapped(lineView); - var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + - (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"); - cm.display.input.setUneditable(gutterWrap); - wrap.insertBefore(gutterWrap, lineView.text); - if (lineView.line.gutterClass) - gutterWrap.className += " " + lineView.line.gutterClass; - if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) - lineView.lineNumber = gutterWrap.appendChild( - elt("div", lineNumberFor(cm.options, lineN), - "CodeMirror-linenumber CodeMirror-gutter-elt", - "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " - + cm.display.lineNumInnerWidth + "px")); - if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { - var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; - if (found) - gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + - dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] / + "px")); - } - } - } - - function updateLineWidgets(cm, lineView, dims) { - if (lineView.alignable) lineView.alignable = null; - for (var node = lineView.node.firstChild, next; node; node = next) { - var next = node.nextSibling; - if (node.className == "CodeMirror-linewidget") - lineView.node.removeChild(node); - } - insertLineWidgets(cm, lineView, dims); - } - - // Build a line's DOM representation from scratch - function buildLineElement(cm, lineView, lineN, dims) { - var built = getLineContent(cm, lineView); - lineView.text = lineView.node = built.pre; - if (built.bgClass) lineView.bgClass = built.bgClass; - if (built.textClass) lineView.textClass = built.textClass; - - updateLineClasses(lineView); - updateLineGutter(cm, lineView, lineN, dims); - insertLineWidgets(cm, lineView, dims); - return lineView.node; - } - - // A lineView may contain multiple logical lines (when merged by - // collapsed spans). The widgets for all of them need to be drawn. - function insertLineWidgets(cm, lineView, dims) { - insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); - if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) - insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); - } - - function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { - if (!line.widgets) return; - var wrap = ensureLineWrapped(lineView); - for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); - if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); - positionLineWidget(widget, node, lineView, dims); - cm.display.input.setUneditable(node); - if (allowAbove && widget.above) - wrap.insertBefore(node, lineView.gutter || lineView.text); - else - wrap.appendChild(node); - signalLater(widget, "redraw"); - } - } - - function positionLineWidget(widget, node, lineView, dims) { - if (widget.noHScroll) { - (lineView.alignable || (lineView.alignable = [])).push(node); - var width = dims.wrapperWidth; - node.style.left = dims.fixedPos + "px"; - if (!widget.coverGutter) { - width -= dims.gutterTotalWidth; - node.style.paddingLeft = dims.gutterTotalWidth + "px"; - } - node.style.width = width + "px"; - } - if (widget.coverGutter) { - node.style.zIndex = 5; - node.style.position = "relative"; - if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; - } - } - - // POSITION OBJECT - - // A Pos instance represents a position within the text. - var Pos = CodeMirror.Pos = function (line, ch) { - if (!(this instanceof Pos)) return new Pos(line, ch); - this.line = line; this.ch = ch; - }; - - // Compare two positions, return 0 if they are the same, a negative - // number when a is less, and a positive number otherwise. - var cmp = CodeMirror.cmpPos = function (a, b) { return a.line - b.line || a.ch - b.ch; }; - - function copyPos(x) { return Pos(x.line, x.ch); } - function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } - function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } - - // INPUT HANDLING - - function ensureFocus(cm) { - if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } - } - - // This will be set to a {lineWise: bool, text: [string]} object, so - // that, when pasting, we know what kind of selections the copied - // text was made out of. - var lastCopied = null; - - function applyTextInput(cm, inserted, deleted, sel, origin) { - var doc = cm.doc; - cm.display.shift = false; - if (!sel) sel = doc.sel; - - var paste = cm.state.pasteIncoming || origin == "paste"; - var textLines = doc.splitLines(inserted), multiPaste = null - // When pasing N lines into N selections, insert one line per selection - if (paste && sel.ranges.length > 1) { - if (lastCopied && lastCopied.text.join("\n") == inserted) { - if (sel.ranges.length % lastCopied.text.length == 0) { - multiPaste = []; - for (var i = 0; i < lastCopied.text.length; i++) - multiPaste.push(doc.splitLines(lastCopied.text[i])); - } - } else if (textLines.length == sel.ranges.length) { - multiPaste = map(textLines, function (l) { return [l]; }); - } - } - - // Normal behavior is to insert the new text into every selection - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i]; - var from = range.from(), to = range.to(); - if (range.empty()) { - if (deleted && deleted > 0) // Handle deletion - from = Pos(from.line, from.ch - deleted); - else if (cm.state.overwrite && !paste) // Handle overwrite - to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); - else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) - from = to = Pos(from.line, 0) - } - var updateInput = cm.curOp.updateInput; - var changeEvent = { - from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, - origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input") - }; - makeChange(cm.doc, changeEvent); - signalLater(cm, "inputRead", cm, changeEvent); - } - if (inserted && !paste) - triggerElectric(cm, inserted); - - ensureCursorVisible(cm); - cm.curOp.updateInput = updateInput; - cm.curOp.typing = true; - cm.state.pasteIncoming = cm.state.cutIncoming = false; - } - - function handlePaste(e, cm) { - var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); - if (pasted) { - e.preventDefault(); - if (!cm.isReadOnly() && !cm.options.disableInput) - runInOp(cm, function () { applyTextInput(cm, pasted, 0, null, "paste"); }); - return true; - } - } - - function triggerElectric(cm, inserted) { - // When an 'electric' character is inserted, immediately trigger a reindent - if (!cm.options.electricChars || !cm.options.smartIndent) return; - var sel = cm.doc.sel; - - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i]; - if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue; - var mode = cm.getModeAt(range.head); - var indented = false; - if (mode.electricChars) { - for (var j = 0; j < mode.electricChars.length; j++) - if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range.head.line, "smart"); - break; - } - } else if (mode.electricInput) { - if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) - indented = indentLine(cm, range.head.line, "smart"); - } - if (indented) signalLater(cm, "electricInput", cm, range.head.line); - } - } - - function copyableRanges(cm) { - var text = [], ranges = []; - for (var i = 0; i < cm.doc.sel.ranges.length; i++) { - var line = cm.doc.sel.ranges[i].head.line; - var lineRange = { anchor: Pos(line, 0), head: Pos(line + 1, 0) }; - ranges.push(lineRange); - text.push(cm.getRange(lineRange.anchor, lineRange.head)); - } - return { text: text, ranges: ranges }; - } - - function disableBrowserMagic(field) { - field.setAttribute("autocorrect", "off"); - field.setAttribute("autocapitalize", "off"); - field.setAttribute("spellcheck", "false"); - } - - // TEXTAREA INPUT STYLE - - function TextareaInput(cm) { - this.cm = cm; - // See input.poll and input.reset - this.prevInput = ""; - - // Flag that indicates whether we expect input to appear real soon - // now (after some event like 'keypress' or 'input') and are - // polling intensively. - this.pollingFast = false; - // Self-resetting timeout for the poller - this.polling = new Delayed(); - // Tracks when input.reset has punted to just putting a short - // string into the textarea instead of the full selection. - this.inaccurateSelection = false; - // Used to work around IE issue with selection being forgotten when focus moves away from textarea - this.hasSelection = false; - this.composing = null; - }; - - function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none"); - var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); - // The textarea is kept positioned near the cursor to prevent the - // fact that it'll be scrolled into view on input from scrolling - // our fake cursor out of view. On webkit, when wrap=off, paste is - // very slow. So make the area wide instead. - if (webkit) te.style.width = "1000px"; - else te.setAttribute("wrap", "off"); - // If border: 0; -- iOS fails to open keyboard (issue #1287) - if (ios) te.style.border = "1px solid black"; - disableBrowserMagic(te); - return div; - } - - TextareaInput.prototype = copyObj({ - init: function (display) { - var input = this, cm = this.cm; - - // Wraps and hides input textarea - var div = this.wrapper = hiddenTextarea(); - // The semihidden textarea that is focused when the editor is - // focused, and receives input. - var te = this.textarea = div.firstChild; - display.wrapper.insertBefore(div, display.wrapper.firstChild); - - // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) - if (ios) te.style.width = "0px"; - - on(te, "input", function () { - if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; - input.poll(); - }); - - on(te, "paste", function (e) { - if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return - - cm.state.pasteIncoming = true; - input.fastPoll(); - }); - - function prepareCopyCut(e) { - if (signalDOMEvent(cm, e)) return - if (cm.somethingSelected()) { - lastCopied = { lineWise: false, text: cm.getSelections() }; - if (input.inaccurateSelection) { - input.prevInput = ""; - input.inaccurateSelection = false; - te.value = lastCopied.text.join("\n"); - selectInput(te); - } - } else if (!cm.options.lineWiseCopyCut) { - return; - } else { - var ranges = copyableRanges(cm); - lastCopied = { lineWise: true, text: ranges.text }; - if (e.type == "cut") { - cm.setSelections(ranges.ranges, null, sel_dontScroll); - } else { - input.prevInput = ""; - te.value = ranges.text.join("\n"); - selectInput(te); - } - } - if (e.type == "cut") cm.state.cutIncoming = true; - } - on(te, "cut", prepareCopyCut); - on(te, "copy", prepareCopyCut); - - on(display.scroller, "paste", function (e) { - if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return; - cm.state.pasteIncoming = true; - input.focus(); - }); - - // Prevent normal selection in the editor (we handle our own) - on(display.lineSpace, "selectstart", function (e) { - if (!eventInWidget(display, e)) e_preventDefault(e); - }); - - on(te, "compositionstart", function () { - var start = cm.getCursor("from"); - if (input.composing) input.composing.range.clear() - input.composing = { - start: start, - range: cm.markText(start, cm.getCursor("to"), { className: "CodeMirror-composing" }) - }; - }); - on(te, "compositionend", function () { - if (input.composing) { - input.poll(); - input.composing.range.clear(); - input.composing = null; - } - }); - }, - - prepareSelection: function () { - // Redraw the selection and/or cursor - var cm = this.cm, display = cm.display, doc = cm.doc; - var result = prepareSelection(cm); - - // Move the hidden textarea near the cursor to prevent scrolling artifacts - if (cm.options.moveInputWithCursor) { - var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); - result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, - headPos.top + lineOff.top - wrapOff.top)); - result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, - headPos.left + lineOff.left - wrapOff.left)); - } - - return result; - }, - - showSelection: function (drawn) { - var cm = this.cm, display = cm.display; - removeChildrenAndAdd(display.cursorDiv, drawn.cursors); - removeChildrenAndAdd(display.selectionDiv, drawn.selection); - if (drawn.teTop != null) { - this.wrapper.style.top = drawn.teTop + "px"; - this.wrapper.style.left = drawn.teLeft + "px"; - } - }, - - // Reset the input to correspond to the selection (or to be empty, - // when not typing and nothing is selected) - reset: function (typing) { - if (this.contextMenuPending) return; - var minimal, selected, cm = this.cm, doc = cm.doc; - if (cm.somethingSelected()) { - this.prevInput = ""; - var range = doc.sel.primary(); - minimal = hasCopyEvent && - (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); - var content = minimal ? "-" : selected || cm.getSelection(); - this.textarea.value = content; - if (cm.state.focused) selectInput(this.textarea); - if (ie && ie_version >= 9) this.hasSelection = content; - } else if (!typing) { - this.prevInput = this.textarea.value = ""; - if (ie && ie_version >= 9) this.hasSelection = null; - } - this.inaccurateSelection = minimal; - }, - - getField: function () { return this.textarea; }, - - supportsTouch: function () { return false; }, - - focus: function () { - if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { - try { this.textarea.focus(); } - catch (e) { } // IE8 will throw if the textarea is display: none or not in DOM - } - }, - - blur: function () { this.textarea.blur(); }, - - resetPosition: function () { - this.wrapper.style.top = this.wrapper.style.left = 0; - }, - - receivedFocus: function () { this.slowPoll(); }, - - // Poll for input changes, using the normal rate of polling. This - // runs as long as the editor is focused. - slowPoll: function () { - var input = this; - if (input.pollingFast) return; - input.polling.set(this.cm.options.pollInterval, function () { - input.poll(); - if (input.cm.state.focused) input.slowPoll(); - }); - }, - - // When an event has just come in that is likely to add or change - // something in the input textarea, we poll faster, to ensure that - // the change appears on the screen quickly. - fastPoll: function () { - var missed = false, input = this; - input.pollingFast = true; - function p() { - var changed = input.poll(); - if (!changed && !missed) { missed = true; input.polling.set(60, p); } - else { input.pollingFast = false; input.slowPoll(); } - } - input.polling.set(20, p); - }, - - // Read input from the textarea, and update the document to match. - // When something is selected, it is present in the textarea, and - // selected (unless it is huge, in which case a placeholder is - // used). When nothing is selected, the cursor sits after previously - // seen text (can be empty), which is stored in prevInput (we must - // not reset the textarea when typing, because that breaks IME). - poll: function () { - var cm = this.cm, input = this.textarea, prevInput = this.prevInput; - // Since this is called a *lot*, try to bail out as cheaply as - // possible when it is clear that nothing happened. hasSelection - // will be the case when there is a lot of text in the textarea, - // in which case reading its value would be expensive. - if (this.contextMenuPending || !cm.state.focused || - (hasSelection(input) && !prevInput && !this.composing) || - cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) - return false; - - var text = input.value; - // If nothing changed, bail. - if (text == prevInput && !cm.somethingSelected()) return false; - // Work around nonsensical selection resetting in IE9/10, and - // inexplicable appearance of private area unicode characters on - // some key combos in Mac (#2689). - if (ie && ie_version >= 9 && this.hasSelection === text || - mac && /[\uf700-\uf7ff]/.test(text)) { - cm.display.input.reset(); - return false; - } - - if (cm.doc.sel == cm.display.selForContextMenu) { - var first = text.charCodeAt(0); - if (first == 0x200b && !prevInput) prevInput = "\u200b"; - if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } - } - // Find the part of the input that is actually new - var same = 0, l = Math.min(prevInput.length, text.length); - while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; - - var self = this; - runInOp(cm, function () { - applyTextInput(cm, text.slice(same), prevInput.length - same, - null, self.composing ? "*compose" : null); - - // Don't leave long text in the textarea, since it makes further polling slow - if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; - else self.prevInput = text; - - if (self.composing) { - self.composing.range.clear(); - self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), - { className: "CodeMirror-composing" }); - } - }); - return true; - }, - - ensurePolled: function () { - if (this.pollingFast && this.poll()) this.pollingFast = false; - }, - - onKeyPress: function () { - if (ie && ie_version >= 9) this.hasSelection = null; - this.fastPoll(); - }, - - onContextMenu: function (e) { - var input = this, cm = input.cm, display = cm.display, te = input.textarea; - var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; - if (!pos || presto) return; // Opera is difficult. - - // Reset the current text selection only if the click is done outside of the selection - // and 'resetSelectionOnContextMenu' option is true. - var reset = cm.options.resetSelectionOnContextMenu; - if (reset && cm.doc.sel.contains(pos) == -1) - operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); - - var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; - input.wrapper.style.cssText = "position: absolute" - var wrapperBox = input.wrapper.getBoundingClientRect() - te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + - "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + - (ie ? "rgba(255, 255, 255, .05)" : "transparent") + - "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; - if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) - display.input.focus(); - if (webkit) window.scrollTo(null, oldScrollY); - display.input.reset(); - // Adds "Select all" to context menu in FF - if (!cm.somethingSelected()) te.value = input.prevInput = " "; - input.contextMenuPending = true; - display.selForContextMenu = cm.doc.sel; - clearTimeout(display.detectingSelectAll); - - // Select-all will be greyed out if there's nothing to select, so - // this adds a zero-width space so that we can later check whether - // it got selected. - function prepareSelectAllHack() { - if (te.selectionStart != null) { - var selected = cm.somethingSelected(); - var extval = "\u200b" + (selected ? te.value : ""); - te.value = "\u21da"; // Used to catch context-menu undo - te.value = extval; - input.prevInput = selected ? "" : "\u200b"; - te.selectionStart = 1; te.selectionEnd = extval.length; - // Re-set this, in case some other handler touched the - // selection in the meantime. - display.selForContextMenu = cm.doc.sel; - } - } - function rehide() { - input.contextMenuPending = false; - input.wrapper.style.cssText = oldWrapperCSS - te.style.cssText = oldCSS; - if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); - - // Try to detect the user choosing select-all - if (te.selectionStart != null) { - if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); - var i = 0, poll = function () { - if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && - te.selectionEnd > 0 && input.prevInput == "\u200b") - operation(cm, commands.selectAll)(cm); - else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); - else display.input.reset(); - }; - display.detectingSelectAll = setTimeout(poll, 200); - } - } - - if (ie && ie_version >= 9) prepareSelectAllHack(); - if (captureRightClick) { - e_stop(e); - var mouseup = function () { - off(window, "mouseup", mouseup); - setTimeout(rehide, 20); - }; - on(window, "mouseup", mouseup); - } else { - setTimeout(rehide, 50); - } - }, - - readOnlyChanged: function (val) { - if (!val) this.reset(); - }, - - setUneditable: nothing, - - needsContentAttribute: false - }, TextareaInput.prototype); - - // CONTENTEDITABLE INPUT STYLE - - function ContentEditableInput(cm) { - this.cm = cm; - this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; - this.polling = new Delayed(); - this.gracePeriod = false; - } - - ContentEditableInput.prototype = copyObj({ - init: function (display) { - var input = this, cm = input.cm; - var div = input.div = display.lineDiv; - disableBrowserMagic(div); - - on(div, "paste", function (e) { - if (!signalDOMEvent(cm, e)) handlePaste(e, cm); - }) - - on(div, "compositionstart", function (e) { - var data = e.data; - input.composing = { sel: cm.doc.sel, data: data, startData: data }; - if (!data) return; - var prim = cm.doc.sel.primary(); - var line = cm.getLine(prim.head.line); - var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); - if (found > -1 && found <= prim.head.ch) - input.composing.sel = simpleSelection(Pos(prim.head.line, found), - Pos(prim.head.line, found + data.length)); - }); - on(div, "compositionupdate", function (e) { - input.composing.data = e.data; - }); - on(div, "compositionend", function (e) { - var ours = input.composing; - if (!ours) return; - if (e.data != ours.startData && !/\u200b/.test(e.data)) - ours.data = e.data; - // Need a small delay to prevent other code (input event, - // selection polling) from doing damage when fired right after - // compositionend. - setTimeout(function () { - if (!ours.handled) - input.applyComposition(ours); - if (input.composing == ours) - input.composing = null; - }, 50); - }); - - on(div, "touchstart", function () { - input.forceCompositionEnd(); - }); - - on(div, "input", function () { - if (input.composing) return; - if (cm.isReadOnly() || !input.pollContent()) - runInOp(input.cm, function () { regChange(cm); }); - }); - - function onCopyCut(e) { - if (signalDOMEvent(cm, e)) return - if (cm.somethingSelected()) { - lastCopied = { lineWise: false, text: cm.getSelections() }; - if (e.type == "cut") cm.replaceSelection("", null, "cut"); - } else if (!cm.options.lineWiseCopyCut) { - return; - } else { - var ranges = copyableRanges(cm); - lastCopied = { lineWise: true, text: ranges.text }; - if (e.type == "cut") { - cm.operation(function () { - cm.setSelections(ranges.ranges, 0, sel_dontScroll); - cm.replaceSelection("", null, "cut"); - }); - } - } - // iOS exposes the clipboard API, but seems to discard content inserted into it - if (e.clipboardData && !ios) { - e.preventDefault(); - e.clipboardData.clearData(); - e.clipboardData.setData("text/plain", lastCopied.text.join("\n")); - } else { - // Old-fashioned briefly-focus-a-textarea hack - var kludge = hiddenTextarea(), te = kludge.firstChild; - cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); - te.value = lastCopied.text.join("\n"); - var hadFocus = document.activeElement; - selectInput(te); - setTimeout(function () { - cm.display.lineSpace.removeChild(kludge); - hadFocus.focus(); - }, 50); - } - } - on(div, "copy", onCopyCut); - on(div, "cut", onCopyCut); - }, - - prepareSelection: function () { - var result = prepareSelection(this.cm, false); - result.focus = this.cm.state.focused; - return result; - }, - - showSelection: function (info, takeFocus) { - if (!info || !this.cm.display.view.length) return; - if (info.focus || takeFocus) this.showPrimarySelection(); - this.showMultipleSelections(info); - }, - - showPrimarySelection: function () { - var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); - var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); - var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); - if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && - cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && - cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) - return; - - var start = posToDOM(this.cm, prim.from()); - var end = posToDOM(this.cm, prim.to()); - if (!start && !end) return; - - var view = this.cm.display.view; - var old = sel.rangeCount && sel.getRangeAt(0); - if (!start) { - start = { node: view[0].measure.map[2], offset: 0 }; - } else if (!end) { // FIXME dangerously hacky - var measure = view[view.length - 1].measure; - var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; - end = { node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3] }; - } - - try { var rng = range(start.node, start.offset, end.offset, end.node); } - catch (e) { } // Our model of the DOM might be outdated, in which case the range we try to set can be impossible - if (rng) { - if (!gecko && this.cm.state.focused) { - sel.collapse(start.node, start.offset); - if (!rng.collapsed) sel.addRange(rng); - } else { - sel.removeAllRanges(); - sel.addRange(rng); - } - if (old && sel.anchorNode == null) sel.addRange(old); - else if (gecko) this.startGracePeriod(); - } - this.rememberSelection(); - }, - - startGracePeriod: function () { - var input = this; - clearTimeout(this.gracePeriod); - this.gracePeriod = setTimeout(function () { - input.gracePeriod = false; - if (input.selectionChanged()) - input.cm.operation(function () { input.cm.curOp.selectionChanged = true; }); - }, 20); - }, - - showMultipleSelections: function (info) { - removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); - removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); - }, - - rememberSelection: function () { - var sel = window.getSelection(); - this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; - this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; - }, - - selectionInEditor: function () { - var sel = window.getSelection(); - if (!sel.rangeCount) return false; - var node = sel.getRangeAt(0).commonAncestorContainer; - return contains(this.div, node); - }, - - focus: function () { - if (this.cm.options.readOnly != "nocursor") this.div.focus(); - }, - blur: function () { this.div.blur(); }, - getField: function () { return this.div; }, - - supportsTouch: function () { return true; }, - - receivedFocus: function () { - var input = this; - if (this.selectionInEditor()) - this.pollSelection(); - else - runInOp(this.cm, function () { input.cm.curOp.selectionChanged = true; }); - - function poll() { - if (input.cm.state.focused) { - input.pollSelection(); - input.polling.set(input.cm.options.pollInterval, poll); - } - } - this.polling.set(this.cm.options.pollInterval, poll); - }, - - selectionChanged: function () { - var sel = window.getSelection(); - return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || - sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; - }, - - pollSelection: function () { - if (!this.composing && !this.gracePeriod && this.selectionChanged()) { - var sel = window.getSelection(), cm = this.cm; - this.rememberSelection(); - var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); - var head = domToPos(cm, sel.focusNode, sel.focusOffset); - if (anchor && head) runInOp(cm, function () { - setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); - if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; - }); - } - }, - - pollContent: function () { - var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); - var from = sel.from(), to = sel.to(); - if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; - - var fromIndex; - if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { - var fromLine = lineNo(display.view[0].line); - var fromNode = display.view[0].node; - } else { - var fromLine = lineNo(display.view[fromIndex].line); - var fromNode = display.view[fromIndex - 1].node.nextSibling; - } - var toIndex = findViewIndex(cm, to.line); - if (toIndex == display.view.length - 1) { - var toLine = display.viewTo - 1; - var toNode = display.lineDiv.lastChild; - } else { - var toLine = lineNo(display.view[toIndex + 1].line) - 1; - var toNode = display.view[toIndex + 1].node.previousSibling; - } - - var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); - var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); - while (newText.length > 1 && oldText.length > 1) { - if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } - else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } - else break; - } - - var cutFront = 0, cutEnd = 0; - var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); - while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) - ++cutFront; - var newBot = lst(newText), oldBot = lst(oldText); - var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), - oldBot.length - (oldText.length == 1 ? cutFront : 0)); - while (cutEnd < maxCutEnd && - newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) - ++cutEnd; - - newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); - newText[0] = newText[0].slice(cutFront); - - var chFrom = Pos(fromLine, cutFront); - var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); - if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { - replaceRange(cm.doc, newText, chFrom, chTo, "+input"); - return true; - } - }, - - ensurePolled: function () { - this.forceCompositionEnd(); - }, - reset: function () { - this.forceCompositionEnd(); - }, - forceCompositionEnd: function () { - if (!this.composing || this.composing.handled) return; - this.applyComposition(this.composing); - this.composing.handled = true; - this.div.blur(); - this.div.focus(); - }, - applyComposition: function (composing) { - if (this.cm.isReadOnly()) - operation(this.cm, regChange)(this.cm) - else if (composing.data && composing.data != composing.startData) - operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); - }, - - setUneditable: function (node) { - node.contentEditable = "false" - }, - - onKeyPress: function (e) { - e.preventDefault(); - if (!this.cm.isReadOnly()) - operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); - }, - - readOnlyChanged: function (val) { - this.div.contentEditable = String(val != "nocursor") - }, - - onContextMenu: nothing, - resetPosition: nothing, - - needsContentAttribute: true - }, ContentEditableInput.prototype); - - function posToDOM(cm, pos) { - var view = findViewForLine(cm, pos.line); - if (!view || view.hidden) return null; - var line = getLine(cm.doc, pos.line); - var info = mapFromLineView(view, line, pos.line); - - var order = getOrder(line), side = "left"; - if (order) { - var partPos = getBidiPartAt(order, pos.ch); - side = partPos % 2 ? "right" : "left"; - } - var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); - result.offset = result.collapse == "right" ? result.end : result.start; - return result; - } - - function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } - - function domToPos(cm, node, offset) { - var lineNode; - if (node == cm.display.lineDiv) { - lineNode = cm.display.lineDiv.childNodes[offset]; - if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); - node = null; offset = 0; - } else { - for (lineNode = node; ; lineNode = lineNode.parentNode) { - if (!lineNode || lineNode == cm.display.lineDiv) return null; - if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; - } - } - for (var i = 0; i < cm.display.view.length; i++) { - var lineView = cm.display.view[i]; - if (lineView.node == lineNode) - return locateNodeInLineView(lineView, node, offset); - } - } - - function locateNodeInLineView(lineView, node, offset) { - var wrapper = lineView.text.firstChild, bad = false; - if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); - if (node == wrapper) { - bad = true; - node = wrapper.childNodes[offset]; - offset = 0; - if (!node) { - var line = lineView.rest ? lst(lineView.rest) : lineView.line; - return badPos(Pos(lineNo(line), line.text.length), bad); - } - } - - var textNode = node.nodeType == 3 ? node : null, topNode = node; - if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { - textNode = node.firstChild; - if (offset) offset = textNode.nodeValue.length; - } - while (topNode.parentNode != wrapper) topNode = topNode.parentNode; - var measure = lineView.measure, maps = measure.maps; - - function find(textNode, topNode, offset) { - for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map = i < 0 ? measure.map : maps[i]; - for (var j = 0; j < map.length; j += 3) { - var curNode = map[j + 2]; - if (curNode == textNode || curNode == topNode) { - var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); - var ch = map[j] + offset; - if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; - return Pos(line, ch); - } - } - } - } - var found = find(textNode, topNode, offset); - if (found) return badPos(found, bad); - - // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems - for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { - found = find(after, after.firstChild, 0); - if (found) - return badPos(Pos(found.line, found.ch - dist), bad); - else - dist += after.textContent.length; - } - for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { - found = find(before, before.firstChild, -1); - if (found) - return badPos(Pos(found.line, found.ch + dist), bad); - else - dist += after.textContent.length; - } - } - - function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator(); - function recognizeMarker(id) { return function (marker) { return marker.id == id; }; } - function walk(node) { - if (node.nodeType == 1) { - var cmText = node.getAttribute("cm-text"); - if (cmText != null) { - if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); - text += cmText; - return; - } - var markerID = node.getAttribute("cm-marker"), range; - if (markerID) { - var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); - if (found.length && (range = found[0].find())) - text += getBetween(cm.doc, range.from, range.to).join(lineSep); - return; - } - if (node.getAttribute("contenteditable") == "false") return; - for (var i = 0; i < node.childNodes.length; i++) - walk(node.childNodes[i]); - if (/^(pre|div|p)$/i.test(node.nodeName)) - closing = true; - } else if (node.nodeType == 3) { - var val = node.nodeValue; - if (!val) return; - if (closing) { - text += lineSep; - closing = false; - } - text += val; - } - } - for (; ;) { - walk(from); - if (from == to) break; - from = from.nextSibling; - } - return text; - } - - CodeMirror.inputStyles = { "textarea": TextareaInput, "contenteditable": ContentEditableInput }; - - // SELECTION / CURSOR - - // Selection objects are immutable. A new one is created every time - // the selection changes. A selection is one or more non-overlapping - // (and non-touching) ranges, sorted, and an integer that indicates - // which one is the primary selection (the one that's scrolled into - // view, that getCursor returns, etc). - function Selection(ranges, primIndex) { - this.ranges = ranges; - this.primIndex = primIndex; - } - - Selection.prototype = { - primary: function () { return this.ranges[this.primIndex]; }, - equals: function (other) { - if (other == this) return true; - if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; - for (var i = 0; i < this.ranges.length; i++) { - var here = this.ranges[i], there = other.ranges[i]; - if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; - } - return true; - }, - deepCopy: function () { - for (var out = [], i = 0; i < this.ranges.length; i++) - out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); - return new Selection(out, this.primIndex); - }, - somethingSelected: function () { - for (var i = 0; i < this.ranges.length; i++) - if (!this.ranges[i].empty()) return true; - return false; - }, - contains: function (pos, end) { - if (!end) end = pos; - for (var i = 0; i < this.ranges.length; i++) { - var range = this.ranges[i]; - if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) - return i; - } - return -1; - } - }; - - function Range(anchor, head) { - this.anchor = anchor; this.head = head; - } - - Range.prototype = { - from: function () { return minPos(this.anchor, this.head); }, - to: function () { return maxPos(this.anchor, this.head); }, - empty: function () { - return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; - } - }; - - // Take an unsorted, potentially overlapping set of ranges, and - // build a selection out of it. 'Consumes' ranges array (modifying - // it). - function normalizeSelection(ranges, primIndex) { - var prim = ranges[primIndex]; - ranges.sort(function (a, b) { return cmp(a.from(), b.from()); }); - primIndex = indexOf(ranges, prim); - for (var i = 1; i < ranges.length; i++) { - var cur = ranges[i], prev = ranges[i - 1]; - if (cmp(prev.to(), cur.from()) >= 0) { - var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); - var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; - if (i <= primIndex) --primIndex; - ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); - } - } - return new Selection(ranges, primIndex); - } - - function simpleSelection(anchor, head) { - return new Selection([new Range(anchor, head || anchor)], 0); - } - - // Most of the external API clips given positions to make sure they - // actually exist within the document. - function clipLine(doc, n) { return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1)); } - function clipPos(doc, pos) { - if (pos.line < doc.first) return Pos(doc.first, 0); - var last = doc.first + doc.size - 1; - if (pos.line > last) return Pos(last, getLine(doc, last).text.length); - return clipToLen(pos, getLine(doc, pos.line).text.length); - } - function clipToLen(pos, linelen) { - var ch = pos.ch; - if (ch == null || ch > linelen) return Pos(pos.line, linelen); - else if (ch < 0) return Pos(pos.line, 0); - else return pos; - } - function isLine(doc, l) { return l >= doc.first && l < doc.first + doc.size; } - function clipPosArray(doc, array) { - for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); - return out; - } - - // SELECTION UPDATES - - // The 'scroll' parameter given to many of these indicated whether - // the new cursor position should be scrolled into view after - // modifying the selection. - - // If shift is held or the extend flag is set, extends a range to - // include a given position (and optionally a second position). - // Otherwise, simply returns the range between the given positions. - // Used for cursor motion and such. - function extendRange(doc, range, head, other) { - if (doc.cm && doc.cm.display.shift || doc.extend) { - var anchor = range.anchor; - if (other) { - var posBefore = cmp(head, anchor) < 0; - if (posBefore != (cmp(other, anchor) < 0)) { - anchor = head; - head = other; - } else if (posBefore != (cmp(head, other) < 0)) { - head = other; - } - } - return new Range(anchor, head); - } else { - return new Range(other || head, head); - } - } - - // Extend the primary selection range, discard the rest. - function extendSelection(doc, head, other, options) { - setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); - } - - // Extend all selections (pos is an array of selections with length - // equal the number of selections) - function extendSelections(doc, heads, options) { - for (var out = [], i = 0; i < doc.sel.ranges.length; i++) - out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); - var newSel = normalizeSelection(out, doc.sel.primIndex); - setSelection(doc, newSel, options); - } - - // Updates a single range in the selection. - function replaceOneSelection(doc, i, range, options) { - var ranges = doc.sel.ranges.slice(0); - ranges[i] = range; - setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); - } - - // Reset the selection to a single range. - function setSimpleSelection(doc, anchor, head, options) { - setSelection(doc, simpleSelection(anchor, head), options); - } - - // Give beforeSelectionChange handlers a change to influence a - // selection update. - function filterSelectionChange(doc, sel, options) { - var obj = { - ranges: sel.ranges, - update: function (ranges) { - this.ranges = []; - for (var i = 0; i < ranges.length; i++) - this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), - clipPos(doc, ranges[i].head)); - }, - origin: options && options.origin - }; - signal(doc, "beforeSelectionChange", doc, obj); - if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); - if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); - else return sel; - } - - function setSelectionReplaceHistory(doc, sel, options) { - var done = doc.history.done, last = lst(done); - if (last && last.ranges) { - done[done.length - 1] = sel; - setSelectionNoUndo(doc, sel, options); - } else { - setSelection(doc, sel, options); - } - } - - // Set a new selection. - function setSelection(doc, sel, options) { - setSelectionNoUndo(doc, sel, options); - addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); - } - - function setSelectionNoUndo(doc, sel, options) { - if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) - sel = filterSelectionChange(doc, sel, options); - - var bias = options && options.bias || - (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); - setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); - - if (!(options && options.scroll === false) && doc.cm) - ensureCursorVisible(doc.cm); - } - - function setSelectionInner(doc, sel) { - if (sel.equals(doc.sel)) return; - - doc.sel = sel; - - if (doc.cm) { - doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; - signalCursorActivity(doc.cm); - } - signalLater(doc, "cursorActivity", doc); - } - - // Verify that the selection does not partially select any atomic - // marked ranges. - function reCheckSelection(doc) { - setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); - } - - // Return a selection that does not partially select any atomic - // ranges. - function skipAtomicInSelection(doc, sel, bias, mayClear) { - var out; - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; - var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); - var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); - if (out || newAnchor != range.anchor || newHead != range.head) { - if (!out) out = sel.ranges.slice(0, i); - out[i] = new Range(newAnchor, newHead); - } - } - return out ? normalizeSelection(out, sel.primIndex) : sel; - } - - function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { - var line = getLine(doc, pos.line); - if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var sp = line.markedSpans[i], m = sp.marker; - if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && - (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { - if (mayClear) { - signal(m, "beforeCursorEnter"); - if (m.explicitlyCleared) { - if (!line.markedSpans) break; - else { --i; continue; } - } - } - if (!m.atomic) continue; - - if (oldPos) { - var near = m.find(dir < 0 ? 1 : -1), diff; - if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) - near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); - if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) - return skipAtomicInner(doc, near, pos, dir, mayClear); - } - - var far = m.find(dir < 0 ? -1 : 1); - if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) - far = movePos(doc, far, dir, far.line == pos.line ? line : null); - return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null; - } - } - return pos; - } - - // Ensure a given position is not inside an atomic range. - function skipAtomic(doc, pos, oldPos, bias, mayClear) { - var dir = bias || 1; - var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || - skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)); - if (!found) { - doc.cantEdit = true; - return Pos(doc.first, 0); - } - return found; - } - - function movePos(doc, pos, dir, line) { - if (dir < 0 && pos.ch == 0) { - if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1)); - else return null; - } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { - if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0); - else return null; - } else { - return new Pos(pos.line, pos.ch + dir); - } - } - - // SELECTION DRAWING - - function updateSelection(cm) { - cm.display.input.showSelection(cm.display.input.prepareSelection()); - } - - function prepareSelection(cm, primary) { - var doc = cm.doc, result = {}; - var curFragment = result.cursors = document.createDocumentFragment(); - var selFragment = result.selection = document.createDocumentFragment(); - - for (var i = 0; i < doc.sel.ranges.length; i++) { - if (primary === false && i == doc.sel.primIndex) continue; - var range = doc.sel.ranges[i]; - if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue; - var collapsed = range.empty(); - if (collapsed || cm.options.showCursorWhenSelecting) - drawSelectionCursor(cm, range.head, curFragment); - if (!collapsed) - drawSelectionRange(cm, range, selFragment); - } - return result; - } - - // Draws a cursor for the given range - function drawSelectionCursor(cm, head, output) { - var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); - - var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); - - var documentZoom = getDocumentZoom(); - - cursor.style.left = pos.left / documentZoom + "px"; - cursor.style.top = pos.top / documentZoom + "px"; - cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight / documentZoom + "px"; - - if (pos.other) { - // Secondary cursor, shown when on a 'jump' in bi-directional text - var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); - otherCursor.style.display = ""; - otherCursor.style.left = pos.other.left / documentZoom + "px"; - otherCursor.style.top = pos.other.top / documentZoom + "px"; - otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 / documentZoom + "px"; - } - } - - // Draws the given range as a highlighted selection - function drawSelectionRange(cm, range, output) { - var display = cm.display, doc = cm.doc; - var fragment = document.createDocumentFragment(); - var padding = paddingH(cm.display), leftSide = padding.left; - var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; - - function add(left, top, width, bottom) { - if (top < 0) top = 0; - top = Math.round(top); - bottom = Math.round(bottom); - - var documentZoom = getDocumentZoom(); - - fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left / documentZoom + - "px; top: " + top / documentZoom + "px; width: " + (width == null ? rightSide - left : width) / documentZoom + - "px; height: " + (bottom - top) / documentZoom + "px")); - } - - function drawForLine(line, fromArg, toArg) { - var lineObj = getLine(doc, line); - var lineLen = lineObj.text.length; - var start, end; - function coords(ch, bias) { - return charCoords(cm, Pos(line, ch), "div", lineObj, bias); - } - - iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) { - var leftPos = coords(from, "left"), rightPos, left, right; - if (from == to) { - rightPos = leftPos; - left = right = leftPos.left; - } else { - rightPos = coords(to - 1, "right"); - if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } - left = leftPos.left; - right = rightPos.right; - } - if (fromArg == null && from == 0) left = leftSide; - if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part - add(left, leftPos.top, null, leftPos.bottom); - left = leftSide; - if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); - } - if (toArg == null && to == lineLen) right = rightSide; - if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) - start = leftPos; - if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) - end = rightPos; - if (left < leftSide + 1) left = leftSide; - add(left, rightPos.top, right - left, rightPos.bottom); - }); - return { start: start, end: end }; - } - - var sFrom = range.from(), sTo = range.to(); - if (sFrom.line == sTo.line) { - drawForLine(sFrom.line, sFrom.ch, sTo.ch); - } else { - var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); - var singleVLine = visualLine(fromLine) == visualLine(toLine); - var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; - var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; - if (singleVLine) { - if (leftEnd.top < rightStart.top - 2) { - add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); - add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); - } else { - add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); - } - } - if (leftEnd.bottom < rightStart.top) - add(leftSide, leftEnd.bottom, null, rightStart.top); - } - - output.appendChild(fragment); - } - - // Cursor-blinking - function restartBlink(cm) { - if (!cm.state.focused) return; - var display = cm.display; - clearInterval(display.blinker); - var on = true; - display.cursorDiv.style.visibility = ""; - if (cm.options.cursorBlinkRate > 0) - display.blinker = setInterval(function () { - display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; - }, cm.options.cursorBlinkRate); - else if (cm.options.cursorBlinkRate < 0) - display.cursorDiv.style.visibility = "hidden"; - } - - // HIGHLIGHT WORKER - - function startWorker(cm, time) { - if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) - cm.state.highlight.set(time, bind(highlightWorker, cm)); - } - - function highlightWorker(cm) { - var doc = cm.doc; - if (doc.frontier < doc.first) doc.frontier = doc.first; - if (doc.frontier >= cm.display.viewTo) return; - var end = +new Date + cm.options.workTime; - var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); - var changedLines = []; - - doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) { - if (doc.frontier >= cm.display.viewFrom) { // Visible - var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength; - var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true); - line.styles = highlighted.styles; - var oldCls = line.styleClasses, newCls = highlighted.classes; - if (newCls) line.styleClasses = newCls; - else if (oldCls) line.styleClasses = null; - var ischange = !oldStyles || oldStyles.length != line.styles.length || - oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); - for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; - if (ischange) changedLines.push(doc.frontier); - line.stateAfter = tooLong ? state : copyState(doc.mode, state); - } else { - if (line.text.length <= cm.options.maxHighlightLength) - processLine(cm, line.text, state); - line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; - } - ++doc.frontier; - if (+new Date > end) { - startWorker(cm, cm.options.workDelay); - return true; - } - }); - if (changedLines.length) runInOp(cm, function () { - for (var i = 0; i < changedLines.length; i++) - regLineChange(cm, changedLines[i], "text"); - }); - } - - // Finds the line to start with when starting a parse. Tries to - // find a line with a stateAfter, so that it can start with a - // valid state. If that fails, it returns the line with the - // smallest indentation, which tends to need the least context to - // parse correctly. - function findStartLine(cm, n, precise) { - var minindent, minline, doc = cm.doc; - var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); - for (var search = n; search > lim; --search) { - if (search <= doc.first) return doc.first; - var line = getLine(doc, search - 1); - if (line.stateAfter && (!precise || search <= doc.frontier)) return search; - var indented = countColumn(line.text, null, cm.options.tabSize); - if (minline == null || minindent > indented) { - minline = search - 1; - minindent = indented; - } - } - return minline; - } - - function getStateBefore(cm, n, precise) { - var doc = cm.doc, display = cm.display; - if (!doc.mode.startState) return true; - var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos - 1).stateAfter; - if (!state) state = startState(doc.mode); - else state = copyState(doc.mode, state); - doc.iter(pos, n, function (line) { - processLine(cm, line.text, state); - var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; - line.stateAfter = save ? copyState(doc.mode, state) : null; - ++pos; - }); - if (precise) doc.frontier = pos; - return state; - } - - // POSITION MEASUREMENT - - function paddingTop(display) { return display.lineSpace.offsetTop; } - function paddingVert(display) { return display.mover.offsetHeight - display.lineSpace.offsetHeight; } - function paddingH(display) { - if (display.cachedPaddingH) return display.cachedPaddingH; - var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); - var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; - var data = { left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight) }; - if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; - return data; - } - - function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } - function displayWidth(cm) { - return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; - } - function displayHeight(cm) { - return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; - } - - // Ensure the lineView.wrapping.heights array is populated. This is - // an array of bottom offsets for the lines that make up a drawn - // line. When lineWrapping is on, there might be more than one - // height. - function ensureLineHeights(cm, lineView, rect) { - var wrapping = cm.options.lineWrapping; - var curWidth = wrapping && displayWidth(cm); - if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { - var heights = lineView.measure.heights = []; - if (wrapping) { - lineView.measure.width = curWidth; - var rects = lineView.text.firstChild.getClientRects(); - for (var i = 0; i < rects.length - 1; i++) { - var cur = rects[i], next = rects[i + 1]; - if (Math.abs(cur.bottom - next.bottom) > 2) - heights.push((cur.bottom + next.top) / 2 - rect.top); - } - } - heights.push(rect.bottom - rect.top); - } - } - - // Find a line map (mapping character offsets to text nodes) and a - // measurement cache for the given line number. (A line view might - // contain multiple lines when collapsed ranges are present.) - function mapFromLineView(lineView, line, lineN) { - if (lineView.line == line) - return { map: lineView.measure.map, cache: lineView.measure.cache }; - for (var i = 0; i < lineView.rest.length; i++) - if (lineView.rest[i] == line) - return { map: lineView.measure.maps[i], cache: lineView.measure.caches[i] }; - for (var i = 0; i < lineView.rest.length; i++) - if (lineNo(lineView.rest[i]) > lineN) - return { map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true }; - } - - // Render a line into the hidden node display.externalMeasured. Used - // when measurement is needed for a line that's not in the viewport. - function updateExternalMeasurement(cm, line) { - line = visualLine(line); - var lineN = lineNo(line); - var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); - view.lineN = lineN; - var built = view.built = buildLineContent(cm, view); - view.text = built.pre; - removeChildrenAndAdd(cm.display.lineMeasure, built.pre); - return view; - } - - // Get a {top, bottom, left, right} box (in line-local coordinates) - // for a given character. - function measureChar(cm, line, ch, bias) { - return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); - } - - // Find a line view that corresponds to the given line number. - function findViewForLine(cm, lineN) { - if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) - return cm.display.view[findViewIndex(cm, lineN)]; - var ext = cm.display.externalMeasured; - if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) - return ext; - } - - // Measurement can be split in two steps, the set-up work that - // applies to the whole line, and the measurement of the actual - // character. Functions like coordsChar, that need to do a lot of - // measurements in a row, can thus ensure that the set-up work is - // only done once. - function prepareMeasureForLine(cm, line) { - var lineN = lineNo(line); - var view = findViewForLine(cm, lineN); - if (view && !view.text) { - view = null; - } else if (view && view.changes) { - updateLineForChanges(cm, view, lineN, getDimensions(cm)); - cm.curOp.forceUpdate = true; - } - if (!view) - view = updateExternalMeasurement(cm, line); - - var info = mapFromLineView(view, line, lineN); - return { - line: line, view: view, rect: null, - map: info.map, cache: info.cache, before: info.before, - hasHeights: false - }; - } - - // Given a prepared measurement object, measures the position of an - // actual character (or fetches it from the cache). - function measureCharPrepared(cm, prepared, ch, bias, varHeight) { - if (prepared.before) ch = -1; - var key = ch + (bias || ""), found; - if (prepared.cache.hasOwnProperty(key)) { - found = prepared.cache[key]; - } else { - if (!prepared.rect) - prepared.rect = prepared.view.text.getBoundingClientRect(); - if (!prepared.hasHeights) { - ensureLineHeights(cm, prepared.view, prepared.rect); - prepared.hasHeights = true; - } - found = measureCharInner(cm, prepared, ch, bias); - if (!found.bogus) prepared.cache[key] = found; - } - return { - left: found.left, right: found.right, - top: varHeight ? found.rtop : found.top, - bottom: varHeight ? found.rbottom : found.bottom - }; - } - - var nullRect = { left: 0, right: 0, top: 0, bottom: 0 }; - - function nodeAndOffsetInLineMap(map, ch, bias) { - var node, start, end, collapse; - // First, search the line map for the text node corresponding to, - // or closest to, the target character. - for (var i = 0; i < map.length; i += 3) { - var mStart = map[i], mEnd = map[i + 1]; - if (ch < mStart) { - start = 0; end = 1; - collapse = "left"; - } else if (ch < mEnd) { - start = ch - mStart; - end = start + 1; - } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { - end = mEnd - mStart; - start = end - 1; - if (ch >= mEnd) collapse = "right"; - } - if (start != null) { - node = map[i + 2]; - if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) - collapse = bias; - if (bias == "left" && start == 0) - while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { - node = map[(i -= 3) + 2]; - collapse = "left"; - } - if (bias == "right" && start == mEnd - mStart) - while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { - node = map[(i += 3) + 2]; - collapse = "right"; - } - break; - } - } - return { node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd }; - } - - function getUsefulRect(rects, bias) { - var rect = nullRect - if (bias == "left") for (var i = 0; i < rects.length; i++) { - if ((rect = rects[i]).left != rect.right) break - } else for (var i = rects.length - 1; i >= 0; i--) { - if ((rect = rects[i]).left != rect.right) break - } - return rect - } - - function measureCharInner(cm, prepared, ch, bias) { - var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); - var node = place.node, start = place.start, end = place.end, collapse = place.collapse; - - var rect; - if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. - for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned - while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; - while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; - if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) - rect = node.parentNode.getBoundingClientRect(); - else - rect = getUsefulRect(range(node, start, end).getClientRects(), bias) - if (rect.left || rect.right || start == 0) break; - end = start; - start = start - 1; - collapse = "right"; - } - if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); - } else { // If it is a widget, simply get the box for the whole widget. - if (start > 0) collapse = bias = "right"; - var rects; - if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) - rect = rects[bias == "right" ? rects.length - 1 : 0]; - else - rect = node.getBoundingClientRect(); - } - if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { - var rSpan = node.parentNode.getClientRects()[0]; - if (rSpan) - rect = { left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom }; - else - rect = nullRect; - } - - var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; - var mid = (rtop + rbot) / 2; - var heights = prepared.view.measure.heights; - for (var i = 0; i < heights.length - 1; i++) - if (mid < heights[i]) break; - var top = i ? heights[i - 1] : 0, bot = heights[i]; - var result = { - left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, - right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, - top: top, bottom: bot - }; - if (!rect.left && !rect.right) result.bogus = true; - if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } - - return result; - } - - // Work around problem with bounding client rects on ranges being - // returned incorrectly when zoomed on IE10 and below. - function maybeUpdateRectForZooming(measure, rect) { - if (!window.screen || screen.logicalXDPI == null || - screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) - return rect; - var scaleX = screen.logicalXDPI / screen.deviceXDPI; - var scaleY = screen.logicalYDPI / screen.deviceYDPI; - return { - left: rect.left * scaleX, right: rect.right * scaleX, - top: rect.top * scaleY, bottom: rect.bottom * scaleY - }; - } - - function clearLineMeasurementCacheFor(lineView) { - if (lineView.measure) { - lineView.measure.cache = {}; - lineView.measure.heights = null; - if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) - lineView.measure.caches[i] = {}; - } - } - - function clearLineMeasurementCache(cm) { - cm.display.externalMeasure = null; - removeChildren(cm.display.lineMeasure); - for (var i = 0; i < cm.display.view.length; i++) - clearLineMeasurementCacheFor(cm.display.view[i]); - } - - function clearCaches(cm) { - clearLineMeasurementCache(cm); - cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; - if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; - cm.display.lineNumChars = null; - } - - function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } - function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } - - // Converts a {top, bottom, left, right} box from line-local - // coordinates into another coordinate system. Context may be one of - // "line", "div" (display.lineDiv), "local"/null (editor), "window", - // or "page". - function intoCoordSystem(cm, lineObj, rect, context) { - if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { - var size = widgetHeight(lineObj.widgets[i]); - rect.top += size; rect.bottom += size; - } - if (context == "line") return rect; - if (!context) context = "local"; - var yOff = heightAtLine(lineObj); - if (context == "local") yOff += paddingTop(cm.display); - else yOff -= cm.display.viewOffset; - if (context == "page" || context == "window") { - var lOff = cm.display.lineSpace.getBoundingClientRect(); - yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); - var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); - rect.left += xOff; rect.right += xOff; - } - rect.top += yOff; rect.bottom += yOff; - return rect; - } - - // Coverts a box from "div" coords to another coordinate system. - // Context may be "window", "page", "div", or "local"/null. - function fromCoordSystem(cm, coords, context) { - if (context == "div") return coords; - var left = coords.left, top = coords.top; - // First move into "page" coordinate system - if (context == "page") { - left -= pageScrollX(); - top -= pageScrollY(); - } else if (context == "local" || !context) { - var localBox = cm.display.sizer.getBoundingClientRect(); - left += localBox.left; - top += localBox.top; - } - - var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); - return { left: left - lineSpaceBox.left, top: top - lineSpaceBox.top }; - } - - function charCoords(cm, pos, context, lineObj, bias) { - if (!lineObj) lineObj = getLine(cm.doc, pos.line); - return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); - } - - // Returns a box for a given cursor position, which may have an - // 'other' property containing the position of the secondary cursor - // on a bidi boundary. - function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { - lineObj = lineObj || getLine(cm.doc, pos.line); - if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); - function get(ch, right) { - var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); - if (right) m.left = m.right; else m.right = m.left; - return intoCoordSystem(cm, lineObj, m, context); - } - function getBidi(ch, partPos) { - var part = order[partPos], right = part.level % 2; - if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { - part = order[--partPos]; - ch = bidiRight(part) - (part.level % 2 ? 0 : 1); - right = true; - } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { - part = order[++partPos]; - ch = bidiLeft(part) - part.level % 2; - right = false; - } - if (right && ch == part.to && ch > part.from) return get(ch - 1); - return get(ch, right); - } - var order = getOrder(lineObj), ch = pos.ch; - if (!order) return get(ch); - var partPos = getBidiPartAt(order, ch); - var val = getBidi(ch, partPos); - if (bidiOther != null) val.other = getBidi(ch, bidiOther); - return val; - } - - // Used to cheaply estimate the coordinates for a position. Used for - // intermediate scroll updates. - function estimateCoords(cm, pos) { - var left = 0, pos = clipPos(cm.doc, pos); - if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; - var lineObj = getLine(cm.doc, pos.line); - var top = heightAtLine(lineObj) + paddingTop(cm.display); - return { left: left, right: left, top: top, bottom: top + lineObj.height }; - } - - // Positions returned by coordsChar contain some extra information. - // xRel is the relative x position of the input coordinates compared - // to the found position (so xRel > 0 means the coordinates are to - // the right of the character position, for example). When outside - // is true, that means the coordinates lie outside the line's - // vertical range. - function PosWithInfo(line, ch, outside, xRel) { - var pos = Pos(line, ch); - pos.xRel = xRel; - if (outside) pos.outside = true; - return pos; - } - - // Compute the character position closest to the given coordinates. - // Input must be lineSpace-local ("div" coordinate system). - function coordsChar(cm, x, y) { - var doc = cm.doc; - y += cm.display.viewOffset; - if (y < 0) return PosWithInfo(doc.first, 0, true, -1); - var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; - if (lineN > last) - return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); - if (x < 0) x = 0; - - var lineObj = getLine(doc, lineN); - for (; ;) { - var found = coordsCharInner(cm, lineObj, lineN, x, y); - var merged = collapsedSpanAtEnd(lineObj); - var mergedPos = merged && merged.find(0, true); - if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) - lineN = lineNo(lineObj = mergedPos.to.line); - else - return found; - } - } - - function coordsCharInner(cm, lineObj, lineNo, x, y) { - var innerOff = y - heightAtLine(lineObj); - var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; - var preparedMeasure = prepareMeasureForLine(cm, lineObj); - - function getX(ch) { - var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); - wrongLine = true; - if (innerOff > sp.bottom) return sp.left - adjust; - else if (innerOff < sp.top) return sp.left + adjust; - else wrongLine = false; - return sp.left; - } - - var bidi = getOrder(lineObj), dist = lineObj.text.length; - var from = lineLeft(lineObj), to = lineRight(lineObj); - var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; - - if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); - // Do a binary search between these bounds. - for (; ;) { - if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { - var ch = x < fromX || x - fromX <= toX - x ? from : to; - var outside = ch == from ? fromOutside : toOutside - var xDiff = x - (ch == from ? fromX : toX); - // This is a kludge to handle the case where the coordinates - // are after a line-wrapped line. We should replace it with a - // more general handling of cursor positions around line - // breaks. (Issue #4078) - if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 && - ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) { - var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right"); - if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) { - outside = false - ch++ - xDiff = x - charSize.right - } - } - while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; - var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); - return pos; - } - var step = Math.ceil(dist / 2), middle = from + step; - if (bidi) { - middle = from; - for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); - } - var middleX = getX(middle); - if (middleX > x) { to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step; } - else { from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step; } - } - } - - var measureText; - // Compute the default text height. - function textHeight(display) { - if (display.cachedTextHeight != null) return display.cachedTextHeight; - if (measureText == null) { - measureText = elt("pre"); - // Measure a bunch of lines, for browsers that compute - // fractional heights. - for (var i = 0; i < 49; ++i) { - measureText.appendChild(document.createTextNode("x")); - measureText.appendChild(elt("br")); - } - measureText.appendChild(document.createTextNode("x")); - } - removeChildrenAndAdd(display.measure, measureText); - var height = measureText.offsetHeight / 50; - if (height > 3) display.cachedTextHeight = height; - removeChildren(display.measure); - return height || 1; - } - - // Compute the default character width. - function charWidth(display) { - if (display.cachedCharWidth != null) return display.cachedCharWidth; - var anchor = elt("span", "xxxxxxxxxx"); - var pre = elt("pre", [anchor]); - removeChildrenAndAdd(display.measure, pre); - var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; - if (width > 2) display.cachedCharWidth = width; - return width || 10; - } - - // OPERATIONS - - // Operations are used to wrap a series of changes to the editor - // state in such a way that each change won't have to update the - // cursor and display (which would be awkward, slow, and - // error-prone). Instead, display updates are batched and then all - // combined and executed at once. - - var operationGroup = null; - - var nextOpId = 0; - // Start a new operation. - function startOperation(cm) { - cm.curOp = { - cm: cm, - viewChanged: false, // Flag that indicates that lines might need to be redrawn - startHeight: cm.doc.height, // Used to detect need to update scrollbar - forceUpdate: false, // Used to force a redraw - updateInput: null, // Whether to reset the input textarea - typing: false, // Whether this reset should be careful to leave existing text (for compositing) - changeObjs: null, // Accumulated changes, for firing change events - cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on - cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already - selectionChanged: false, // Whether the selection needs to be redrawn - updateMaxLine: false, // Set when the widest line needs to be determined anew - scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet - scrollToPos: null, // Used to scroll to a specific position - focus: false, - id: ++nextOpId // Unique ID - }; - if (operationGroup) { - operationGroup.ops.push(cm.curOp); - } else { - cm.curOp.ownsGroup = operationGroup = { - ops: [cm.curOp], - delayedCallbacks: [] - }; - } - } - - function fireCallbacksForOps(group) { - // Calls delayed callbacks and cursorActivity handlers until no - // new ones appear - var callbacks = group.delayedCallbacks, i = 0; - do { - for (; i < callbacks.length; i++) - callbacks[i].call(null); - for (var j = 0; j < group.ops.length; j++) { - var op = group.ops[j]; - if (op.cursorActivityHandlers) - while (op.cursorActivityCalled < op.cursorActivityHandlers.length) - op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); - } - } while (i < callbacks.length); - } - - // Finish an operation, updating the display and signalling delayed events - function endOperation(cm) { - var op = cm.curOp, group = op.ownsGroup; - if (!group) return; - - try { fireCallbacksForOps(group); } - finally { - operationGroup = null; - for (var i = 0; i < group.ops.length; i++) - group.ops[i].cm.curOp = null; - endOperations(group); - } - } - - // The DOM updates done when an operation finishes are batched so - // that the minimum number of relayouts are required. - function endOperations(group) { - var ops = group.ops; - for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_R1(ops[i]); - for (var i = 0; i < ops.length; i++) // Write DOM (maybe) - endOperation_W1(ops[i]); - for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_R2(ops[i]); - for (var i = 0; i < ops.length; i++) // Write DOM (maybe) - endOperation_W2(ops[i]); - for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_finish(ops[i]); - } - - function endOperation_R1(op) { - var cm = op.cm, display = cm.display; - maybeClipScrollbars(cm); - if (op.updateMaxLine) findMaxLine(cm); - - op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || - op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || - op.scrollToPos.to.line >= display.viewTo) || - display.maxLineChanged && cm.options.lineWrapping; - op.update = op.mustUpdate && - new DisplayUpdate(cm, op.mustUpdate && { top: op.scrollTop, ensure: op.scrollToPos }, op.forceUpdate); - } - - function endOperation_W1(op) { - op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); - } - - function endOperation_R2(op) { - var cm = op.cm, display = cm.display; - if (op.updatedDisplay) updateHeightsInViewport(cm); - - op.barMeasure = measureForScrollbars(cm); - - // If the max line changed since it was last measured, measure it, - // and ensure the document's width matches it. - // updateDisplay_W2 will use these properties to do the actual resizing - if (display.maxLineChanged && !cm.options.lineWrapping) { - op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; - cm.display.sizerWidth = op.adjustWidthTo; - op.barMeasure.scrollWidth = - Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); - op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); - } - - if (op.updatedDisplay || op.selectionChanged) - op.preparedSelection = display.input.prepareSelection(op.focus); - } - - function endOperation_W2(op) { - var cm = op.cm; - - if (op.adjustWidthTo != null) { - cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; - if (op.maxScrollLeft < cm.doc.scrollLeft) - setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); - cm.display.maxLineChanged = false; - } - - var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()) - if (op.preparedSelection) - cm.display.input.showSelection(op.preparedSelection, takeFocus); - if (op.updatedDisplay || op.startHeight != cm.doc.height) - updateScrollbars(cm, op.barMeasure); - if (op.updatedDisplay) - setDocumentHeight(cm, op.barMeasure); - - if (op.selectionChanged) restartBlink(cm); - - if (cm.state.focused && op.updateInput) - cm.display.input.reset(op.typing); - if (takeFocus) ensureFocus(op.cm); - } - - function endOperation_finish(op) { - var cm = op.cm, display = cm.display, doc = cm.doc; - - if (op.updatedDisplay) postUpdateDisplay(cm, op.update); - - // Abort mouse wheel delta measurement, when scrolling explicitly - if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) - display.wheelStartX = display.wheelStartY = null; - - // Propagate the scroll position to the actual DOM scroller - if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { - doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); - display.scrollbars.setScrollTop(doc.scrollTop); - display.scroller.scrollTop = doc.scrollTop; - } - if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { - doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); - display.scrollbars.setScrollLeft(doc.scrollLeft); - display.scroller.scrollLeft = doc.scrollLeft; - alignHorizontally(cm); - } - // If we need to scroll a specific position into view, do so. - if (op.scrollToPos) { - var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), - clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); - if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); - } - - // Fire events for markers that are hidden/unidden by editing or - // undoing - var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; - if (hidden) for (var i = 0; i < hidden.length; ++i) - if (!hidden[i].lines.length) signal(hidden[i], "hide"); - if (unhidden) for (var i = 0; i < unhidden.length; ++i) - if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); - - if (display.wrapper.offsetHeight) - doc.scrollTop = cm.display.scroller.scrollTop; - - // Fire change events, and delayed event handlers - if (op.changeObjs) - signal(cm, "changes", cm, op.changeObjs); - if (op.update) - op.update.finish(); - } - - // Run the given function in an operation - function runInOp(cm, f) { - if (cm.curOp) return f(); - startOperation(cm); - try { return f(); } - finally { endOperation(cm); } - } - // Wraps a function in an operation. Returns the wrapped function. - function operation(cm, f) { - return function () { - if (cm.curOp) return f.apply(cm, arguments); - startOperation(cm); - try { return f.apply(cm, arguments); } - finally { endOperation(cm); } - }; - } - // Used to add methods to editor and doc instances, wrapping them in - // operations. - function methodOp(f) { - return function () { - if (this.curOp) return f.apply(this, arguments); - startOperation(this); - try { return f.apply(this, arguments); } - finally { endOperation(this); } - }; - } - function docMethodOp(f) { - return function () { - var cm = this.cm; - if (!cm || cm.curOp) return f.apply(this, arguments); - startOperation(cm); - try { return f.apply(this, arguments); } - finally { endOperation(cm); } - }; - } - - // VIEW TRACKING - - // These objects are used to represent the visible (currently drawn) - // part of the document. A LineView may correspond to multiple - // logical lines, if those are connected by collapsed ranges. - function LineView(doc, line, lineN) { - // The starting line - this.line = line; - // Continuing lines, if any - this.rest = visualLineContinued(line); - // Number of logical lines in this visual line - this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; - this.node = this.text = null; - this.hidden = lineIsHidden(doc, line); - } - - // Create a range of LineView objects for the given lines. - function buildViewArray(cm, from, to) { - var array = [], nextPos; - for (var pos = from; pos < to; pos = nextPos) { - var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); - nextPos = pos + view.size; - array.push(view); - } - return array; - } - - // Updates the display.view data structure for a given change to the - // document. From and to are in pre-change coordinates. Lendiff is - // the amount of lines added or subtracted by the change. This is - // used for changes that span multiple lines, or change the way - // lines are divided into visual lines. regLineChange (below) - // registers single-line changes. - function regChange(cm, from, to, lendiff) { - if (from == null) from = cm.doc.first; - if (to == null) to = cm.doc.first + cm.doc.size; - if (!lendiff) lendiff = 0; - - var display = cm.display; - if (lendiff && to < display.viewTo && - (display.updateLineNumbers == null || display.updateLineNumbers > from)) - display.updateLineNumbers = from; - - cm.curOp.viewChanged = true; - - if (from >= display.viewTo) { // Change after - if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) - resetView(cm); - } else if (to <= display.viewFrom) { // Change before - if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { - resetView(cm); - } else { - display.viewFrom += lendiff; - display.viewTo += lendiff; - } - } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap - resetView(cm); - } else if (from <= display.viewFrom) { // Top overlap - var cut = viewCuttingPoint(cm, to, to + lendiff, 1); - if (cut) { - display.view = display.view.slice(cut.index); - display.viewFrom = cut.lineN; - display.viewTo += lendiff; - } else { - resetView(cm); - } - } else if (to >= display.viewTo) { // Bottom overlap - var cut = viewCuttingPoint(cm, from, from, -1); - if (cut) { - display.view = display.view.slice(0, cut.index); - display.viewTo = cut.lineN; - } else { - resetView(cm); - } - } else { // Gap in the middle - var cutTop = viewCuttingPoint(cm, from, from, -1); - var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); - if (cutTop && cutBot) { - display.view = display.view.slice(0, cutTop.index) - .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) - .concat(display.view.slice(cutBot.index)); - display.viewTo += lendiff; - } else { - resetView(cm); - } - } - - var ext = display.externalMeasured; - if (ext) { - if (to < ext.lineN) - ext.lineN += lendiff; - else if (from < ext.lineN + ext.size) - display.externalMeasured = null; - } - } - - // Register a change to a single line. Type must be one of "text", - // "gutter", "class", "widget" - function regLineChange(cm, line, type) { - cm.curOp.viewChanged = true; - var display = cm.display, ext = cm.display.externalMeasured; - if (ext && line >= ext.lineN && line < ext.lineN + ext.size) - display.externalMeasured = null; - - if (line < display.viewFrom || line >= display.viewTo) return; - var lineView = display.view[findViewIndex(cm, line)]; - if (lineView.node == null) return; - var arr = lineView.changes || (lineView.changes = []); - if (indexOf(arr, type) == -1) arr.push(type); - } - - // Clear the view. - function resetView(cm) { - cm.display.viewFrom = cm.display.viewTo = cm.doc.first; - cm.display.view = []; - cm.display.viewOffset = 0; - } - - // Find the view element corresponding to a given line. Return null - // when the line isn't visible. - function findViewIndex(cm, n) { - if (n >= cm.display.viewTo) return null; - n -= cm.display.viewFrom; - if (n < 0) return null; - var view = cm.display.view; - for (var i = 0; i < view.length; i++) { - n -= view[i].size; - if (n < 0) return i; - } - } - - function viewCuttingPoint(cm, oldN, newN, dir) { - var index = findViewIndex(cm, oldN), diff, view = cm.display.view; - if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) - return { index: index, lineN: newN }; - for (var i = 0, n = cm.display.viewFrom; i < index; i++) - n += view[i].size; - if (n != oldN) { - if (dir > 0) { - if (index == view.length - 1) return null; - diff = (n + view[index].size) - oldN; - index++; - } else { - diff = n - oldN; - } - oldN += diff; newN += diff; - } - while (visualLineNo(cm.doc, newN) != newN) { - if (index == (dir < 0 ? 0 : view.length - 1)) return null; - newN += dir * view[index - (dir < 0 ? 1 : 0)].size; - index += dir; - } - return { index: index, lineN: newN }; - } - - // Force the view to cover a given range, adding empty view element - // or clipping off existing ones as needed. - function adjustView(cm, from, to) { - var display = cm.display, view = display.view; - if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { - display.view = buildViewArray(cm, from, to); - display.viewFrom = from; - } else { - if (display.viewFrom > from) - display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); - else if (display.viewFrom < from) - display.view = display.view.slice(findViewIndex(cm, from)); - display.viewFrom = from; - if (display.viewTo < to) - display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); - else if (display.viewTo > to) - display.view = display.view.slice(0, findViewIndex(cm, to)); - } - display.viewTo = to; - } - - // Count the number of lines in the view whose DOM representation is - // out of date (or nonexistent). - function countDirtyView(cm) { - var view = cm.display.view, dirty = 0; - for (var i = 0; i < view.length; i++) { - var lineView = view[i]; - if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; - } - return dirty; - } - - // EVENT HANDLERS - - // Attach the necessary event handlers when initializing the editor - function registerEventHandlers(cm) { - var d = cm.display; - on(d.scroller, "mousedown", operation(cm, onMouseDown)); - // Older IE's will not fire a second mousedown for a double click - if (ie && ie_version < 11) - on(d.scroller, "dblclick", operation(cm, function (e) { - if (signalDOMEvent(cm, e)) return; - var pos = posFromMouse(cm, e); - if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; - e_preventDefault(e); - var word = cm.findWordAt(pos); - extendSelection(cm.doc, word.anchor, word.head); - })); - else - on(d.scroller, "dblclick", function (e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); - // Some browsers fire contextmenu *after* opening the menu, at - // which point we can't mess with it anymore. Context menu is - // handled in onMouseDown for these browsers. - if (!captureRightClick) on(d.scroller, "contextmenu", function (e) { onContextMenu(cm, e); }); - - // Used to suppress mouse event handling when a touch happens - var touchFinished, prevTouch = { end: 0 }; - function finishTouch() { - if (d.activeTouch) { - touchFinished = setTimeout(function () { d.activeTouch = null; }, 1000); - prevTouch = d.activeTouch; - prevTouch.end = +new Date; - } - }; - function isMouseLikeTouchEvent(e) { - if (e.touches.length != 1) return false; - var touch = e.touches[0]; - return touch.radiusX <= 1 && touch.radiusY <= 1; - } - function farAway(touch, other) { - if (other.left == null) return true; - var dx = other.left - touch.left, dy = other.top - touch.top; - return dx * dx + dy * dy > 20 * 20; - } - on(d.scroller, "touchstart", function (e) { - if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { - clearTimeout(touchFinished); - var now = +new Date; - d.activeTouch = { - start: now, moved: false, - prev: now - prevTouch.end <= 300 ? prevTouch : null - }; - if (e.touches.length == 1) { - d.activeTouch.left = e.touches[0].pageX; - d.activeTouch.top = e.touches[0].pageY; - } - } - }); - on(d.scroller, "touchmove", function () { - if (d.activeTouch) d.activeTouch.moved = true; - }); - on(d.scroller, "touchend", function (e) { - var touch = d.activeTouch; - if (touch && !eventInWidget(d, e) && touch.left != null && - !touch.moved && new Date - touch.start < 300) { - var pos = cm.coordsChar(d.activeTouch, "page"), range; - if (!touch.prev || farAway(touch, touch.prev)) // Single tap - range = new Range(pos, pos); - else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap - range = cm.findWordAt(pos); - else // Triple tap - range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); - cm.setSelection(range.anchor, range.head); - cm.focus(); - e_preventDefault(e); - } - finishTouch(); - }); - on(d.scroller, "touchcancel", finishTouch); - - // Sync scrolling between fake scrollbars and real scrollable - // area, ensure viewport is updated when scrolling. - on(d.scroller, "scroll", function () { - if (d.scroller.clientHeight) { - setScrollTop(cm, d.scroller.scrollTop); - setScrollLeft(cm, d.scroller.scrollLeft, true); - signal(cm, "scroll", cm); - } - }); - - // Listen to wheel events in order to try and update the viewport on time. - on(d.scroller, "mousewheel", function (e) { onScrollWheel(cm, e); }); - on(d.scroller, "DOMMouseScroll", function (e) { onScrollWheel(cm, e); }); - - // Prevent wrapper from ever scrolling - on(d.wrapper, "scroll", function () { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); - - d.dragFunctions = { - enter: function (e) { if (!signalDOMEvent(cm, e)) e_stop(e); }, - over: function (e) { if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); } }, - start: function (e) { onDragStart(cm, e); }, - drop: operation(cm, onDrop), - leave: function (e) { if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); } } - }; - - var inp = d.input.getField(); - on(inp, "keyup", function (e) { onKeyUp.call(cm, e); }); - on(inp, "keydown", operation(cm, onKeyDown)); - on(inp, "keypress", operation(cm, onKeyPress)); - on(inp, "focus", bind(onFocus, cm)); - on(inp, "blur", bind(onBlur, cm)); - } - - function dragDropChanged(cm, value, old) { - var wasOn = old && old != CodeMirror.Init; - if (!value != !wasOn) { - var funcs = cm.display.dragFunctions; - var toggle = value ? on : off; - toggle(cm.display.scroller, "dragstart", funcs.start); - toggle(cm.display.scroller, "dragenter", funcs.enter); - toggle(cm.display.scroller, "dragover", funcs.over); - toggle(cm.display.scroller, "dragleave", funcs.leave); - toggle(cm.display.scroller, "drop", funcs.drop); - } - } - - // Called when the window resizes - function onResize(cm) { - var d = cm.display; - if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) - return; - // Might be a text scaling operation, clear size caches. - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; - d.scrollbarsClipped = false; - cm.setSize(); - } - - // MOUSE EVENTS - - // Return true when the given mouse event happened in a widget - function eventInWidget(display, e) { - for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { - if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || - (n.parentNode == display.sizer && n != display.mover)) - return true; - } - } - - // Given a mouse event, find the corresponding position. If liberal - // is false, it checks whether a gutter or scrollbar was clicked, - // and returns null if it was. forRect is used by rectangular - // selections, and tries to estimate a character position even for - // coordinates beyond the right of the text. - function posFromMouse(cm, e, liberal, forRect) { - var display = cm.display; - if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; - - var x, y, space = display.lineSpace.getBoundingClientRect(); - // Fails unpredictably on IE[67] when mouse is dragged around quickly. - try { x = e.clientX - space.left; y = e.clientY - space.top; } - catch (e) { return null; } - var coords = coordsChar(cm, x, y), line; - if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { - var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; - coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); - } - return coords; - } - - // A mouse down can be a single click, double click, triple click, - // start of selection drag, start of text drag, new cursor - // (ctrl-click), rectangle drag (alt-drag), or xwin - // middle-click-paste. Or it might be a click on something we should - // not interfere with, such as a scrollbar or widget. - function onMouseDown(e) { - var cm = this, display = cm.display; - if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return; - display.shift = e.shiftKey; - - if (eventInWidget(display, e)) { - if (!webkit) { - // Briefly turn off draggability, to allow widgets to do - // normal dragging things. - display.scroller.draggable = false; - setTimeout(function () { display.scroller.draggable = true; }, 100); - } - return; - } - if (clickInGutter(cm, e)) return; - var start = posFromMouse(cm, e); - window.focus(); - - switch (e_button(e)) { - case 1: - // #3261: make sure, that we're not starting a second selection - if (cm.state.selectingText) - cm.state.selectingText(e); - else if (start) - leftButtonDown(cm, e, start); - else if (e_target(e) == display.scroller) - e_preventDefault(e); - break; - case 2: - if (webkit) cm.state.lastMiddleDown = +new Date; - if (start) extendSelection(cm.doc, start); - setTimeout(function () { display.input.focus(); }, 20); - e_preventDefault(e); - break; - case 3: - if (captureRightClick) onContextMenu(cm, e); - else delayBlurEvent(cm); - break; - } - } - - var lastClick, lastDoubleClick; - function leftButtonDown(cm, e, start) { - if (ie) setTimeout(bind(ensureFocus, cm), 0); - else cm.curOp.focus = activeElt(); - - var now = +new Date, type; - if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { - type = "triple"; - } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { - type = "double"; - lastDoubleClick = { time: now, pos: start }; - } else { - type = "single"; - lastClick = { time: now, pos: start }; - } - - var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; - if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && - type == "single" && (contained = sel.contains(start)) > -1 && - (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && - (cmp(contained.to(), start) > 0 || start.xRel < 0)) - leftButtonStartDrag(cm, e, start, modifier); - else - leftButtonSelect(cm, e, start, type, modifier); - } - - // Start a text drag. When it ends, see if any dragging actually - // happen, and treat as a click if it didn't. - function leftButtonStartDrag(cm, e, start, modifier) { - var display = cm.display, startTime = +new Date; - var dragEnd = operation(cm, function (e2) { - if (webkit) display.scroller.draggable = false; - cm.state.draggingText = false; - off(document, "mouseup", dragEnd); - off(display.scroller, "drop", dragEnd); - if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { - e_preventDefault(e2); - if (!modifier && +new Date - 200 < startTime) - extendSelection(cm.doc, start); - // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) - if (webkit || ie && ie_version == 9) - setTimeout(function () { document.body.focus(); display.input.focus(); }, 20); - else - display.input.focus(); - } - }); - // Let the drag handler handle this. - if (webkit) display.scroller.draggable = true; - cm.state.draggingText = dragEnd; - dragEnd.copy = mac ? e.altKey : e.ctrlKey - // IE's approach to draggable - if (display.scroller.dragDrop) display.scroller.dragDrop(); - on(document, "mouseup", dragEnd); - on(display.scroller, "drop", dragEnd); - } - - // Normal selection, as opposed to text dragging. - function leftButtonSelect(cm, e, start, type, addNew) { - var display = cm.display, doc = cm.doc; - e_preventDefault(e); - - var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; - if (addNew && !e.shiftKey) { - ourIndex = doc.sel.contains(start); - if (ourIndex > -1) - ourRange = ranges[ourIndex]; - else - ourRange = new Range(start, start); - } else { - ourRange = doc.sel.primary(); - ourIndex = doc.sel.primIndex; - } - - if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) { - type = "rect"; - if (!addNew) ourRange = new Range(start, start); - start = posFromMouse(cm, e, true, true); - ourIndex = -1; - } else if (type == "double") { - var word = cm.findWordAt(start); - if (cm.display.shift || doc.extend) - ourRange = extendRange(doc, ourRange, word.anchor, word.head); - else - ourRange = word; - } else if (type == "triple") { - var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); - if (cm.display.shift || doc.extend) - ourRange = extendRange(doc, ourRange, line.anchor, line.head); - else - ourRange = line; - } else { - ourRange = extendRange(doc, ourRange, start); - } - - if (!addNew) { - ourIndex = 0; - setSelection(doc, new Selection([ourRange], 0), sel_mouse); - startSel = doc.sel; - } else if (ourIndex == -1) { - ourIndex = ranges.length; - setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), - { scroll: false, origin: "*mouse" }); - } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { - setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), - { scroll: false, origin: "*mouse" }); - startSel = doc.sel; - } else { - replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); - } - - var lastPos = start; - function extendTo(pos) { - if (cmp(lastPos, pos) == 0) return; - lastPos = pos; - - if (type == "rect") { - var ranges = [], tabSize = cm.options.tabSize; - var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); - var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); - var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); - for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); - line <= end; line++) { - var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); - if (left == right) - ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); - else if (text.length > leftPos) - ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); - } - if (!ranges.length) ranges.push(new Range(start, start)); - setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), - { origin: "*mouse", scroll: false }); - cm.scrollIntoView(pos); - } else { - var oldRange = ourRange; - var anchor = oldRange.anchor, head = pos; - if (type != "single") { - if (type == "double") - var range = cm.findWordAt(pos); - else - var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); - if (cmp(range.anchor, anchor) > 0) { - head = range.head; - anchor = minPos(oldRange.from(), range.anchor); - } else { - head = range.anchor; - anchor = maxPos(oldRange.to(), range.head); - } - } - var ranges = startSel.ranges.slice(0); - ranges[ourIndex] = new Range(clipPos(doc, anchor), head); - setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); - } - } - - var editorSize = display.wrapper.getBoundingClientRect(); - // Used to ensure timeout re-tries don't fire when another extend - // happened in the meantime (clearTimeout isn't reliable -- at - // least on Chrome, the timeouts still happen even when cleared, - // if the clear happens after their scheduled firing time). - var counter = 0; - - function extend(e) { - var curCount = ++counter; - var cur = posFromMouse(cm, e, true, type == "rect"); - if (!cur) return; - if (cmp(cur, lastPos) != 0) { - cm.curOp.focus = activeElt(); - extendTo(cur); - var visible = visibleLines(display, doc); - if (cur.line >= visible.to || cur.line < visible.from) - setTimeout(operation(cm, function () { if (counter == curCount) extend(e); }), 150); - } else { - var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; - if (outside) setTimeout(operation(cm, function () { - if (counter != curCount) return; - display.scroller.scrollTop += outside; - extend(e); - }), 50); - } - } - - function done(e) { - cm.state.selectingText = false; - counter = Infinity; - e_preventDefault(e); - display.input.focus(); - off(document, "mousemove", move); - off(document, "mouseup", up); - doc.history.lastSelOrigin = null; - } - - var move = operation(cm, function (e) { - if (!e_button(e)) done(e); - else extend(e); - }); - var up = operation(cm, done); - cm.state.selectingText = up; - on(document, "mousemove", move); - on(document, "mouseup", up); - } - - // Determines whether an event happened in the gutter, and fires the - // handlers for the corresponding event. - function gutterEvent(cm, e, type, prevent) { - try { var mX = e.clientX, mY = e.clientY; } - catch (e) { return false; } - if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; - if (prevent) e_preventDefault(e); - - var display = cm.display; - var lineBox = display.lineDiv.getBoundingClientRect(); - - if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); - mY -= lineBox.top - display.viewOffset; - - for (var i = 0; i < cm.options.gutters.length; ++i) { - var g = display.gutters.childNodes[i]; - if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.doc, mY); - var gutter = cm.options.gutters[i]; - signal(cm, type, cm, line, gutter, e); - return e_defaultPrevented(e); - } - } - } - - function clickInGutter(cm, e) { - return gutterEvent(cm, e, "gutterClick", true); - } - - // Kludge to work around strange IE behavior where it'll sometimes - // re-fire a series of drag-related events right after the drop (#1551) - var lastDrop = 0; - - function onDrop(e) { - var cm = this; - clearDragCursor(cm); - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) - return; - e_preventDefault(e); - if (ie) lastDrop = +new Date; - var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; - if (!pos || cm.isReadOnly()) return; - // Might be a file drop, in which case we simply extract the text - // and insert it. - if (files && files.length && window.FileReader && window.File) { - var n = files.length, text = Array(n), read = 0; - var loadFile = function (file, i) { - if (cm.options.allowDropFileTypes && - indexOf(cm.options.allowDropFileTypes, file.type) == -1) - return; - - var reader = new FileReader; - reader.onload = operation(cm, function () { - var content = reader.result; - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = ""; - text[i] = content; - if (++read == n) { - pos = clipPos(cm.doc, pos); - var change = { - from: pos, to: pos, - text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), - origin: "paste" - }; - makeChange(cm.doc, change); - setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); - } - }); - reader.readAsText(file); - }; - for (var i = 0; i < n; ++i) loadFile(files[i], i); - } else { // Normal drop - // Don't do a replace if the drop happened inside of the selected text. - if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { - cm.state.draggingText(e); - // Ensure the editor is re-focused - setTimeout(function () { cm.display.input.focus(); }, 20); - return; - } - try { - var text = e.dataTransfer.getData("Text"); - if (text) { - if (cm.state.draggingText && !cm.state.draggingText.copy) - var selected = cm.listSelections(); - setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); - if (selected) for (var i = 0; i < selected.length; ++i) - replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); - cm.replaceSelection(text, "around", "paste"); - cm.display.input.focus(); - } - } - catch (e) { } - } - } - - function onDragStart(cm, e) { - if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; - - e.dataTransfer.setData("Text", cm.getSelection()); - e.dataTransfer.effectAllowed = "copyMove" - - // Use dummy image instead of default browsers image. - // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. - if (e.dataTransfer.setDragImage && !safari) { - var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); - img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; - if (presto) { - img.width = img.height = 1; - cm.display.wrapper.appendChild(img); - // Force a relayout, or Opera won't use our image for some obscure reason - img._top = img.offsetTop; - } - e.dataTransfer.setDragImage(img, 0, 0); - if (presto) img.parentNode.removeChild(img); - } - } - - function onDragOver(cm, e) { - var pos = posFromMouse(cm, e); - if (!pos) return; - var frag = document.createDocumentFragment(); - drawSelectionCursor(cm, pos, frag); - if (!cm.display.dragCursor) { - cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors"); - cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv); - } - removeChildrenAndAdd(cm.display.dragCursor, frag); - } - - function clearDragCursor(cm) { - if (cm.display.dragCursor) { - cm.display.lineSpace.removeChild(cm.display.dragCursor); - cm.display.dragCursor = null; - } - } - - // SCROLL EVENTS - - // Sync the scrollable area and scrollbars, ensure the viewport - // covers the visible area. - function setScrollTop(cm, val) { - if (Math.abs(cm.doc.scrollTop - val) < 2) return; - cm.doc.scrollTop = val; - if (!gecko) updateDisplaySimple(cm, { top: val }); - if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; - cm.display.scrollbars.setScrollTop(val); - if (gecko) updateDisplaySimple(cm); - startWorker(cm, 100); - } - // Sync scroller and scrollbar, ensure the gutter elements are - // aligned. - function setScrollLeft(cm, val, isScroller) { - if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; - val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); - cm.doc.scrollLeft = val; - alignHorizontally(cm); - if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; - cm.display.scrollbars.setScrollLeft(val); - } - - // Since the delta values reported on mouse wheel events are - // unstandardized between browsers and even browser versions, and - // generally horribly unpredictable, this code starts by measuring - // the scroll effect that the first few mouse wheel events have, - // and, from that, detects the way it can convert deltas to pixel - // offsets afterwards. - // - // The reason we want to know the amount a wheel event will scroll - // is that it gives us a chance to update the display before the - // actual scrolling happens, reducing flickering. - - var wheelSamples = 0, wheelPixelsPerUnit = null; - // Fill in a browser-detected starting value on browsers where we - // know one. These don't have to be accurate -- the result of them - // being wrong would just be a slight flicker on the first wheel - // scroll (if it is large enough). - if (ie) wheelPixelsPerUnit = -.53; - else if (gecko) wheelPixelsPerUnit = 15; - else if (chrome) wheelPixelsPerUnit = -.7; - else if (safari) wheelPixelsPerUnit = -1 / 3; - - var wheelEventDelta = function (e) { - var dx = e.wheelDeltaX, dy = e.wheelDeltaY; - if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; - if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; - else if (dy == null) dy = e.wheelDelta; - return { x: dx, y: dy }; - }; - CodeMirror.wheelEventPixels = function (e) { - var delta = wheelEventDelta(e); - delta.x *= wheelPixelsPerUnit; - delta.y *= wheelPixelsPerUnit; - return delta; - }; - - function onScrollWheel(cm, e) { - var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; - - var display = cm.display, scroll = display.scroller; - // Quit if there's nothing to scroll here - var canScrollX = scroll.scrollWidth > scroll.clientWidth; - var canScrollY = scroll.scrollHeight > scroll.clientHeight; - if (!(dx && canScrollX || dy && canScrollY)) return; - - // Webkit browsers on OS X abort momentum scrolls when the target - // of the scroll event is removed from the scrollable element. - // This hack (see related code in patchDisplay) makes sure the - // element is kept around. - if (dy && mac && webkit) { - outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { - for (var i = 0; i < view.length; i++) { - if (view[i].node == cur) { - cm.display.currentWheelTarget = cur; - break outer; - } - } - } - } - - // On some browsers, horizontal scrolling will cause redraws to - // happen before the gutter has been realigned, causing it to - // wriggle around in a most unseemly way. When we have an - // estimated pixels/delta value, we just handle horizontal - // scrolling entirely here. It'll be slightly off from native, but - // better than glitching out. - if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { - if (dy && canScrollY) - setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); - setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); - // Only prevent default scrolling if vertical scrolling is - // actually possible. Otherwise, it causes vertical scroll - // jitter on OSX trackpads when deltaX is small and deltaY - // is large (issue #3579) - if (!dy || (dy && canScrollY)) - e_preventDefault(e); - display.wheelStartX = null; // Abort measurement, if in progress - return; - } - - // 'Project' the visible viewport to cover the area that is being - // scrolled into view (if we know enough to estimate it). - if (dy && wheelPixelsPerUnit != null) { - var pixels = dy * wheelPixelsPerUnit; - var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; - if (pixels < 0) top = Math.max(0, top + pixels - 50); - else bot = Math.min(cm.doc.height, bot + pixels + 50); - updateDisplaySimple(cm, { top: top, bottom: bot }); - } - - if (wheelSamples < 20) { - if (display.wheelStartX == null) { - display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; - display.wheelDX = dx; display.wheelDY = dy; - setTimeout(function () { - if (display.wheelStartX == null) return; - var movedX = scroll.scrollLeft - display.wheelStartX; - var movedY = scroll.scrollTop - display.wheelStartY; - var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || - (movedX && display.wheelDX && movedX / display.wheelDX); - display.wheelStartX = display.wheelStartY = null; - if (!sample) return; - wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); - ++wheelSamples; - }, 200); - } else { - display.wheelDX += dx; display.wheelDY += dy; - } - } - } - - // KEY EVENTS - - // Run a handler that was bound to a key. - function doHandleBinding(cm, bound, dropShift) { - if (typeof bound == "string") { - bound = commands[bound]; - if (!bound) return false; - } - // Ensure previous input has been read, so that the handler sees a - // consistent view of the document - cm.display.input.ensurePolled(); - var prevShift = cm.display.shift, done = false; - try { - if (cm.isReadOnly()) cm.state.suppressEdits = true; - if (dropShift) cm.display.shift = false; - done = bound(cm) != Pass; - } finally { - cm.display.shift = prevShift; - cm.state.suppressEdits = false; - } - return done; - } - - function lookupKeyForEditor(cm, name, handle) { - for (var i = 0; i < cm.state.keyMaps.length; i++) { - var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); - if (result) return result; - } - return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) - || lookupKey(name, cm.options.keyMap, handle, cm); - } - - var stopSeq = new Delayed; - function dispatchKey(cm, name, e, handle) { - var seq = cm.state.keySeq; - if (seq) { - if (isModifierKey(name)) return "handled"; - stopSeq.set(50, function () { - if (cm.state.keySeq == seq) { - cm.state.keySeq = null; - cm.display.input.reset(); - } - }); - name = seq + " " + name; - } - var result = lookupKeyForEditor(cm, name, handle); - - if (result == "multi") - cm.state.keySeq = name; - if (result == "handled") - signalLater(cm, "keyHandled", cm, name, e); - - if (result == "handled" || result == "multi") { - e_preventDefault(e); - restartBlink(cm); - } - - if (seq && !result && /\'$/.test(name)) { - e_preventDefault(e); - return true; - } - return !!result; - } - - // Handle a key from the keydown event. - function handleKeyBinding(cm, e) { - var name = keyName(e, true); - if (!name) return false; - - if (e.shiftKey && !cm.state.keySeq) { - // First try to resolve full name (including 'Shift-'). Failing - // that, see if there is a cursor-motion command (starting with - // 'go') bound to the keyname without 'Shift-'. - return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); }) - || dispatchKey(cm, name, e, function (b) { - if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) - return doHandleBinding(cm, b); - }); - } else { - return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); }); - } - } - - // Handle a key from the keypress event - function handleCharBinding(cm, e, ch) { - return dispatchKey(cm, "'" + ch + "'", e, - function (b) { return doHandleBinding(cm, b, true); }); - } - - var lastStoppedKey = null; - function onKeyDown(e) { - var cm = this; - cm.curOp.focus = activeElt(); - if (signalDOMEvent(cm, e)) return; - // IE does strange things with escape. - if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; - var code = e.keyCode; - cm.display.shift = code == 16 || e.shiftKey; - var handled = handleKeyBinding(cm, e); - if (presto) { - lastStoppedKey = handled ? code : null; - // Opera has no cut event... we try to at least catch the key combo - if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) - cm.replaceSelection("", null, "cut"); - } - - // Turn mouse into crosshair when Alt is held on Mac. - if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) - showCrossHair(cm); - } - - function showCrossHair(cm) { - var lineDiv = cm.display.lineDiv; - addClass(lineDiv, "CodeMirror-crosshair"); - - function up(e) { - if (e.keyCode == 18 || !e.altKey) { - rmClass(lineDiv, "CodeMirror-crosshair"); - off(document, "keyup", up); - off(document, "mouseover", up); - } - } - on(document, "keyup", up); - on(document, "mouseover", up); - } - - function onKeyUp(e) { - if (e.keyCode == 16) this.doc.sel.shift = false; - signalDOMEvent(this, e); - } - - function onKeyPress(e) { - var cm = this; - if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; - var keyCode = e.keyCode, charCode = e.charCode; - if (presto && keyCode == lastStoppedKey) { lastStoppedKey = null; e_preventDefault(e); return; } - if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; - var ch = String.fromCharCode(charCode == null ? keyCode : charCode); - if (handleCharBinding(cm, e, ch)) return; - cm.display.input.onKeyPress(e); - } - - // FOCUS/BLUR EVENTS - - function delayBlurEvent(cm) { - cm.state.delayingBlurEvent = true; - setTimeout(function () { - if (cm.state.delayingBlurEvent) { - cm.state.delayingBlurEvent = false; - onBlur(cm); - } - }, 100); - } - - function onFocus(cm) { - if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; - - if (cm.options.readOnly == "nocursor") return; - if (!cm.state.focused) { - signal(cm, "focus", cm); - cm.state.focused = true; - addClass(cm.display.wrapper, "CodeMirror-focused"); - // This test prevents this from firing when a context - // menu is closed (since the input reset would kill the - // select-all detection hack) - if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { - cm.display.input.reset(); - if (webkit) setTimeout(function () { cm.display.input.reset(true); }, 20); // Issue #1730 - } - cm.display.input.receivedFocus(); - } - restartBlink(cm); - } - function onBlur(cm) { - if (cm.state.delayingBlurEvent) return; - - if (cm.state.focused) { - signal(cm, "blur", cm); - cm.state.focused = false; - rmClass(cm.display.wrapper, "CodeMirror-focused"); - } - clearInterval(cm.display.blinker); - setTimeout(function () { if (!cm.state.focused) cm.display.shift = false; }, 150); - } - - // CONTEXT MENU HANDLING - - // To make the context menu work, we need to briefly unhide the - // textarea (making it as unobtrusive as possible) to let the - // right-click take effect on it. - function onContextMenu(cm, e) { - if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; - if (signalDOMEvent(cm, e, "contextmenu")) return; - cm.display.input.onContextMenu(e); - } - - function contextMenuInGutter(cm, e) { - if (!hasHandler(cm, "gutterContextMenu")) return false; - return gutterEvent(cm, e, "gutterContextMenu", false); - } - - // UPDATING - - // Compute the position of the end of a change (its 'to' property - // refers to the pre-change end). - var changeEnd = CodeMirror.changeEnd = function (change) { - if (!change.text) return change.to; - return Pos(change.from.line + change.text.length - 1, - lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); - }; - - // Adjust a position to refer to the post-change position of the - // same text, or the end of the change if the change covers it. - function adjustForChange(pos, change) { - if (cmp(pos, change.from) < 0) return pos; - if (cmp(pos, change.to) <= 0) return changeEnd(change); - - var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; - if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; - return Pos(line, ch); - } - - function computeSelAfterChange(doc, change) { - var out = []; - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i]; - out.push(new Range(adjustForChange(range.anchor, change), - adjustForChange(range.head, change))); - } - return normalizeSelection(out, doc.sel.primIndex); - } - - function offsetPos(pos, old, nw) { - if (pos.line == old.line) - return Pos(nw.line, pos.ch - old.ch + nw.ch); - else - return Pos(nw.line + (pos.line - old.line), pos.ch); - } - - // Used by replaceSelections to allow moving the selection to the - // start or around the replaced test. Hint may be "start" or "around". - function computeReplacedSel(doc, changes, hint) { - var out = []; - var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; - for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - var from = offsetPos(change.from, oldPrev, newPrev); - var to = offsetPos(changeEnd(change), oldPrev, newPrev); - oldPrev = change.to; - newPrev = to; - if (hint == "around") { - var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; - out[i] = new Range(inv ? to : from, inv ? from : to); - } else { - out[i] = new Range(from, from); - } - } - return new Selection(out, doc.sel.primIndex); - } - - // Allow "beforeChange" event handlers to influence a change - function filterChange(doc, change, update) { - var obj = { - canceled: false, - from: change.from, - to: change.to, - text: change.text, - origin: change.origin, - cancel: function () { this.canceled = true; } - }; - if (update) obj.update = function (from, to, text, origin) { - if (from) this.from = clipPos(doc, from); - if (to) this.to = clipPos(doc, to); - if (text) this.text = text; - if (origin !== undefined) this.origin = origin; - }; - signal(doc, "beforeChange", doc, obj); - if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); - - if (obj.canceled) return null; - return { from: obj.from, to: obj.to, text: obj.text, origin: obj.origin }; - } - - // Apply a change to a document, and add it to the document's - // history, and propagating it to all linked documents. - function makeChange(doc, change, ignoreReadOnly) { - if (doc.cm) { - if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); - if (doc.cm.state.suppressEdits) return; - } - - if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { - change = filterChange(doc, change, true); - if (!change) return; - } - - // Possibly split or suppress the update based on the presence - // of read-only spans in its range. - var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); - if (split) { - for (var i = split.length - 1; i >= 0; --i) - makeChangeInner(doc, { from: split[i].from, to: split[i].to, text: i ? [""] : change.text }); - } else { - makeChangeInner(doc, change); - } - } - - function makeChangeInner(doc, change) { - if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; - var selAfter = computeSelAfterChange(doc, change); - addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); - - makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); - var rebased = []; - - linkedDocs(doc, function (doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); - } - makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); - }); - } - - // Revert a change stored in a document's history. - function makeChangeFromHistory(doc, type, allowSelectionOnly) { - if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) return; - - var hist = doc.history, event, selAfter = doc.sel; - var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; - - // Verify that there is a useable event (so that ctrl-z won't - // needlessly clear selection events) - for (var i = 0; i < source.length; i++) { - event = source[i]; - if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) - break; - } - if (i == source.length) return; - hist.lastOrigin = hist.lastSelOrigin = null; - - for (; ;) { - event = source.pop(); - if (event.ranges) { - pushSelectionToHistory(event, dest); - if (allowSelectionOnly && !event.equals(doc.sel)) { - setSelection(doc, event, { clearRedo: false }); - return; - } - selAfter = event; - } - else break; - } - - // Build up a reverse change object to add to the opposite history - // stack (redo when undoing, and vice versa). - var antiChanges = []; - pushSelectionToHistory(selAfter, dest); - dest.push({ changes: antiChanges, generation: hist.generation }); - hist.generation = event.generation || ++hist.maxGeneration; - - var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); - - for (var i = event.changes.length - 1; i >= 0; --i) { - var change = event.changes[i]; - change.origin = type; - if (filter && !filterChange(doc, change, false)) { - source.length = 0; - return; - } - - antiChanges.push(historyChangeFromChange(doc, change)); - - var after = i ? computeSelAfterChange(doc, change) : lst(source); - makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); - if (!i && doc.cm) doc.cm.scrollIntoView({ from: change.from, to: changeEnd(change) }); - var rebased = []; - - // Propagate to the linked documents - linkedDocs(doc, function (doc, sharedHist) { - if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); - } - makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); - }); - } - } - - // Sub-views need their line numbers shifted when text is added - // above or below them in the parent document. - function shiftDoc(doc, distance) { - if (distance == 0) return; - doc.first += distance; - doc.sel = new Selection(map(doc.sel.ranges, function (range) { - return new Range(Pos(range.anchor.line + distance, range.anchor.ch), - Pos(range.head.line + distance, range.head.ch)); - }), doc.sel.primIndex); - if (doc.cm) { - regChange(doc.cm, doc.first, doc.first - distance, distance); - for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) - regLineChange(doc.cm, l, "gutter"); - } - } - - // More lower-level change function, handling only a single document - // (not linked ones). - function makeChangeSingleDoc(doc, change, selAfter, spans) { - if (doc.cm && !doc.cm.curOp) - return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); - - if (change.to.line < doc.first) { - shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); - return; - } - if (change.from.line > doc.lastLine()) return; - - // Clip the change to the size of this doc - if (change.from.line < doc.first) { - var shift = change.text.length - 1 - (doc.first - change.from.line); - shiftDoc(doc, shift); - change = { - from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), - text: [lst(change.text)], origin: change.origin - }; - } - var last = doc.lastLine(); - if (change.to.line > last) { - change = { - from: change.from, to: Pos(last, getLine(doc, last).text.length), - text: [change.text[0]], origin: change.origin - }; - } - - change.removed = getBetween(doc, change.from, change.to); - - if (!selAfter) selAfter = computeSelAfterChange(doc, change); - if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); - else updateDoc(doc, change, spans); - setSelectionNoUndo(doc, selAfter, sel_dontScroll); - } - - // Handle the interaction of a change to a document with the editor - // that this document is part of. - function makeChangeSingleDocInEditor(cm, change, spans) { - var doc = cm.doc, display = cm.display, from = change.from, to = change.to; - - var recomputeMaxLength = false, checkWidthStart = from.line; - if (!cm.options.lineWrapping) { - checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); - doc.iter(checkWidthStart, to.line + 1, function (line) { - if (line == display.maxLine) { - recomputeMaxLength = true; - return true; - } - }); - } - - if (doc.sel.contains(change.from, change.to) > -1) - signalCursorActivity(cm); - - updateDoc(doc, change, spans, estimateHeight(cm)); - - if (!cm.options.lineWrapping) { - doc.iter(checkWidthStart, from.line + change.text.length, function (line) { - var len = lineLength(line); - if (len > display.maxLineLength) { - display.maxLine = line; - display.maxLineLength = len; - display.maxLineChanged = true; - recomputeMaxLength = false; - } - }); - if (recomputeMaxLength) cm.curOp.updateMaxLine = true; - } - - // Adjust frontier, schedule worker - doc.frontier = Math.min(doc.frontier, from.line); - startWorker(cm, 400); - - var lendiff = change.text.length - (to.line - from.line) - 1; - // Remember that these lines changed, for updating the display - if (change.full) - regChange(cm); - else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) - regLineChange(cm, from.line, "text"); - else - regChange(cm, from.line, to.line + 1, lendiff); - - var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); - if (changeHandler || changesHandler) { - var obj = { - from: from, to: to, - text: change.text, - removed: change.removed, - origin: change.origin - }; - if (changeHandler) signalLater(cm, "change", cm, obj); - if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); - } - cm.display.selForContextMenu = null; - } - - function replaceRange(doc, code, from, to, origin) { - if (!to) to = from; - if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } - if (typeof code == "string") code = doc.splitLines(code); - makeChange(doc, { from: from, to: to, text: code, origin: origin }); - } - - // SCROLLING THINGS INTO VIEW - - // If an editor sits on the top or bottom of the window, partially - // scrolled out of view, this ensures that the cursor is visible. - function maybeScrollWindow(cm, coords) { - if (signalDOMEvent(cm, "scrollCursorIntoView")) return; - - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; - if (coords.top + box.top < 0) doScroll = true; - else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; - if (doScroll != null && !phantom) { - var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + - (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + - (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + - coords.left + "px; width: 2px;"); - cm.display.lineSpace.appendChild(scrollNode); - scrollNode.scrollIntoView(doScroll); - cm.display.lineSpace.removeChild(scrollNode); - } - } - - // Scroll a given position into view (immediately), verifying that - // it actually became visible (as line heights are accurately - // measured, the position of something may 'drift' during drawing). - function scrollPosIntoView(cm, pos, end, margin) { - if (margin == null) margin = 0; - for (var limit = 0; limit < 5; limit++) { - var changed = false, coords = cursorCoords(cm, pos); - var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); - var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), - Math.min(coords.top, endCoords.top) - margin, - Math.max(coords.left, endCoords.left), - Math.max(coords.bottom, endCoords.bottom) + margin); - var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; - if (scrollPos.scrollTop != null) { - setScrollTop(cm, scrollPos.scrollTop); - if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; - } - if (scrollPos.scrollLeft != null) { - setScrollLeft(cm, scrollPos.scrollLeft); - if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; - } - if (!changed) break; - } - return coords; - } - - // Scroll a given set of coordinates into view (immediately). - function scrollIntoView(cm, x1, y1, x2, y2) { - var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); - if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); - if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); - } - - // Calculate a new scroll position needed to scroll the given - // rectangle into view. Returns an object with scrollTop and - // scrollLeft properties. When these are undefined, the - // vertical/horizontal position does not need to be adjusted. - function calculateScrollPos(cm, x1, y1, x2, y2) { - var display = cm.display, snapMargin = textHeight(cm.display); - if (y1 < 0) y1 = 0; - var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; - var screen = displayHeight(cm), result = {}; - if (y2 - y1 > screen) y2 = y1 + screen; - var docBottom = cm.doc.height + paddingVert(display); - var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; - if (y1 < screentop) { - result.scrollTop = atTop ? 0 : y1; - } else if (y2 > screentop + screen) { - var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); - if (newTop != screentop) result.scrollTop = newTop; - } - - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); - var tooWide = x2 - x1 > screenw; - if (tooWide) x2 = x1 + screenw; - if (x1 < 10) - result.scrollLeft = 0; - else if (x1 < screenleft) - result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); - else if (x2 > screenw + screenleft - 3) - result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; - return result; - } - - // Store a relative adjustment to the scroll position in the current - // operation (to be applied when the operation finishes). - function addToScrollPos(cm, left, top) { - if (left != null || top != null) resolveScrollToPos(cm); - if (left != null) - cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; - if (top != null) - cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; - } - - // Make sure that at the end of the operation the current cursor is - // shown. - function ensureCursorVisible(cm) { - resolveScrollToPos(cm); - var cur = cm.getCursor(), from = cur, to = cur; - if (!cm.options.lineWrapping) { - from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; - to = Pos(cur.line, cur.ch + 1); - } - cm.curOp.scrollToPos = { from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true }; - } - - // When an operation has its scrollToPos property set, and another - // scroll action is applied before the end of the operation, this - // 'simulates' scrolling that position into view in a cheap way, so - // that the effect of intermediate scroll commands is not ignored. - function resolveScrollToPos(cm) { - var range = cm.curOp.scrollToPos; - if (range) { - cm.curOp.scrollToPos = null; - var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); - var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), - Math.min(from.top, to.top) - range.margin, - Math.max(from.right, to.right), - Math.max(from.bottom, to.bottom) + range.margin); - cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); - } - } - - // API UTILITIES - - // Indent the given line. The how parameter can be "smart", - // "add"/null, "subtract", or "prev". When aggressive is false - // (typically set to true for forced single-line indents), empty - // lines are not indented, and places where the mode returns Pass - // are left alone. - function indentLine(cm, n, how, aggressive) { - var doc = cm.doc, state; - if (how == null) how = "add"; - if (how == "smart") { - // Fall back to "prev" when the mode doesn't have an indentation - // method. - if (!doc.mode.indent) how = "prev"; - else state = getStateBefore(cm, n); - } - - var tabSize = cm.options.tabSize; - var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); - if (line.stateAfter) line.stateAfter = null; - var curSpaceString = line.text.match(/^\s*/)[0], indentation; - if (!aggressive && !/\S/.test(line.text)) { - indentation = 0; - how = "not"; - } else if (how == "smart") { - indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); - if (indentation == Pass || indentation > 150) { - if (!aggressive) return; - how = "prev"; - } - } - if (how == "prev") { - if (n > doc.first) indentation = countColumn(getLine(doc, n - 1).text, null, tabSize); - else indentation = 0; - } else if (how == "add") { - indentation = curSpace + cm.options.indentUnit; - } else if (how == "subtract") { - indentation = curSpace - cm.options.indentUnit; - } else if (typeof how == "number") { - indentation = curSpace + how; - } - indentation = Math.max(0, indentation); - - var indentString = "", pos = 0; - if (cm.options.indentWithTabs) - for (var i = Math.floor(indentation / tabSize); i; --i) { pos += tabSize; indentString += "\t"; } - if (pos < indentation) indentString += spaceStr(indentation - pos); - - if (indentString != curSpaceString) { - replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); - line.stateAfter = null; - return true; - } else { - // Ensure that, if the cursor was in the whitespace at the start - // of the line, it is moved to the end of that space. - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i]; - if (range.head.line == n && range.head.ch < curSpaceString.length) { - var pos = Pos(n, curSpaceString.length); - replaceOneSelection(doc, i, new Range(pos, pos)); - break; - } - } - } - } - - // Utility for applying a change to a line by handle or number, - // returning the number and optionally registering the line as - // changed. - function changeLine(doc, handle, changeType, op) { - var no = handle, line = handle; - if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); - else no = lineNo(handle); - if (no == null) return null; - if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); - return line; - } - - // Helper for deleting text near the selection(s), used to implement - // backspace, delete, and similar functionality. - function deleteNearSelection(cm, compute) { - var ranges = cm.doc.sel.ranges, kill = []; - // Build up a set of ranges to kill first, merging overlapping - // ranges. - for (var i = 0; i < ranges.length; i++) { - var toKill = compute(ranges[i]); - while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { - var replaced = kill.pop(); - if (cmp(replaced.from, toKill.from) < 0) { - toKill.from = replaced.from; - break; - } - } - kill.push(toKill); - } - // Next, remove those actual ranges. - runInOp(cm, function () { - for (var i = kill.length - 1; i >= 0; i--) - replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); - ensureCursorVisible(cm); - }); - } - - // Used for horizontal relative motion. Dir is -1 or 1 (left or - // right), unit can be "char", "column" (like char, but doesn't - // cross line boundaries), "word" (across next word), or "group" (to - // the start of next group of word or non-word-non-whitespace - // chars). The visually param controls whether, in right-to-left - // text, direction 1 means to move towards the next index in the - // string, or towards the character to the right of the current - // position. The resulting position will have a hitSide=true - // property if it reached the end of the document. - function findPosH(doc, pos, dir, unit, visually) { - var line = pos.line, ch = pos.ch, origDir = dir; - var lineObj = getLine(doc, line); - function findNextLine() { - var l = line + dir; - if (l < doc.first || l >= doc.first + doc.size) return false - line = l; - return lineObj = getLine(doc, l); - } - function moveOnce(boundToLine) { - var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); - if (next == null) { - if (!boundToLine && findNextLine()) { - if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); - else ch = dir < 0 ? lineObj.text.length : 0; - } else return false - } else ch = next; - return true; - } - - if (unit == "char") { - moveOnce() - } else if (unit == "column") { - moveOnce(true) - } else if (unit == "word" || unit == "group") { - var sawType = null, group = unit == "group"; - var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); - for (var first = true; ; first = false) { - if (dir < 0 && !moveOnce(!first)) break; - var cur = lineObj.text.charAt(ch) || "\n"; - var type = isWordChar(cur, helper) ? "w" - : group && cur == "\n" ? "n" - : !group || /\s/.test(cur) ? null - : "p"; - if (group && !first && !type) type = "s"; - if (sawType && sawType != type) { - if (dir < 0) { dir = 1; moveOnce(); } - break; - } - - if (type) sawType = type; - if (dir > 0 && !moveOnce(!first)) break; - } - } - var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true); - if (!cmp(pos, result)) result.hitSide = true; - return result; - } - - // For relative vertical movement. Dir may be -1 or 1. Unit can be - // "page" or "line". The resulting position will have a hitSide=true - // property if it reached the end of the document. - function findPosV(cm, pos, dir, unit) { - var doc = cm.doc, x = pos.left, y; - if (unit == "page") { - var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); - y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); - } else if (unit == "line") { - y = dir > 0 ? pos.bottom + 3 : pos.top - 3; - } - for (; ;) { - var target = coordsChar(cm, x, y); - if (!target.outside) break; - if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } - y += dir * 5; - } - return target; - } - - // EDITOR METHODS - - // The publicly visible API. Note that methodOp(f) means - // 'wrap f in an operation, performed on its `this` parameter'. - - // This is not the complete set of editor methods. Most of the - // methods defined on the Doc type are also injected into - // CodeMirror.prototype, for backwards compatibility and - // convenience. - - CodeMirror.prototype = { - constructor: CodeMirror, - focus: function () { window.focus(); this.display.input.focus(); }, - - setOption: function (option, value) { - var options = this.options, old = options[option]; - if (options[option] == value && option != "mode") return; - options[option] = value; - if (optionHandlers.hasOwnProperty(option)) - operation(this, optionHandlers[option])(this, value, old); - }, - - getOption: function (option) { return this.options[option]; }, - getDoc: function () { return this.doc; }, - - addKeyMap: function (map, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); - }, - removeKeyMap: function (map) { - var maps = this.state.keyMaps; - for (var i = 0; i < maps.length; ++i) - if (maps[i] == map || maps[i].name == map) { - maps.splice(i, 1); - return true; - } - }, - - addOverlay: methodOp(function (spec, options) { - var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); - if (mode.startState) throw new Error("Overlays may not be stateful."); - this.state.overlays.push({ mode: mode, modeSpec: spec, opaque: options && options.opaque }); - this.state.modeGen++; - regChange(this); - }), - removeOverlay: methodOp(function (spec) { - var overlays = this.state.overlays; - for (var i = 0; i < overlays.length; ++i) { - var cur = overlays[i].modeSpec; - if (cur == spec || typeof spec == "string" && cur.name == spec) { - overlays.splice(i, 1); - this.state.modeGen++; - regChange(this); - return; - } - } - }), - - indentLine: methodOp(function (n, dir, aggressive) { - if (typeof dir != "string" && typeof dir != "number") { - if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; - else dir = dir ? "add" : "subtract"; - } - if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); - }), - indentSelection: methodOp(function (how) { - var ranges = this.doc.sel.ranges, end = -1; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - if (!range.empty()) { - var from = range.from(), to = range.to(); - var start = Math.max(end, from.line); - end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; - for (var j = start; j < end; ++j) - indentLine(this, j, how); - var newRanges = this.doc.sel.ranges; - if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); - } else if (range.head.line > end) { - indentLine(this, range.head.line, how, true); - end = range.head.line; - if (i == this.doc.sel.primIndex) ensureCursorVisible(this); - } - } - }), - - // Fetch the parser token for a given character. Useful for hacks - // that want to inspect the mode state (say, for completion). - getTokenAt: function (pos, precise) { - return takeToken(this, pos, precise); - }, - - getLineTokens: function (line, precise) { - return takeToken(this, Pos(line), precise, true); - }, - - getTokenTypeAt: function (pos) { - pos = clipPos(this.doc, pos); - var styles = getLineStyles(this, getLine(this.doc, pos.line)); - var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; - var type; - if (ch == 0) type = styles[2]; - else for (; ;) { - var mid = (before + after) >> 1; - if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; - else if (styles[mid * 2 + 1] < ch) before = mid + 1; - else { type = styles[mid * 2 + 2]; break; } - } - var cut = type ? type.indexOf("cm-overlay ") : -1; - return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); - }, - - getModeAt: function (pos) { - var mode = this.doc.mode; - if (!mode.innerMode) return mode; - return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; - }, - - getHelper: function (pos, type) { - return this.getHelpers(pos, type)[0]; - }, - - getHelpers: function (pos, type) { - var found = []; - if (!helpers.hasOwnProperty(type)) return found; - var help = helpers[type], mode = this.getModeAt(pos); - if (typeof mode[type] == "string") { - if (help[mode[type]]) found.push(help[mode[type]]); - } else if (mode[type]) { - for (var i = 0; i < mode[type].length; i++) { - var val = help[mode[type][i]]; - if (val) found.push(val); - } - } else if (mode.helperType && help[mode.helperType]) { - found.push(help[mode.helperType]); - } else if (help[mode.name]) { - found.push(help[mode.name]); - } - for (var i = 0; i < help._global.length; i++) { - var cur = help._global[i]; - if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) - found.push(cur.val); - } - return found; - }, - - getStateAfter: function (line, precise) { - var doc = this.doc; - line = clipLine(doc, line == null ? doc.first + doc.size - 1 : line); - return getStateBefore(this, line + 1, precise); - }, - - cursorCoords: function (start, mode) { - var pos, range = this.doc.sel.primary(); - if (start == null) pos = range.head; - else if (typeof start == "object") pos = clipPos(this.doc, start); - else pos = start ? range.from() : range.to(); - return cursorCoords(this, pos, mode || "page"); - }, - - charCoords: function (pos, mode) { - return charCoords(this, clipPos(this.doc, pos), mode || "page"); - }, - - coordsChar: function (coords, mode) { - coords = fromCoordSystem(this, coords, mode || "page"); - return coordsChar(this, coords.left, coords.top); - }, - - lineAtHeight: function (height, mode) { - height = fromCoordSystem(this, { top: height, left: 0 }, mode || "page").top; - return lineAtHeight(this.doc, height + this.display.viewOffset); - }, - heightAtLine: function (line, mode) { - var end = false, lineObj; - if (typeof line == "number") { - var last = this.doc.first + this.doc.size - 1; - if (line < this.doc.first) line = this.doc.first; - else if (line > last) { line = last; end = true; } - lineObj = getLine(this.doc, line); - } else { - lineObj = line; - } - return intoCoordSystem(this, lineObj, { top: 0, left: 0 }, mode || "page").top + - (end ? this.doc.height - heightAtLine(lineObj) : 0); - }, - - defaultTextHeight: function () { return textHeight(this.display); }, - defaultCharWidth: function () { return charWidth(this.display); }, - - setGutterMarker: methodOp(function (line, gutterID, value) { - return changeLine(this.doc, line, "gutter", function (line) { - var markers = line.gutterMarkers || (line.gutterMarkers = {}); - markers[gutterID] = value; - if (!value && isEmpty(markers)) line.gutterMarkers = null; - return true; - }); - }), - - clearGutter: methodOp(function (gutterID) { - var cm = this, doc = cm.doc, i = doc.first; - doc.iter(function (line) { - if (line.gutterMarkers && line.gutterMarkers[gutterID]) { - line.gutterMarkers[gutterID] = null; - regLineChange(cm, i, "gutter"); - if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; - } - ++i; - }); - }), - - lineInfo: function (line) { - if (typeof line == "number") { - if (!isLine(this.doc, line)) return null; - var n = line; - line = getLine(this.doc, line); - if (!line) return null; - } else { - var n = lineNo(line); - if (n == null) return null; - } - return { - line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, - textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, - widgets: line.widgets - }; - }, - - getViewport: function () { return { from: this.display.viewFrom, to: this.display.viewTo }; }, - - addWidget: function (pos, node, scroll, vert, horiz) { - var display = this.display; - pos = cursorCoords(this, clipPos(this.doc, pos)); - var top = pos.bottom, left = pos.left; - node.style.position = "absolute"; - node.setAttribute("cm-ignore-events", "true"); - this.display.input.setUneditable(node); - display.sizer.appendChild(node); - if (vert == "over") { - top = pos.top; - } else if (vert == "above" || vert == "near") { - var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), - hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); - // Default to positioning above (if specified and possible); otherwise default to positioning below - if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) - top = pos.top - node.offsetHeight; - else if (pos.bottom + node.offsetHeight <= vspace) - top = pos.bottom; - if (left + node.offsetWidth > hspace) - left = hspace - node.offsetWidth; - } - node.style.top = top + "px"; - node.style.left = node.style.right = ""; - if (horiz == "right") { - left = display.sizer.clientWidth - node.offsetWidth; - node.style.right = "0px"; - } else { - if (horiz == "left") left = 0; - else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; - node.style.left = left + "px"; - } - if (scroll) - scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); - }, - - triggerOnKeyDown: methodOp(onKeyDown), - triggerOnKeyPress: methodOp(onKeyPress), - triggerOnKeyUp: onKeyUp, - - execCommand: function (cmd) { - if (commands.hasOwnProperty(cmd)) - return commands[cmd].call(null, this); - }, - - triggerElectric: methodOp(function (text) { triggerElectric(this, text); }), - - findPosH: function (from, amount, unit, visually) { - var dir = 1; - if (amount < 0) { dir = -1; amount = -amount; } - for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { - cur = findPosH(this.doc, cur, dir, unit, visually); - if (cur.hitSide) break; - } - return cur; - }, - - moveH: methodOp(function (dir, unit) { - var cm = this; - cm.extendSelectionsBy(function (range) { - if (cm.display.shift || cm.doc.extend || range.empty()) - return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); - else - return dir < 0 ? range.from() : range.to(); - }, sel_move); - }), - - deleteH: methodOp(function (dir, unit) { - var sel = this.doc.sel, doc = this.doc; - if (sel.somethingSelected()) - doc.replaceSelection("", null, "+delete"); - else - deleteNearSelection(this, function (range) { - var other = findPosH(doc, range.head, dir, unit, false); - return dir < 0 ? { from: other, to: range.head } : { from: range.head, to: other }; - }); - }), - - findPosV: function (from, amount, unit, goalColumn) { - var dir = 1, x = goalColumn; - if (amount < 0) { dir = -1; amount = -amount; } - for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { - var coords = cursorCoords(this, cur, "div"); - if (x == null) x = coords.left; - else coords.left = x; - cur = findPosV(this, coords, dir, unit); - if (cur.hitSide) break; - } - return cur; - }, - - moveV: methodOp(function (dir, unit) { - var cm = this, doc = this.doc, goals = []; - var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); - doc.extendSelectionsBy(function (range) { - if (collapse) - return dir < 0 ? range.from() : range.to(); - var headPos = cursorCoords(cm, range.head, "div"); - if (range.goalColumn != null) headPos.left = range.goalColumn; - goals.push(headPos.left); - var pos = findPosV(cm, headPos, dir, unit); - if (unit == "page" && range == doc.sel.primary()) - addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); - return pos; - }, sel_move); - if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) - doc.sel.ranges[i].goalColumn = goals[i]; - }), - - // Find the word at the given position (as returned by coordsChar). - findWordAt: function (pos) { - var doc = this.doc, line = getLine(doc, pos.line).text; - var start = pos.ch, end = pos.ch; - if (line) { - var helper = this.getHelper(pos, "wordChars"); - if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; - var startChar = line.charAt(start); - var check = isWordChar(startChar, helper) - ? function (ch) { return isWordChar(ch, helper); } - : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); } - : function (ch) { return !/\s/.test(ch) && !isWordChar(ch); }; - while (start > 0 && check(line.charAt(start - 1))) --start; - while (end < line.length && check(line.charAt(end))) ++end; - } - return new Range(Pos(pos.line, start), Pos(pos.line, end)); - }, - - toggleOverwrite: function (value) { - if (value != null && value == this.state.overwrite) return; - if (this.state.overwrite = !this.state.overwrite) - addClass(this.display.cursorDiv, "CodeMirror-overwrite"); - else - rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); - - signal(this, "overwriteToggle", this, this.state.overwrite); - }, - hasFocus: function () { return this.display.input.getField() == activeElt(); }, - isReadOnly: function () { return !!(this.options.readOnly || this.doc.cantEdit); }, - - scrollTo: methodOp(function (x, y) { - if (x != null || y != null) resolveScrollToPos(this); - if (x != null) this.curOp.scrollLeft = x; - if (y != null) this.curOp.scrollTop = y; - }), - getScrollInfo: function () { - var scroller = this.display.scroller; - return { - left: scroller.scrollLeft, top: scroller.scrollTop, - height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, - width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, - clientHeight: displayHeight(this), clientWidth: displayWidth(this) - }; - }, - - scrollIntoView: methodOp(function (range, margin) { - if (range == null) { - range = { from: this.doc.sel.primary().head, to: null }; - if (margin == null) margin = this.options.cursorScrollMargin; - } else if (typeof range == "number") { - range = { from: Pos(range, 0), to: null }; - } else if (range.from == null) { - range = { from: range, to: null }; - } - if (!range.to) range.to = range.from; - range.margin = margin || 0; - - if (range.from.line != null) { - resolveScrollToPos(this); - this.curOp.scrollToPos = range; - } else { - var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), - Math.min(range.from.top, range.to.top) - range.margin, - Math.max(range.from.right, range.to.right), - Math.max(range.from.bottom, range.to.bottom) + range.margin); - this.scrollTo(sPos.scrollLeft, sPos.scrollTop); - } - }), - - setSize: methodOp(function (width, height) { - var cm = this; - function interpret(val) { - return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; - } - if (width != null) cm.display.wrapper.style.width = interpret(width); - if (height != null) cm.display.wrapper.style.height = interpret(height); - if (cm.options.lineWrapping) clearLineMeasurementCache(this); - var lineNo = cm.display.viewFrom; - cm.doc.iter(lineNo, cm.display.viewTo, function (line) { - if (line.widgets) for (var i = 0; i < line.widgets.length; i++) - if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } - ++lineNo; - }); - cm.curOp.forceUpdate = true; - signal(cm, "refresh", this); - }), - - operation: function (f) { return runInOp(this, f); }, - - refresh: methodOp(function () { - var oldHeight = this.display.cachedTextHeight; - regChange(this); - this.curOp.forceUpdate = true; - clearCaches(this); - this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); - updateGutterSpace(this); - if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) - estimateLineHeights(this); - signal(this, "refresh", this); - }), - - swapDoc: methodOp(function (doc) { - var old = this.doc; - old.cm = null; - attachDoc(this, doc); - clearCaches(this); - this.display.input.reset(); - this.scrollTo(doc.scrollLeft, doc.scrollTop); - this.curOp.forceScroll = true; - signalLater(this, "swapDoc", this, old); - return old; - }), - - getInputField: function () { return this.display.input.getField(); }, - getWrapperElement: function () { return this.display.wrapper; }, - getScrollerElement: function () { return this.display.scroller; }, - getGutterElement: function () { return this.display.gutters; } - }; - eventMixin(CodeMirror); - - // OPTION DEFAULTS - - // The default configuration options. - var defaults = CodeMirror.defaults = {}; - // Functions to run when options are changed. - var optionHandlers = CodeMirror.optionHandlers = {}; - - function option(name, deflt, handle, notOnInit) { - CodeMirror.defaults[name] = deflt; - if (handle) optionHandlers[name] = - notOnInit ? function (cm, val, old) { if (old != Init) handle(cm, val, old); } : handle; - } - - // Passed to option handlers when there is no old value. - var Init = CodeMirror.Init = { toString: function () { return "CodeMirror.Init"; } }; - - // These two are, on init, called from the constructor because they - // have to be initialized before the editor can start at all. - option("value", "", function (cm, val) { - cm.setValue(val); - }, true); - option("mode", null, function (cm, val) { - cm.doc.modeOption = val; - loadMode(cm); - }, true); - - option("indentUnit", 2, loadMode, true); - option("indentWithTabs", false); - option("smartIndent", true); - option("tabSize", 4, function (cm) { - resetModeState(cm); - clearCaches(cm); - regChange(cm); - }, true); - option("lineSeparator", null, function (cm, val) { - cm.doc.lineSep = val; - if (!val) return; - var newBreaks = [], lineNo = cm.doc.first; - cm.doc.iter(function (line) { - for (var pos = 0; ;) { - var found = line.text.indexOf(val, pos); - if (found == -1) break; - pos = found + val.length; - newBreaks.push(Pos(lineNo, found)); - } - lineNo++; - }); - for (var i = newBreaks.length - 1; i >= 0; i--) - replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) - }); - option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) { - cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); - if (old != CodeMirror.Init) cm.refresh(); - }); - option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { cm.refresh(); }, true); - option("electricChars", true); - option("inputStyle", mobile ? "contenteditable" : "textarea", function () { - throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME - }, true); - option("rtlMoveVisually", !windows); - option("wholeLineUpdateBefore", true); - - option("theme", "default", function (cm) { - themeChanged(cm); - guttersChanged(cm); - }, true); - option("keyMap", "default", function (cm, val, old) { - var next = getKeyMap(val); - var prev = old != CodeMirror.Init && getKeyMap(old); - if (prev && prev.detach) prev.detach(cm, next); - if (next.attach) next.attach(cm, prev || null); - }); - option("extraKeys", null); - - option("lineWrapping", false, wrappingChanged, true); - option("gutters", [], function (cm) { - setGuttersForLineNumbers(cm.options); - guttersChanged(cm); - }, true); - option("fixedGutter", true, function (cm, val) { - cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; - cm.refresh(); - }, true); - option("coverGutterNextToScrollbar", false, function (cm) { updateScrollbars(cm); }, true); - option("scrollbarStyle", "native", function (cm) { - initScrollbars(cm); - updateScrollbars(cm); - cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); - cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); - }, true); - option("lineNumbers", false, function (cm) { - setGuttersForLineNumbers(cm.options); - guttersChanged(cm); - }, true); - option("firstLineNumber", 1, guttersChanged, true); - option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true); - option("showCursorWhenSelecting", false, updateSelection, true); - - option("resetSelectionOnContextMenu", true); - option("lineWiseCopyCut", true); - - option("readOnly", false, function (cm, val) { - if (val == "nocursor") { - onBlur(cm); - cm.display.input.blur(); - cm.display.disabled = true; - } else { - cm.display.disabled = false; - } - cm.display.input.readOnlyChanged(val) - }); - option("disableInput", false, function (cm, val) { if (!val) cm.display.input.reset(); }, true); - option("dragDrop", true, dragDropChanged); - option("allowDropFileTypes", null); - - option("cursorBlinkRate", 530); - option("cursorScrollMargin", 0); - option("cursorHeight", 1, updateSelection, true); - option("singleCursorHeightPerLine", true, updateSelection, true); - option("workTime", 100); - option("workDelay", 100); - option("flattenSpans", true, resetModeState, true); - option("addModeClass", false, resetModeState, true); - option("pollInterval", 100); - option("undoDepth", 200, function (cm, val) { cm.doc.history.undoDepth = val; }); - option("historyEventDelay", 1250); - option("viewportMargin", 10, function (cm) { cm.refresh(); }, true); - option("maxHighlightLength", 10000, resetModeState, true); - option("moveInputWithCursor", true, function (cm, val) { - if (!val) cm.display.input.resetPosition(); - }); - - option("tabindex", null, function (cm, val) { - cm.display.input.getField().tabIndex = val || ""; - }); - option("autofocus", null); - - // MODE DEFINITION AND QUERYING - - // Known modes, by name and by MIME - var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; - - // Extra arguments are stored as the mode's dependencies, which is - // used by (legacy) mechanisms like loadmode.js to automatically - // load a mode. (Preferred mechanism is the require/define calls.) - CodeMirror.defineMode = function (name, mode) { - if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; - if (arguments.length > 2) - mode.dependencies = Array.prototype.slice.call(arguments, 2); - modes[name] = mode; - }; - - CodeMirror.defineMIME = function (mime, spec) { - mimeModes[mime] = spec; - }; - - // Given a MIME type, a {name, ...options} config object, or a name - // string, return a mode config object. - CodeMirror.resolveMode = function (spec) { - if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { - spec = mimeModes[spec]; - } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { - var found = mimeModes[spec.name]; - if (typeof found == "string") found = { name: found }; - spec = createObj(found, spec); - spec.name = found.name; - } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { - return CodeMirror.resolveMode("application/xml"); - } - if (typeof spec == "string") return { name: spec }; - else return spec || { name: "null" }; - }; - - // Given a mode spec (anything that resolveMode accepts), find and - // initialize an actual mode object. - CodeMirror.getMode = function (options, spec) { - var spec = CodeMirror.resolveMode(spec); - var mfactory = modes[spec.name]; - if (!mfactory) return CodeMirror.getMode(options, "text/plain"); - var modeObj = mfactory(options, spec); - if (modeExtensions.hasOwnProperty(spec.name)) { - var exts = modeExtensions[spec.name]; - for (var prop in exts) { - if (!exts.hasOwnProperty(prop)) continue; - if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; - modeObj[prop] = exts[prop]; - } - } - modeObj.name = spec.name; - if (spec.helperType) modeObj.helperType = spec.helperType; - if (spec.modeProps) for (var prop in spec.modeProps) - modeObj[prop] = spec.modeProps[prop]; - - return modeObj; - }; - - // Minimal default mode. - CodeMirror.defineMode("null", function () { - return { token: function (stream) { stream.skipToEnd(); } }; - }); - CodeMirror.defineMIME("text/plain", "null"); - - // This can be used to attach properties to mode objects from - // outside the actual mode definition. - var modeExtensions = CodeMirror.modeExtensions = {}; - CodeMirror.extendMode = function (mode, properties) { - var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); - copyObj(properties, exts); - }; - - // EXTENSIONS - - CodeMirror.defineExtension = function (name, func) { - CodeMirror.prototype[name] = func; - }; - CodeMirror.defineDocExtension = function (name, func) { - Doc.prototype[name] = func; - }; - CodeMirror.defineOption = option; - - var initHooks = []; - CodeMirror.defineInitHook = function (f) { initHooks.push(f); }; - - var helpers = CodeMirror.helpers = {}; - CodeMirror.registerHelper = function (type, name, value) { - if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = { _global: [] }; - helpers[type][name] = value; - }; - CodeMirror.registerGlobalHelper = function (type, name, predicate, value) { - CodeMirror.registerHelper(type, name, value); - helpers[type]._global.push({ pred: predicate, val: value }); - }; - - // MODE STATE HANDLING - - // Utility functions for working with state. Exported because nested - // modes need to do this for their inner modes. - - var copyState = CodeMirror.copyState = function (mode, state) { - if (state === true) return state; - if (mode.copyState) return mode.copyState(state); - var nstate = {}; - for (var n in state) { - var val = state[n]; - if (val instanceof Array) val = val.concat([]); - nstate[n] = val; - } - return nstate; - }; - - var startState = CodeMirror.startState = function (mode, a1, a2) { - return mode.startState ? mode.startState(a1, a2) : true; - }; - - // Given a mode and a state (for that mode), find the inner mode and - // state at the position that the state refers to. - CodeMirror.innerMode = function (mode, state) { - while (mode.innerMode) { - var info = mode.innerMode(state); - if (!info || info.mode == mode) break; - state = info.state; - mode = info.mode; - } - return info || { mode: mode, state: state }; - }; - - // STANDARD COMMANDS - - // Commands are parameter-less actions that can be performed on an - // editor, mostly used for keybindings. - var commands = CodeMirror.commands = { - selectAll: function (cm) { cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll); }, - singleSelection: function (cm) { - cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); - }, - killLine: function (cm) { - deleteNearSelection(cm, function (range) { - if (range.empty()) { - var len = getLine(cm.doc, range.head.line).text.length; - if (range.head.ch == len && range.head.line < cm.lastLine()) - return { from: range.head, to: Pos(range.head.line + 1, 0) }; - else - return { from: range.head, to: Pos(range.head.line, len) }; - } else { - return { from: range.from(), to: range.to() }; - } - }); - }, - deleteLine: function (cm) { - deleteNearSelection(cm, function (range) { - return { - from: Pos(range.from().line, 0), - to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) - }; - }); - }, - delLineLeft: function (cm) { - deleteNearSelection(cm, function (range) { - return { from: Pos(range.from().line, 0), to: range.from() }; - }); - }, - delWrappedLineLeft: function (cm) { - deleteNearSelection(cm, function (range) { - var top = cm.charCoords(range.head, "div").top + 5; - var leftPos = cm.coordsChar({ left: 0, top: top }, "div"); - return { from: leftPos, to: range.from() }; - }); - }, - delWrappedLineRight: function (cm) { - deleteNearSelection(cm, function (range) { - var top = cm.charCoords(range.head, "div").top + 5; - var rightPos = cm.coordsChar({ left: cm.display.lineDiv.offsetWidth + 100, top: top }, "div"); - return { from: range.from(), to: rightPos }; - }); - }, - undo: function (cm) { cm.undo(); }, - redo: function (cm) { cm.redo(); }, - undoSelection: function (cm) { cm.undoSelection(); }, - redoSelection: function (cm) { cm.redoSelection(); }, - goDocStart: function (cm) { cm.extendSelection(Pos(cm.firstLine(), 0)); }, - goDocEnd: function (cm) { cm.extendSelection(Pos(cm.lastLine())); }, - goLineStart: function (cm) { - cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); }, - { origin: "+move", bias: 1 }); - }, - goLineStartSmart: function (cm) { - cm.extendSelectionsBy(function (range) { - return lineStartSmart(cm, range.head); - }, { origin: "+move", bias: 1 }); - }, - goLineEnd: function (cm) { - cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); }, - { origin: "+move", bias: -1 }); - }, - goLineRight: function (cm) { - cm.extendSelectionsBy(function (range) { - var top = cm.charCoords(range.head, "div").top + 5; - return cm.coordsChar({ left: cm.display.lineDiv.offsetWidth + 100, top: top }, "div"); - }, sel_move); - }, - goLineLeft: function (cm) { - cm.extendSelectionsBy(function (range) { - var top = cm.charCoords(range.head, "div").top + 5; - return cm.coordsChar({ left: 0, top: top }, "div"); - }, sel_move); - }, - goLineLeftSmart: function (cm) { - cm.extendSelectionsBy(function (range) { - var top = cm.charCoords(range.head, "div").top + 5; - var pos = cm.coordsChar({ left: 0, top: top }, "div"); - if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); - return pos; - }, sel_move); - }, - goLineUp: function (cm) { cm.moveV(-1, "line"); }, - goLineDown: function (cm) { cm.moveV(1, "line"); }, - goPageUp: function (cm) { cm.moveV(-1, "page"); }, - goPageDown: function (cm) { cm.moveV(1, "page"); }, - goCharLeft: function (cm) { cm.moveH(-1, "char"); }, - goCharRight: function (cm) { cm.moveH(1, "char"); }, - goColumnLeft: function (cm) { cm.moveH(-1, "column"); }, - goColumnRight: function (cm) { cm.moveH(1, "column"); }, - goWordLeft: function (cm) { cm.moveH(-1, "word"); }, - goGroupRight: function (cm) { cm.moveH(1, "group"); }, - goGroupLeft: function (cm) { cm.moveH(-1, "group"); }, - goWordRight: function (cm) { cm.moveH(1, "word"); }, - delCharBefore: function (cm) { cm.deleteH(-1, "char"); }, - delCharAfter: function (cm) { cm.deleteH(1, "char"); }, - delWordBefore: function (cm) { cm.deleteH(-1, "word"); }, - delWordAfter: function (cm) { cm.deleteH(1, "word"); }, - delGroupBefore: function (cm) { cm.deleteH(-1, "group"); }, - delGroupAfter: function (cm) { cm.deleteH(1, "group"); }, - indentAuto: function (cm) { cm.indentSelection("smart"); }, - indentMore: function (cm) { cm.indentSelection("add"); }, - indentLess: function (cm) { cm.indentSelection("subtract"); }, - insertTab: function (cm) { cm.replaceSelection("\t"); }, - insertSoftTab: function (cm) { - var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; - for (var i = 0; i < ranges.length; i++) { - var pos = ranges[i].from(); - var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); - spaces.push(spaceStr(tabSize - col % tabSize)); - } - cm.replaceSelections(spaces); - }, - defaultTab: function (cm) { - if (cm.somethingSelected()) cm.indentSelection("add"); - else cm.execCommand("insertTab"); - }, - transposeChars: function (cm) { - runInOp(cm, function () { - var ranges = cm.listSelections(), newSel = []; - for (var i = 0; i < ranges.length; i++) { - var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; - if (line) { - if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); - if (cur.ch > 0) { - cur = new Pos(cur.line, cur.ch + 1); - cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), - Pos(cur.line, cur.ch - 2), cur, "+transpose"); - } else if (cur.line > cm.doc.first) { - var prev = getLine(cm.doc, cur.line - 1).text; - if (prev) - cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + - prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); - } - } - newSel.push(new Range(cur, cur)); - } - cm.setSelections(newSel); - }); - }, - newlineAndIndent: function (cm) { - runInOp(cm, function () { - var len = cm.listSelections().length; - for (var i = 0; i < len; i++) { - var range = cm.listSelections()[i]; - cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input"); - cm.indentLine(range.from().line + 1, null, true); - } - ensureCursorVisible(cm); - }); - }, - openLine: function (cm) { cm.replaceSelection("\n", "start") }, - toggleOverwrite: function (cm) { cm.toggleOverwrite(); } - }; - - - // STANDARD KEYMAPS - - var keyMap = CodeMirror.keyMap = {}; - - keyMap.basic = { - "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", - "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", - "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", - "Tab": "defaultTab", "Shift-Tab": "indentAuto", - "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", - "Esc": "singleSelection" - }; - // Note that the save and find-related commands aren't defined by - // default. User code or addons can define them. Unknown commands - // are simply ignored. - keyMap.pcDefault = { - "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", - "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", - "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", - "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", - "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", - "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", - "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", - fallthrough: "basic" - }; - // Very basic readline/emacs-style bindings, which are standard on Mac. - keyMap.emacsy = { - "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", - "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", - "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", - "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", - "Ctrl-O": "openLine" - }; - keyMap.macDefault = { - "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", - "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", - "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", - "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", - "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", - "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", - "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", - fallthrough: ["basic", "emacsy"] - }; - keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; - - // KEYMAP DISPATCH - - function normalizeKeyName(name) { - var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; - var alt, ctrl, shift, cmd; - for (var i = 0; i < parts.length - 1; i++) { - var mod = parts[i]; - if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; - else if (/^a(lt)?$/i.test(mod)) alt = true; - else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; - else if (/^s(hift)$/i.test(mod)) shift = true; - else throw new Error("Unrecognized modifier name: " + mod); - } - if (alt) name = "Alt-" + name; - if (ctrl) name = "Ctrl-" + name; - if (cmd) name = "Cmd-" + name; - if (shift) name = "Shift-" + name; - return name; - } - - // This is a kludge to keep keymaps mostly working as raw objects - // (backwards compatibility) while at the same time support features - // like normalization and multi-stroke key bindings. It compiles a - // new normalized keymap, and then updates the old object to reflect - // this. - CodeMirror.normalizeKeyMap = function (keymap) { - var copy = {}; - for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { - var value = keymap[keyname]; - if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; - if (value == "...") { delete keymap[keyname]; continue; } - - var keys = map(keyname.split(" "), normalizeKeyName); - for (var i = 0; i < keys.length; i++) { - var val, name; - if (i == keys.length - 1) { - name = keys.join(" "); - val = value; - } else { - name = keys.slice(0, i + 1).join(" "); - val = "..."; - } - var prev = copy[name]; - if (!prev) copy[name] = val; - else if (prev != val) throw new Error("Inconsistent bindings for " + name); - } - delete keymap[keyname]; - } - for (var prop in copy) keymap[prop] = copy[prop]; - return keymap; - }; - - var lookupKey = CodeMirror.lookupKey = function (key, map, handle, context) { - map = getKeyMap(map); - var found = map.call ? map.call(key, context) : map[key]; - if (found === false) return "nothing"; - if (found === "...") return "multi"; - if (found != null && handle(found)) return "handled"; - - if (map.fallthrough) { - if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") - return lookupKey(key, map.fallthrough, handle, context); - for (var i = 0; i < map.fallthrough.length; i++) { - var result = lookupKey(key, map.fallthrough[i], handle, context); - if (result) return result; - } - } - }; - - // Modifier key presses don't count as 'real' key presses for the - // purpose of keymap fallthrough. - var isModifierKey = CodeMirror.isModifierKey = function (value) { - var name = typeof value == "string" ? value : keyNames[value.keyCode]; - return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; - }; - - // Look up the name of a key as indicated by an event object. - var keyName = CodeMirror.keyName = function (event, noShift) { - if (presto && event.keyCode == 34 && event["char"]) return false; - var base = keyNames[event.keyCode], name = base; - if (name == null || event.altGraphKey) return false; - if (event.altKey && base != "Alt") name = "Alt-" + name; - if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; - if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; - return name; - }; - - function getKeyMap(val) { - return typeof val == "string" ? keyMap[val] : val; - } - - // FROMTEXTAREA - - CodeMirror.fromTextArea = function (textarea, options) { - options = options ? copyObj(options) : {}; - options.value = textarea.value; - if (!options.tabindex && textarea.tabIndex) - options.tabindex = textarea.tabIndex; - if (!options.placeholder && textarea.placeholder) - options.placeholder = textarea.placeholder; - // Set autofocus to true if this textarea is focused, or if it has - // autofocus and no other element is focused. - if (options.autofocus == null) { - var hasFocus = activeElt(); - options.autofocus = hasFocus == textarea || - textarea.getAttribute("autofocus") != null && hasFocus == document.body; - } - - function save() { textarea.value = cm.getValue(); } - if (textarea.form) { - on(textarea.form, "submit", save); - // Deplorable hack to make the submit method do the right thing. - if (!options.leaveSubmitMethodAlone) { - var form = textarea.form, realSubmit = form.submit; - try { - var wrappedSubmit = form.submit = function () { - save(); - form.submit = realSubmit; - form.submit(); - form.submit = wrappedSubmit; - }; - } catch (e) { } - } - } - - options.finishInit = function (cm) { - cm.save = save; - cm.getTextArea = function () { return textarea; }; - cm.toTextArea = function () { - cm.toTextArea = isNaN; // Prevent this from being ran twice - save(); - textarea.parentNode.removeChild(cm.getWrapperElement()); - textarea.style.display = ""; - if (textarea.form) { - off(textarea.form, "submit", save); - if (typeof textarea.form.submit == "function") - textarea.form.submit = realSubmit; - } - }; - }; - - textarea.style.display = "none"; - var cm = CodeMirror(function (node) { - textarea.parentNode.insertBefore(node, textarea.nextSibling); - }, options); - return cm; - }; - - // STRING STREAM - - // Fed to the mode parsers, provides helper functions to make - // parsers more succinct. - - var StringStream = CodeMirror.StringStream = function (string, tabSize) { - this.pos = this.start = 0; - this.string = string; - this.tabSize = tabSize || 8; - this.lastColumnPos = this.lastColumnValue = 0; - this.lineStart = 0; - }; - - StringStream.prototype = { - eol: function () { return this.pos >= this.string.length; }, - sol: function () { return this.pos == this.lineStart; }, - peek: function () { return this.string.charAt(this.pos) || undefined; }, - next: function () { - if (this.pos < this.string.length) - return this.string.charAt(this.pos++); - }, - eat: function (match) { - var ch = this.string.charAt(this.pos); - if (typeof match == "string") var ok = ch == match; - else var ok = ch && (match.test ? match.test(ch) : match(ch)); - if (ok) { ++this.pos; return ch; } - }, - eatWhile: function (match) { - var start = this.pos; - while (this.eat(match)) { } - return this.pos > start; - }, - eatSpace: function () { - var start = this.pos; - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; - return this.pos > start; - }, - skipToEnd: function () { this.pos = this.string.length; }, - skipTo: function (ch) { - var found = this.string.indexOf(ch, this.pos); - if (found > -1) { this.pos = found; return true; } - }, - backUp: function (n) { this.pos -= n; }, - column: function () { - if (this.lastColumnPos < this.start) { - this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); - this.lastColumnPos = this.start; - } - return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); - }, - indentation: function () { - return countColumn(this.string, null, this.tabSize) - - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); - }, - match: function (pattern, consume, caseInsensitive) { - if (typeof pattern == "string") { - var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }; - var substr = this.string.substr(this.pos, pattern.length); - if (cased(substr) == cased(pattern)) { - if (consume !== false) this.pos += pattern.length; - return true; - } - } else { - var match = this.string.slice(this.pos).match(pattern); - if (match && match.index > 0) return null; - if (match && consume !== false) this.pos += match[0].length; - return match; - } - }, - current: function () { return this.string.slice(this.start, this.pos); }, - hideFirstChars: function (n, inner) { - this.lineStart += n; - try { return inner(); } - finally { this.lineStart -= n; } - } - }; - - // TEXTMARKERS - - // Created with markText and setBookmark methods. A TextMarker is a - // handle that can be used to clear or find a marked position in the - // document. Line objects hold arrays (markedSpans) containing - // {from, to, marker} object pointing to such marker objects, and - // indicating that such a marker is present on that line. Multiple - // lines may point to the same marker when it spans across lines. - // The spans will have null for their from/to properties when the - // marker continues beyond the start/end of the line. Markers have - // links back to the lines they currently touch. - - var nextMarkerId = 0; - - var TextMarker = CodeMirror.TextMarker = function (doc, type) { - this.lines = []; - this.type = type; - this.doc = doc; - this.id = ++nextMarkerId; - }; - eventMixin(TextMarker); - - // Clear the marker. - TextMarker.prototype.clear = function () { - if (this.explicitlyCleared) return; - var cm = this.doc.cm, withOp = cm && !cm.curOp; - if (withOp) startOperation(cm); - if (hasHandler(this, "clear")) { - var found = this.find(); - if (found) signalLater(this, "clear", found.from, found.to); - } - var min = null, max = null; - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); - if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); - else if (cm) { - if (span.to != null) max = lineNo(line); - if (span.from != null) min = lineNo(line); - } - line.markedSpans = removeMarkedSpan(line.markedSpans, span); - if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) - updateLineHeight(line, textHeight(cm.display)); - } - if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { - var visual = visualLine(this.lines[i]), len = lineLength(visual); - if (len > cm.display.maxLineLength) { - cm.display.maxLine = visual; - cm.display.maxLineLength = len; - cm.display.maxLineChanged = true; - } - } - - if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); - this.lines.length = 0; - this.explicitlyCleared = true; - if (this.atomic && this.doc.cantEdit) { - this.doc.cantEdit = false; - if (cm) reCheckSelection(cm.doc); - } - if (cm) signalLater(cm, "markerCleared", cm, this); - if (withOp) endOperation(cm); - if (this.parent) this.parent.clear(); - }; - - // Find the position of the marker in the document. Returns a {from, - // to} object by default. Side can be passed to get a specific side - // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the - // Pos objects returned contain a line object, rather than a line - // number (used to prevent looking up the same line twice). - TextMarker.prototype.find = function (side, lineObj) { - if (side == null && this.type == "bookmark") side = 1; - var from, to; - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); - if (span.from != null) { - from = Pos(lineObj ? line : lineNo(line), span.from); - if (side == -1) return from; - } - if (span.to != null) { - to = Pos(lineObj ? line : lineNo(line), span.to); - if (side == 1) return to; - } - } - return from && { from: from, to: to }; - }; - - // Signals that the marker's widget changed, and surrounding layout - // should be recomputed. - TextMarker.prototype.changed = function () { - var pos = this.find(-1, true), widget = this, cm = this.doc.cm; - if (!pos || !cm) return; - runInOp(cm, function () { - var line = pos.line, lineN = lineNo(pos.line); - var view = findViewForLine(cm, lineN); - if (view) { - clearLineMeasurementCacheFor(view); - cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; - } - cm.curOp.updateMaxLine = true; - if (!lineIsHidden(widget.doc, line) && widget.height != null) { - var oldHeight = widget.height; - widget.height = null; - var dHeight = widgetHeight(widget) - oldHeight; - if (dHeight) - updateLineHeight(line, line.height + dHeight); - } - }); - }; - - TextMarker.prototype.attachLine = function (line) { - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp; - if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) - (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); - } - this.lines.push(line); - }; - TextMarker.prototype.detachLine = function (line) { - this.lines.splice(indexOf(this.lines, line), 1); - if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp; - (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); - } - }; - - // Collapsed markers have unique ids, in order to be able to order - // them, which is needed for uniquely determining an outer marker - // when they overlap (they may nest, but not partially overlap). - var nextMarkerId = 0; - - // Create a marker, wire it up to the right lines, and - function markText(doc, from, to, options, type) { - // Shared markers (across linked documents) are handled separately - // (markTextShared will call out to this again, once per - // document). - if (options && options.shared) return markTextShared(doc, from, to, options, type); - // Ensure we are in an operation. - if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); - - var marker = new TextMarker(doc, type), diff = cmp(from, to); - if (options) copyObj(options, marker, false); - // Don't connect empty markers unless clearWhenEmpty is false - if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) - return marker; - if (marker.replacedWith) { - // Showing up as a widget implies collapsed (widget replaces text) - marker.collapsed = true; - marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); - if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); - if (options.insertLeft) marker.widgetNode.insertLeft = true; - } - if (marker.collapsed) { - if (conflictingCollapsedRange(doc, from.line, from, to, marker) || - from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) - throw new Error("Inserting collapsed marker partially overlapping an existing one"); - sawCollapsedSpans = true; - } - - if (marker.addToHistory) - addChangeToHistory(doc, { from: from, to: to, origin: "markText" }, doc.sel, NaN); - - var curLine = from.line, cm = doc.cm, updateMaxLine; - doc.iter(curLine, to.line + 1, function (line) { - if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) - updateMaxLine = true; - if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); - addMarkedSpan(line, new MarkedSpan(marker, - curLine == from.line ? from.ch : null, - curLine == to.line ? to.ch : null)); - ++curLine; - }); - // lineIsHidden depends on the presence of the spans, so needs a second pass - if (marker.collapsed) doc.iter(from.line, to.line + 1, function (line) { - if (lineIsHidden(doc, line)) updateLineHeight(line, 0); - }); - - if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function () { marker.clear(); }); - - if (marker.readOnly) { - sawReadOnlySpans = true; - if (doc.history.done.length || doc.history.undone.length) - doc.clearHistory(); - } - if (marker.collapsed) { - marker.id = ++nextMarkerId; - marker.atomic = true; - } - if (cm) { - // Sync editor state - if (updateMaxLine) cm.curOp.updateMaxLine = true; - if (marker.collapsed) - regChange(cm, from.line, to.line + 1); - else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) - for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); - if (marker.atomic) reCheckSelection(cm.doc); - signalLater(cm, "markerAdded", cm, marker); - } - return marker; - } - - // SHARED TEXTMARKERS - - // A shared marker spans multiple linked documents. It is - // implemented as a meta-marker-object controlling multiple normal - // markers. - var SharedTextMarker = CodeMirror.SharedTextMarker = function (markers, primary) { - this.markers = markers; - this.primary = primary; - for (var i = 0; i < markers.length; ++i) - markers[i].parent = this; - }; - eventMixin(SharedTextMarker); - - SharedTextMarker.prototype.clear = function () { - if (this.explicitlyCleared) return; - this.explicitlyCleared = true; - for (var i = 0; i < this.markers.length; ++i) - this.markers[i].clear(); - signalLater(this, "clear"); - }; - SharedTextMarker.prototype.find = function (side, lineObj) { - return this.primary.find(side, lineObj); - }; - - function markTextShared(doc, from, to, options, type) { - options = copyObj(options); - options.shared = false; - var markers = [markText(doc, from, to, options, type)], primary = markers[0]; - var widget = options.widgetNode; - linkedDocs(doc, function (doc) { - if (widget) options.widgetNode = widget.cloneNode(true); - markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); - for (var i = 0; i < doc.linked.length; ++i) - if (doc.linked[i].isParent) return; - primary = lst(markers); - }); - return new SharedTextMarker(markers, primary); - } - - function findSharedMarkers(doc) { - return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), - function (m) { return m.parent; }); - } - - function copySharedMarkers(doc, markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], pos = marker.find(); - var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); - if (cmp(mFrom, mTo)) { - var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); - marker.markers.push(subMark); - subMark.parent = marker; - } - } - } - - function detachSharedMarkers(markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], linked = [marker.primary.doc];; - linkedDocs(marker.primary.doc, function (d) { linked.push(d); }); - for (var j = 0; j < marker.markers.length; j++) { - var subMarker = marker.markers[j]; - if (indexOf(linked, subMarker.doc) == -1) { - subMarker.parent = null; - marker.markers.splice(j--, 1); - } - } - } - } - - // TEXTMARKER SPANS - - function MarkedSpan(marker, from, to) { - this.marker = marker; - this.from = from; this.to = to; - } - - // Search an array of spans for a span matching the given marker. - function getMarkedSpanFor(spans, marker) { - if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if (span.marker == marker) return span; - } - } - // Remove a span from an array, returning undefined if no spans are - // left (we don't store arrays for lines without spans). - function removeMarkedSpan(spans, span) { - for (var r, i = 0; i < spans.length; ++i) - if (spans[i] != span) (r || (r = [])).push(spans[i]); - return r; - } - // Add a span to a line. - function addMarkedSpan(line, span) { - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; - span.marker.attachLine(line); - } - - // Used for the algorithm that adjusts markers for a change in the - // document. These functions cut an array of spans at a given - // character position, returning an array of remaining chunks (or - // undefined if nothing remains). - function markedSpansBefore(old, startCh, isInsert) { - if (old) for (var i = 0, nw; i < old.length; ++i) { - var span = old[i], marker = span.marker; - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); - if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); - (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); - } - } - return nw; - } - function markedSpansAfter(old, endCh, isInsert) { - if (old) for (var i = 0, nw; i < old.length; ++i) { - var span = old[i], marker = span.marker; - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); - if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); - (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, - span.to == null ? null : span.to - endCh)); - } - } - return nw; - } - - // Given a change object, compute the new set of marker spans that - // cover the line in which the change took place. Removes spans - // entirely within the change, reconnects spans belonging to the - // same marker that appear on both sides of the change, and cuts off - // spans partially within the change. Returns an array of span - // arrays with one element for each line in (after) the change. - function stretchSpansOverChange(doc, change) { - if (change.full) return null; - var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; - var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; - if (!oldFirst && !oldLast) return null; - - var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; - // Get the spans that 'stick out' on both sides - var first = markedSpansBefore(oldFirst, startCh, isInsert); - var last = markedSpansAfter(oldLast, endCh, isInsert); - - // Next, merge those two ends - var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); - if (first) { - // Fix up .to properties of first - for (var i = 0; i < first.length; ++i) { - var span = first[i]; - if (span.to == null) { - var found = getMarkedSpanFor(last, span.marker); - if (!found) span.to = startCh; - else if (sameLine) span.to = found.to == null ? null : found.to + offset; - } - } - } - if (last) { - // Fix up .from in last (or move them into first in case of sameLine) - for (var i = 0; i < last.length; ++i) { - var span = last[i]; - if (span.to != null) span.to += offset; - if (span.from == null) { - var found = getMarkedSpanFor(first, span.marker); - if (!found) { - span.from = offset; - if (sameLine) (first || (first = [])).push(span); - } - } else { - span.from += offset; - if (sameLine) (first || (first = [])).push(span); - } - } - } - // Make sure we didn't create any zero-length spans - if (first) first = clearEmptySpans(first); - if (last && last != first) last = clearEmptySpans(last); - - var newMarkers = [first]; - if (!sameLine) { - // Fill gap with whole-line-spans - var gap = change.text.length - 2, gapMarkers; - if (gap > 0 && first) - for (var i = 0; i < first.length; ++i) - if (first[i].to == null) - (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); - for (var i = 0; i < gap; ++i) - newMarkers.push(gapMarkers); - newMarkers.push(last); - } - return newMarkers; - } - - // Remove spans that are empty and don't have a clearWhenEmpty - // option of false. - function clearEmptySpans(spans) { - for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) - spans.splice(i--, 1); - } - if (!spans.length) return null; - return spans; - } - - // Used for un/re-doing changes from the history. Combines the - // result of computing the existing spans with the set of spans that - // existed in the history (so that deleting around a span and then - // undoing brings back the span). - function mergeOldSpans(doc, change) { - var old = getOldSpans(doc, change); - var stretched = stretchSpansOverChange(doc, change); - if (!old) return stretched; - if (!stretched) return old; - - for (var i = 0; i < old.length; ++i) { - var oldCur = old[i], stretchCur = stretched[i]; - if (oldCur && stretchCur) { - spans: for (var j = 0; j < stretchCur.length; ++j) { - var span = stretchCur[j]; - for (var k = 0; k < oldCur.length; ++k) - if (oldCur[k].marker == span.marker) continue spans; - oldCur.push(span); - } - } else if (stretchCur) { - old[i] = stretchCur; - } - } - return old; - } - - // Used to 'clip' out readOnly ranges when making a change. - function removeReadOnlyRanges(doc, from, to) { - var markers = null; - doc.iter(from.line, to.line + 1, function (line) { - if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var mark = line.markedSpans[i].marker; - if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) - (markers || (markers = [])).push(mark); - } - }); - if (!markers) return null; - var parts = [{ from: from, to: to }]; - for (var i = 0; i < markers.length; ++i) { - var mk = markers[i], m = mk.find(0); - for (var j = 0; j < parts.length; ++j) { - var p = parts[j]; - if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; - var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); - if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) - newParts.push({ from: p.from, to: m.from }); - if (dto > 0 || !mk.inclusiveRight && !dto) - newParts.push({ from: m.to, to: p.to }); - parts.splice.apply(parts, newParts); - j += newParts.length - 1; - } - } - return parts; - } - - // Connect or disconnect spans from a line. - function detachMarkedSpans(line) { - var spans = line.markedSpans; - if (!spans) return; - for (var i = 0; i < spans.length; ++i) - spans[i].marker.detachLine(line); - line.markedSpans = null; - } - function attachMarkedSpans(line, spans) { - if (!spans) return; - for (var i = 0; i < spans.length; ++i) - spans[i].marker.attachLine(line); - line.markedSpans = spans; - } - - // Helpers used when computing which overlapping collapsed span - // counts as the larger one. - function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } - function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } - - // Returns a number indicating which of two overlapping collapsed - // spans is larger (and thus includes the other). Falls back to - // comparing ids when the spans cover exactly the same range. - function compareCollapsedMarkers(a, b) { - var lenDiff = a.lines.length - b.lines.length; - if (lenDiff != 0) return lenDiff; - var aPos = a.find(), bPos = b.find(); - var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); - if (fromCmp) return -fromCmp; - var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); - if (toCmp) return toCmp; - return b.id - a.id; - } - - // Find out whether a line ends or starts in a collapsed span. If - // so, return the marker for that span. - function collapsedSpanAtSide(line, start) { - var sps = sawCollapsedSpans && line.markedSpans, found; - if (sps) for (var sp, i = 0; i < sps.length; ++i) { - sp = sps[i]; - if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && - (!found || compareCollapsedMarkers(found, sp.marker) < 0)) - found = sp.marker; - } - return found; - } - function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } - function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } - - // Test whether there exists a collapsed span that partially - // overlaps (covers the start or end, but not both) of a new span. - // Such overlap is not allowed. - function conflictingCollapsedRange(doc, lineNo, from, to, marker) { - var line = getLine(doc, lineNo); - var sps = sawCollapsedSpans && line.markedSpans; - if (sps) for (var i = 0; i < sps.length; ++i) { - var sp = sps[i]; - if (!sp.marker.collapsed) continue; - var found = sp.marker.find(0); - var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); - var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); - if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; - if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || - fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) - return true; - } - } - - // A visual line is a line as drawn on the screen. Folding, for - // example, can cause multiple logical lines to appear on the same - // visual line. This finds the start of the visual line that the - // given line is part of (usually that is the line itself). - function visualLine(line) { - var merged; - while (merged = collapsedSpanAtStart(line)) - line = merged.find(-1, true).line; - return line; - } - - // Returns an array of logical lines that continue the visual line - // started by the argument, or undefined if there are no such lines. - function visualLineContinued(line) { - var merged, lines; - while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line; - (lines || (lines = [])).push(line); - } - return lines; - } - - // Get the line number of the start of the visual line that the - // given line number is part of. - function visualLineNo(doc, lineN) { - var line = getLine(doc, lineN), vis = visualLine(line); - if (line == vis) return lineN; - return lineNo(vis); - } - // Get the line number of the start of the next visual line after - // the given line. - function visualLineEndNo(doc, lineN) { - if (lineN > doc.lastLine()) return lineN; - var line = getLine(doc, lineN), merged; - if (!lineIsHidden(doc, line)) return lineN; - while (merged = collapsedSpanAtEnd(line)) - line = merged.find(1, true).line; - return lineNo(line) + 1; - } - - // Compute whether a line is hidden. Lines count as hidden when they - // are part of a visual line that starts with another line, or when - // they are entirely covered by collapsed, non-widget span. - function lineIsHidden(doc, line) { - var sps = sawCollapsedSpans && line.markedSpans; - if (sps) for (var sp, i = 0; i < sps.length; ++i) { - sp = sps[i]; - if (!sp.marker.collapsed) continue; - if (sp.from == null) return true; - if (sp.marker.widgetNode) continue; - if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) - return true; - } - } - function lineIsHiddenInner(doc, line, span) { - if (span.to == null) { - var end = span.marker.find(1, true); - return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); - } - if (span.marker.inclusiveRight && span.to == line.text.length) - return true; - for (var sp, i = 0; i < line.markedSpans.length; ++i) { - sp = line.markedSpans[i]; - if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && - (sp.to == null || sp.to != span.from) && - (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && - lineIsHiddenInner(doc, line, sp)) return true; - } - } - - // LINE WIDGETS - - // Line widgets are block elements displayed above or below a line. - - var LineWidget = CodeMirror.LineWidget = function (doc, node, options) { - if (options) for (var opt in options) if (options.hasOwnProperty(opt)) - this[opt] = options[opt]; - this.doc = doc; - this.node = node; - }; - eventMixin(LineWidget); - - function adjustScrollWhenAboveVisible(cm, line, diff) { - if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) - addToScrollPos(cm, null, diff); - } - - LineWidget.prototype.clear = function () { - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); - if (no == null || !ws) return; - for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); - if (!ws.length) line.widgets = null; - var height = widgetHeight(this); - updateLineHeight(line, Math.max(0, line.height - height)); - if (cm) runInOp(cm, function () { - adjustScrollWhenAboveVisible(cm, line, -height); - regLineChange(cm, no, "widget"); - }); - }; - LineWidget.prototype.changed = function () { - var oldH = this.height, cm = this.doc.cm, line = this.line; - this.height = null; - var diff = widgetHeight(this) - oldH; - if (!diff) return; - updateLineHeight(line, line.height + diff); - if (cm) runInOp(cm, function () { - cm.curOp.forceUpdate = true; - adjustScrollWhenAboveVisible(cm, line, diff); - }); - }; - - function widgetHeight(widget) { - if (widget.height != null) return widget.height; - var cm = widget.doc.cm; - if (!cm) return 0; - if (!contains(document.body, widget.node)) { - var parentStyle = "position: relative;"; - if (widget.coverGutter) - parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; - if (widget.noHScroll) - parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; - removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); - } - return widget.height = widget.node.parentNode.offsetHeight; - } - - function addLineWidget(doc, handle, node, options) { - var widget = new LineWidget(doc, node, options); - var cm = doc.cm; - if (cm && widget.noHScroll) cm.display.alignWidgets = true; - changeLine(doc, handle, "widget", function (line) { - var widgets = line.widgets || (line.widgets = []); - if (widget.insertAt == null) widgets.push(widget); - else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); - widget.line = line; - if (cm && !lineIsHidden(doc, line)) { - var aboveVisible = heightAtLine(line) < doc.scrollTop; - updateLineHeight(line, line.height + widgetHeight(widget)); - if (aboveVisible) addToScrollPos(cm, null, widget.height); - cm.curOp.forceUpdate = true; - } - return true; - }); - return widget; - } - - // LINE DATA STRUCTURE - - // Line objects. These hold state related to a line, including - // highlighting info (the styles array). - var Line = CodeMirror.Line = function (text, markedSpans, estimateHeight) { - this.text = text; - attachMarkedSpans(this, markedSpans); - this.height = estimateHeight ? estimateHeight(this) : 1; - }; - eventMixin(Line); - Line.prototype.lineNo = function () { return lineNo(this); }; - - // Change the content (text, markers) of a line. Automatically - // invalidates cached information and tries to re-estimate the - // line's height. - function updateLine(line, text, markedSpans, estimateHeight) { - line.text = text; - if (line.stateAfter) line.stateAfter = null; - if (line.styles) line.styles = null; - if (line.order != null) line.order = null; - detachMarkedSpans(line); - attachMarkedSpans(line, markedSpans); - var estHeight = estimateHeight ? estimateHeight(line) : 1; - if (estHeight != line.height) updateLineHeight(line, estHeight); - } - - // Detach a line from the document tree and its markers. - function cleanUpLine(line) { - line.parent = null; - detachMarkedSpans(line); - } - - function extractLineClasses(type, output) { - if (type) for (; ;) { - var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); - if (!lineClass) break; - type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); - var prop = lineClass[1] ? "bgClass" : "textClass"; - if (output[prop] == null) - output[prop] = lineClass[2]; - else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) - output[prop] += " " + lineClass[2]; - } - return type; - } - - function callBlankLine(mode, state) { - if (mode.blankLine) return mode.blankLine(state); - if (!mode.innerMode) return; - var inner = CodeMirror.innerMode(mode, state); - if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); - } - - function readToken(mode, stream, state, inner) { - for (var i = 0; i < 10; i++) { - if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; - var style = mode.token(stream, state); - if (stream.pos > stream.start) return style; - } - throw new Error("Mode " + mode.name + " failed to advance stream."); - } - - // Utility for getTokenAt and getLineTokens - function takeToken(cm, pos, precise, asArray) { - function getObj(copy) { - return { - start: stream.start, end: stream.pos, - string: stream.current(), - type: style || null, - state: copy ? copyState(doc.mode, state) : state - }; - } - - var doc = cm.doc, mode = doc.mode, style; - pos = clipPos(doc, pos); - var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); - var stream = new StringStream(line.text, cm.options.tabSize), tokens; - if (asArray) tokens = []; - while ((asArray || stream.pos < pos.ch) && !stream.eol()) { - stream.start = stream.pos; - style = readToken(mode, stream, state); - if (asArray) tokens.push(getObj(true)); - } - return asArray ? tokens : getObj(); - } - - // Run the given mode's parser over a line, calling f for each token. - function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { - var flattenSpans = mode.flattenSpans; - if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; - var curStart = 0, curStyle = null; - var stream = new StringStream(text, cm.options.tabSize), style; - var inner = cm.options.addModeClass && [null]; - if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); - while (!stream.eol()) { - if (stream.pos > cm.options.maxHighlightLength) { - flattenSpans = false; - if (forceToEnd) processLine(cm, text, state, stream.pos); - stream.pos = text.length; - style = null; - } else { - style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); - } - if (inner) { - var mName = inner[0].name; - if (mName) style = "m-" + (style ? mName + " " + style : mName); - } - if (!flattenSpans || curStyle != style) { - while (curStart < stream.start) { - curStart = Math.min(stream.start, curStart + 50000); - f(curStart, curStyle); - } - curStyle = style; - } - stream.start = stream.pos; - } - while (curStart < stream.pos) { - // Webkit seems to refuse to render text nodes longer than 57444 characters - var pos = Math.min(stream.pos, curStart + 50000); - f(pos, curStyle); - curStart = pos; - } - } - - // Compute a style array (an array starting with a mode generation - // -- for invalidation -- followed by pairs of end positions and - // style strings), which is used to highlight the tokens on the - // line. - function highlightLine(cm, line, state, forceToEnd) { - // A styles array always starts with a number identifying the - // mode/overlays that it is based on (for easy invalidation). - var st = [cm.state.modeGen], lineClasses = {}; - // Compute the base array of styles - runMode(cm, line.text, cm.doc.mode, state, function (end, style) { - st.push(end, style); - }, lineClasses, forceToEnd); - - // Run overlays, adjust style array. - for (var o = 0; o < cm.state.overlays.length; ++o) { - var overlay = cm.state.overlays[o], i = 1, at = 0; - runMode(cm, line.text, overlay.mode, true, function (end, style) { - var start = i; - // Ensure there's a token end at the current position, and that i points at it - while (at < end) { - var i_end = st[i]; - if (i_end > end) - st.splice(i, 1, end, st[i + 1], i_end); - i += 2; - at = Math.min(end, i_end); - } - if (!style) return; - if (overlay.opaque) { - st.splice(start, i - start, end, "cm-overlay " + style); - i = start + 2; - } else { - for (; start < i; start += 2) { - var cur = st[start + 1]; - st[start + 1] = (cur ? cur + " " : "") + "cm-overlay " + style; - } - } - }, lineClasses); - } - - return { styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null }; - } - - function getLineStyles(cm, line, updateFrontier) { - if (!line.styles || line.styles[0] != cm.state.modeGen) { - var state = getStateBefore(cm, lineNo(line)); - var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state); - line.stateAfter = state; - line.styles = result.styles; - if (result.classes) line.styleClasses = result.classes; - else if (line.styleClasses) line.styleClasses = null; - if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; - } - return line.styles; - } - - // Lightweight form of highlight -- proceed over this line and - // update state, but don't save a style array. Used for lines that - // aren't currently visible. - function processLine(cm, text, state, startAt) { - var mode = cm.doc.mode; - var stream = new StringStream(text, cm.options.tabSize); - stream.start = stream.pos = startAt || 0; - if (text == "") callBlankLine(mode, state); - while (!stream.eol()) { - readToken(mode, stream, state); - stream.start = stream.pos; - } - } - - // Convert a style as returned by a mode (either null, or a string - // containing one or more styles) to a CSS style. This is cached, - // and also looks for line-wide styles. - var styleToClassCache = {}, styleToClassCacheWithMode = {}; - function interpretTokenStyle(style, options) { - if (!style || /^\s*$/.test(style)) return null; - var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; - return cache[style] || - (cache[style] = style.replace(/\S+/g, "cm-$&")); - } - - // Render the DOM representation of the text of a line. Also builds - // up a 'line map', which points at the DOM nodes that represent - // specific stretches of text, and is used by the measuring code. - // The returned object contains the DOM node, this map, and - // information about line-wide styles that were set by the mode. - function buildLineContent(cm, lineView) { - // The padding-right forces the element to have a 'border', which - // is needed on Webkit to be able to get line-level bounding - // rectangles for it (in measureChar). - var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); - var builder = { - pre: elt("pre", [content], "CodeMirror-line"), content: content, - col: 0, pos: 0, cm: cm, - trailingSpace: false, - splitSpaces: (ie || webkit) && cm.getOption("lineWrapping") - }; - lineView.measure = {}; - - // Iterate over the logical lines that make up this visual line. - for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { - var line = i ? lineView.rest[i - 1] : lineView.line, order; - builder.pos = 0; - builder.addToken = buildToken; - // Optionally wire in some hacks into the token-rendering - // algorithm, to deal with browser quirks. - if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) - builder.addToken = buildTokenBadBidi(builder.addToken, order); - builder.map = []; - var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); - insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); - if (line.styleClasses) { - if (line.styleClasses.bgClass) - builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); - if (line.styleClasses.textClass) - builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); - } - - // Ensure at least a single node is present, for measuring. - if (builder.map.length == 0) - builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); - - // Store the map and a cache object for the current logical line - if (i == 0) { - lineView.measure.map = builder.map; - lineView.measure.cache = {}; - } else { - (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); - (lineView.measure.caches || (lineView.measure.caches = [])).push({}); - } - } - - // See issue #2901 - if (webkit) { - var last = builder.content.lastChild - if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) - builder.content.className = "cm-tab-wrap-hack"; - } - - signal(cm, "renderLine", cm, lineView.line, builder.pre); - if (builder.pre.className) - builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); - - return builder; - } - - function defaultSpecialCharPlaceholder(ch) { - var token = elt("span", "\u2022", "cm-invalidchar"); - token.title = "\\u" + ch.charCodeAt(0).toString(16); - token.setAttribute("aria-label", token.title); - return token; - } - - // Build up the DOM representation for a single token, and add it to - // the line map. Takes care to render special characters separately. - function buildToken(builder, text, style, startStyle, endStyle, title, css) { - if (!text) return; - var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text - var special = builder.cm.state.specialChars, mustWrap = false; - if (!special.test(text)) { - builder.col += text.length; - var content = document.createTextNode(displayText); - builder.map.push(builder.pos, builder.pos + text.length, content); - if (ie && ie_version < 9) mustWrap = true; - builder.pos += text.length; - } else { - var content = document.createDocumentFragment(), pos = 0; - while (true) { - special.lastIndex = pos; - var m = special.exec(text); - var skipped = m ? m.index - pos : text.length - pos; - if (skipped) { - var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); - if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); - else content.appendChild(txt); - builder.map.push(builder.pos, builder.pos + skipped, txt); - builder.col += skipped; - builder.pos += skipped; - } - if (!m) break; - pos += skipped + 1; - if (m[0] == "\t") { - var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; - var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); - txt.setAttribute("role", "presentation"); - txt.setAttribute("cm-text", "\t"); - builder.col += tabWidth; - } else if (m[0] == "\r" || m[0] == "\n") { - var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")); - txt.setAttribute("cm-text", m[0]); - builder.col += 1; - } else { - var txt = builder.cm.options.specialCharPlaceholder(m[0]); - txt.setAttribute("cm-text", m[0]); - if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); - else content.appendChild(txt); - builder.col += 1; - } - builder.map.push(builder.pos, builder.pos + 1, txt); - builder.pos++; - } - } - builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 - if (style || startStyle || endStyle || mustWrap || css) { - var fullStyle = style || ""; - if (startStyle) fullStyle += startStyle; - if (endStyle) fullStyle += endStyle; - var token = elt("span", [content], fullStyle, css); - if (title) token.title = title; - return builder.content.appendChild(token); - } - builder.content.appendChild(content); - } - - function splitSpaces(text, trailingBefore) { - if (text.length > 1 && !/ /.test(text)) return text - var spaceBefore = trailingBefore, result = "" - for (var i = 0; i < text.length; i++) { - var ch = text.charAt(i) - if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) - ch = "\u00a0" - result += ch - spaceBefore = ch == " " - } - return result - } - - // Work around nonsense dimensions being reported for stretches of - // right-to-left text. - function buildTokenBadBidi(inner, order) { - return function (builder, text, style, startStyle, endStyle, title, css) { - style = style ? style + " cm-force-border" : "cm-force-border"; - var start = builder.pos, end = start + text.length; - for (; ;) { - // Find the part that overlaps with the start of this text - for (var i = 0; i < order.length; i++) { - var part = order[i]; - if (part.to > start && part.from <= start) break; - } - if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); - inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); - startStyle = null; - text = text.slice(part.to - start); - start = part.to; - } - }; - } - - function buildCollapsedSpan(builder, size, marker, ignoreWidget) { - var widget = !ignoreWidget && marker.widgetNode; - if (widget) builder.map.push(builder.pos, builder.pos + size, widget); - if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { - if (!widget) - widget = builder.content.appendChild(document.createElement("span")); - widget.setAttribute("cm-marker", marker.id); - } - if (widget) { - builder.cm.display.input.setUneditable(widget); - builder.content.appendChild(widget); - } - builder.pos += size; - builder.trailingSpace = false - } - - // Outputs a number of spans to make up a line, taking highlighting - // and marked text into account. - function insertLineContent(line, builder, styles) { - var spans = line.markedSpans, allText = line.text, at = 0; - if (!spans) { - for (var i = 1; i < styles.length; i += 2) - builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i + 1], builder.cm.options)); - return; - } - - var len = allText.length, pos = 0, i = 1, text = "", style, css; - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; - for (; ;) { - if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = title = css = ""; - collapsed = null; nextChange = Infinity; - var foundBookmarks = [], endStyles - for (var j = 0; j < spans.length; ++j) { - var sp = spans[j], m = sp.marker; - if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { - foundBookmarks.push(m); - } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { - if (sp.to != null && sp.to != pos && nextChange > sp.to) { - nextChange = sp.to; - spanEndStyle = ""; - } - if (m.className) spanStyle += " " + m.className; - if (m.css) css = (css ? css + ";" : "") + m.css; - if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; - if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to) - if (m.title && !title) title = m.title; - if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) - collapsed = sp; - } else if (sp.from > pos && nextChange > sp.from) { - nextChange = sp.from; - } - } - if (endStyles) for (var j = 0; j < endStyles.length; j += 2) - if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j] - - if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j) - buildCollapsedSpan(builder, 0, foundBookmarks[j]); - if (collapsed && (collapsed.from || 0) == pos) { - buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, - collapsed.marker, collapsed.from == null); - if (collapsed.to == null) return; - if (collapsed.to == pos) collapsed = false; - } - } - if (pos >= len) break; - - var upto = Math.min(len, nextChange); - while (true) { - if (text) { - var end = pos + text.length; - if (!collapsed) { - var tokenText = end > upto ? text.slice(0, upto - pos) : text; - builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); - } - if (end >= upto) { text = text.slice(upto - pos); pos = upto; break; } - pos = end; - spanStartStyle = ""; - } - text = allText.slice(at, at = styles[i++]); - style = interpretTokenStyle(styles[i++], builder.cm.options); - } - } - } - - // DOCUMENT DATA STRUCTURE - - // By default, updates that start and end at the beginning of a line - // are treated specially, in order to make the association of line - // widgets and marker elements with the text behave more intuitive. - function isWholeLineUpdate(doc, change) { - return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && - (!doc.cm || doc.cm.options.wholeLineUpdateBefore); - } - - // Perform a change on the document data structure. - function updateDoc(doc, change, markedSpans, estimateHeight) { - function spansFor(n) { return markedSpans ? markedSpans[n] : null; } - function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight); - signalLater(line, "change", line, change); - } - function linesFor(start, end) { - for (var i = start, result = []; i < end; ++i) - result.push(new Line(text[i], spansFor(i), estimateHeight)); - return result; - } - - var from = change.from, to = change.to, text = change.text; - var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); - var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; - - // Adjust the line structure - if (change.full) { - doc.insert(0, linesFor(0, text.length)); - doc.remove(text.length, doc.size - text.length); - } else if (isWholeLineUpdate(doc, change)) { - // This is a whole-line replace. Treated specially to make - // sure line objects move the way they are supposed to. - var added = linesFor(0, text.length - 1); - update(lastLine, lastLine.text, lastSpans); - if (nlines) doc.remove(from.line, nlines); - if (added.length) doc.insert(from.line, added); - } else if (firstLine == lastLine) { - if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); - } else { - var added = linesFor(1, text.length - 1); - added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - doc.insert(from.line + 1, added); - } - } else if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); - doc.remove(from.line + 1, nlines); - } else { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); - var added = linesFor(1, text.length - 1); - if (nlines > 1) doc.remove(from.line + 1, nlines - 1); - doc.insert(from.line + 1, added); - } - - signalLater(doc, "change", doc, change); - } - - // The document is represented as a BTree consisting of leaves, with - // chunk of lines in them, and branches, with up to ten leaves or - // other branch nodes below them. The top node is always a branch - // node, and is the document object itself (meaning it has - // additional methods and properties). - // - // All nodes have parent links. The tree is used both to go from - // line numbers to line objects, and to go from objects to numbers. - // It also indexes by height, and is used to convert between height - // and line object, and to find the total height of the document. - // - // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html - - function LeafChunk(lines) { - this.lines = lines; - this.parent = null; - for (var i = 0, height = 0; i < lines.length; ++i) { - lines[i].parent = this; - height += lines[i].height; - } - this.height = height; - } - - LeafChunk.prototype = { - chunkSize: function () { return this.lines.length; }, - // Remove the n lines at offset 'at'. - removeInner: function (at, n) { - for (var i = at, e = at + n; i < e; ++i) { - var line = this.lines[i]; - this.height -= line.height; - cleanUpLine(line); - signalLater(line, "delete"); - } - this.lines.splice(at, n); - }, - // Helper used to collapse a small branch into a single leaf. - collapse: function (lines) { - lines.push.apply(lines, this.lines); - }, - // Insert the given array of lines at offset 'at', count them as - // having the given height. - insertInner: function (at, lines, height) { - this.height += height; - this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); - for (var i = 0; i < lines.length; ++i) lines[i].parent = this; - }, - // Used to iterate over a part of the tree. - iterN: function (at, n, op) { - for (var e = at + n; at < e; ++at) - if (op(this.lines[at])) return true; - } - }; - - function BranchChunk(children) { - this.children = children; - var size = 0, height = 0; - for (var i = 0; i < children.length; ++i) { - var ch = children[i]; - size += ch.chunkSize(); height += ch.height; - ch.parent = this; - } - this.size = size; - this.height = height; - this.parent = null; - } - - BranchChunk.prototype = { - chunkSize: function () { return this.size; }, - removeInner: function (at, n) { - this.size -= n; - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at < sz) { - var rm = Math.min(n, sz - at), oldHeight = child.height; - child.removeInner(at, rm); - this.height -= oldHeight - child.height; - if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } - if ((n -= rm) == 0) break; - at = 0; - } else at -= sz; - } - // If the result is smaller than 25 lines, ensure that it is a - // single leaf node. - if (this.size - n < 25 && - (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { - var lines = []; - this.collapse(lines); - this.children = [new LeafChunk(lines)]; - this.children[0].parent = this; - } - }, - collapse: function (lines) { - for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); - }, - insertInner: function (at, lines, height) { - this.size += lines.length; - this.height += height; - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at <= sz) { - child.insertInner(at, lines, height); - if (child.lines && child.lines.length > 50) { - // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. - // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. - var remaining = child.lines.length % 25 + 25 - for (var pos = remaining; pos < child.lines.length;) { - var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); - child.height -= leaf.height; - this.children.splice(++i, 0, leaf); - leaf.parent = this; - } - child.lines = child.lines.slice(0, remaining); - this.maybeSpill(); - } - break; - } - at -= sz; - } - }, - // When a node has grown, check whether it should be split. - maybeSpill: function () { - if (this.children.length <= 10) return; - var me = this; - do { - var spilled = me.children.splice(me.children.length - 5, 5); - var sibling = new BranchChunk(spilled); - if (!me.parent) { // Become the parent node - var copy = new BranchChunk(me.children); - copy.parent = me; - me.children = [copy, sibling]; - me = copy; - } else { - me.size -= sibling.size; - me.height -= sibling.height; - var myIndex = indexOf(me.parent.children, me); - me.parent.children.splice(myIndex + 1, 0, sibling); - } - sibling.parent = me.parent; - } while (me.children.length > 10); - me.parent.maybeSpill(); - }, - iterN: function (at, n, op) { - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); - if (at < sz) { - var used = Math.min(n, sz - at); - if (child.iterN(at, used, op)) return true; - if ((n -= used) == 0) break; - at = 0; - } else at -= sz; - } - } - }; - - var nextDocId = 0; - var Doc = CodeMirror.Doc = function (text, mode, firstLine, lineSep) { - if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep); - if (firstLine == null) firstLine = 0; - - BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); - this.first = firstLine; - this.scrollTop = this.scrollLeft = 0; - this.cantEdit = false; - this.cleanGeneration = 1; - this.frontier = firstLine; - var start = Pos(firstLine, 0); - this.sel = simpleSelection(start); - this.history = new History(null); - this.id = ++nextDocId; - this.modeOption = mode; - this.lineSep = lineSep; - this.extend = false; - - if (typeof text == "string") text = this.splitLines(text); - updateDoc(this, { from: start, to: start, text: text }); - setSelection(this, simpleSelection(start), sel_dontScroll); - }; - - Doc.prototype = createObj(BranchChunk.prototype, { - constructor: Doc, - // Iterate over the document. Supports two forms -- with only one - // argument, it calls that for each line in the document. With - // three, it iterates over the range given by the first two (with - // the second being non-inclusive). - iter: function (from, to, op) { - if (op) this.iterN(from - this.first, to - from, op); - else this.iterN(this.first, this.first + this.size, from); - }, - - // Non-public interface for adding and removing lines. - insert: function (at, lines) { - var height = 0; - for (var i = 0; i < lines.length; ++i) height += lines[i].height; - this.insertInner(at - this.first, lines, height); - }, - remove: function (at, n) { this.removeInner(at - this.first, n); }, - - // From here, the methods are part of the public interface. Most - // are also available from CodeMirror (editor) instances. - - getValue: function (lineSep) { - var lines = getLines(this, this.first, this.first + this.size); - if (lineSep === false) return lines; - return lines.join(lineSep || this.lineSeparator()); - }, - setValue: docMethodOp(function (code) { - var top = Pos(this.first, 0), last = this.first + this.size - 1; - makeChange(this, { - from: top, to: Pos(last, getLine(this, last).text.length), - text: this.splitLines(code), origin: "setValue", full: true - }, true); - setSelection(this, simpleSelection(top)); - }), - replaceRange: function (code, from, to, origin) { - from = clipPos(this, from); - to = to ? clipPos(this, to) : from; - replaceRange(this, code, from, to, origin); - }, - getRange: function (from, to, lineSep) { - var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); - if (lineSep === false) return lines; - return lines.join(lineSep || this.lineSeparator()); - }, - - getLine: function (line) { var l = this.getLineHandle(line); return l && l.text; }, - - getLineHandle: function (line) { if (isLine(this, line)) return getLine(this, line); }, - getLineNumber: function (line) { return lineNo(line); }, - - getLineHandleVisualStart: function (line) { - if (typeof line == "number") line = getLine(this, line); - return visualLine(line); - }, - - lineCount: function () { return this.size; }, - firstLine: function () { return this.first; }, - lastLine: function () { return this.first + this.size - 1; }, - - clipPos: function (pos) { return clipPos(this, pos); }, - - getCursor: function (start) { - var range = this.sel.primary(), pos; - if (start == null || start == "head") pos = range.head; - else if (start == "anchor") pos = range.anchor; - else if (start == "end" || start == "to" || start === false) pos = range.to(); - else pos = range.from(); - return pos; - }, - listSelections: function () { return this.sel.ranges; }, - somethingSelected: function () { return this.sel.somethingSelected(); }, - - setCursor: docMethodOp(function (line, ch, options) { - setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); - }), - setSelection: docMethodOp(function (anchor, head, options) { - setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); - }), - extendSelection: docMethodOp(function (head, other, options) { - extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); - }), - extendSelections: docMethodOp(function (heads, options) { - extendSelections(this, clipPosArray(this, heads), options); - }), - extendSelectionsBy: docMethodOp(function (f, options) { - var heads = map(this.sel.ranges, f); - extendSelections(this, clipPosArray(this, heads), options); - }), - setSelections: docMethodOp(function (ranges, primary, options) { - if (!ranges.length) return; - for (var i = 0, out = []; i < ranges.length; i++) - out[i] = new Range(clipPos(this, ranges[i].anchor), - clipPos(this, ranges[i].head)); - if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); - setSelection(this, normalizeSelection(out, primary), options); - }), - addSelection: docMethodOp(function (anchor, head, options) { - var ranges = this.sel.ranges.slice(0); - ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); - setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); - }), - - getSelection: function (lineSep) { - var ranges = this.sel.ranges, lines; - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - lines = lines ? lines.concat(sel) : sel; - } - if (lineSep === false) return lines; - else return lines.join(lineSep || this.lineSeparator()); - }, - getSelections: function (lineSep) { - var parts = [], ranges = this.sel.ranges; - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()); - parts[i] = sel; - } - return parts; - }, - replaceSelection: function (code, collapse, origin) { - var dup = []; - for (var i = 0; i < this.sel.ranges.length; i++) - dup[i] = code; - this.replaceSelections(dup, collapse, origin || "+input"); - }, - replaceSelections: docMethodOp(function (code, collapse, origin) { - var changes = [], sel = this.sel; - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - changes[i] = { from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin }; - } - var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); - for (var i = changes.length - 1; i >= 0; i--) - makeChange(this, changes[i]); - if (newSel) setSelectionReplaceHistory(this, newSel); - else if (this.cm) ensureCursorVisible(this.cm); - }), - undo: docMethodOp(function () { makeChangeFromHistory(this, "undo"); }), - redo: docMethodOp(function () { makeChangeFromHistory(this, "redo"); }), - undoSelection: docMethodOp(function () { makeChangeFromHistory(this, "undo", true); }), - redoSelection: docMethodOp(function () { makeChangeFromHistory(this, "redo", true); }), - - setExtending: function (val) { this.extend = val; }, - getExtending: function () { return this.extend; }, - - historySize: function () { - var hist = this.history, done = 0, undone = 0; - for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; - for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; - return { undo: done, redo: undone }; - }, - clearHistory: function () { this.history = new History(this.history.maxGeneration); }, - - markClean: function () { - this.cleanGeneration = this.changeGeneration(true); - }, - changeGeneration: function (forceSplit) { - if (forceSplit) - this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; - return this.history.generation; - }, - isClean: function (gen) { - return this.history.generation == (gen || this.cleanGeneration); - }, - - getHistory: function () { - return { - done: copyHistoryArray(this.history.done), - undone: copyHistoryArray(this.history.undone) - }; - }, - setHistory: function (histData) { - var hist = this.history = new History(this.history.maxGeneration); - hist.done = copyHistoryArray(histData.done.slice(0), null, true); - hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); - }, - - addLineClass: docMethodOp(function (handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - if (!line[prop]) line[prop] = cls; - else if (classTest(cls).test(line[prop])) return false; - else line[prop] += " " + cls; - return true; - }); - }), - removeLineClass: docMethodOp(function (handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { - var prop = where == "text" ? "textClass" - : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - var cur = line[prop]; - if (!cur) return false; - else if (cls == null) line[prop] = null; - else { - var found = cur.match(classTest(cls)); - if (!found) return false; - var end = found.index + found[0].length; - line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; - } - return true; - }); - }), - - addLineWidget: docMethodOp(function (handle, node, options) { - return addLineWidget(this, handle, node, options); - }), - removeLineWidget: function (widget) { widget.clear(); }, - - markText: function (from, to, options) { - return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range"); - }, - setBookmark: function (pos, options) { - var realOpts = { - replacedWith: options && (options.nodeType == null ? options.widget : options), - insertLeft: options && options.insertLeft, - clearWhenEmpty: false, shared: options && options.shared, - handleMouseEvents: options && options.handleMouseEvents - }; - pos = clipPos(this, pos); - return markText(this, pos, pos, realOpts, "bookmark"); - }, - findMarksAt: function (pos) { - pos = clipPos(this, pos); - var markers = [], spans = getLine(this, pos.line).markedSpans; - if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if ((span.from == null || span.from <= pos.ch) && - (span.to == null || span.to >= pos.ch)) - markers.push(span.marker.parent || span.marker); - } - return markers; - }, - findMarks: function (from, to, filter) { - from = clipPos(this, from); to = clipPos(this, to); - var found = [], lineNo = from.line; - this.iter(from.line, to.line + 1, function (line) { - var spans = line.markedSpans; - if (spans) for (var i = 0; i < spans.length; i++) { - var span = spans[i]; - if (!(span.to != null && lineNo == from.line && from.ch >= span.to || - span.from == null && lineNo != from.line || - span.from != null && lineNo == to.line && span.from >= to.ch) && - (!filter || filter(span.marker))) - found.push(span.marker.parent || span.marker); - } - ++lineNo; - }); - return found; - }, - getAllMarks: function () { - var markers = []; - this.iter(function (line) { - var sps = line.markedSpans; - if (sps) for (var i = 0; i < sps.length; ++i) - if (sps[i].from != null) markers.push(sps[i].marker); - }); - return markers; - }, - - posFromIndex: function (off) { - var ch, lineNo = this.first, sepSize = this.lineSeparator().length; - this.iter(function (line) { - var sz = line.text.length + sepSize; - if (sz > off) { ch = off; return true; } - off -= sz; - ++lineNo; - }); - return clipPos(this, Pos(lineNo, ch)); - }, - indexFromPos: function (coords) { - coords = clipPos(this, coords); - var index = coords.ch; - if (coords.line < this.first || coords.ch < 0) return 0; - var sepSize = this.lineSeparator().length; - this.iter(this.first, coords.line, function (line) { - index += line.text.length + sepSize; - }); - return index; - }, - - copy: function (copyHistory) { - var doc = new Doc(getLines(this, this.first, this.first + this.size), - this.modeOption, this.first, this.lineSep); - doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; - doc.sel = this.sel; - doc.extend = false; - if (copyHistory) { - doc.history.undoDepth = this.history.undoDepth; - doc.setHistory(this.getHistory()); - } - return doc; - }, - - linkedDoc: function (options) { - if (!options) options = {}; - var from = this.first, to = this.first + this.size; - if (options.from != null && options.from > from) from = options.from; - if (options.to != null && options.to < to) to = options.to; - var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep); - if (options.sharedHist) copy.history = this.history; - (this.linked || (this.linked = [])).push({ doc: copy, sharedHist: options.sharedHist }); - copy.linked = [{ doc: this, isParent: true, sharedHist: options.sharedHist }]; - copySharedMarkers(copy, findSharedMarkers(this)); - return copy; - }, - unlinkDoc: function (other) { - if (other instanceof CodeMirror) other = other.doc; - if (this.linked) for (var i = 0; i < this.linked.length; ++i) { - var link = this.linked[i]; - if (link.doc != other) continue; - this.linked.splice(i, 1); - other.unlinkDoc(this); - detachSharedMarkers(findSharedMarkers(this)); - break; - } - // If the histories were shared, split them again - if (other.history == this.history) { - var splitIds = [other.id]; - linkedDocs(other, function (doc) { splitIds.push(doc.id); }, true); - other.history = new History(null); - other.history.done = copyHistoryArray(this.history.done, splitIds); - other.history.undone = copyHistoryArray(this.history.undone, splitIds); - } - }, - iterLinkedDocs: function (f) { linkedDocs(this, f); }, - - getMode: function () { return this.mode; }, - getEditor: function () { return this.cm; }, - - splitLines: function (str) { - if (this.lineSep) return str.split(this.lineSep); - return splitLinesAuto(str); - }, - lineSeparator: function () { return this.lineSep || "\n"; } - }); - - // Public alias. - Doc.prototype.eachLine = Doc.prototype.iter; - - // Set up methods on CodeMirror's prototype to redirect to the editor's document. - var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); - for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) - CodeMirror.prototype[prop] = (function (method) { - return function () { return method.apply(this.doc, arguments); }; - })(Doc.prototype[prop]); - - eventMixin(Doc); - - // Call f for all linked documents. - function linkedDocs(doc, f, sharedHistOnly) { - function propagate(doc, skip, sharedHist) { - if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { - var rel = doc.linked[i]; - if (rel.doc == skip) continue; - var shared = sharedHist && rel.sharedHist; - if (sharedHistOnly && !shared) continue; - f(rel.doc, shared); - propagate(rel.doc, doc, shared); - } - } - propagate(doc, null, true); - } - - // Attach a document to an editor. - function attachDoc(cm, doc) { - if (doc.cm) throw new Error("This document is already in use."); - cm.doc = doc; - doc.cm = cm; - estimateLineHeights(cm); - loadMode(cm); - if (!cm.options.lineWrapping) findMaxLine(cm); - cm.options.mode = doc.modeOption; - regChange(cm); - } - - // LINE UTILITIES - - // Find the line object corresponding to the given line number. - function getLine(doc, n) { - n -= doc.first; - if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); - for (var chunk = doc; !chunk.lines;) { - for (var i = 0; ; ++i) { - var child = chunk.children[i], sz = child.chunkSize(); - if (n < sz) { chunk = child; break; } - n -= sz; - } - } - return chunk.lines[n]; - } - - // Get the part of a document between two positions, as an array of - // strings. - function getBetween(doc, start, end) { - var out = [], n = start.line; - doc.iter(start.line, end.line + 1, function (line) { - var text = line.text; - if (n == end.line) text = text.slice(0, end.ch); - if (n == start.line) text = text.slice(start.ch); - out.push(text); - ++n; - }); - return out; - } - // Get the lines between from and to, as array of strings. - function getLines(doc, from, to) { - var out = []; - doc.iter(from, to, function (line) { out.push(line.text); }); - return out; - } - - // Update the height of a line, propagating the height change - // upwards to parent nodes. - function updateLineHeight(line, height) { - var diff = height - line.height; - if (diff) for (var n = line; n; n = n.parent) n.height += diff; - } - - // Given a line object, find its line number by walking up through - // its parent links. - function lineNo(line) { - if (line.parent == null) return null; - var cur = line.parent, no = indexOf(cur.lines, line); - for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { - for (var i = 0; ; ++i) { - if (chunk.children[i] == cur) break; - no += chunk.children[i].chunkSize(); - } - } - return no + cur.first; - } - - // Find the line at the given vertical position, using the height - // information in the document tree. - function lineAtHeight(chunk, h) { - var n = chunk.first; - outer: do { - for (var i = 0; i < chunk.children.length; ++i) { - var child = chunk.children[i], ch = child.height; - if (h < ch) { chunk = child; continue outer; } - h -= ch; - n += child.chunkSize(); - } - return n; - } while (!chunk.lines); - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i], lh = line.height; - if (h < lh) break; - h -= lh; - } - return n + i; - } - - - // Find the height above the given line. - function heightAtLine(lineObj) { - lineObj = visualLine(lineObj); - - var h = 0, chunk = lineObj.parent; - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i]; - if (line == lineObj) break; - else h += line.height; - } - for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { - for (var i = 0; i < p.children.length; ++i) { - var cur = p.children[i]; - if (cur == chunk) break; - else h += cur.height; - } - } - return h; - } - - // Get the bidi ordering for the given line (and cache it). Returns - // false for lines that are fully left-to-right, and an array of - // BidiSpan objects otherwise. - function getOrder(line) { - var order = line.order; - if (order == null) order = line.order = bidiOrdering(line.text); - return order; - } - - // HISTORY - - function History(startGen) { - // Arrays of change events and selections. Doing something adds an - // event to done and clears undo. Undoing moves events from done - // to undone, redoing moves them in the other direction. - this.done = []; this.undone = []; - this.undoDepth = Infinity; - // Used to track when changes can be merged into a single undo - // event - this.lastModTime = this.lastSelTime = 0; - this.lastOp = this.lastSelOp = null; - this.lastOrigin = this.lastSelOrigin = null; - // Used by the isClean() method - this.generation = this.maxGeneration = startGen || 1; - } - - // Create a history change event from an updateDoc-style change - // object. - function historyChangeFromChange(doc, change) { - var histChange = { from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to) }; - attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); - linkedDocs(doc, function (doc) { attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true); - return histChange; - } - - // Pop all selection events off the end of a history array. Stop at - // a change event. - function clearSelectionEvents(array) { - while (array.length) { - var last = lst(array); - if (last.ranges) array.pop(); - else break; - } - } - - // Find the top change event in the history. Pop off selection - // events that are in the way. - function lastChangeEvent(hist, force) { - if (force) { - clearSelectionEvents(hist.done); - return lst(hist.done); - } else if (hist.done.length && !lst(hist.done).ranges) { - return lst(hist.done); - } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { - hist.done.pop(); - return lst(hist.done); - } - } - - // Register a change in the history. Merges changes that are within - // a single operation, ore are close together with an origin that - // allows merging (starting with "+") into a single event. - function addChangeToHistory(doc, change, selAfter, opId) { - var hist = doc.history; - hist.undone.length = 0; - var time = +new Date, cur; - - if ((hist.lastOp == opId || - hist.lastOrigin == change.origin && change.origin && - ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || - change.origin.charAt(0) == "*")) && - (cur = lastChangeEvent(hist, hist.lastOp == opId))) { - // Merge this change into the last event - var last = lst(cur.changes); - if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { - // Optimized case for simple insertion -- don't want to add - // new changesets for every character typed - last.to = changeEnd(change); - } else { - // Add new sub-event - cur.changes.push(historyChangeFromChange(doc, change)); - } - } else { - // Can not be merged, start a new event. - var before = lst(hist.done); - if (!before || !before.ranges) - pushSelectionToHistory(doc.sel, hist.done); - cur = { - changes: [historyChangeFromChange(doc, change)], - generation: hist.generation - }; - hist.done.push(cur); - while (hist.done.length > hist.undoDepth) { - hist.done.shift(); - if (!hist.done[0].ranges) hist.done.shift(); - } - } - hist.done.push(selAfter); - hist.generation = ++hist.maxGeneration; - hist.lastModTime = hist.lastSelTime = time; - hist.lastOp = hist.lastSelOp = opId; - hist.lastOrigin = hist.lastSelOrigin = change.origin; - - if (!last) signal(doc, "historyAdded"); - } - - function selectionEventCanBeMerged(doc, origin, prev, sel) { - var ch = origin.charAt(0); - return ch == "*" || - ch == "+" && - prev.ranges.length == sel.ranges.length && - prev.somethingSelected() == sel.somethingSelected() && - new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); - } - - // Called whenever the selection changes, sets the new selection as - // the pending selection in the history, and pushes the old pending - // selection into the 'done' array when it was significantly - // different (in number of selected ranges, emptiness, or time). - function addSelectionToHistory(doc, sel, opId, options) { - var hist = doc.history, origin = options && options.origin; - - // A new event is started when the previous origin does not match - // the current, or the origins don't allow matching. Origins - // starting with * are always merged, those starting with + are - // merged when similar and close together in time. - if (opId == hist.lastSelOp || - (origin && hist.lastSelOrigin == origin && - (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || - selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) - hist.done[hist.done.length - 1] = sel; - else - pushSelectionToHistory(sel, hist.done); - - hist.lastSelTime = +new Date; - hist.lastSelOrigin = origin; - hist.lastSelOp = opId; - if (options && options.clearRedo !== false) - clearSelectionEvents(hist.undone); - } - - function pushSelectionToHistory(sel, dest) { - var top = lst(dest); - if (!(top && top.ranges && top.equals(sel))) - dest.push(sel); - } - - // Used to store marked span information in the history. - function attachLocalSpans(doc, change, from, to) { - var existing = change["spans_" + doc.id], n = 0; - doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) { - if (line.markedSpans) - (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; - ++n; - }); - } - - // When un/re-doing restores text containing marked spans, those - // that have been explicitly cleared should not be restored. - function removeClearedSpans(spans) { - if (!spans) return null; - for (var i = 0, out; i < spans.length; ++i) { - if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } - else if (out) out.push(spans[i]); - } - return !out ? spans : out.length ? out : null; - } - - // Retrieve and filter the old marked spans stored in a change event. - function getOldSpans(doc, change) { - var found = change["spans_" + doc.id]; - if (!found) return null; - for (var i = 0, nw = []; i < change.text.length; ++i) - nw.push(removeClearedSpans(found[i])); - return nw; - } - - // Used both to provide a JSON-safe object in .getHistory, and, when - // detaching a document, to split the history in two - function copyHistoryArray(events, newGroup, instantiateSel) { - for (var i = 0, copy = []; i < events.length; ++i) { - var event = events[i]; - if (event.ranges) { - copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); - continue; - } - var changes = event.changes, newChanges = []; - copy.push({ changes: newChanges }); - for (var j = 0; j < changes.length; ++j) { - var change = changes[j], m; - newChanges.push({ from: change.from, to: change.to, text: change.text }); - if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { - if (indexOf(newGroup, Number(m[1])) > -1) { - lst(newChanges)[prop] = change[prop]; - delete change[prop]; - } - } - } - } - return copy; - } - - // Rebasing/resetting history to deal with externally-sourced changes - - function rebaseHistSelSingle(pos, from, to, diff) { - if (to < pos.line) { - pos.line += diff; - } else if (from < pos.line) { - pos.line = from; - pos.ch = 0; - } - } - - // Tries to rebase an array of history events given a change in the - // document. If the change touches the same lines as the event, the - // event, and everything 'behind' it, is discarded. If the change is - // before the event, the event's positions are updated. Uses a - // copy-on-write scheme for the positions, to avoid having to - // reallocate them all on every rebase, but also avoid problems with - // shared position objects being unsafely updated. - function rebaseHistArray(array, from, to, diff) { - for (var i = 0; i < array.length; ++i) { - var sub = array[i], ok = true; - if (sub.ranges) { - if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } - for (var j = 0; j < sub.ranges.length; j++) { - rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); - rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); - } - continue; - } - for (var j = 0; j < sub.changes.length; ++j) { - var cur = sub.changes[j]; - if (to < cur.from.line) { - cur.from = Pos(cur.from.line + diff, cur.from.ch); - cur.to = Pos(cur.to.line + diff, cur.to.ch); - } else if (from <= cur.to.line) { - ok = false; - break; - } - } - if (!ok) { - array.splice(0, i + 1); - i = 0; - } - } - } - - function rebaseHist(hist, change) { - var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; - rebaseHistArray(hist.done, from, to, diff); - rebaseHistArray(hist.undone, from, to, diff); - } - - // EVENT UTILITIES - - // Due to the fact that we still support jurassic IE versions, some - // compatibility wrappers are needed. - - var e_preventDefault = CodeMirror.e_preventDefault = function (e) { - if (e.preventDefault) e.preventDefault(); - else e.returnValue = false; - }; - var e_stopPropagation = CodeMirror.e_stopPropagation = function (e) { - if (e.stopPropagation) e.stopPropagation(); - else e.cancelBubble = true; - }; - function e_defaultPrevented(e) { - return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; - } - var e_stop = CodeMirror.e_stop = function (e) { e_preventDefault(e); e_stopPropagation(e); }; - - function e_target(e) { return e.target || e.srcElement; } - function e_button(e) { - var b = e.which; - if (b == null) { - if (e.button & 1) b = 1; - else if (e.button & 2) b = 3; - else if (e.button & 4) b = 2; - } - if (mac && e.ctrlKey && b == 1) b = 3; - return b; - } - - // EVENT HANDLING - - // Lightweight event framework. on/off also work on DOM nodes, - // registering native DOM handlers. - - var on = CodeMirror.on = function (emitter, type, f) { - if (emitter.addEventListener) - emitter.addEventListener(type, f, false); - else if (emitter.attachEvent) - emitter.attachEvent("on" + type, f); - else { - var map = emitter._handlers || (emitter._handlers = {}); - var arr = map[type] || (map[type] = []); - arr.push(f); - } - }; - - var noHandlers = [] - function getHandlers(emitter, type, copy) { - var arr = emitter._handlers && emitter._handlers[type] - if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers - else return arr || noHandlers - } - - var off = CodeMirror.off = function (emitter, type, f) { - if (emitter.removeEventListener) - emitter.removeEventListener(type, f, false); - else if (emitter.detachEvent) - emitter.detachEvent("on" + type, f); - else { - var handlers = getHandlers(emitter, type, false) - for (var i = 0; i < handlers.length; ++i) - if (handlers[i] == f) { handlers.splice(i, 1); break; } - } - }; - - var signal = CodeMirror.signal = function (emitter, type /*, values...*/) { - var handlers = getHandlers(emitter, type, true) - if (!handlers.length) return; - var args = Array.prototype.slice.call(arguments, 2); - for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args); - }; - - var orphanDelayedCallbacks = null; - - // Often, we want to signal events at a point where we are in the - // middle of some work, but don't want the handler to start calling - // other methods on the editor, which might be in an inconsistent - // state or simply not expect any other events to happen. - // signalLater looks whether there are any handlers, and schedules - // them to be executed when the last operation ends, or, if no - // operation is active, when a timeout fires. - function signalLater(emitter, type /*, values...*/) { - var arr = getHandlers(emitter, type, false) - if (!arr.length) return; - var args = Array.prototype.slice.call(arguments, 2), list; - if (operationGroup) { - list = operationGroup.delayedCallbacks; - } else if (orphanDelayedCallbacks) { - list = orphanDelayedCallbacks; - } else { - list = orphanDelayedCallbacks = []; - setTimeout(fireOrphanDelayed, 0); - } - function bnd(f) { return function () { f.apply(null, args); }; }; - for (var i = 0; i < arr.length; ++i) - list.push(bnd(arr[i])); - } - - function fireOrphanDelayed() { - var delayed = orphanDelayedCallbacks; - orphanDelayedCallbacks = null; - for (var i = 0; i < delayed.length; ++i) delayed[i](); - } - - // The DOM events that CodeMirror handles can be overridden by - // registering a (non-DOM) handler on the editor for the event name, - // and preventDefault-ing the event in that handler. - function signalDOMEvent(cm, e, override) { - if (typeof e == "string") - e = { type: e, preventDefault: function () { this.defaultPrevented = true; } }; - signal(cm, override || e.type, cm, e); - return e_defaultPrevented(e) || e.codemirrorIgnore; - } - - function signalCursorActivity(cm) { - var arr = cm._handlers && cm._handlers.cursorActivity; - if (!arr) return; - var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); - for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) - set.push(arr[i]); - } - - function hasHandler(emitter, type) { - return getHandlers(emitter, type).length > 0 - } - - // Add on and off methods to a constructor's prototype, to make - // registering events on such objects more convenient. - function eventMixin(ctor) { - ctor.prototype.on = function (type, f) { on(this, type, f); }; - ctor.prototype.off = function (type, f) { off(this, type, f); }; - } - - // MISC UTILITIES - - // Number of pixels added to scroller and sizer to hide scrollbar - var scrollerGap = 30; - - // Returned or thrown by various protocols to signal 'I'm not - // handling this'. - var Pass = CodeMirror.Pass = { toString: function () { return "CodeMirror.Pass"; } }; - - // Reused option objects for setSelection & friends - var sel_dontScroll = { scroll: false }, sel_mouse = { origin: "*mouse" }, sel_move = { origin: "+move" }; - - function Delayed() { this.id = null; } - Delayed.prototype.set = function (ms, f) { - clearTimeout(this.id); - this.id = setTimeout(f, ms); - }; - - // Counts the column offset in a string, taking tabs into account. - // Used mostly to find indentation. - var countColumn = CodeMirror.countColumn = function (string, end, tabSize, startIndex, startValue) { - if (end == null) { - end = string.search(/[^\s\u00a0]/); - if (end == -1) end = string.length; - } - for (var i = startIndex || 0, n = startValue || 0; ;) { - var nextTab = string.indexOf("\t", i); - if (nextTab < 0 || nextTab >= end) - return n + (end - i); - n += nextTab - i; - n += tabSize - (n % tabSize); - i = nextTab + 1; - } - }; - - // The inverse of countColumn -- find the offset that corresponds to - // a particular column. - var findColumn = CodeMirror.findColumn = function (string, goal, tabSize) { - for (var pos = 0, col = 0; ;) { - var nextTab = string.indexOf("\t", pos); - if (nextTab == -1) nextTab = string.length; - var skipped = nextTab - pos; - if (nextTab == string.length || col + skipped >= goal) - return pos + Math.min(skipped, goal - col); - col += nextTab - pos; - col += tabSize - (col % tabSize); - pos = nextTab + 1; - if (col >= goal) return pos; - } - } - - var spaceStrs = [""]; - function spaceStr(n) { - while (spaceStrs.length <= n) - spaceStrs.push(lst(spaceStrs) + " "); - return spaceStrs[n]; - } - - function lst(arr) { return arr[arr.length - 1]; } - - var selectInput = function (node) { node.select(); }; - if (ios) // Mobile Safari apparently has a bug where select() is broken. - selectInput = function (node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; - else if (ie) // Suppress mysterious IE10 errors - selectInput = function (node) { try { node.select(); } catch (_e) { } }; - - function indexOf(array, elt) { - for (var i = 0; i < array.length; ++i) - if (array[i] == elt) return i; - return -1; - } - function map(array, f) { - var out = []; - for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); - return out; - } - - function nothing() { } - - function createObj(base, props) { - var inst; - if (Object.create) { - inst = Object.create(base); - } else { - nothing.prototype = base; - inst = new nothing(); - } - if (props) copyObj(props, inst); - return inst; - }; - - function copyObj(obj, target, overwrite) { - if (!target) target = {}; - for (var prop in obj) - if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) - target[prop] = obj[prop]; - return target; - } - - function bind(f) { - var args = Array.prototype.slice.call(arguments, 1); - return function () { return f.apply(null, args); }; - } - - var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; - var isWordCharBasic = CodeMirror.isWordChar = function (ch) { - return /\w/.test(ch) || ch > "\x80" && - (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); - }; - function isWordChar(ch, helper) { - if (!helper) return isWordCharBasic(ch); - if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; - return helper.test(ch); - } - - function isEmpty(obj) { - for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; - return true; - } - - // Extending unicode characters. A series of a non-extending char + - // any number of extending chars is treated as a single unit as far - // as editing and measuring is concerned. This is not fully correct, - // since some scripts/fonts/browsers also treat other configurations - // of code points as a group. - var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; - function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } - - // DOM UTILITIES - - function elt(tag, content, className, style) { - var e = document.createElement(tag); - if (className) e.className = className; - if (style) e.style.cssText = style; - if (typeof content == "string") e.appendChild(document.createTextNode(content)); - else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); - return e; - } - - var range; - if (document.createRange) range = function (node, start, end, endNode) { - var r = document.createRange(); - r.setEnd(endNode || node, end); - r.setStart(node, start); - return r; - }; - else range = function (node, start, end) { - var r = document.body.createTextRange(); - try { r.moveToElementText(node.parentNode); } - catch (e) { return r; } - r.collapse(true); - r.moveEnd("character", end); - r.moveStart("character", start); - return r; - }; - - function removeChildren(e) { - for (var count = e.childNodes.length; count > 0; --count) - e.removeChild(e.firstChild); - return e; - } - - function removeChildrenAndAdd(parent, e) { - return removeChildren(parent).appendChild(e); - } - - var contains = CodeMirror.contains = function (parent, child) { - if (child.nodeType == 3) // Android browser always returns false when child is a textnode - child = child.parentNode; - if (parent.contains) - return parent.contains(child); - do { - if (child.nodeType == 11) child = child.host; - if (child == parent) return true; - } while (child = child.parentNode); - }; - - function activeElt() { - var activeElement = document.activeElement; - while (activeElement && activeElement.root && activeElement.root.activeElement) - activeElement = activeElement.root.activeElement; - return activeElement; - } - // Older versions of IE throws unspecified error when touching - // document.activeElement in some cases (during loading, in iframe) - if (ie && ie_version < 11) activeElt = function () { - try { return document.activeElement; } - catch (e) { return document.body; } - }; - - function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } - var rmClass = CodeMirror.rmClass = function (node, cls) { - var current = node.className; - var match = classTest(cls).exec(current); - if (match) { - var after = current.slice(match.index + match[0].length); - node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); - } - }; - var addClass = CodeMirror.addClass = function (node, cls) { - var current = node.className; - if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; - }; - function joinClasses(a, b) { - var as = a.split(" "); - for (var i = 0; i < as.length; i++) - if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; - return b; - } - - // WINDOW-WIDE EVENTS - - // These must be handled carefully, because naively registering a - // handler for each editor will cause the editors to never be - // garbage collected. - - function forEachCodeMirror(f) { - if (!document.body.getElementsByClassName) return; - var byClass = document.body.getElementsByClassName("CodeMirror"); - for (var i = 0; i < byClass.length; i++) { - var cm = byClass[i].CodeMirror; - if (cm) f(cm); - } - } - - var globalsRegistered = false; - function ensureGlobalHandlers() { - if (globalsRegistered) return; - registerGlobalHandlers(); - globalsRegistered = true; - } - function registerGlobalHandlers() { - // When the window resizes, we need to refresh active editors. - var resizeTimer; - on(window, "resize", function () { - if (resizeTimer == null) resizeTimer = setTimeout(function () { - resizeTimer = null; - forEachCodeMirror(onResize); - }, 100); - }); - // When the window loses focus, we want to show the editor as blurred - on(window, "blur", function () { - forEachCodeMirror(onBlur); - }); - } - - // FEATURE DETECTION - - // Detect drag-and-drop - var dragAndDrop = function () { - // There is *some* kind of drag-and-drop support in IE6-8, but I - // couldn't get it to work yet. - if (ie && ie_version < 9) return false; - var div = elt('div'); - return "draggable" in div || "dragDrop" in div; - }(); - - var zwspSupported; - function zeroWidthElement(measure) { - if (zwspSupported == null) { - var test = elt("span", "\u200b"); - removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); - if (measure.firstChild.offsetHeight != 0) - zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); - } - var node = zwspSupported ? elt("span", "\u200b") : - elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); - node.setAttribute("cm-text", ""); - return node; - } - - // Feature-detect IE's crummy client rect reporting for bidi text - var badBidiRects; - function hasBadBidiRects(measure) { - if (badBidiRects != null) return badBidiRects; - var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); - var r0 = range(txt, 0, 1).getBoundingClientRect(); - var r1 = range(txt, 1, 2).getBoundingClientRect(); - removeChildren(measure); - if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) - return badBidiRects = (r1.right - r0.right < 3); - } - - // See if "".split is the broken IE version, if so, provide an - // alternative way to split lines. - var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function (string) { - var pos = 0, result = [], l = string.length; - while (pos <= l) { - var nl = string.indexOf("\n", pos); - if (nl == -1) nl = string.length; - var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); - var rt = line.indexOf("\r"); - if (rt != -1) { - result.push(line.slice(0, rt)); - pos += rt + 1; - } else { - result.push(line); - pos = nl + 1; - } - } - return result; - } : function (string) { return string.split(/\r\n?|\n/); }; - - var hasSelection = window.getSelection ? function (te) { - try { return te.selectionStart != te.selectionEnd; } - catch (e) { return false; } - } : function (te) { - try { var range = te.ownerDocument.selection.createRange(); } - catch (e) { } - if (!range || range.parentElement() != te) return false; - return range.compareEndPoints("StartToEnd", range) != 0; - }; - - var hasCopyEvent = (function () { - var e = elt("div"); - if ("oncopy" in e) return true; - e.setAttribute("oncopy", "return;"); - return typeof e.oncopy == "function"; - })(); - - var badZoomedRects = null; - function hasBadZoomedRects(measure) { - if (badZoomedRects != null) return badZoomedRects; - var node = removeChildrenAndAdd(measure, elt("span", "x")); - var normal = node.getBoundingClientRect(); - var fromRange = range(node, 0, 1).getBoundingClientRect(); - return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; - } - - // KEY NAMES - - var keyNames = CodeMirror.keyNames = { - 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", - 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", - 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", - 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", - 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", - 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", - 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", - 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" - }; - (function () { - // Number keys - for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); - // Alphabetic keys - for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); - // Function keys - for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; - })(); - - // BIDI HELPERS - - function iterateBidiSections(order, from, to, f) { - if (!order) return f(from, to, "ltr"); - var found = false; - for (var i = 0; i < order.length; ++i) { - var part = order[i]; - if (part.from < to && part.to > from || from == to && part.to == from) { - f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); - found = true; - } - } - if (!found) f(from, to, "ltr"); - } - - function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } - function bidiRight(part) { return part.level % 2 ? part.from : part.to; } - - function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } - function lineRight(line) { - var order = getOrder(line); - if (!order) return line.text.length; - return bidiRight(lst(order)); - } - - function lineStart(cm, lineN) { - var line = getLine(cm.doc, lineN); - var visual = visualLine(line); - if (visual != line) lineN = lineNo(visual); - var order = getOrder(visual); - var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); - return Pos(lineN, ch); - } - function lineEnd(cm, lineN) { - var merged, line = getLine(cm.doc, lineN); - while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line; - lineN = null; - } - var order = getOrder(line); - var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); - return Pos(lineN == null ? lineNo(line) : lineN, ch); - } - function lineStartSmart(cm, pos) { - var start = lineStart(cm, pos.line); - var line = getLine(cm.doc, start.line); - var order = getOrder(line); - if (!order || order[0].level == 0) { - var firstNonWS = Math.max(0, line.text.search(/\S/)); - var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; - return Pos(start.line, inWS ? 0 : firstNonWS); - } - return start; - } - - function compareBidiLevel(order, a, b) { - var linedir = order[0].level; - if (a == linedir) return true; - if (b == linedir) return false; - return a < b; - } - var bidiOther; - function getBidiPartAt(order, pos) { - bidiOther = null; - for (var i = 0, found; i < order.length; ++i) { - var cur = order[i]; - if (cur.from < pos && cur.to > pos) return i; - if ((cur.from == pos || cur.to == pos)) { - if (found == null) { - found = i; - } else if (compareBidiLevel(order, cur.level, order[found].level)) { - if (cur.from != cur.to) bidiOther = found; - return i; - } else { - if (cur.from != cur.to) bidiOther = i; - return found; - } - } - } - return found; - } - - function moveInLine(line, pos, dir, byUnit) { - if (!byUnit) return pos + dir; - do pos += dir; - while (pos > 0 && isExtendingChar(line.text.charAt(pos))); - return pos; - } - - // This is needed in order to move 'visually' through bi-directional - // text -- i.e., pressing left should make the cursor go left, even - // when in RTL text. The tricky part is the 'jumps', where RTL and - // LTR text touch each other. This often requires the cursor offset - // to move more than one unit, in order to visually move one unit. - function moveVisually(line, start, dir, byUnit) { - var bidi = getOrder(line); - if (!bidi) return moveLogically(line, start, dir, byUnit); - var pos = getBidiPartAt(bidi, start), part = bidi[pos]; - var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); - - for (; ;) { - if (target > part.from && target < part.to) return target; - if (target == part.from || target == part.to) { - if (getBidiPartAt(bidi, target) == pos) return target; - part = bidi[pos += dir]; - return (dir > 0) == part.level % 2 ? part.to : part.from; - } else { - part = bidi[pos += dir]; - if (!part) return null; - if ((dir > 0) == part.level % 2) - target = moveInLine(line, part.to, -1, byUnit); - else - target = moveInLine(line, part.from, 1, byUnit); - } - } - } - - function moveLogically(line, start, dir, byUnit) { - var target = start + dir; - if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; - return target < 0 || target > line.text.length ? null : target; - } - - // Bidirectional ordering algorithm - // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm - // that this (partially) implements. - - // One-char codes used for character types: - // L (L): Left-to-Right - // R (R): Right-to-Left - // r (AL): Right-to-Left Arabic - // 1 (EN): European Number - // + (ES): European Number Separator - // % (ET): European Number Terminator - // n (AN): Arabic Number - // , (CS): Common Number Separator - // m (NSM): Non-Spacing Mark - // b (BN): Boundary Neutral - // s (B): Paragraph Separator - // t (S): Segment Separator - // w (WS): Whitespace - // N (ON): Other Neutrals - - // Returns null if characters are ordered as they appear - // (left-to-right), or an array of sections ({from, to, level} - // objects) in the order in which they occur visually. - var bidiOrdering = (function () { - // Character types for codepoints 0 to 0xff - var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; - // Character types for codepoints 0x600 to 0x6ff - var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; - function charType(code) { - if (code <= 0xf7) return lowTypes.charAt(code); - else if (0x590 <= code && code <= 0x5f4) return "R"; - else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); - else if (0x6ee <= code && code <= 0x8ac) return "r"; - else if (0x2000 <= code && code <= 0x200b) return "w"; - else if (code == 0x200c) return "b"; - else return "L"; - } - - var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; - var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; - // Browsers seem to always treat the boundaries of block elements as being L. - var outerType = "L"; - - function BidiSpan(level, from, to) { - this.level = level; - this.from = from; this.to = to; - } - - return function (str) { - if (!bidiRE.test(str)) return false; - var len = str.length, types = []; - for (var i = 0, type; i < len; ++i) - types.push(type = charType(str.charCodeAt(i))); - - // W1. Examine each non-spacing mark (NSM) in the level run, and - // change the type of the NSM to the type of the previous - // character. If the NSM is at the start of the level run, it will - // get the type of sor. - for (var i = 0, prev = outerType; i < len; ++i) { - var type = types[i]; - if (type == "m") types[i] = prev; - else prev = type; - } - - // W2. Search backwards from each instance of a European number - // until the first strong type (R, L, AL, or sor) is found. If an - // AL is found, change the type of the European number to Arabic - // number. - // W3. Change all ALs to R. - for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i]; - if (type == "1" && cur == "r") types[i] = "n"; - else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } - } - - // W4. A single European separator between two European numbers - // changes to a European number. A single common separator between - // two numbers of the same type changes to that type. - for (var i = 1, prev = types[0]; i < len - 1; ++i) { - var type = types[i]; - if (type == "+" && prev == "1" && types[i + 1] == "1") types[i] = "1"; - else if (type == "," && prev == types[i + 1] && - (prev == "1" || prev == "n")) types[i] = prev; - prev = type; - } - - // W5. A sequence of European terminators adjacent to European - // numbers changes to all European numbers. - // W6. Otherwise, separators and terminators change to Other - // Neutral. - for (var i = 0; i < len; ++i) { - var type = types[i]; - if (type == ",") types[i] = "N"; - else if (type == "%") { - for (var end = i + 1; end < len && types[end] == "%"; ++end) { } - var replace = (i && types[i - 1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; - for (var j = i; j < end; ++j) types[j] = replace; - i = end - 1; - } - } - - // W7. Search backwards from each instance of a European number - // until the first strong type (R, L, or sor) is found. If an L is - // found, then change the type of the European number to L. - for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i]; - if (cur == "L" && type == "1") types[i] = "L"; - else if (isStrong.test(type)) cur = type; - } - - // N1. A sequence of neutrals takes the direction of the - // surrounding strong text if the text on both sides has the same - // direction. European and Arabic numbers act as if they were R in - // terms of their influence on neutrals. Start-of-level-run (sor) - // and end-of-level-run (eor) are used at level run boundaries. - // N2. Any remaining neutrals take the embedding direction. - for (var i = 0; i < len; ++i) { - if (isNeutral.test(types[i])) { - for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) { } - var before = (i ? types[i - 1] : outerType) == "L"; - var after = (end < len ? types[end] : outerType) == "L"; - var replace = before || after ? "L" : "R"; - for (var j = i; j < end; ++j) types[j] = replace; - i = end - 1; - } - } - - // Here we depart from the documented algorithm, in order to avoid - // building up an actual levels array. Since there are only three - // levels (0, 1, 2) in an implementation that doesn't take - // explicit embedding into account, we can build up the order on - // the fly, without following the level-based algorithm. - var order = [], m; - for (var i = 0; i < len;) { - if (countsAsLeft.test(types[i])) { - var start = i; - for (++i; i < len && countsAsLeft.test(types[i]); ++i) { } - order.push(new BidiSpan(0, start, i)); - } else { - var pos = i, at = order.length; - for (++i; i < len && types[i] != "L"; ++i) { } - for (var j = pos; j < i;) { - if (countsAsNum.test(types[j])) { - if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); - var nstart = j; - for (++j; j < i && countsAsNum.test(types[j]); ++j) { } - order.splice(at, 0, new BidiSpan(2, nstart, j)); - pos = j; - } else ++j; - } - if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); - } - } - if (order[0].level == 1 && (m = str.match(/^\s+/))) { - order[0].from = m[0].length; - order.unshift(new BidiSpan(0, 0, m[0].length)); - } - if (lst(order).level == 1 && (m = str.match(/\s+$/))) { - lst(order).to -= m[0].length; - order.push(new BidiSpan(0, len - m[0].length, len)); - } - if (order[0].level == 2) - order.unshift(new BidiSpan(1, order[0].to, order[0].to)); - if (order[0].level != lst(order).level) - order.push(new BidiSpan(order[0].level, len, len)); - - return order; - }; - })(); - - // THE END - - CodeMirror.version = "5.17.0"; - - return CodeMirror; -})(); - -// @ts-ignore -window.CodeMirror = CodeMirror; - -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - -// TODO actually recognize syntax of TypeScript constructs - -(function () { - "use strict"; - - function expressionAllowed(stream, state, backUp) { - return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) || - (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) - } - - CodeMirror.defineMode("javascript", function (config, parserConfig) { - var indentUnit = config.indentUnit; - var statementIndent = parserConfig.statementIndent; - var jsonldMode = parserConfig.jsonld; - var jsonMode = parserConfig.json || jsonldMode; - var isTS = parserConfig.typescript; - var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; - - // Tokenizer - - var keywords = function () { - function kw(type) { return { type: type, style: "keyword" }; } - var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); - var operator = kw("operator"), atom = { type: "atom", style: "atom" }; - - var jsKeywords = { - "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, - "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C, - "var": kw("var"), "const": kw("var"), "let": kw("var"), - "function": kw("function"), "catch": kw("catch"), - "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), - "in": operator, "typeof": operator, "instanceof": operator, - "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, - "this": kw("this"), "class": kw("class"), "super": kw("atom"), - "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, - "await": C, "async": kw("async") - }; - - // Extend the 'normal' keywords with the TypeScript language extensions - if (isTS) { - var type = { type: "variable", style: "variable-3" }; - var tsKeywords = { - // object-like things - "interface": kw("class"), - "implements": C, - "namespace": C, - "module": kw("module"), - "enum": kw("module"), - - // scope modifiers - "public": kw("modifier"), - "private": kw("modifier"), - "protected": kw("modifier"), - "abstract": kw("modifier"), - - // operators - "as": operator, - - // types - "string": type, "number": type, "boolean": type, "any": type - }; - - for (var attr in tsKeywords) { - jsKeywords[attr] = tsKeywords[attr]; - } - } - - return jsKeywords; - }(); - - var isOperatorChar = /[+\-*&%=<>!?|~^]/; - var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; - - function readRegexp(stream) { - var escaped = false, next, inSet = false; - while ((next = stream.next()) != null) { - if (!escaped) { - if (next == "/" && !inSet) return; - if (next == "[") inSet = true; - else if (inSet && next == "]") inSet = false; - } - escaped = !escaped && next == "\\"; - } - } - - // Used as scratch variables to communicate multiple values without - // consing up tons of objects. - var type, content; - function ret(tp, style, cont) { - type = tp; content = cont; - return style; - } - function tokenBase(stream, state) { - var ch = stream.next(); - if (ch == '"' || ch == "'") { - state.tokenize = tokenString(ch); - return state.tokenize(stream, state); - } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { - return ret("number", "number"); - } else if (ch == "." && stream.match("..")) { - return ret("spread", "meta"); - } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { - return ret(ch); - } else if (ch == "=" && stream.eat(">")) { - return ret("=>", "operator"); - } else if (ch == "0" && stream.eat(/x/i)) { - stream.eatWhile(/[\da-f]/i); - return ret("number", "number"); - } else if (ch == "0" && stream.eat(/o/i)) { - stream.eatWhile(/[0-7]/i); - return ret("number", "number"); - } else if (ch == "0" && stream.eat(/b/i)) { - stream.eatWhile(/[01]/i); - return ret("number", "number"); - } else if (/\d/.test(ch)) { - stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); - return ret("number", "number"); - } else if (ch == "/") { - if (stream.eat("*")) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } else if (stream.eat("/")) { - stream.skipToEnd(); - return ret("comment", "comment"); - } else if (expressionAllowed(stream, state, 1)) { - readRegexp(stream); - stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); - return ret("regexp", "string-2"); - } else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator", stream.current()); - } - } else if (ch == "`") { - state.tokenize = tokenQuasi; - return tokenQuasi(stream, state); - } else if (ch == "#") { - stream.skipToEnd(); - return ret("error", "error"); - } else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator", stream.current()); - } else if (wordRE.test(ch)) { - stream.eatWhile(wordRE); - var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; - return (known && state.lastType != ".") ? ret(known.type, known.style, word) : - ret("variable", "variable", word); - } - } - - function tokenString(quote) { - return function (stream, state) { - var escaped = false, next; - if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)) { - state.tokenize = tokenBase; - return ret("jsonld-keyword", "meta"); - } - while ((next = stream.next()) != null) { - if (next == quote && !escaped) break; - escaped = !escaped && next == "\\"; - } - if (!escaped) state.tokenize = tokenBase; - return ret("string", "string"); - }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - function tokenQuasi(stream, state) { - var escaped = false, next; - while ((next = stream.next()) != null) { - if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && next == "\\"; - } - return ret("quasi", "string-2", stream.current()); - } - - var brackets = "([{}])"; - // This is a crude lookahead trick to try and notice that we're - // parsing the argument patterns for a fat-arrow function before we - // actually hit the arrow token. It only works if the arrow is on - // the same line as the arguments and there's no strange noise - // (comments) in between. Fallback is to only notice when we hit the - // arrow, and not declare the arguments as locals for the arrow - // body. - function findFatArrow(stream, state) { - if (state.fatArrowAt) state.fatArrowAt = null; - var arrow = stream.string.indexOf("=>", stream.start); - if (arrow < 0) return; - - var depth = 0, sawSomething = false; - for (var pos = arrow - 1; pos >= 0; --pos) { - var ch = stream.string.charAt(pos); - var bracket = brackets.indexOf(ch); - if (bracket >= 0 && bracket < 3) { - if (!depth) { ++pos; break; } - if (--depth == 0) break; - } else if (bracket >= 3 && bracket < 6) { - ++depth; - } else if (wordRE.test(ch)) { - sawSomething = true; - } else if (/["'\/]/.test(ch)) { - return; - } else if (sawSomething && !depth) { - ++pos; - break; - } - } - if (sawSomething && !depth) state.fatArrowAt = pos; - } - - // Parser - - var atomicTypes = { "atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true }; - - function JSLexical(indented, column, type, align, prev, info) { - this.indented = indented; - this.column = column; - this.type = type; - this.prev = prev; - this.info = info; - if (align != null) this.align = align; - } - - function inScope(state, varname) { - for (var v = state.localVars; v; v = v.next) - if (v.name == varname) return true; - for (var cx = state.context; cx; cx = cx.prev) { - for (var v = cx.vars; v; v = v.next) - if (v.name == varname) return true; - } - } - - function parseJS(state, style, type, content, stream) { - var cc = state.cc; - // Communicate our context to the combinators. - // (Less wasteful than consing up a hundred closures on every call.) - cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; - - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = true; - - while (true) { - var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; - if (combinator(type, content)) { - while (cc.length && cc[cc.length - 1].lex) - cc.pop()(); - if (cx.marked) return cx.marked; - if (type == "variable" && inScope(state, content)) return "variable-2"; - return style; - } - } - } - - // Combinator utils - - var cx = { state: null, column: null, marked: null, cc: null }; - function pass() { - for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); - } - function cont() { - pass.apply(null, arguments); - return true; - } - function register(varname) { - function inList(list) { - for (var v = list; v; v = v.next) - if (v.name == varname) return true; - return false; - } - var state = cx.state; - cx.marked = "def"; - if (state.context) { - if (inList(state.localVars)) return; - state.localVars = { name: varname, next: state.localVars }; - } else { - if (inList(state.globalVars)) return; - if (parserConfig.globalVars) - state.globalVars = { name: varname, next: state.globalVars }; - } - } - - // Combinators - - var defaultVars = { name: "this", next: { name: "arguments" } }; - function pushcontext() { - cx.state.context = { prev: cx.state.context, vars: cx.state.localVars }; - cx.state.localVars = defaultVars; - } - function popcontext() { - cx.state.localVars = cx.state.context.vars; - cx.state.context = cx.state.context.prev; - } - function pushlex(type, info) { - var result = function () { - var state = cx.state, indent = state.indented; - if (state.lexical.type == "stat") indent = state.lexical.indented; - else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) - indent = outer.indented; - state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); - }; - result.lex = true; - return result; - } - function poplex() { - var state = cx.state; - if (state.lexical.prev) { - if (state.lexical.type == ")") - state.indented = state.lexical.indented; - state.lexical = state.lexical.prev; - } - } - poplex.lex = true; - - function expect(wanted) { - function exp(type) { - if (type == wanted) return cont(); - else if (wanted == ";") return pass(); - else return cont(exp); - }; - return exp; - } - - function statement(type, value) { - if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); - if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); - if (type == "keyword b") return cont(pushlex("form"), statement, poplex); - if (type == "{") return cont(pushlex("}"), block, poplex); - if (type == ";") return cont(); - if (type == "if") { - if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) - cx.state.cc.pop()(); - return cont(pushlex("form"), expression, statement, poplex, maybeelse); - } - if (type == "function") return cont(functiondef); - if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); - if (type == "variable") return cont(pushlex("stat"), maybelabel); - if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), - block, poplex, poplex); - if (type == "case") return cont(expression, expect(":")); - if (type == "default") return cont(expect(":")); - if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), - statement, poplex, popcontext); - if (type == "class") return cont(pushlex("form"), className, poplex); - if (type == "export") return cont(pushlex("stat"), afterExport, poplex); - if (type == "import") return cont(pushlex("stat"), afterImport, poplex); - if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex) - if (type == "async") return cont(statement) - return pass(pushlex("stat"), expression, expect(";"), poplex); - } - function expression(type) { - return expressionInner(type, false); - } - function expressionNoComma(type) { - return expressionInner(type, true); - } - function expressionInner(type, noComma) { - if (cx.state.fatArrowAt == cx.stream.start) { - var body = noComma ? arrowBodyNoComma : arrowBody; - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); - else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); - } - - var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; - if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); - if (type == "function") return cont(functiondef, maybeop); - if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression); - if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); - if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); - if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); - if (type == "{") return contCommasep(objprop, "}", null, maybeop); - if (type == "quasi") return pass(quasi, maybeop); - if (type == "new") return cont(maybeTarget(noComma)); - return cont(); - } - function maybeexpression(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expression); - } - function maybeexpressionNoComma(type) { - if (type.match(/[;\}\)\],]/)) return pass(); - return pass(expressionNoComma); - } - - function maybeoperatorComma(type, value) { - if (type == ",") return cont(expression); - return maybeoperatorNoComma(type, value, false); - } - function maybeoperatorNoComma(type, value, noComma) { - var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; - var expr = noComma == false ? expression : expressionNoComma; - if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); - if (type == "operator") { - if (/\+\+|--/.test(value)) return cont(me); - if (value == "?") return cont(expression, expect(":"), expr); - return cont(expr); - } - if (type == "quasi") { return pass(quasi, me); } - if (type == ";") return; - if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); - if (type == ".") return cont(property, me); - if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); - } - function quasi(type, value) { - if (type != "quasi") return pass(); - if (value.slice(value.length - 2) != "${") return cont(quasi); - return cont(expression, continueQuasi); - } - function continueQuasi(type) { - if (type == "}") { - cx.marked = "string-2"; - cx.state.tokenize = tokenQuasi; - return cont(quasi); - } - } - function arrowBody(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expression); - } - function arrowBodyNoComma(type) { - findFatArrow(cx.stream, cx.state); - return pass(type == "{" ? statement : expressionNoComma); - } - function maybeTarget(noComma) { - return function (type) { - if (type == ".") return cont(noComma ? targetNoComma : target); - else return pass(noComma ? expressionNoComma : expression); - }; - } - function target(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); } - } - function targetNoComma(_, value) { - if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); } - } - function maybelabel(type) { - if (type == ":") return cont(poplex, statement); - return pass(maybeoperatorComma, expect(";"), poplex); - } - function property(type) { - if (type == "variable") { cx.marked = "property"; return cont(); } - } - function objprop(type, value) { - if (type == "async") return cont(objprop); - if (type == "variable" || cx.style == "keyword") { - cx.marked = "property"; - if (value == "get" || value == "set") return cont(getterSetter); - return cont(afterprop); - } else if (type == "number" || type == "string") { - cx.marked = jsonldMode ? "property" : (cx.style + " property"); - return cont(afterprop); - } else if (type == "jsonld-keyword") { - return cont(afterprop); - } else if (type == "modifier") { - return cont(objprop) - } else if (type == "[") { - return cont(expression, expect("]"), afterprop); - } else if (type == "spread") { - return cont(expression); - } - } - function getterSetter(type) { - if (type != "variable") return pass(afterprop); - cx.marked = "property"; - return cont(functiondef); - } - function afterprop(type) { - if (type == ":") return cont(expressionNoComma); - if (type == "(") return pass(functiondef); - } - function commasep(what, end) { - function proceed(type, value) { - if (type == ",") { - var lex = cx.state.lexical; - if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; - return cont(function (type, value) { - if (type == end || value == end) return pass() - return pass(what) - }, proceed); - } - if (type == end || value == end) return cont(); - return cont(expect(end)); - } - return function (type, value) { - if (type == end || value == end) return cont(); - return pass(what, proceed); - }; - } - function contCommasep(what, end, info) { - for (var i = 3; i < arguments.length; i++) - cx.cc.push(arguments[i]); - return cont(pushlex(end, info), commasep(what, end), poplex); - } - function block(type) { - if (type == "}") return cont(); - return pass(statement, block); - } - function maybetype(type) { - if (isTS && type == ":") return cont(typeexpr); - } - function maybedefault(_, value) { - if (value == "=") return cont(expressionNoComma); - } - function typeexpr(type) { - if (type == "variable") { cx.marked = "variable-3"; return cont(afterType); } - } - function afterType(type, value) { - if (value == "<") return cont(commasep(typeexpr, ">"), afterType) - if (type == "[") return cont(expect("]"), afterType) - } - function vardef() { - return pass(pattern, maybetype, maybeAssign, vardefCont); - } - function pattern(type, value) { - if (type == "modifier") return cont(pattern) - if (type == "variable") { register(value); return cont(); } - if (type == "spread") return cont(pattern); - if (type == "[") return contCommasep(pattern, "]"); - if (type == "{") return contCommasep(proppattern, "}"); - } - function proppattern(type, value) { - if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { - register(value); - return cont(maybeAssign); - } - if (type == "variable") cx.marked = "property"; - if (type == "spread") return cont(pattern); - if (type == "}") return pass(); - return cont(expect(":"), pattern, maybeAssign); - } - function maybeAssign(_type, value) { - if (value == "=") return cont(expressionNoComma); - } - function vardefCont(type) { - if (type == ",") return cont(vardef); - } - function maybeelse(type, value) { - if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); - } - function forspec(type) { - if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); - } - function forspec1(type) { - if (type == "var") return cont(vardef, expect(";"), forspec2); - if (type == ";") return cont(forspec2); - if (type == "variable") return cont(formaybeinof); - return pass(expression, expect(";"), forspec2); - } - function formaybeinof(_type, value) { - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return cont(maybeoperatorComma, forspec2); - } - function forspec2(type, value) { - if (type == ";") return cont(forspec3); - if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } - return pass(expression, expect(";"), forspec3); - } - function forspec3(type) { - if (type != ")") cont(expression); - } - function functiondef(type, value) { - if (value == "*") { cx.marked = "keyword"; return cont(functiondef); } - if (type == "variable") { register(value); return cont(functiondef); } - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext); - } - function funarg(type) { - if (type == "spread") return cont(funarg); - return pass(pattern, maybetype, maybedefault); - } - function className(type, value) { - if (type == "variable") { register(value); return cont(classNameAfter); } - } - function classNameAfter(type, value) { - if (value == "extends") return cont(expression, classNameAfter); - if (type == "{") return cont(pushlex("}"), classBody, poplex); - } - function classBody(type, value) { - if (type == "variable" || cx.style == "keyword") { - if (value == "static") { - cx.marked = "keyword"; - return cont(classBody); - } - cx.marked = "property"; - if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); - return cont(functiondef, classBody); - } - if (value == "*") { - cx.marked = "keyword"; - return cont(classBody); - } - if (type == ";") return cont(classBody); - if (type == "}") return cont(); - } - function classGetterSetter(type) { - if (type != "variable") return pass(); - cx.marked = "property"; - return cont(); - } - function afterExport(_type, value) { - if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } - if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } - return pass(statement); - } - function afterImport(type) { - if (type == "string") return cont(); - return pass(importSpec, maybeFrom); - } - function importSpec(type, value) { - if (type == "{") return contCommasep(importSpec, "}"); - if (type == "variable") register(value); - if (value == "*") cx.marked = "keyword"; - return cont(maybeAs); - } - function maybeAs(_type, value) { - if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } - } - function maybeFrom(_type, value) { - if (value == "from") { cx.marked = "keyword"; return cont(expression); } - } - function arrayLiteral(type) { - if (type == "]") return cont(); - return pass(expressionNoComma, commasep(expressionNoComma, "]")); - } - - function isContinuedStatement(state, textAfter) { - return state.lastType == "operator" || state.lastType == "," || - isOperatorChar.test(textAfter.charAt(0)) || - /[,.]/.test(textAfter.charAt(0)); - } - - // Interface - - return { - startState: function (basecolumn) { - var state = { - tokenize: tokenBase, - lastType: "sof", - cc: [], - lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), - localVars: parserConfig.localVars, - context: parserConfig.localVars && { vars: parserConfig.localVars }, - indented: basecolumn || 0 - }; - if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") - state.globalVars = parserConfig.globalVars; - return state; - }, - - token: function (stream, state) { - if (stream.sol()) { - if (!state.lexical.hasOwnProperty("align")) - state.lexical.align = false; - state.indented = stream.indentation(); - findFatArrow(stream, state); - } - if (state.tokenize != tokenComment && stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - if (type == "comment") return style; - state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; - return parseJS(state, style, type, content, stream); - }, - - indent: function (state, textAfter) { - if (state.tokenize == tokenComment) return CodeMirror.Pass; - if (state.tokenize != tokenBase) return 0; - var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; - // Kludge to prevent 'maybelse' from blocking lexical scope pops - if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { - var c = state.cc[i]; - if (c == poplex) lexical = lexical.prev; - else if (c != maybeelse) break; - } - if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; - if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") - lexical = lexical.prev; - var type = lexical.type, closing = firstChar == type; - - if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); - else if (type == "form" && firstChar == "{") return lexical.indented; - else if (type == "form") return lexical.indented + indentUnit; - else if (type == "stat") - return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); - else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) - return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); - else if (lexical.align) return lexical.column + (closing ? 0 : 1); - else return lexical.indented + (closing ? 0 : indentUnit); - }, - - electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, - blockCommentStart: jsonMode ? null : "/*", - blockCommentEnd: jsonMode ? null : "*/", - lineComment: jsonMode ? null : "//", - fold: "brace", - closeBrackets: "()[]{}''\"\"``", - - helperType: jsonMode ? "json" : "javascript", - jsonldMode: jsonldMode, - jsonMode: jsonMode, - - expressionAllowed: expressionAllowed, - skipExpression: function (state) { - var top = state.cc[state.cc.length - 1] - if (top == expression || top == expressionNoComma) state.cc.pop() - } - }; - }); - - CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); - - CodeMirror.defineMIME("text/javascript", "javascript"); - CodeMirror.defineMIME("text/ecmascript", "javascript"); - CodeMirror.defineMIME("application/javascript", "javascript"); - CodeMirror.defineMIME("application/x-javascript", "javascript"); - CodeMirror.defineMIME("application/ecmascript", "javascript"); - CodeMirror.defineMIME("application/json", { name: "javascript", json: true }); - CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true }); - CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true }); - CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); - CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); - -})(); - -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: http://codemirror.net/LICENSE - -(function () { - var defaults = { - pairs: "()[]{}''\"\"", - triples: "", - explode: "[]{}" - }; - - var Pos = CodeMirror.Pos; - - CodeMirror.defineOption("autoCloseBrackets", false, function (cm, val, old) { - if (old && old != CodeMirror.Init) { - cm.removeKeyMap(keyMap); - cm.state.closeBrackets = null; - } - if (val) { - cm.state.closeBrackets = val; - cm.addKeyMap(keyMap); - } - }); - - function getOption(conf, name) { - if (name == "pairs" && typeof conf == "string") return conf; - if (typeof conf == "object" && conf[name] != null) return conf[name]; - return defaults[name]; - } - - var bind = defaults.pairs + "`"; - var keyMap = { Backspace: handleBackspace, Enter: handleEnter }; - for (var i = 0; i < bind.length; i++) - keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i)); - - function handler(ch) { - return function (cm) { return handleChar(cm, ch); }; - } - - function getConfig(cm) { - var deflt = cm.state.closeBrackets; - if (!deflt) return null; - var mode = cm.getModeAt(cm.getCursor()); - return mode.closeBrackets || deflt; - } - - function handleBackspace(cm) { - var conf = getConfig(cm); - if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; - - var pairs = getOption(conf, "pairs"); - var ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - if (!ranges[i].empty()) return CodeMirror.Pass; - var around = charsAround(cm, ranges[i].head); - if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; - } - for (var i = ranges.length - 1; i >= 0; i--) { - var cur = ranges[i].head; - cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); - } - } - - function handleEnter(cm) { - var conf = getConfig(cm); - var explode = conf && getOption(conf, "explode"); - if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; - - var ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - if (!ranges[i].empty()) return CodeMirror.Pass; - var around = charsAround(cm, ranges[i].head); - if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; - } - cm.operation(function () { - cm.replaceSelection("\n\n", null); - cm.execCommand("goCharLeft"); - ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - var line = ranges[i].head.line; - cm.indentLine(line, null, true); - cm.indentLine(line + 1, null, true); - } - }); - } - - function contractSelection(sel) { - var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; - return { - anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), - head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1)) - }; - } - - function handleChar(cm, ch) { - var conf = getConfig(cm); - if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; - - var pairs = getOption(conf, "pairs"); - var pos = pairs.indexOf(ch); - if (pos == -1) return CodeMirror.Pass; - var triples = getOption(conf, "triples"); - - var identical = pairs.charAt(pos + 1) == ch; - var ranges = cm.listSelections(); - var opening = pos % 2 == 0; - - var type; - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i], cur = range.head, curType; - var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); - if (opening && !range.empty()) { - curType = "surround"; - } else if ((identical || !opening) && next == ch) { - if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) - curType = "skipThree"; - else - curType = "skip"; - } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && - cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch && - (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) { - curType = "addFour"; - } else if (identical) { - if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both"; - else return CodeMirror.Pass; - } else if (opening && (cm.getLine(cur.line).length == cur.ch || - isClosingBracket(next, pairs) || - /\s/.test(next))) { - curType = "both"; - } else { - return CodeMirror.Pass; - } - if (!type) type = curType; - else if (type != curType) return CodeMirror.Pass; - } - - var left = pos % 2 ? pairs.charAt(pos - 1) : ch; - var right = pos % 2 ? ch : pairs.charAt(pos + 1); - cm.operation(function () { - if (type == "skip") { - cm.execCommand("goCharRight"); - } else if (type == "skipThree") { - for (var i = 0; i < 3; i++) - cm.execCommand("goCharRight"); - } else if (type == "surround") { - var sels = cm.getSelections(); - for (var i = 0; i < sels.length; i++) - sels[i] = left + sels[i] + right; - cm.replaceSelections(sels, "around"); - sels = cm.listSelections().slice(); - for (var i = 0; i < sels.length; i++) - sels[i] = contractSelection(sels[i]); - cm.setSelections(sels); - } else if (type == "both") { - cm.replaceSelection(left + right, null); - cm.triggerElectric(left + right); - cm.execCommand("goCharLeft"); - } else if (type == "addFour") { - cm.replaceSelection(left + left + left + left, "before"); - cm.execCommand("goCharRight"); - } - }); - } - - function isClosingBracket(ch, pairs) { - var pos = pairs.lastIndexOf(ch); - return pos > -1 && pos % 2 == 1; - } - - function charsAround(cm, pos) { - var str = cm.getRange(Pos(pos.line, pos.ch - 1), - Pos(pos.line, pos.ch + 1)); - return str.length == 2 ? str : null; - } - - // Project the token type that will exists after the given char is - // typed, and use it to determine whether it would cause the start - // of a string token. - function enteringString(cm, pos, ch) { - var line = cm.getLine(pos.line); - var token = cm.getTokenAt(pos); - if (/\bstring2?\b/.test(token.type)) return false; - var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); - stream.pos = stream.start = token.start; - for (; ;) { - var type1 = cm.getMode().token(stream, token.state); - if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1); - stream.start = stream.pos; - } - } -})(); - -// CodeMirror, copyright (c) by Marijn Haverbeke and others -// Distributed under an MIT license: https://codemirror.net/LICENSE - -// declare global: DOMRect - -(function () { - "use strict"; - - var HINT_ELEMENT_CLASS = "CodeMirror-hint"; - var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; - - // This is the old interface, kept around for now to stay - // backwards-compatible. - CodeMirror.showHint = function (cm, getHints, options) { - if (!getHints) return cm.showHint(options); - if (options && options.async) getHints.async = true; - var newOpts = { hint: getHints }; - if (options) for (var prop in options) newOpts[prop] = options[prop]; - return cm.showHint(newOpts); - }; - - CodeMirror.defineExtension("showHint", function (options) { - options = parseOptions(this, this.getCursor("start"), options); - var selections = this.listSelections() - if (selections.length > 1) return; - // By default, don't allow completion when something is selected. - // A hint function can have a `supportsSelection` property to - // indicate that it can handle selections. - if (this.somethingSelected()) { - if (!options.hint.supportsSelection) return; - // Don't try with cross-line selections - for (var i = 0; i < selections.length; i++) - if (selections[i].head.line != selections[i].anchor.line) return; - } - - if (this.state.completionActive) this.state.completionActive.close(); - var completion = this.state.completionActive = new Completion(this, options); - if (!completion.options.hint) return; - - CodeMirror.signal(this, "startCompletion", this); - completion.update(true); - }); - - CodeMirror.defineExtension("closeHint", function () { - if (this.state.completionActive) this.state.completionActive.close() - }) - - function Completion(cm, options) { - this.cm = cm; - this.options = options; - this.widget = null; - this.debounce = 0; - this.tick = 0; - this.startPos = this.cm.getCursor("start"); - this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; - - if (this.options.updateOnCursorActivity) { - var self = this; - cm.on("cursorActivity", this.activityFunc = function () { self.cursorActivity(); }); - } - } - - var requestAnimationFrame = window.requestAnimationFrame || function (fn) { - return setTimeout(fn, 1000 / 60); - }; - var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; - - Completion.prototype = { - close: function () { - if (!this.active()) return; - this.cm.state.completionActive = null; - this.tick = null; - if (this.options.updateOnCursorActivity) { - this.cm.off("cursorActivity", this.activityFunc); - } - - if (this.widget && this.data) CodeMirror.signal(this.data, "close"); - if (this.widget) this.widget.close(); - CodeMirror.signal(this.cm, "endCompletion", this.cm); - }, - - active: function () { - return this.cm.state.completionActive == this; - }, - - pick: function (data, i) { - var completion = data.list[i], self = this; - this.cm.operation(function () { - if (completion.hint) - completion.hint(self.cm, data, completion); - else - self.cm.replaceRange(getText(completion), completion.from || data.from, - completion.to || data.to, "complete"); - CodeMirror.signal(data, "pick", completion); - self.cm.scrollIntoView(); - }); - if (this.options.closeOnPick) { - this.close(); - } - }, - - cursorActivity: function () { - if (this.debounce) { - cancelAnimationFrame(this.debounce); - this.debounce = 0; - } - - var identStart = this.startPos; - if (this.data) { - identStart = this.data.from; - } - - var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); - if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || - pos.ch < identStart.ch || this.cm.somethingSelected() || - (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { - this.close(); - } else { - var self = this; - this.debounce = requestAnimationFrame(function () { self.update(); }); - if (this.widget) this.widget.disable(); - } - }, - - update: function (first) { - if (this.tick == null) return - var self = this, myTick = ++this.tick - fetchHints(this.options.hint, this.cm, this.options, function (data) { - if (self.tick == myTick) self.finishUpdate(data, first) - }) - }, - - finishUpdate: function (data, first) { - if (this.data) CodeMirror.signal(this.data, "update"); - - var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); - if (this.widget) this.widget.close(); - - this.data = data; - - if (data && data.list.length) { - if (picked && data.list.length == 1) { - this.pick(data, 0); - } else { - this.widget = new Widget(this, data); - CodeMirror.signal(data, "shown"); - } - } - } - }; - - function parseOptions(cm, pos, options) { - var editor = cm.options.hintOptions; - var out = {}; - for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; - if (editor) for (var prop in editor) - if (editor[prop] !== undefined) out[prop] = editor[prop]; - if (options) for (var prop in options) - if (options[prop] !== undefined) out[prop] = options[prop]; - if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) - return out; - } - - function getText(completion) { - if (typeof completion == "string") return completion; - else return completion.text; - } - - function buildKeyMap(completion, handle) { - var baseMap = { - Up: function () { handle.moveFocus(-1); }, - Down: function () { handle.moveFocus(1); }, - PageUp: function () { handle.moveFocus(-handle.menuSize() + 1, true); }, - PageDown: function () { handle.moveFocus(handle.menuSize() - 1, true); }, - Home: function () { handle.setFocus(0); }, - End: function () { handle.setFocus(handle.length - 1); }, - Enter: handle.pick, - Tab: handle.pick, - Esc: handle.close - }; - - var mac = /Mac/.test(navigator.platform); - - if (mac) { - baseMap["Ctrl-P"] = function () { handle.moveFocus(-1); }; - baseMap["Ctrl-N"] = function () { handle.moveFocus(1); }; - } - - var custom = completion.options.customKeys; - var ourMap = custom ? {} : baseMap; - function addBinding(key, val) { - var bound; - if (typeof val != "string") - bound = function (cm) { return val(cm, handle); }; - // This mechanism is deprecated - else if (baseMap.hasOwnProperty(val)) - bound = baseMap[val]; - else - bound = val; - ourMap[key] = bound; - } - if (custom) - for (var key in custom) if (custom.hasOwnProperty(key)) - addBinding(key, custom[key]); - var extra = completion.options.extraKeys; - if (extra) - for (var key in extra) if (extra.hasOwnProperty(key)) - addBinding(key, extra[key]); - return ourMap; - } - - function getHintElement(hintsElement, el) { - while (el && el != hintsElement) { - if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; - el = el.parentNode; - } - } - - function Widget(completion, data) { - this.completion = completion; - this.data = data; - this.picked = false; - var widget = this, cm = completion.cm; - var ownerDocument = cm.getInputField().ownerDocument; - var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow; - var hints = this.hints = ownerDocument.createElement("ul"); - var theme = completion.cm.options.theme; - hints.className = "CodeMirror-hints " + theme; - this.selectedHint = data.selectedHint || 0; - - var completions = data.list; - for (var i = 0; i < completions.length; ++i) { - var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i]; - var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); - if (cur.className != null) className = cur.className + " " + className; - elt.className = className; - if (cur.render) cur.render(elt, data, cur); - else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur))); - elt.hintId = i; - CodeMirror.on(elt, "mouseover", function (e) { - widget.changeActive(this.hintId); - }); - CodeMirror.on(elt, "touchstart", function (e) { - widget.changeActive(this.hintId); - }); - CodeMirror.on(elt, "touchend", function (e) { - var cur = cm.getCursor(); - var self = this; - setTimeout(function () { - cm.focus(); - var cur2 = cm.getCursor(); - if (cur2.line == cur.line && cur2.ch == 0) { - var textLen = self.innerText.length; - cm.setCursor({ line: cur.line, ch: cur.ch + textLen }); - } - }, 10); - }); - } - - var container = completion.options.container || ownerDocument.body; - var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); - var left = pos.left, top = pos.bottom, below = true; - var offsetLeft = 0, offsetTop = 0; - if (container !== ownerDocument.body) { - // We offset the cursor position because left and top are relative to the offsetParent's top left corner. - var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1; - var offsetParent = isContainerPositioned ? container : container.offsetParent; - var offsetParentPosition = offsetParent.getBoundingClientRect(); - var bodyPosition = ownerDocument.body.getBoundingClientRect(); - offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft); - offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop); - } - var documentZoom = getDocumentZoom(); - hints.style.fontSize = 16 / documentZoom * 0.9 + "px"; - hints.style.left = (left - offsetLeft) / documentZoom + "px"; - hints.style.top = (top - offsetTop) / documentZoom + "px"; - - // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. - var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); - var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); - container.appendChild(hints); - - var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect(); - var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false; - - // Compute in the timeout to avoid reflow on init - var startScroll; - setTimeout(function () { startScroll = cm.getScrollInfo(); }); - - var overlapY = box.bottom - winH; - if (overlapY > 0) { - var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); - if (curTop - height > 0) { // Fits above cursor - hints.style.top = (top = pos.top - height - offsetTop) / documentZoom + "px"; - below = false; - } else if (height > winH) { - hints.style.height = (winH - 5) / documentZoom + "px"; - hints.style.top = (top = pos.bottom - box.top - offsetTop) / documentZoom + "px"; - var cursor = cm.getCursor(); - if (data.from.ch != cursor.ch) { - pos = cm.cursorCoords(cursor); - hints.style.left = (left = pos.left - offsetLeft) / documentZoom + "px"; - box = hints.getBoundingClientRect(); - } - } - } - var overlapX = box.right - winW; - if (overlapX > 0) { - if (box.right - box.left > winW) { - hints.style.width = (winW - 5) / documentZoom + "px"; - overlapX -= (box.right - box.left) - winW; - } - hints.style.left = (left = pos.left - overlapX - offsetLeft) / documentZoom + "px"; - } - if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) - node.style.paddingRight = cm.display.nativeBarWidth / documentZoom + "px" - - cm.addKeyMap(this.keyMap = buildKeyMap(completion, { - moveFocus: function (n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, - setFocus: function (n) { widget.changeActive(n); }, - menuSize: function () { return widget.screenAmount(); }, - length: completions.length, - close: function () { completion.close(); }, - pick: function () { widget.pick(); }, - data: data - })); - - if (completion.options.closeOnUnfocus) { - var closingOnBlur; - cm.on("blur", this.onBlur = function () { closingOnBlur = setTimeout(function () { completion.close(); }, 100); }); - cm.on("focus", this.onFocus = function () { clearTimeout(closingOnBlur); }); - } - - cm.on("scroll", this.onScroll = function () { - // fix "startScroll == undfined" - if (!startScroll) return; - var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); - var newTop = top + startScroll.top - curScroll.top; - var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop); - if (!below) point += hints.offsetHeight; - if (point <= editor.top || point >= editor.bottom) return completion.close(); - hints.style.top = newTop / documentZoom + "px"; - hints.style.left = (left + startScroll.left - curScroll.left) / documentZoom + "px"; - }); - - CodeMirror.on(hints, "dblclick", function (e) { - var t = getHintElement(hints, e.target || e.srcElement); - if (t && t.hintId != null) { widget.changeActive(t.hintId); widget.pick(); } - }); - - CodeMirror.on(hints, "click", function (e) { - var t = getHintElement(hints, e.target || e.srcElement); - if (t && t.hintId != null) { - widget.changeActive(t.hintId); - if (completion.options.completeOnSingleClick) widget.pick(); - } - }); - - CodeMirror.on(hints, "mousedown", function () { - setTimeout(function () { cm.focus(); }, 20); - }); - - //滑动修复 - CodeMirror.on(hints, "touchmove", function (event) { - if (ios && this.scrollHeight <= this.offsetHeight + 5 && this.scrollWidth <= this.offsetWidth + 5) { - event.preventDefault(); - } - else { - event.stopPropagation(); - } - }); - hints.style.WebkitOverflowScrolling = 'touch'; - - // The first hint doesn't need to be scrolled to on init - var selectedHintRange = this.getSelectedHintRange(); - if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) { - this.scrollToActive(); - } - - CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); - return true; - } - - Widget.prototype = { - close: function () { - if (this.completion.widget != this) return; - this.completion.widget = null; - this.hints.parentNode.removeChild(this.hints); - this.completion.cm.removeKeyMap(this.keyMap); - - var cm = this.completion.cm; - if (this.completion.options.closeOnUnfocus) { - cm.off("blur", this.onBlur); - cm.off("focus", this.onFocus); - } - cm.off("scroll", this.onScroll); - }, - - disable: function () { - this.completion.cm.removeKeyMap(this.keyMap); - var widget = this; - this.keyMap = { Enter: function () { widget.picked = true; } }; - this.completion.cm.addKeyMap(this.keyMap); - }, - - pick: function () { - this.completion.pick(this.data, this.selectedHint); - }, - - changeActive: function (i, avoidWrap) { - if (i >= this.data.list.length) - i = avoidWrap ? this.data.list.length - 1 : 0; - else if (i < 0) - i = avoidWrap ? 0 : this.data.list.length - 1; - if (this.selectedHint == i) return; - var node = this.hints.childNodes[this.selectedHint]; - if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); - node = this.hints.childNodes[this.selectedHint = i]; - node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; - this.scrollToActive() - CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); - }, - - scrollToActive: function () { - var selectedHintRange = this.getSelectedHintRange(); - var node1 = this.hints.childNodes[selectedHintRange.from]; - var node2 = this.hints.childNodes[selectedHintRange.to]; - var firstNode = this.hints.firstChild; - if (node1.offsetTop < this.hints.scrollTop) - this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop; - else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) - this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop; - }, - - screenAmount: function () { - return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; - }, - - getSelectedHintRange: function () { - var margin = this.completion.options.scrollMargin || 0; - return { - from: Math.max(0, this.selectedHint - margin), - to: Math.min(this.data.list.length - 1, this.selectedHint + margin), - }; - } - }; - - function applicableHelpers(cm, helpers) { - if (!cm.somethingSelected()) return helpers - var result = [] - for (var i = 0; i < helpers.length; i++) - if (helpers[i].supportsSelection) result.push(helpers[i]) - return result - } - - function fetchHints(hint, cm, options, callback) { - if (hint.async) { - hint(cm, callback, options) - } else { - var result = hint(cm, options) - if (result && result.then) result.then(callback) - else callback(result) - } - } - - function resolveAutoHints(cm, pos) { - var helpers = cm.getHelpers(pos, "hint"), words - if (helpers.length) { - var resolved = function (cm, callback, options) { - var app = applicableHelpers(cm, helpers); - function run(i) { - if (i == app.length) return callback(null) - fetchHints(app[i], cm, options, function (result) { - if (result && result.list.length > 0) callback(result) - else run(i + 1) - }) - } - run(0) - } - resolved.async = true - resolved.supportsSelection = true - return resolved - } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { - return function (cm) { return CodeMirror.hint.fromList(cm, { words: words }) } - } else if (CodeMirror.hint.anyword) { - return function (cm, options) { return CodeMirror.hint.anyword(cm, options) } - } else { - return function () { } - } - } - - CodeMirror.registerHelper("hint", "auto", { - resolve: resolveAutoHints - }); - - CodeMirror.registerHelper("hint", "fromList", function (cm, options) { - var cur = cm.getCursor(), token = cm.getTokenAt(cur) - var term, from = CodeMirror.Pos(cur.line, token.start), to = cur - if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) { - term = token.string.substr(0, cur.ch - token.start) - } else { - term = "" - from = cur - } - var found = []; - for (var i = 0; i < options.words.length; i++) { - var word = options.words[i]; - if (word.slice(0, term.length) == term) - found.push(word); - } - - if (found.length) return { list: found, from: from, to: to }; - }); - - CodeMirror.commands.autocomplete = CodeMirror.showHint; - - var defaultOptions = { - hint: CodeMirror.hint.auto, - completeSingle: true, - alignWithWord: true, - closeCharacters: /[\s()\[\]{};:>,]/, - closeOnPick: true, - closeOnUnfocus: true, - updateOnCursorActivity: true, - completeOnSingleClick: true, - container: null, - customKeys: null, - extraKeys: null, - paddingForScrollbar: true, - moveOnOverlap: true, - }; - - CodeMirror.defineOption("hintOptions", null); -})(); - -export default CodeMirror; \ No newline at end of file + +function getDocumentZoom() { + //一般body的缩放是xy同步的 + var transform = getComputedStyle(document.body).transform; + // @ts-ignore + if (transform == 'none') transform = 1; + // @ts-ignore + else transform = +transform.slice(7, -1).split(',')[0]; + return +transform; +} + +// BROWSER SNIFFING + +// Kludges for bugs and behavior differences that can't be feature +// detected are enabled based on userAgent etc sniffing. +var userAgent = navigator.userAgent; +var platform = navigator.platform; + +var gecko = /gecko\/\d/i.test(userAgent); +var ie_upto10 = /MSIE \d/.test(userAgent); +var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); +var ie = ie_upto10 || ie_11up; +// @ts-ignore +var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); +var webkit = /WebKit\//.test(userAgent); +var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); +var chrome = /Chrome\//.test(userAgent); +var presto = /Opera\//.test(userAgent); +var safari = /Apple Computer/.test(navigator.vendor); +var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); +var phantom = /PhantomJS/.test(userAgent); + +var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); +// This is woefully incomplete. Suggestions for alternative methods welcome. +var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); +var mac = ios || /Mac/.test(platform); +var chromeOS = /\bCrOS\b/.test(userAgent); +var windows = /win/i.test(platform); + +var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/); +// @ts-ignore +if (presto_version) presto_version = Number(presto_version[1]); +// @ts-ignore +if (presto_version && presto_version >= 15) { presto = false; webkit = true; } +// Some browsers use the wrong event properties to signal cmd/ctrl on OS X +// @ts-ignore +var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); +var captureRightClick = gecko || (ie && ie_version >= 9); + +// Optimize some code when these features are not used. +var sawReadOnlySpans = false, sawCollapsedSpans = false; + +// EDITOR CONSTRUCTOR + +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// This is CodeMirror (http://codemirror.net), a code editor +// implemented in JavaScript on top of the browser's DOM. +// +// You can find some technical background for some of the code below +// at http://marijnhaverbeke.nl/blog/#cm-internals . + +/** + * @type { typeof import('codemirror/index') } + */ +// @ts-ignore +var CodeMirror = (function () { + + // A CodeMirror instance represents an editor. This is the object + // that user code is usually dealing with. + + function CodeMirror(place, options) { + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + + this.options = options = options ? copyObj(options) : {}; + // Determine effective options based on given values and defaults. + copyObj(defaults, options, false); + setGuttersForLineNumbers(options); + + var doc = options.value; + if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator); + this.doc = doc; + + var input = new CodeMirror.inputStyles[options.inputStyle](this); + var display = this.display = new Display(place, doc, input); + display.wrapper.CodeMirror = this; + updateGutters(this); + themeChanged(this); + if (options.lineWrapping) + this.display.wrapper.className += " CodeMirror-wrap"; + if (options.autofocus && !mobile) display.input.focus(); + initScrollbars(this); + + this.state = { + keyMaps: [], // stores maps added by addKeyMap + overlays: [], // highlighting overlays, as added by addOverlay + modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info + overwrite: false, + delayingBlurEvent: false, + focused: false, + suppressEdits: false, // used to disable editing during key handlers when in readOnly mode + pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll + selectingText: false, + draggingText: false, + highlight: new Delayed(), // stores highlight worker timeout + keySeq: null, // Unfinished key sequence + specialChars: null + }; + + var cm = this; + + // Override magic textarea content restore that IE sometimes does + // on our hidden textarea on reload + if (ie && ie_version < 11) setTimeout(function () { cm.display.input.reset(true); }, 20); + + registerEventHandlers(this); + ensureGlobalHandlers(); + + startOperation(this); + this.curOp.forceUpdate = true; + attachDoc(this, doc); + + if ((options.autofocus && !mobile) || cm.hasFocus()) + setTimeout(bind(onFocus, this), 20); + else + onBlur(this); + + for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + optionHandlers[opt](this, options[opt], Init); + maybeUpdateLineNumberWidth(this); + if (options.finishInit) options.finishInit(this); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); + endOperation(this); + // Suppress optimizelegibility in Webkit, since it breaks text + // measuring on line wrapping boundaries. + if (webkit && options.lineWrapping && + getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") + display.lineDiv.style.textRendering = "auto"; + } + + // DISPLAY CONSTRUCTOR + + // The display handles the DOM integration, both for input reading + // and content drawing. It holds references to DOM nodes and + // display-related state. + + function Display(place, doc, input) { + var d = this; + this.input = input; + + // Covers bottom-right square when both scrollbars are present. + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.scrollbarFiller.setAttribute("cm-not-content", "true"); + // Covers bottom of gutter when coverGutterNextToScrollbar is on + // and h scrollbar is present. + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); + d.gutterFiller.setAttribute("cm-not-content", "true"); + // Will contain the actual code, positioned to cover the viewport. + d.lineDiv = elt("div", null, "CodeMirror-code"); + // Elements are added to these to represent selection and cursors. + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); + d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + // A visibility: hidden element used to find the size of things. + d.measure = elt("div", null, "CodeMirror-measure"); + // When lines outside of the viewport are measured, they are drawn in this. + d.lineMeasure = elt("div", null, "CodeMirror-measure"); + // Wraps everything that needs to exist inside the vertically-padded coordinate system + d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], + null, "position: relative; outline: none"); + // Moved around its parent to cover visible view. + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + // Set to the height of the document, allowing scrolling. + d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); + d.sizerWidth = null; + // Behavior of elts with overflow: auto and padding is + // inconsistent across browsers. This is used to ensure the + // scrollable area is big enough. + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); + // Will contain the gutters, if any. + d.gutters = elt("div", null, "CodeMirror-gutters"); + d.lineGutter = null; + // Actual scrollable element. + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); + d.scroller.setAttribute("tabIndex", "-1"); + // The element in which the editor lives. + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + + // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } + if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; + + if (place) { + if (place.appendChild) place.appendChild(d.wrapper); + else place(d.wrapper); + } + + // Current rendered range (may be bigger than the view window). + d.viewFrom = d.viewTo = doc.first; + d.reportedViewFrom = d.reportedViewTo = doc.first; + // Information about the rendered lines. + d.view = []; + d.renderedView = null; + // Holds info about a single rendered line when it was rendered + // for measurement, while not in view. + d.externalMeasured = null; + // Empty space (in pixels) above the view + d.viewOffset = 0; + d.lastWrapHeight = d.lastWrapWidth = 0; + d.updateLineNumbers = null; + + d.nativeBarWidth = d.barHeight = d.barWidth = 0; + d.scrollbarsClipped = false; + + // Used to only resize the line number gutter when necessary (when + // the amount of lines crosses a boundary that makes its width change) + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + // Set to true when a non-horizontal-scrolling line widget is + // added. As an optimization, line widget aligning is skipped when + // this is false. + d.alignWidgets = false; + + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + + // Tracks the maximum line length so that the horizontal scrollbar + // can be kept static when scrolling. + d.maxLine = null; + d.maxLineLength = 0; + d.maxLineChanged = false; + + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + // True when shift is held down. + d.shift = false; + + // Used to track whether anything happened since the context menu + // was opened. + d.selForContextMenu = null; + + d.activeTouch = null; + + input.init(d); + } + + // STATE UPDATES + + // Used to get the editor into a consistent state again when options change. + + function loadMode(cm) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + resetModeState(cm); + } + + function resetModeState(cm) { + cm.doc.iter(function (line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); + cm.doc.frontier = cm.doc.first; + startWorker(cm, 100); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); + } + + function wrappingChanged(cm) { + if (cm.options.lineWrapping) { + addClass(cm.display.wrapper, "CodeMirror-wrap"); + cm.display.sizer.style.minWidth = ""; + cm.display.sizerWidth = null; + } else { + rmClass(cm.display.wrapper, "CodeMirror-wrap"); + findMaxLine(cm); + } + estimateLineHeights(cm); + regChange(cm); + clearCaches(cm); + setTimeout(function () { updateScrollbars(cm); }, 100); + } + + // Returns a function that estimates the height of a line, to use as + // first approximation until the line becomes visible (and is thus + // properly measurable). + function estimateHeight(cm) { + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + return function (line) { + if (lineIsHidden(cm.doc, line)) return 0; + + var widgetsHeight = 0; + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + } + + if (wrapping) + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; + else + return widgetsHeight + th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function (line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); + } + + function themeChanged(cm) { + cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); + clearCaches(cm); + } + + function guttersChanged(cm) { + updateGutters(cm); + regChange(cm); + setTimeout(function () { alignHorizontally(cm); }, 20); + } + + // Rebuild the gutter elements, ensure the margin to the left of the + // code matches their width. + function updateGutters(cm) { + var gutters = cm.display.gutters, specs = cm.options.gutters; + removeChildren(gutters); + for (var i = 0; i < specs.length; ++i) { + var gutterClass = specs[i]; + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + if (gutterClass == "CodeMirror-linenumbers") { + cm.display.lineGutter = gElt; + gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + } + } + gutters.style.display = i ? "" : "none"; + updateGutterSpace(cm); + } + + function updateGutterSpace(cm) { + var width = cm.display.gutters.offsetWidth; + cm.display.sizer.style.marginLeft = width + "px"; + } + + // Compute the character length of a line, taking into account + // collapsed ranges (see markText) that might hide parts, and join + // other lines onto it. + function lineLength(line) { + if (line.height == 0) return 0; + var len = line.text.length, merged, cur = line; + while (merged = collapsedSpanAtStart(cur)) { + var found = merged.find(0, true); + cur = found.from.line; + len += found.from.ch - found.to.ch; + } + cur = line; + while (merged = collapsedSpanAtEnd(cur)) { + var found = merged.find(0, true); + len -= cur.text.length - found.from.ch; + cur = found.to.line; + len += cur.text.length - found.to.ch; + } + return len; + } + + // Find the longest line in the document. + function findMaxLine(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(d.maxLine); + d.maxLineChanged = true; + doc.iter(function (line) { + var len = lineLength(line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; + } + }); + } + + // Make sure the gutters options contains the element + // "CodeMirror-linenumbers" when the lineNumbers option is true. + function setGuttersForLineNumbers(options) { + var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0); + options.gutters.splice(found, 1); + } + } + + // SCROLLBARS + + // Prepare DOM reads needed to update the scrollbars. Done in one + // shot to minimize update/measure roundtrips. + function measureForScrollbars(cm) { + var d = cm.display, gutterW = d.gutters.offsetWidth; + var docH = Math.round(cm.doc.height + paddingVert(cm.display)); + return { + clientHeight: d.scroller.clientHeight, + viewHeight: d.wrapper.clientHeight, + scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, + viewWidth: d.wrapper.clientWidth, + barLeft: cm.options.fixedGutter ? gutterW : 0, + docHeight: docH, + scrollHeight: docH + scrollGap(cm) + d.barHeight, + nativeBarWidth: d.nativeBarWidth, + gutterWidth: gutterW + }; + } + + function NativeScrollbars(place, scroll, cm) { + this.cm = cm; + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + place(vert); place(horiz); + + on(vert, "scroll", function () { + if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); + }); + on(horiz, "scroll", function () { + if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); + }); + + this.checkedZeroWidth = false; + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; + } + + NativeScrollbars.prototype = copyObj({ + update: function (measure) { + var needsH = measure.scrollWidth > measure.clientWidth + 1; + var needsV = measure.scrollHeight > measure.clientHeight + 1; + var sWidth = measure.nativeBarWidth; + + if (needsV) { + this.vert.style.display = "block"; + this.vert.style.bottom = needsH ? sWidth + "px" : "0"; + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); + // A bug in IE8 can cause this value to be negative, so guard it. + this.vert.firstChild.style.height = + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; + } else { + this.vert.style.display = ""; + this.vert.firstChild.style.height = "0"; + } + + if (needsH) { + this.horiz.style.display = "block"; + this.horiz.style.right = needsV ? sWidth + "px" : "0"; + this.horiz.style.left = measure.barLeft + "px"; + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); + this.horiz.firstChild.style.width = + (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; + } else { + this.horiz.style.display = ""; + this.horiz.firstChild.style.width = "0"; + } + + if (!this.checkedZeroWidth && measure.clientHeight > 0) { + if (sWidth == 0) this.zeroWidthHack(); + this.checkedZeroWidth = true; + } + + return { right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0 }; + }, + setScrollLeft: function (pos) { + if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; + if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz); + }, + setScrollTop: function (pos) { + if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; + if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert); + }, + zeroWidthHack: function () { + var w = mac && !mac_geMountainLion ? "12px" : "18px"; + this.horiz.style.height = this.vert.style.width = w; + this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; + this.disableHoriz = new Delayed; + this.disableVert = new Delayed; + }, + enableZeroWidthBar: function (bar, delay) { + bar.style.pointerEvents = "auto"; + function maybeDisable() { + // To find out whether the scrollbar is still visible, we + // check whether the element under the pixel in the bottom + // left corner of the scrollbar box is the scrollbar box + // itself (when the bar is still visible) or its filler child + // (when the bar is hidden). If it is still visible, we keep + // it enabled, if it's hidden, we disable pointer events. + var box = bar.getBoundingClientRect(); + var elt = document.elementFromPoint(box.left + 1, box.bottom - 1); + if (elt != bar) bar.style.pointerEvents = "none"; + else delay.set(1000, maybeDisable); + } + delay.set(1000, maybeDisable); + }, + clear: function () { + var parent = this.horiz.parentNode; + parent.removeChild(this.horiz); + parent.removeChild(this.vert); + } + }, NativeScrollbars.prototype); + + function NullScrollbars() { } + + NullScrollbars.prototype = copyObj({ + update: function () { return { bottom: 0, right: 0 }; }, + setScrollLeft: function () { }, + setScrollTop: function () { }, + clear: function () { } + }, NullScrollbars.prototype); + + CodeMirror.scrollbarModel = { "native": NativeScrollbars, "null": NullScrollbars }; + + function initScrollbars(cm) { + if (cm.display.scrollbars) { + cm.display.scrollbars.clear(); + if (cm.display.scrollbars.addClass) + rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function (node) { + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); + // Prevent clicks in the scrollbars from killing focus + on(node, "mousedown", function () { + if (cm.state.focused) setTimeout(function () { cm.display.input.focus(); }, 0); + }); + node.setAttribute("cm-not-content", "true"); + }, function (pos, axis) { + if (axis == "horizontal") setScrollLeft(cm, pos); + else setScrollTop(cm, pos); + }, cm); + if (cm.display.scrollbars.addClass) + addClass(cm.display.wrapper, cm.display.scrollbars.addClass); + } + + function updateScrollbars(cm, measure) { + if (!measure) measure = measureForScrollbars(cm); + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; + updateScrollbarsInner(cm, measure); + for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + if (startWidth != cm.display.barWidth && cm.options.lineWrapping) + updateHeightsInViewport(cm); + updateScrollbarsInner(cm, measureForScrollbars(cm)); + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; + } + } + + // Re-synchronize the fake scrollbars with the actual size of the + // content. + function updateScrollbarsInner(cm, measure) { + var d = cm.display; + var sizes = d.scrollbars.update(measure); + + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" + + if (sizes.right && sizes.bottom) { + d.scrollbarFiller.style.display = "block"; + d.scrollbarFiller.style.height = sizes.bottom + "px"; + d.scrollbarFiller.style.width = sizes.right + "px"; + } else d.scrollbarFiller.style.display = ""; + if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = sizes.bottom + "px"; + d.gutterFiller.style.width = measure.gutterWidth + "px"; + } else d.gutterFiller.style.display = ""; + } + + // Compute the lines that are visible in a given viewport (defaults + // the the current scroll position). viewport may contain top, + // height, and ensure (see op.scrollToPos) properties. + function visibleLines(display, doc, viewport) { + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; + top = Math.floor(top - paddingTop(display)); + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; + + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + // Ensure is a {from: {line, ch}, to: {line, ch}} object, and + // forces those lines into the viewport (if possible). + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; + if (ensureFrom < from) { + from = ensureFrom; + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); + } else if (Math.min(ensureTo, doc.lastLine()) >= to) { + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); + to = ensureTo; + } + } + return { from: from, to: Math.max(to, from + 1) }; + } + + // LINE NUMBERS + + // Re-align line numbers and gutter marks to compensate for + // horizontal scrolling. + function alignHorizontally(cm) { + var display = cm.display, view = display.view; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; + var gutterW = display.gutters.offsetWidth, left = comp + "px"; + for (var i = 0; i < view.length; i++) if (!view[i].hidden) { + if (cm.options.fixedGutter && view[i].gutter) + view[i].gutter.style.left = left; + var align = view[i].alignable; + if (align) for (var j = 0; j < align.length; j++) + align[j].style.left = left; + } + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; + } + + // Used to ensure that the line number gutter is still the right + // size for the current document size. Returns true when an update + // is needed. + function maybeUpdateLineNumberWidth(cm) { + if (!cm.options.lineNumbers) return false; + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + var documentZoom = getDocumentZoom(); + if (last.length != display.lineNumChars) { + var test = display.measure.appendChild(elt("div", [elt("div", last)], + "CodeMirror-linenumber CodeMirror-gutter-elt")); + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; + display.lineGutter.style.width = ""; + display.lineNumInnerWidth = (Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1) /* / documentZoom */; + display.lineNumWidth = (display.lineNumInnerWidth + padding) /* / documentZoom */; + display.lineNumChars = (display.lineNumInnerWidth ? last.length : -1) /* / documentZoom */; + display.lineGutter.style.width = display.lineNumWidth + "px"; + updateGutterSpace(cm); + return true; + } + return false; + } + + function lineNumberFor(options, i) { + return String(options.lineNumberFormatter(i + options.firstLineNumber)); + } + + // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, + // but using getBoundingClientRect to get a sub-pixel-accurate + // result. + function compensateForHScroll(display) { + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + } + + // DISPLAY DRAWING + + function DisplayUpdate(cm, viewport, force) { + var display = cm.display; + + this.viewport = viewport; + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport); + this.editorIsHidden = !display.wrapper.offsetWidth; + this.wrapperHeight = display.wrapper.clientHeight; + this.wrapperWidth = display.wrapper.clientWidth; + this.oldDisplayWidth = displayWidth(cm); + this.force = force; + this.dims = getDimensions(cm); + this.events = []; + } + + DisplayUpdate.prototype.signal = function (emitter, type) { + if (hasHandler(emitter, type)) + this.events.push(arguments); + }; + DisplayUpdate.prototype.finish = function () { + for (var i = 0; i < this.events.length; i++) + signal.apply(null, this.events[i]); + }; + + function maybeClipScrollbars(cm) { + var display = cm.display; + if (!display.scrollbarsClipped && display.scroller.offsetWidth) { + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; + display.heightForcer.style.height = scrollGap(cm) + "px"; + display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; + display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; + display.scrollbarsClipped = true; + } + } + + // Does the actual updating of the line display. Bails out + // (returning false) when there is nothing to be done and forced is + // false. + function updateDisplayIfNeeded(cm, update) { + var display = cm.display, doc = cm.doc; + + if (update.editorIsHidden) { + resetView(cm); + return false; + } + + // Bail out if the visible area is already rendered and nothing changed. + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && + display.renderedView == display.view && countDirtyView(cm) == 0) + return false; + + if (maybeUpdateLineNumberWidth(cm)) { + resetView(cm); + update.dims = getDimensions(cm); + } + + // Compute a suitable new viewport (from & to) + var end = doc.first + doc.size; + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, update.visible.to + cm.options.viewportMargin); + if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); + if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); + if (sawCollapsedSpans) { + from = visualLineNo(cm.doc, from); + to = visualLineEndNo(cm.doc, to); + } + + var different = from != display.viewFrom || to != display.viewTo || + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; + adjustView(cm, from, to); + + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + // Position the mover div to align with the current scroll position + cm.display.mover.style.top = display.viewOffset + "px"; + + var toUpdate = countDirtyView(cm); + if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && + (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) + return false; + + // For big changes, we hide the enclosing element during the + // update, since that speeds up the operations on most browsers. + var focused = activeElt(); + if (toUpdate > 4) display.lineDiv.style.display = "none"; + patchDisplay(cm, display.updateLineNumbers, update.dims); + if (toUpdate > 4) display.lineDiv.style.display = ""; + display.renderedView = display.view; + // There might have been a widget with a focused element that got + // hidden or updated, if so re-focus it. + if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); + + // Prevent selection and cursors from interfering with the scroll + // width and height. + removeChildren(display.cursorDiv); + removeChildren(display.selectionDiv); + display.gutters.style.height = display.sizer.style.minHeight = 0; + + if (different) { + display.lastWrapHeight = update.wrapperHeight; + display.lastWrapWidth = update.wrapperWidth; + startWorker(cm, 400); + } + + display.updateLineNumbers = null; + + return true; + } + + function postUpdateDisplay(cm, update) { + var viewport = update.viewport; + + for (var first = true; ; first = false) { + if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + viewport = { top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top) }; + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + update.visible = visibleLines(cm.display, cm.doc, viewport); + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) + break; + } + if (!updateDisplayIfNeeded(cm, update)) break; + updateHeightsInViewport(cm); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + updateScrollbars(cm, barMeasure); + setDocumentHeight(cm, barMeasure); + } + + update.signal(cm, "update", cm); + if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; + } + } + + function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport); + if (updateDisplayIfNeeded(cm, update)) { + updateHeightsInViewport(cm); + postUpdateDisplay(cm, update); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + updateScrollbars(cm, barMeasure); + setDocumentHeight(cm, barMeasure); + update.finish(); + } + } + + function setDocumentHeight(cm, measure) { + var documentZoom = getDocumentZoom(); + cm.display.sizer.style.minHeight = measure.docHeight / documentZoom + "px"; + cm.display.heightForcer.style.top = measure.docHeight / documentZoom + "px"; + cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) / documentZoom + "px"; + } + + // Read the actual heights of the rendered lines, and update their + // stored heights to match. + function updateHeightsInViewport(cm) { + var display = cm.display; + var prevBottom = display.lineDiv.offsetTop; + for (var i = 0; i < display.view.length; i++) { + var cur = display.view[i], height; + if (cur.hidden) continue; + if (ie && ie_version < 8) { + var bot = cur.node.offsetTop + cur.node.offsetHeight; + height = bot - prevBottom; + prevBottom = bot; + } else { + var box = cur.node.getBoundingClientRect(); + height = box.bottom - box.top; + } + var diff = cur.line.height - height; + if (height < 2) height = textHeight(display); + if (diff > .001 || diff < -.001) { + updateLineHeight(cur.line, height); + updateWidgetHeight(cur.line); + if (cur.rest) for (var j = 0; j < cur.rest.length; j++) + updateWidgetHeight(cur.rest[j]); + } + } + } + + // Read and store the height of line widgets associated with the + // given line. + function updateWidgetHeight(line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) + line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; + } + + // Do a bulk-read of the DOM positions and sizes needed to draw the + // view, so that we don't interleave reading and writing to the DOM. + function getDimensions(cm) { + var d = cm.display, left = {}, width = {}; + var gutterLeft = d.gutters.clientLeft; + for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; + width[cm.options.gutters[i]] = n.clientWidth; + } + return { + fixedPos: compensateForHScroll(d), + gutterTotalWidth: d.gutters.offsetWidth, + gutterLeft: left, + gutterWidth: width, + wrapperWidth: d.wrapper.clientWidth + }; + } + + // Sync the actual display DOM structure with display.view, removing + // nodes for lines that are no longer in view, and creating the ones + // that are not there yet, and updating the ones that are out of + // date. + function patchDisplay(cm, updateNumbersFrom, dims) { + var display = cm.display, lineNumbers = cm.options.lineNumbers; + var container = display.lineDiv, cur = container.firstChild; + + function rm(node) { + var next = node.nextSibling; + // Works around a throw-scroll bug in OS X Webkit + if (webkit && mac && cm.display.currentWheelTarget == node) + node.style.display = "none"; + else + node.parentNode.removeChild(node); + return next; + } + + var view = display.view, lineN = display.viewFrom; + // Loop over the elements in the view, syncing cur (the DOM nodes + // in display.lineDiv) with the view as we go. + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (lineView.hidden) { + } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet + var node = buildLineElement(cm, lineView, lineN, dims); + container.insertBefore(node, cur); + } else { // Already drawn + while (cur != lineView.node) cur = rm(cur); + var updateNumber = lineNumbers && updateNumbersFrom != null && + updateNumbersFrom <= lineN && lineView.lineNumber; + if (lineView.changes) { + if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; + updateLineForChanges(cm, lineView, lineN, dims); + } + if (updateNumber) { + removeChildren(lineView.lineNumber); + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + } + cur = lineView.node.nextSibling; + } + lineN += lineView.size; + } + while (cur) cur = rm(cur); + } + + // When an aspect of a line changes, a string is added to + // lineView.changes. This updates the relevant part of the line's + // DOM structure. + function updateLineForChanges(cm, lineView, lineN, dims) { + for (var j = 0; j < lineView.changes.length; j++) { + var type = lineView.changes[j]; + if (type == "text") updateLineText(cm, lineView); + else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); + else if (type == "class") updateLineClasses(lineView); + else if (type == "widget") updateLineWidgets(cm, lineView, dims); + } + lineView.changes = null; + } + + // Lines with gutter elements, widgets or a background class need to + // be wrapped, and have the extra elements added to the wrapper div + function ensureLineWrapped(lineView) { + if (lineView.node == lineView.text) { + lineView.node = elt("div", null, null, "position: relative"); + if (lineView.text.parentNode) + lineView.text.parentNode.replaceChild(lineView.node, lineView.text); + lineView.node.appendChild(lineView.text); + if (ie && ie_version < 8) lineView.node.style.zIndex = 2; + } + return lineView.node; + } + + function updateLineBackground(lineView) { + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; + if (cls) cls += " CodeMirror-linebackground"; + if (lineView.background) { + if (cls) lineView.background.className = cls; + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + } else if (cls) { + var wrap = ensureLineWrapped(lineView); + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + } + } + + // Wrapper around buildLineContent which will reuse the structure + // in display.externalMeasured when possible. + function getLineContent(cm, lineView) { + var ext = cm.display.externalMeasured; + if (ext && ext.line == lineView.line) { + cm.display.externalMeasured = null; + lineView.measure = ext.measure; + return ext.built; + } + return buildLineContent(cm, lineView); + } + + // Redraw the line's text. Interacts with the background and text + // classes because the mode may output tokens that influence these + // classes. + function updateLineText(cm, lineView) { + var cls = lineView.text.className; + var built = getLineContent(cm, lineView); + if (lineView.text == lineView.node) lineView.node = built.pre; + lineView.text.parentNode.replaceChild(built.pre, lineView.text); + lineView.text = built.pre; + if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { + lineView.bgClass = built.bgClass; + lineView.textClass = built.textClass; + updateLineClasses(lineView); + } else if (cls) { + lineView.text.className = cls; + } + } + + function updateLineClasses(lineView) { + updateLineBackground(lineView); + if (lineView.line.wrapClass) + ensureLineWrapped(lineView).className = lineView.line.wrapClass; + else if (lineView.node != lineView.text) + lineView.node.className = ""; + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; + lineView.text.className = textClass || ""; + } + + function updateLineGutter(cm, lineView, lineN, dims) { + if (lineView.gutter) { + lineView.node.removeChild(lineView.gutter); + lineView.gutter = null; + } + if (lineView.gutterBackground) { + lineView.node.removeChild(lineView.gutterBackground); + lineView.gutterBackground = null; + } + if (lineView.line.gutterClass) { + var wrap = ensureLineWrapped(lineView); + lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, + "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + + "px; width: " + dims.gutterTotalWidth + "px"); + wrap.insertBefore(lineView.gutterBackground, lineView.text); + } + var markers = lineView.line.gutterMarkers; + if (cm.options.lineNumbers || markers) { + var wrap = ensureLineWrapped(lineView); + var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"); + cm.display.input.setUneditable(gutterWrap); + wrap.insertBefore(gutterWrap, lineView.text); + if (lineView.line.gutterClass) + gutterWrap.className += " " + lineView.line.gutterClass; + if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) + lineView.lineNumber = gutterWrap.appendChild( + elt("div", lineNumberFor(cm.options, lineN), + "CodeMirror-linenumber CodeMirror-gutter-elt", + "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + + cm.display.lineNumInnerWidth + "px")); + if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + if (found) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] / + "px")); + } + } + } + + function updateLineWidgets(cm, lineView, dims) { + if (lineView.alignable) lineView.alignable = null; + for (var node = lineView.node.firstChild, next; node; node = next) { + var next = node.nextSibling; + if (node.className == "CodeMirror-linewidget") + lineView.node.removeChild(node); + } + insertLineWidgets(cm, lineView, dims); + } + + // Build a line's DOM representation from scratch + function buildLineElement(cm, lineView, lineN, dims) { + var built = getLineContent(cm, lineView); + lineView.text = lineView.node = built.pre; + if (built.bgClass) lineView.bgClass = built.bgClass; + if (built.textClass) lineView.textClass = built.textClass; + + updateLineClasses(lineView); + updateLineGutter(cm, lineView, lineN, dims); + insertLineWidgets(cm, lineView, dims); + return lineView.node; + } + + // A lineView may contain multiple logical lines (when merged by + // collapsed spans). The widgets for all of them need to be drawn. + function insertLineWidgets(cm, lineView, dims) { + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); + } + + function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { + if (!line.widgets) return; + var wrap = ensureLineWrapped(lineView); + for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); + if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); + positionLineWidget(widget, node, lineView, dims); + cm.display.input.setUneditable(node); + if (allowAbove && widget.above) + wrap.insertBefore(node, lineView.gutter || lineView.text); + else + wrap.appendChild(node); + signalLater(widget, "redraw"); + } + } + + function positionLineWidget(widget, node, lineView, dims) { + if (widget.noHScroll) { + (lineView.alignable || (lineView.alignable = [])).push(node); + var width = dims.wrapperWidth; + node.style.left = dims.fixedPos + "px"; + if (!widget.coverGutter) { + width -= dims.gutterTotalWidth; + node.style.paddingLeft = dims.gutterTotalWidth + "px"; + } + node.style.width = width + "px"; + } + if (widget.coverGutter) { + node.style.zIndex = 5; + node.style.position = "relative"; + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + } + } + + // POSITION OBJECT + + // A Pos instance represents a position within the text. + var Pos = CodeMirror.Pos = function (line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + }; + + // Compare two positions, return 0 if they are the same, a negative + // number when a is less, and a positive number otherwise. + var cmp = CodeMirror.cmpPos = function (a, b) { return a.line - b.line || a.ch - b.ch; }; + + function copyPos(x) { return Pos(x.line, x.ch); } + function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } + function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } + + // INPUT HANDLING + + function ensureFocus(cm) { + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + } + + // This will be set to a {lineWise: bool, text: [string]} object, so + // that, when pasting, we know what kind of selections the copied + // text was made out of. + var lastCopied = null; + + function applyTextInput(cm, inserted, deleted, sel, origin) { + var doc = cm.doc; + cm.display.shift = false; + if (!sel) sel = doc.sel; + + var paste = cm.state.pasteIncoming || origin == "paste"; + var textLines = doc.splitLines(inserted), multiPaste = null + // When pasing N lines into N selections, insert one line per selection + if (paste && sel.ranges.length > 1) { + if (lastCopied && lastCopied.text.join("\n") == inserted) { + if (sel.ranges.length % lastCopied.text.length == 0) { + multiPaste = []; + for (var i = 0; i < lastCopied.text.length; i++) + multiPaste.push(doc.splitLines(lastCopied.text[i])); + } + } else if (textLines.length == sel.ranges.length) { + multiPaste = map(textLines, function (l) { return [l]; }); + } + } + + // Normal behavior is to insert the new text into every selection + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + var from = range.from(), to = range.to(); + if (range.empty()) { + if (deleted && deleted > 0) // Handle deletion + from = Pos(from.line, from.ch - deleted); + else if (cm.state.overwrite && !paste) // Handle overwrite + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); + else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) + from = to = Pos(from.line, 0) + } + var updateInput = cm.curOp.updateInput; + var changeEvent = { + from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, + origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input") + }; + makeChange(cm.doc, changeEvent); + signalLater(cm, "inputRead", cm, changeEvent); + } + if (inserted && !paste) + triggerElectric(cm, inserted); + + ensureCursorVisible(cm); + cm.curOp.updateInput = updateInput; + cm.curOp.typing = true; + cm.state.pasteIncoming = cm.state.cutIncoming = false; + } + + function handlePaste(e, cm) { + var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); + if (pasted) { + e.preventDefault(); + if (!cm.isReadOnly() && !cm.options.disableInput) + runInOp(cm, function () { applyTextInput(cm, pasted, 0, null, "paste"); }); + return true; + } + } + + function triggerElectric(cm, inserted) { + // When an 'electric' character is inserted, immediately trigger a reindent + if (!cm.options.electricChars || !cm.options.smartIndent) return; + var sel = cm.doc.sel; + + for (var i = sel.ranges.length - 1; i >= 0; i--) { + var range = sel.ranges[i]; + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue; + var mode = cm.getModeAt(range.head); + var indented = false; + if (mode.electricChars) { + for (var j = 0; j < mode.electricChars.length; j++) + if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { + indented = indentLine(cm, range.head.line, "smart"); + break; + } + } else if (mode.electricInput) { + if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) + indented = indentLine(cm, range.head.line, "smart"); + } + if (indented) signalLater(cm, "electricInput", cm, range.head.line); + } + } + + function copyableRanges(cm) { + var text = [], ranges = []; + for (var i = 0; i < cm.doc.sel.ranges.length; i++) { + var line = cm.doc.sel.ranges[i].head.line; + var lineRange = { anchor: Pos(line, 0), head: Pos(line + 1, 0) }; + ranges.push(lineRange); + text.push(cm.getRange(lineRange.anchor, lineRange.head)); + } + return { text: text, ranges: ranges }; + } + + function disableBrowserMagic(field) { + field.setAttribute("autocorrect", "off"); + field.setAttribute("autocapitalize", "off"); + field.setAttribute("spellcheck", "false"); + } + + // TEXTAREA INPUT STYLE + + function TextareaInput(cm) { + this.cm = cm; + // See input.poll and input.reset + this.prevInput = ""; + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false; + // Self-resetting timeout for the poller + this.polling = new Delayed(); + // Tracks when input.reset has punted to just putting a short + // string into the textarea instead of the full selection. + this.inaccurateSelection = false; + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false; + this.composing = null; + }; + + function hiddenTextarea() { + var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none"); + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + // The textarea is kept positioned near the cursor to prevent the + // fact that it'll be scrolled into view on input from scrolling + // our fake cursor out of view. On webkit, when wrap=off, paste is + // very slow. So make the area wide instead. + if (webkit) te.style.width = "1000px"; + else te.setAttribute("wrap", "off"); + // If border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) te.style.border = "1px solid black"; + disableBrowserMagic(te); + return div; + } + + TextareaInput.prototype = copyObj({ + init: function (display) { + var input = this, cm = this.cm; + + // Wraps and hides input textarea + var div = this.wrapper = hiddenTextarea(); + // The semihidden textarea that is focused when the editor is + // focused, and receives input. + var te = this.textarea = div.firstChild; + display.wrapper.insertBefore(div, display.wrapper.firstChild); + + // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) + if (ios) te.style.width = "0px"; + + on(te, "input", function () { + if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; + input.poll(); + }); + + on(te, "paste", function (e) { + if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return + + cm.state.pasteIncoming = true; + input.fastPoll(); + }); + + function prepareCopyCut(e) { + if (signalDOMEvent(cm, e)) return + if (cm.somethingSelected()) { + lastCopied = { lineWise: false, text: cm.getSelections() }; + if (input.inaccurateSelection) { + input.prevInput = ""; + input.inaccurateSelection = false; + te.value = lastCopied.text.join("\n"); + selectInput(te); + } + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = { lineWise: true, text: ranges.text }; + if (e.type == "cut") { + cm.setSelections(ranges.ranges, null, sel_dontScroll); + } else { + input.prevInput = ""; + te.value = ranges.text.join("\n"); + selectInput(te); + } + } + if (e.type == "cut") cm.state.cutIncoming = true; + } + on(te, "cut", prepareCopyCut); + on(te, "copy", prepareCopyCut); + + on(display.scroller, "paste", function (e) { + if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return; + cm.state.pasteIncoming = true; + input.focus(); + }); + + // Prevent normal selection in the editor (we handle our own) + on(display.lineSpace, "selectstart", function (e) { + if (!eventInWidget(display, e)) e_preventDefault(e); + }); + + on(te, "compositionstart", function () { + var start = cm.getCursor("from"); + if (input.composing) input.composing.range.clear() + input.composing = { + start: start, + range: cm.markText(start, cm.getCursor("to"), { className: "CodeMirror-composing" }) + }; + }); + on(te, "compositionend", function () { + if (input.composing) { + input.poll(); + input.composing.range.clear(); + input.composing = null; + } + }); + }, + + prepareSelection: function () { + // Redraw the selection and/or cursor + var cm = this.cm, display = cm.display, doc = cm.doc; + var result = prepareSelection(cm); + + // Move the hidden textarea near the cursor to prevent scrolling artifacts + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)); + result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)); + } + + return result; + }, + + showSelection: function (drawn) { + var cm = this.cm, display = cm.display; + removeChildrenAndAdd(display.cursorDiv, drawn.cursors); + removeChildrenAndAdd(display.selectionDiv, drawn.selection); + if (drawn.teTop != null) { + this.wrapper.style.top = drawn.teTop + "px"; + this.wrapper.style.left = drawn.teLeft + "px"; + } + }, + + // Reset the input to correspond to the selection (or to be empty, + // when not typing and nothing is selected) + reset: function (typing) { + if (this.contextMenuPending) return; + var minimal, selected, cm = this.cm, doc = cm.doc; + if (cm.somethingSelected()) { + this.prevInput = ""; + var range = doc.sel.primary(); + minimal = hasCopyEvent && + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); + var content = minimal ? "-" : selected || cm.getSelection(); + this.textarea.value = content; + if (cm.state.focused) selectInput(this.textarea); + if (ie && ie_version >= 9) this.hasSelection = content; + } else if (!typing) { + this.prevInput = this.textarea.value = ""; + if (ie && ie_version >= 9) this.hasSelection = null; + } + this.inaccurateSelection = minimal; + }, + + getField: function () { return this.textarea; }, + + supportsTouch: function () { return false; }, + + focus: function () { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { + try { this.textarea.focus(); } + catch (e) { } // IE8 will throw if the textarea is display: none or not in DOM + } + }, + + blur: function () { this.textarea.blur(); }, + + resetPosition: function () { + this.wrapper.style.top = this.wrapper.style.left = 0; + }, + + receivedFocus: function () { this.slowPoll(); }, + + // Poll for input changes, using the normal rate of polling. This + // runs as long as the editor is focused. + slowPoll: function () { + var input = this; + if (input.pollingFast) return; + input.polling.set(this.cm.options.pollInterval, function () { + input.poll(); + if (input.cm.state.focused) input.slowPoll(); + }); + }, + + // When an event has just come in that is likely to add or change + // something in the input textarea, we poll faster, to ensure that + // the change appears on the screen quickly. + fastPoll: function () { + var missed = false, input = this; + input.pollingFast = true; + function p() { + var changed = input.poll(); + if (!changed && !missed) { missed = true; input.polling.set(60, p); } + else { input.pollingFast = false; input.slowPoll(); } + } + input.polling.set(20, p); + }, + + // Read input from the textarea, and update the document to match. + // When something is selected, it is present in the textarea, and + // selected (unless it is huge, in which case a placeholder is + // used). When nothing is selected, the cursor sits after previously + // seen text (can be empty), which is stored in prevInput (we must + // not reset the textarea when typing, because that breaks IME). + poll: function () { + var cm = this.cm, input = this.textarea, prevInput = this.prevInput; + // Since this is called a *lot*, try to bail out as cheaply as + // possible when it is clear that nothing happened. hasSelection + // will be the case when there is a lot of text in the textarea, + // in which case reading its value would be expensive. + if (this.contextMenuPending || !cm.state.focused || + (hasSelection(input) && !prevInput && !this.composing) || + cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) + return false; + + var text = input.value; + // If nothing changed, bail. + if (text == prevInput && !cm.somethingSelected()) return false; + // Work around nonsensical selection resetting in IE9/10, and + // inexplicable appearance of private area unicode characters on + // some key combos in Mac (#2689). + if (ie && ie_version >= 9 && this.hasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { + cm.display.input.reset(); + return false; + } + + if (cm.doc.sel == cm.display.selForContextMenu) { + var first = text.charCodeAt(0); + if (first == 0x200b && !prevInput) prevInput = "\u200b"; + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } + } + // Find the part of the input that is actually new + var same = 0, l = Math.min(prevInput.length, text.length); + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + + var self = this; + runInOp(cm, function () { + applyTextInput(cm, text.slice(same), prevInput.length - same, + null, self.composing ? "*compose" : null); + + // Don't leave long text in the textarea, since it makes further polling slow + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; + else self.prevInput = text; + + if (self.composing) { + self.composing.range.clear(); + self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), + { className: "CodeMirror-composing" }); + } + }); + return true; + }, + + ensurePolled: function () { + if (this.pollingFast && this.poll()) this.pollingFast = false; + }, + + onKeyPress: function () { + if (ie && ie_version >= 9) this.hasSelection = null; + this.fastPoll(); + }, + + onContextMenu: function (e) { + var input = this, cm = input.cm, display = cm.display, te = input.textarea; + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; + if (!pos || presto) return; // Opera is difficult. + + // Reset the current text selection only if the click is done outside of the selection + // and 'resetSelectionOnContextMenu' option is true. + var reset = cm.options.resetSelectionOnContextMenu; + if (reset && cm.doc.sel.contains(pos) == -1) + operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); + + var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; + input.wrapper.style.cssText = "position: absolute" + var wrapperBox = input.wrapper.getBoundingClientRect() + te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) + display.input.focus(); + if (webkit) window.scrollTo(null, oldScrollY); + display.input.reset(); + // Adds "Select all" to context menu in FF + if (!cm.somethingSelected()) te.value = input.prevInput = " "; + input.contextMenuPending = true; + display.selForContextMenu = cm.doc.sel; + clearTimeout(display.detectingSelectAll); + + // Select-all will be greyed out if there's nothing to select, so + // this adds a zero-width space so that we can later check whether + // it got selected. + function prepareSelectAllHack() { + if (te.selectionStart != null) { + var selected = cm.somethingSelected(); + var extval = "\u200b" + (selected ? te.value : ""); + te.value = "\u21da"; // Used to catch context-menu undo + te.value = extval; + input.prevInput = selected ? "" : "\u200b"; + te.selectionStart = 1; te.selectionEnd = extval.length; + // Re-set this, in case some other handler touched the + // selection in the meantime. + display.selForContextMenu = cm.doc.sel; + } + } + function rehide() { + input.contextMenuPending = false; + input.wrapper.style.cssText = oldWrapperCSS + te.style.cssText = oldCSS; + if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); + + // Try to detect the user choosing select-all + if (te.selectionStart != null) { + if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); + var i = 0, poll = function () { + if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && + te.selectionEnd > 0 && input.prevInput == "\u200b") + operation(cm, commands.selectAll)(cm); + else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); + else display.input.reset(); + }; + display.detectingSelectAll = setTimeout(poll, 200); + } + } + + if (ie && ie_version >= 9) prepareSelectAllHack(); + if (captureRightClick) { + e_stop(e); + var mouseup = function () { + off(window, "mouseup", mouseup); + setTimeout(rehide, 20); + }; + on(window, "mouseup", mouseup); + } else { + setTimeout(rehide, 50); + } + }, + + readOnlyChanged: function (val) { + if (!val) this.reset(); + }, + + setUneditable: nothing, + + needsContentAttribute: false + }, TextareaInput.prototype); + + // CONTENTEDITABLE INPUT STYLE + + function ContentEditableInput(cm) { + this.cm = cm; + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; + this.polling = new Delayed(); + this.gracePeriod = false; + } + + ContentEditableInput.prototype = copyObj({ + init: function (display) { + var input = this, cm = input.cm; + var div = input.div = display.lineDiv; + disableBrowserMagic(div); + + on(div, "paste", function (e) { + if (!signalDOMEvent(cm, e)) handlePaste(e, cm); + }) + + on(div, "compositionstart", function (e) { + var data = e.data; + input.composing = { sel: cm.doc.sel, data: data, startData: data }; + if (!data) return; + var prim = cm.doc.sel.primary(); + var line = cm.getLine(prim.head.line); + var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); + if (found > -1 && found <= prim.head.ch) + input.composing.sel = simpleSelection(Pos(prim.head.line, found), + Pos(prim.head.line, found + data.length)); + }); + on(div, "compositionupdate", function (e) { + input.composing.data = e.data; + }); + on(div, "compositionend", function (e) { + var ours = input.composing; + if (!ours) return; + if (e.data != ours.startData && !/\u200b/.test(e.data)) + ours.data = e.data; + // Need a small delay to prevent other code (input event, + // selection polling) from doing damage when fired right after + // compositionend. + setTimeout(function () { + if (!ours.handled) + input.applyComposition(ours); + if (input.composing == ours) + input.composing = null; + }, 50); + }); + + on(div, "touchstart", function () { + input.forceCompositionEnd(); + }); + + on(div, "input", function () { + if (input.composing) return; + if (cm.isReadOnly() || !input.pollContent()) + runInOp(input.cm, function () { regChange(cm); }); + }); + + function onCopyCut(e) { + if (signalDOMEvent(cm, e)) return + if (cm.somethingSelected()) { + lastCopied = { lineWise: false, text: cm.getSelections() }; + if (e.type == "cut") cm.replaceSelection("", null, "cut"); + } else if (!cm.options.lineWiseCopyCut) { + return; + } else { + var ranges = copyableRanges(cm); + lastCopied = { lineWise: true, text: ranges.text }; + if (e.type == "cut") { + cm.operation(function () { + cm.setSelections(ranges.ranges, 0, sel_dontScroll); + cm.replaceSelection("", null, "cut"); + }); + } + } + // iOS exposes the clipboard API, but seems to discard content inserted into it + if (e.clipboardData && !ios) { + e.preventDefault(); + e.clipboardData.clearData(); + e.clipboardData.setData("text/plain", lastCopied.text.join("\n")); + } else { + // Old-fashioned briefly-focus-a-textarea hack + var kludge = hiddenTextarea(), te = kludge.firstChild; + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); + te.value = lastCopied.text.join("\n"); + var hadFocus = document.activeElement; + selectInput(te); + setTimeout(function () { + cm.display.lineSpace.removeChild(kludge); + hadFocus.focus(); + }, 50); + } + } + on(div, "copy", onCopyCut); + on(div, "cut", onCopyCut); + }, + + prepareSelection: function () { + var result = prepareSelection(this.cm, false); + result.focus = this.cm.state.focused; + return result; + }, + + showSelection: function (info, takeFocus) { + if (!info || !this.cm.display.view.length) return; + if (info.focus || takeFocus) this.showPrimarySelection(); + this.showMultipleSelections(info); + }, + + showPrimarySelection: function () { + var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); + var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); + var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); + if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && + cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && + cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) + return; + + var start = posToDOM(this.cm, prim.from()); + var end = posToDOM(this.cm, prim.to()); + if (!start && !end) return; + + var view = this.cm.display.view; + var old = sel.rangeCount && sel.getRangeAt(0); + if (!start) { + start = { node: view[0].measure.map[2], offset: 0 }; + } else if (!end) { // FIXME dangerously hacky + var measure = view[view.length - 1].measure; + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; + end = { node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3] }; + } + + try { var rng = range(start.node, start.offset, end.offset, end.node); } + catch (e) { } // Our model of the DOM might be outdated, in which case the range we try to set can be impossible + if (rng) { + if (!gecko && this.cm.state.focused) { + sel.collapse(start.node, start.offset); + if (!rng.collapsed) sel.addRange(rng); + } else { + sel.removeAllRanges(); + sel.addRange(rng); + } + if (old && sel.anchorNode == null) sel.addRange(old); + else if (gecko) this.startGracePeriod(); + } + this.rememberSelection(); + }, + + startGracePeriod: function () { + var input = this; + clearTimeout(this.gracePeriod); + this.gracePeriod = setTimeout(function () { + input.gracePeriod = false; + if (input.selectionChanged()) + input.cm.operation(function () { input.cm.curOp.selectionChanged = true; }); + }, 20); + }, + + showMultipleSelections: function (info) { + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); + }, + + rememberSelection: function () { + var sel = window.getSelection(); + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; + }, + + selectionInEditor: function () { + var sel = window.getSelection(); + if (!sel.rangeCount) return false; + var node = sel.getRangeAt(0).commonAncestorContainer; + return contains(this.div, node); + }, + + focus: function () { + if (this.cm.options.readOnly != "nocursor") this.div.focus(); + }, + blur: function () { this.div.blur(); }, + getField: function () { return this.div; }, + + supportsTouch: function () { return true; }, + + receivedFocus: function () { + var input = this; + if (this.selectionInEditor()) + this.pollSelection(); + else + runInOp(this.cm, function () { input.cm.curOp.selectionChanged = true; }); + + function poll() { + if (input.cm.state.focused) { + input.pollSelection(); + input.polling.set(input.cm.options.pollInterval, poll); + } + } + this.polling.set(this.cm.options.pollInterval, poll); + }, + + selectionChanged: function () { + var sel = window.getSelection(); + return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; + }, + + pollSelection: function () { + if (!this.composing && !this.gracePeriod && this.selectionChanged()) { + var sel = window.getSelection(), cm = this.cm; + this.rememberSelection(); + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); + var head = domToPos(cm, sel.focusNode, sel.focusOffset); + if (anchor && head) runInOp(cm, function () { + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); + if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; + }); + } + }, + + pollContent: function () { + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); + var from = sel.from(), to = sel.to(); + if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; + + var fromIndex; + if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { + var fromLine = lineNo(display.view[0].line); + var fromNode = display.view[0].node; + } else { + var fromLine = lineNo(display.view[fromIndex].line); + var fromNode = display.view[fromIndex - 1].node.nextSibling; + } + var toIndex = findViewIndex(cm, to.line); + if (toIndex == display.view.length - 1) { + var toLine = display.viewTo - 1; + var toNode = display.lineDiv.lastChild; + } else { + var toLine = lineNo(display.view[toIndex + 1].line) - 1; + var toNode = display.view[toIndex + 1].node.previousSibling; + } + + var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); + while (newText.length > 1 && oldText.length > 1) { + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } + else break; + } + + var cutFront = 0, cutEnd = 0; + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); + while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) + ++cutFront; + var newBot = lst(newText), oldBot = lst(oldText); + var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + oldBot.length - (oldText.length == 1 ? cutFront : 0)); + while (cutEnd < maxCutEnd && + newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) + ++cutEnd; + + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); + newText[0] = newText[0].slice(cutFront); + + var chFrom = Pos(fromLine, cutFront); + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); + if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { + replaceRange(cm.doc, newText, chFrom, chTo, "+input"); + return true; + } + }, + + ensurePolled: function () { + this.forceCompositionEnd(); + }, + reset: function () { + this.forceCompositionEnd(); + }, + forceCompositionEnd: function () { + if (!this.composing || this.composing.handled) return; + this.applyComposition(this.composing); + this.composing.handled = true; + this.div.blur(); + this.div.focus(); + }, + applyComposition: function (composing) { + if (this.cm.isReadOnly()) + operation(this.cm, regChange)(this.cm) + else if (composing.data && composing.data != composing.startData) + operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); + }, + + setUneditable: function (node) { + node.contentEditable = "false" + }, + + onKeyPress: function (e) { + e.preventDefault(); + if (!this.cm.isReadOnly()) + operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + }, + + readOnlyChanged: function (val) { + this.div.contentEditable = String(val != "nocursor") + }, + + onContextMenu: nothing, + resetPosition: nothing, + + needsContentAttribute: true + }, ContentEditableInput.prototype); + + function posToDOM(cm, pos) { + var view = findViewForLine(cm, pos.line); + if (!view || view.hidden) return null; + var line = getLine(cm.doc, pos.line); + var info = mapFromLineView(view, line, pos.line); + + var order = getOrder(line), side = "left"; + if (order) { + var partPos = getBidiPartAt(order, pos.ch); + side = partPos % 2 ? "right" : "left"; + } + var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); + result.offset = result.collapse == "right" ? result.end : result.start; + return result; + } + + function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } + + function domToPos(cm, node, offset) { + var lineNode; + if (node == cm.display.lineDiv) { + lineNode = cm.display.lineDiv.childNodes[offset]; + if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); + node = null; offset = 0; + } else { + for (lineNode = node; ; lineNode = lineNode.parentNode) { + if (!lineNode || lineNode == cm.display.lineDiv) return null; + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; + } + } + for (var i = 0; i < cm.display.view.length; i++) { + var lineView = cm.display.view[i]; + if (lineView.node == lineNode) + return locateNodeInLineView(lineView, node, offset); + } + } + + function locateNodeInLineView(lineView, node, offset) { + var wrapper = lineView.text.firstChild, bad = false; + if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); + if (node == wrapper) { + bad = true; + node = wrapper.childNodes[offset]; + offset = 0; + if (!node) { + var line = lineView.rest ? lst(lineView.rest) : lineView.line; + return badPos(Pos(lineNo(line), line.text.length), bad); + } + } + + var textNode = node.nodeType == 3 ? node : null, topNode = node; + if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { + textNode = node.firstChild; + if (offset) offset = textNode.nodeValue.length; + } + while (topNode.parentNode != wrapper) topNode = topNode.parentNode; + var measure = lineView.measure, maps = measure.maps; + + function find(textNode, topNode, offset) { + for (var i = -1; i < (maps ? maps.length : 0); i++) { + var map = i < 0 ? measure.map : maps[i]; + for (var j = 0; j < map.length; j += 3) { + var curNode = map[j + 2]; + if (curNode == textNode || curNode == topNode) { + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); + var ch = map[j] + offset; + if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; + return Pos(line, ch); + } + } + } + } + var found = find(textNode, topNode, offset); + if (found) return badPos(found, bad); + + // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems + for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + found = find(after, after.firstChild, 0); + if (found) + return badPos(Pos(found.line, found.ch - dist), bad); + else + dist += after.textContent.length; + } + for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { + found = find(before, before.firstChild, -1); + if (found) + return badPos(Pos(found.line, found.ch + dist), bad); + else + dist += after.textContent.length; + } + } + + function domTextBetween(cm, from, to, fromLine, toLine) { + var text = "", closing = false, lineSep = cm.doc.lineSeparator(); + function recognizeMarker(id) { return function (marker) { return marker.id == id; }; } + function walk(node) { + if (node.nodeType == 1) { + var cmText = node.getAttribute("cm-text"); + if (cmText != null) { + if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); + text += cmText; + return; + } + var markerID = node.getAttribute("cm-marker"), range; + if (markerID) { + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); + if (found.length && (range = found[0].find())) + text += getBetween(cm.doc, range.from, range.to).join(lineSep); + return; + } + if (node.getAttribute("contenteditable") == "false") return; + for (var i = 0; i < node.childNodes.length; i++) + walk(node.childNodes[i]); + if (/^(pre|div|p)$/i.test(node.nodeName)) + closing = true; + } else if (node.nodeType == 3) { + var val = node.nodeValue; + if (!val) return; + if (closing) { + text += lineSep; + closing = false; + } + text += val; + } + } + for (; ;) { + walk(from); + if (from == to) break; + from = from.nextSibling; + } + return text; + } + + CodeMirror.inputStyles = { "textarea": TextareaInput, "contenteditable": ContentEditableInput }; + + // SELECTION / CURSOR + + // Selection objects are immutable. A new one is created every time + // the selection changes. A selection is one or more non-overlapping + // (and non-touching) ranges, sorted, and an integer that indicates + // which one is the primary selection (the one that's scrolled into + // view, that getCursor returns, etc). + function Selection(ranges, primIndex) { + this.ranges = ranges; + this.primIndex = primIndex; + } + + Selection.prototype = { + primary: function () { return this.ranges[this.primIndex]; }, + equals: function (other) { + if (other == this) return true; + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; + for (var i = 0; i < this.ranges.length; i++) { + var here = this.ranges[i], there = other.ranges[i]; + if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; + } + return true; + }, + deepCopy: function () { + for (var out = [], i = 0; i < this.ranges.length; i++) + out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); + return new Selection(out, this.primIndex); + }, + somethingSelected: function () { + for (var i = 0; i < this.ranges.length; i++) + if (!this.ranges[i].empty()) return true; + return false; + }, + contains: function (pos, end) { + if (!end) end = pos; + for (var i = 0; i < this.ranges.length; i++) { + var range = this.ranges[i]; + if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) + return i; + } + return -1; + } + }; + + function Range(anchor, head) { + this.anchor = anchor; this.head = head; + } + + Range.prototype = { + from: function () { return minPos(this.anchor, this.head); }, + to: function () { return maxPos(this.anchor, this.head); }, + empty: function () { + return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; + } + }; + + // Take an unsorted, potentially overlapping set of ranges, and + // build a selection out of it. 'Consumes' ranges array (modifying + // it). + function normalizeSelection(ranges, primIndex) { + var prim = ranges[primIndex]; + ranges.sort(function (a, b) { return cmp(a.from(), b.from()); }); + primIndex = indexOf(ranges, prim); + for (var i = 1; i < ranges.length; i++) { + var cur = ranges[i], prev = ranges[i - 1]; + if (cmp(prev.to(), cur.from()) >= 0) { + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; + if (i <= primIndex) --primIndex; + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + } + } + return new Selection(ranges, primIndex); + } + + function simpleSelection(anchor, head) { + return new Selection([new Range(anchor, head || anchor)], 0); + } + + // Most of the external API clips given positions to make sure they + // actually exist within the document. + function clipLine(doc, n) { return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1)); } + function clipPos(doc, pos) { + if (pos.line < doc.first) return Pos(doc.first, 0); + var last = doc.first + doc.size - 1; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); + return clipToLen(pos, getLine(doc, pos.line).text.length); + } + function clipToLen(pos, linelen) { + var ch = pos.ch; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); + else return pos; + } + function isLine(doc, l) { return l >= doc.first && l < doc.first + doc.size; } + function clipPosArray(doc, array) { + for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); + return out; + } + + // SELECTION UPDATES + + // The 'scroll' parameter given to many of these indicated whether + // the new cursor position should be scrolled into view after + // modifying the selection. + + // If shift is held or the extend flag is set, extends a range to + // include a given position (and optionally a second position). + // Otherwise, simply returns the range between the given positions. + // Used for cursor motion and such. + function extendRange(doc, range, head, other) { + if (doc.cm && doc.cm.display.shift || doc.extend) { + var anchor = range.anchor; + if (other) { + var posBefore = cmp(head, anchor) < 0; + if (posBefore != (cmp(other, anchor) < 0)) { + anchor = head; + head = other; + } else if (posBefore != (cmp(head, other) < 0)) { + head = other; + } + } + return new Range(anchor, head); + } else { + return new Range(other || head, head); + } + } + + // Extend the primary selection range, discard the rest. + function extendSelection(doc, head, other, options) { + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); + } + + // Extend all selections (pos is an array of selections with length + // equal the number of selections) + function extendSelections(doc, heads, options) { + for (var out = [], i = 0; i < doc.sel.ranges.length; i++) + out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); + var newSel = normalizeSelection(out, doc.sel.primIndex); + setSelection(doc, newSel, options); + } + + // Updates a single range in the selection. + function replaceOneSelection(doc, i, range, options) { + var ranges = doc.sel.ranges.slice(0); + ranges[i] = range; + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); + } + + // Reset the selection to a single range. + function setSimpleSelection(doc, anchor, head, options) { + setSelection(doc, simpleSelection(anchor, head), options); + } + + // Give beforeSelectionChange handlers a change to influence a + // selection update. + function filterSelectionChange(doc, sel, options) { + var obj = { + ranges: sel.ranges, + update: function (ranges) { + this.ranges = []; + for (var i = 0; i < ranges.length; i++) + this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), + clipPos(doc, ranges[i].head)); + }, + origin: options && options.origin + }; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); + else return sel; + } + + function setSelectionReplaceHistory(doc, sel, options) { + var done = doc.history.done, last = lst(done); + if (last && last.ranges) { + done[done.length - 1] = sel; + setSelectionNoUndo(doc, sel, options); + } else { + setSelection(doc, sel, options); + } + } + + // Set a new selection. + function setSelection(doc, sel, options) { + setSelectionNoUndo(doc, sel, options); + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + } + + function setSelectionNoUndo(doc, sel, options) { + if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) + sel = filterSelectionChange(doc, sel, options); + + var bias = options && options.bias || + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + + if (!(options && options.scroll === false) && doc.cm) + ensureCursorVisible(doc.cm); + } + + function setSelectionInner(doc, sel) { + if (sel.equals(doc.sel)) return; + + doc.sel = sel; + + if (doc.cm) { + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; + signalCursorActivity(doc.cm); + } + signalLater(doc, "cursorActivity", doc); + } + + // Verify that the selection does not partially select any atomic + // marked ranges. + function reCheckSelection(doc) { + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); + } + + // Return a selection that does not partially select any atomic + // ranges. + function skipAtomicInSelection(doc, sel, bias, mayClear) { + var out; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; + var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); + var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); + if (out || newAnchor != range.anchor || newHead != range.head) { + if (!out) out = sel.ranges.slice(0, i); + out[i] = new Range(newAnchor, newHead); + } + } + return out ? normalizeSelection(out, sel.primIndex) : sel; + } + + function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { + var line = getLine(doc, pos.line); + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var sp = line.markedSpans[i], m = sp.marker; + if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && + (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else { --i; continue; } + } + } + if (!m.atomic) continue; + + if (oldPos) { + var near = m.find(dir < 0 ? 1 : -1), diff; + if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) + near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); + if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) + return skipAtomicInner(doc, near, pos, dir, mayClear); + } + + var far = m.find(dir < 0 ? -1 : 1); + if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) + far = movePos(doc, far, dir, far.line == pos.line ? line : null); + return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null; + } + } + return pos; + } + + // Ensure a given position is not inside an atomic range. + function skipAtomic(doc, pos, oldPos, bias, mayClear) { + var dir = bias || 1; + var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || + skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || + (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)); + if (!found) { + doc.cantEdit = true; + return Pos(doc.first, 0); + } + return found; + } + + function movePos(doc, pos, dir, line) { + if (dir < 0 && pos.ch == 0) { + if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1)); + else return null; + } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { + if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0); + else return null; + } else { + return new Pos(pos.line, pos.ch + dir); + } + } + + // SELECTION DRAWING + + function updateSelection(cm) { + cm.display.input.showSelection(cm.display.input.prepareSelection()); + } + + function prepareSelection(cm, primary) { + var doc = cm.doc, result = {}; + var curFragment = result.cursors = document.createDocumentFragment(); + var selFragment = result.selection = document.createDocumentFragment(); + + for (var i = 0; i < doc.sel.ranges.length; i++) { + if (primary === false && i == doc.sel.primIndex) continue; + var range = doc.sel.ranges[i]; + if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue; + var collapsed = range.empty(); + if (collapsed || cm.options.showCursorWhenSelecting) + drawSelectionCursor(cm, range.head, curFragment); + if (!collapsed) + drawSelectionRange(cm, range, selFragment); + } + return result; + } + + // Draws a cursor for the given range + function drawSelectionCursor(cm, head, output) { + var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); + + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); + + var documentZoom = getDocumentZoom(); + + cursor.style.left = pos.left / documentZoom + "px"; + cursor.style.top = pos.top / documentZoom + "px"; + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight / documentZoom + "px"; + + if (pos.other) { + // Secondary cursor, shown when on a 'jump' in bi-directional text + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); + otherCursor.style.display = ""; + otherCursor.style.left = pos.other.left / documentZoom + "px"; + otherCursor.style.top = pos.other.top / documentZoom + "px"; + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 / documentZoom + "px"; + } + } + + // Draws the given range as a highlighted selection + function drawSelectionRange(cm, range, output) { + var display = cm.display, doc = cm.doc; + var fragment = document.createDocumentFragment(); + var padding = paddingH(cm.display), leftSide = padding.left; + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; + + function add(left, top, width, bottom) { + if (top < 0) top = 0; + top = Math.round(top); + bottom = Math.round(bottom); + + var documentZoom = getDocumentZoom(); + + fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left / documentZoom + + "px; top: " + top / documentZoom + "px; width: " + (width == null ? rightSide - left : width) / documentZoom + + "px; height: " + (bottom - top) / documentZoom + "px")); + } + + function drawForLine(line, fromArg, toArg) { + var lineObj = getLine(doc, line); + var lineLen = lineObj.text.length; + var start, end; + function coords(ch, bias) { + return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + } + + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) { + var leftPos = coords(from, "left"), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1, "right"); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } + if (fromArg == null && from == 0) left = leftSide; + if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part + add(left, leftPos.top, null, leftPos.bottom); + left = leftSide; + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + } + if (toArg == null && to == lineLen) right = rightSide; + if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) + start = leftPos; + if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) + end = rightPos; + if (left < leftSide + 1) left = leftSide; + add(left, rightPos.top, right - left, rightPos.bottom); + }); + return { start: start, end: end }; + } + + var sFrom = range.from(), sTo = range.to(); + if (sFrom.line == sTo.line) { + drawForLine(sFrom.line, sFrom.ch, sTo.ch); + } else { + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); + var singleVLine = visualLine(fromLine) == visualLine(toLine); + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + if (singleVLine) { + if (leftEnd.top < rightStart.top - 2) { + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + } else { + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + } + } + if (leftEnd.bottom < rightStart.top) + add(leftSide, leftEnd.bottom, null, rightStart.top); + } + + output.appendChild(fragment); + } + + // Cursor-blinking + function restartBlink(cm) { + if (!cm.state.focused) return; + var display = cm.display; + clearInterval(display.blinker); + var on = true; + display.cursorDiv.style.visibility = ""; + if (cm.options.cursorBlinkRate > 0) + display.blinker = setInterval(function () { + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); + else if (cm.options.cursorBlinkRate < 0) + display.cursorDiv.style.visibility = "hidden"; + } + + // HIGHLIGHT WORKER + + function startWorker(cm, time) { + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); + } + + function highlightWorker(cm) { + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.viewTo) return; + var end = +new Date + cm.options.workTime; + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); + var changedLines = []; + + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) { + if (doc.frontier >= cm.display.viewFrom) { // Visible + var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength; + var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true); + line.styles = highlighted.styles; + var oldCls = line.styleClasses, newCls = highlighted.classes; + if (newCls) line.styleClasses = newCls; + else if (oldCls) line.styleClasses = null; + var ischange = !oldStyles || oldStyles.length != line.styles.length || + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; + if (ischange) changedLines.push(doc.frontier); + line.stateAfter = tooLong ? state : copyState(doc.mode, state); + } else { + if (line.text.length <= cm.options.maxHighlightLength) + processLine(cm, line.text, state); + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + } + ++doc.frontier; + if (+new Date > end) { + startWorker(cm, cm.options.workDelay); + return true; + } + }); + if (changedLines.length) runInOp(cm, function () { + for (var i = 0; i < changedLines.length; i++) + regLineChange(cm, changedLines[i], "text"); + }); + } + + // Finds the line to start with when starting a parse. Tries to + // find a line with a stateAfter, so that it can start with a + // valid state. If that fails, it returns the line with the + // smallest indentation, which tends to need the least context to + // parse correctly. + function findStartLine(cm, n, precise) { + var minindent, minline, doc = cm.doc; + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + for (var search = n; search > lim; --search) { + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); + if (line.stateAfter && (!precise || search <= doc.frontier)) return search; + var indented = countColumn(line.text, null, cm.options.tabSize); + if (minline == null || minindent > indented) { + minline = search - 1; + minindent = indented; + } + } + return minline; + } + + function getStateBefore(cm, n, precise) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos - 1).stateAfter; + if (!state) state = startState(doc.mode); + else state = copyState(doc.mode, state); + doc.iter(pos, n, function (line) { + processLine(cm, line.text, state); + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; + ++pos; + }); + if (precise) doc.frontier = pos; + return state; + } + + // POSITION MEASUREMENT + + function paddingTop(display) { return display.lineSpace.offsetTop; } + function paddingVert(display) { return display.mover.offsetHeight - display.lineSpace.offsetHeight; } + function paddingH(display) { + if (display.cachedPaddingH) return display.cachedPaddingH; + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + var data = { left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight) }; + if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; + return data; + } + + function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } + function displayWidth(cm) { + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; + } + function displayHeight(cm) { + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; + } + + // Ensure the lineView.wrapping.heights array is populated. This is + // an array of bottom offsets for the lines that make up a drawn + // line. When lineWrapping is on, there might be more than one + // height. + function ensureLineHeights(cm, lineView, rect) { + var wrapping = cm.options.lineWrapping; + var curWidth = wrapping && displayWidth(cm); + if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { + var heights = lineView.measure.heights = []; + if (wrapping) { + lineView.measure.width = curWidth; + var rects = lineView.text.firstChild.getClientRects(); + for (var i = 0; i < rects.length - 1; i++) { + var cur = rects[i], next = rects[i + 1]; + if (Math.abs(cur.bottom - next.bottom) > 2) + heights.push((cur.bottom + next.top) / 2 - rect.top); + } + } + heights.push(rect.bottom - rect.top); + } + } + + // Find a line map (mapping character offsets to text nodes) and a + // measurement cache for the given line number. (A line view might + // contain multiple lines when collapsed ranges are present.) + function mapFromLineView(lineView, line, lineN) { + if (lineView.line == line) + return { map: lineView.measure.map, cache: lineView.measure.cache }; + for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest[i] == line) + return { map: lineView.measure.maps[i], cache: lineView.measure.caches[i] }; + for (var i = 0; i < lineView.rest.length; i++) + if (lineNo(lineView.rest[i]) > lineN) + return { map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true }; + } + + // Render a line into the hidden node display.externalMeasured. Used + // when measurement is needed for a line that's not in the viewport. + function updateExternalMeasurement(cm, line) { + line = visualLine(line); + var lineN = lineNo(line); + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); + view.lineN = lineN; + var built = view.built = buildLineContent(cm, view); + view.text = built.pre; + removeChildrenAndAdd(cm.display.lineMeasure, built.pre); + return view; + } + + // Get a {top, bottom, left, right} box (in line-local coordinates) + // for a given character. + function measureChar(cm, line, ch, bias) { + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); + } + + // Find a line view that corresponds to the given line number. + function findViewForLine(cm, lineN) { + if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) + return cm.display.view[findViewIndex(cm, lineN)]; + var ext = cm.display.externalMeasured; + if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) + return ext; + } + + // Measurement can be split in two steps, the set-up work that + // applies to the whole line, and the measurement of the actual + // character. Functions like coordsChar, that need to do a lot of + // measurements in a row, can thus ensure that the set-up work is + // only done once. + function prepareMeasureForLine(cm, line) { + var lineN = lineNo(line); + var view = findViewForLine(cm, lineN); + if (view && !view.text) { + view = null; + } else if (view && view.changes) { + updateLineForChanges(cm, view, lineN, getDimensions(cm)); + cm.curOp.forceUpdate = true; + } + if (!view) + view = updateExternalMeasurement(cm, line); + + var info = mapFromLineView(view, line, lineN); + return { + line: line, view: view, rect: null, + map: info.map, cache: info.cache, before: info.before, + hasHeights: false + }; + } + + // Given a prepared measurement object, measures the position of an + // actual character (or fetches it from the cache). + function measureCharPrepared(cm, prepared, ch, bias, varHeight) { + if (prepared.before) ch = -1; + var key = ch + (bias || ""), found; + if (prepared.cache.hasOwnProperty(key)) { + found = prepared.cache[key]; + } else { + if (!prepared.rect) + prepared.rect = prepared.view.text.getBoundingClientRect(); + if (!prepared.hasHeights) { + ensureLineHeights(cm, prepared.view, prepared.rect); + prepared.hasHeights = true; + } + found = measureCharInner(cm, prepared, ch, bias); + if (!found.bogus) prepared.cache[key] = found; + } + return { + left: found.left, right: found.right, + top: varHeight ? found.rtop : found.top, + bottom: varHeight ? found.rbottom : found.bottom + }; + } + + var nullRect = { left: 0, right: 0, top: 0, bottom: 0 }; + + function nodeAndOffsetInLineMap(map, ch, bias) { + var node, start, end, collapse; + // First, search the line map for the text node corresponding to, + // or closest to, the target character. + for (var i = 0; i < map.length; i += 3) { + var mStart = map[i], mEnd = map[i + 1]; + if (ch < mStart) { + start = 0; end = 1; + collapse = "left"; + } else if (ch < mEnd) { + start = ch - mStart; + end = start + 1; + } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { + end = mEnd - mStart; + start = end - 1; + if (ch >= mEnd) collapse = "right"; + } + if (start != null) { + node = map[i + 2]; + if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) + collapse = bias; + if (bias == "left" && start == 0) + while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { + node = map[(i -= 3) + 2]; + collapse = "left"; + } + if (bias == "right" && start == mEnd - mStart) + while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { + node = map[(i += 3) + 2]; + collapse = "right"; + } + break; + } + } + return { node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd }; + } + + function getUsefulRect(rects, bias) { + var rect = nullRect + if (bias == "left") for (var i = 0; i < rects.length; i++) { + if ((rect = rects[i]).left != rect.right) break + } else for (var i = rects.length - 1; i >= 0; i--) { + if ((rect = rects[i]).left != rect.right) break + } + return rect + } + + function measureCharInner(cm, prepared, ch, bias) { + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); + var node = place.node, start = place.start, end = place.end, collapse = place.collapse; + + var rect; + if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. + for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; + if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) + rect = node.parentNode.getBoundingClientRect(); + else + rect = getUsefulRect(range(node, start, end).getClientRects(), bias) + if (rect.left || rect.right || start == 0) break; + end = start; + start = start - 1; + collapse = "right"; + } + if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); + } else { // If it is a widget, simply get the box for the whole widget. + if (start > 0) collapse = bias = "right"; + var rects; + if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) + rect = rects[bias == "right" ? rects.length - 1 : 0]; + else + rect = node.getBoundingClientRect(); + } + if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { + var rSpan = node.parentNode.getClientRects()[0]; + if (rSpan) + rect = { left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom }; + else + rect = nullRect; + } + + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; + var mid = (rtop + rbot) / 2; + var heights = prepared.view.measure.heights; + for (var i = 0; i < heights.length - 1; i++) + if (mid < heights[i]) break; + var top = i ? heights[i - 1] : 0, bot = heights[i]; + var result = { + left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, + top: top, bottom: bot + }; + if (!rect.left && !rect.right) result.bogus = true; + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + + return result; + } + + // Work around problem with bounding client rects on ranges being + // returned incorrectly when zoomed on IE10 and below. + function maybeUpdateRectForZooming(measure, rect) { + if (!window.screen || screen.logicalXDPI == null || + screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) + return rect; + var scaleX = screen.logicalXDPI / screen.deviceXDPI; + var scaleY = screen.logicalYDPI / screen.deviceYDPI; + return { + left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY + }; + } + + function clearLineMeasurementCacheFor(lineView) { + if (lineView.measure) { + lineView.measure.cache = {}; + lineView.measure.heights = null; + if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + lineView.measure.caches[i] = {}; + } + } + + function clearLineMeasurementCache(cm) { + cm.display.externalMeasure = null; + removeChildren(cm.display.lineMeasure); + for (var i = 0; i < cm.display.view.length; i++) + clearLineMeasurementCacheFor(cm.display.view[i]); + } + + function clearCaches(cm) { + clearLineMeasurementCache(cm); + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; + cm.display.lineNumChars = null; + } + + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + + // Converts a {top, bottom, left, right} box from line-local + // coordinates into another coordinate system. Context may be one of + // "line", "div" (display.lineDiv), "local"/null (editor), "window", + // or "page". + function intoCoordSystem(cm, lineObj, rect, context) { + if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + var size = widgetHeight(lineObj.widgets[i]); + rect.top += size; rect.bottom += size; + } + if (context == "line") return rect; + if (!context) context = "local"; + var yOff = heightAtLine(lineObj); + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; + if (context == "page" || context == "window") { + var lOff = cm.display.lineSpace.getBoundingClientRect(); + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); + rect.left += xOff; rect.right += xOff; + } + rect.top += yOff; rect.bottom += yOff; + return rect; + } + + // Coverts a box from "div" coords to another coordinate system. + // Context may be "window", "page", "div", or "local"/null. + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + // First move into "page" coordinate system + if (context == "page") { + left -= pageScrollX(); + top -= pageScrollY(); + } else if (context == "local" || !context) { + var localBox = cm.display.sizer.getBoundingClientRect(); + left += localBox.left; + top += localBox.top; + } + + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); + return { left: left - lineSpaceBox.left, top: top - lineSpaceBox.top }; + } + + function charCoords(cm, pos, context, lineObj, bias) { + if (!lineObj) lineObj = getLine(cm.doc, pos.line); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); + } + + // Returns a box for a given cursor position, which may have an + // 'other' property containing the position of the secondary cursor + // on a bidi boundary. + function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { + lineObj = lineObj || getLine(cm.doc, pos.line); + if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); + function get(ch, right) { + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); + if (right) m.left = m.right; else m.right = m.left; + return intoCoordSystem(cm, lineObj, m, context); + } + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; + } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); + } + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; + } + + // Used to cheaply estimate the coordinates for a position. Used for + // intermediate scroll updates. + function estimateCoords(cm, pos) { + var left = 0, pos = clipPos(cm.doc, pos); + if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; + var lineObj = getLine(cm.doc, pos.line); + var top = heightAtLine(lineObj) + paddingTop(cm.display); + return { left: left, right: left, top: top, bottom: top + lineObj.height }; + } + + // Positions returned by coordsChar contain some extra information. + // xRel is the relative x position of the input coordinates compared + // to the found position (so xRel > 0 means the coordinates are to + // the right of the character position, for example). When outside + // is true, that means the coordinates lie outside the line's + // vertical range. + function PosWithInfo(line, ch, outside, xRel) { + var pos = Pos(line, ch); + pos.xRel = xRel; + if (outside) pos.outside = true; + return pos; + } + + // Compute the character position closest to the given coordinates. + // Input must be lineSpace-local ("div" coordinate system). + function coordsChar(cm, x, y) { + var doc = cm.doc; + y += cm.display.viewOffset; + if (y < 0) return PosWithInfo(doc.first, 0, true, -1); + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineN > last) + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); + if (x < 0) x = 0; + + var lineObj = getLine(doc, lineN); + for (; ;) { + var found = coordsCharInner(cm, lineObj, lineN, x, y); + var merged = collapsedSpanAtEnd(lineObj); + var mergedPos = merged && merged.find(0, true); + if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) + lineN = lineNo(lineObj = mergedPos.to.line); + else + return found; + } + } + + function coordsCharInner(cm, lineObj, lineNo, x, y) { + var innerOff = y - heightAtLine(lineObj); + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; + var preparedMeasure = prepareMeasureForLine(cm, lineObj); + + function getX(ch) { + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); + wrongLine = true; + if (innerOff > sp.bottom) return sp.left - adjust; + else if (innerOff < sp.top) return sp.left + adjust; + else wrongLine = false; + return sp.left; + } + + var bidi = getOrder(lineObj), dist = lineObj.text.length; + var from = lineLeft(lineObj), to = lineRight(lineObj); + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + // Do a binary search between these bounds. + for (; ;) { + if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { + var ch = x < fromX || x - fromX <= toX - x ? from : to; + var outside = ch == from ? fromOutside : toOutside + var xDiff = x - (ch == from ? fromX : toX); + // This is a kludge to handle the case where the coordinates + // are after a line-wrapped line. We should replace it with a + // more general handling of cursor positions around line + // breaks. (Issue #4078) + if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 && + ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) { + var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right"); + if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) { + outside = false + ch++ + xDiff = x - charSize.right + } + } + while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; + var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); + return pos; + } + var step = Math.ceil(dist / 2), middle = from + step; + if (bidi) { + middle = from; + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + } + var middleX = getX(middle); + if (middleX > x) { to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step; } + else { from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step; } + } + } + + var measureText; + // Compute the default text height. + function textHeight(display) { + if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (measureText == null) { + measureText = elt("pre"); + // Measure a bunch of lines, for browsers that compute + // fractional heights. + for (var i = 0; i < 49; ++i) { + measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(elt("br")); + } + measureText.appendChild(document.createTextNode("x")); + } + removeChildrenAndAdd(display.measure, measureText); + var height = measureText.offsetHeight / 50; + if (height > 3) display.cachedTextHeight = height; + removeChildren(display.measure); + return height || 1; + } + + // Compute the default character width. + function charWidth(display) { + if (display.cachedCharWidth != null) return display.cachedCharWidth; + var anchor = elt("span", "xxxxxxxxxx"); + var pre = elt("pre", [anchor]); + removeChildrenAndAdd(display.measure, pre); + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; + if (width > 2) display.cachedCharWidth = width; + return width || 10; + } + + // OPERATIONS + + // Operations are used to wrap a series of changes to the editor + // state in such a way that each change won't have to update the + // cursor and display (which would be awkward, slow, and + // error-prone). Instead, display updates are batched and then all + // combined and executed at once. + + var operationGroup = null; + + var nextOpId = 0; + // Start a new operation. + function startOperation(cm) { + cm.curOp = { + cm: cm, + viewChanged: false, // Flag that indicates that lines might need to be redrawn + startHeight: cm.doc.height, // Used to detect need to update scrollbar + forceUpdate: false, // Used to force a redraw + updateInput: null, // Whether to reset the input textarea + typing: false, // Whether this reset should be careful to leave existing text (for compositing) + changeObjs: null, // Accumulated changes, for firing change events + cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already + selectionChanged: false, // Whether the selection needs to be redrawn + updateMaxLine: false, // Set when the widest line needs to be determined anew + scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet + scrollToPos: null, // Used to scroll to a specific position + focus: false, + id: ++nextOpId // Unique ID + }; + if (operationGroup) { + operationGroup.ops.push(cm.curOp); + } else { + cm.curOp.ownsGroup = operationGroup = { + ops: [cm.curOp], + delayedCallbacks: [] + }; + } + } + + function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0; + do { + for (; i < callbacks.length; i++) + callbacks[i].call(null); + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j]; + if (op.cursorActivityHandlers) + while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); + } + } while (i < callbacks.length); + } + + // Finish an operation, updating the display and signalling delayed events + function endOperation(cm) { + var op = cm.curOp, group = op.ownsGroup; + if (!group) return; + + try { fireCallbacksForOps(group); } + finally { + operationGroup = null; + for (var i = 0; i < group.ops.length; i++) + group.ops[i].cm.curOp = null; + endOperations(group); + } + } + + // The DOM updates done when an operation finishes are batched so + // that the minimum number of relayouts are required. + function endOperations(group) { + var ops = group.ops; + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R1(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W1(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R2(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W2(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_finish(ops[i]); + } + + function endOperation_R1(op) { + var cm = op.cm, display = cm.display; + maybeClipScrollbars(cm); + if (op.updateMaxLine) findMaxLine(cm); + + op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || + op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || + op.scrollToPos.to.line >= display.viewTo) || + display.maxLineChanged && cm.options.lineWrapping; + op.update = op.mustUpdate && + new DisplayUpdate(cm, op.mustUpdate && { top: op.scrollTop, ensure: op.scrollToPos }, op.forceUpdate); + } + + function endOperation_W1(op) { + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); + } + + function endOperation_R2(op) { + var cm = op.cm, display = cm.display; + if (op.updatedDisplay) updateHeightsInViewport(cm); + + op.barMeasure = measureForScrollbars(cm); + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplay_W2 will use these properties to do the actual resizing + if (display.maxLineChanged && !cm.options.lineWrapping) { + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; + cm.display.sizerWidth = op.adjustWidthTo; + op.barMeasure.scrollWidth = + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); + } + + if (op.updatedDisplay || op.selectionChanged) + op.preparedSelection = display.input.prepareSelection(op.focus); + } + + function endOperation_W2(op) { + var cm = op.cm; + + if (op.adjustWidthTo != null) { + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; + if (op.maxScrollLeft < cm.doc.scrollLeft) + setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); + cm.display.maxLineChanged = false; + } + + var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()) + if (op.preparedSelection) + cm.display.input.showSelection(op.preparedSelection, takeFocus); + if (op.updatedDisplay || op.startHeight != cm.doc.height) + updateScrollbars(cm, op.barMeasure); + if (op.updatedDisplay) + setDocumentHeight(cm, op.barMeasure); + + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + cm.display.input.reset(op.typing); + if (takeFocus) ensureFocus(op.cm); + } + + function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; + + if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + + // Abort mouse wheel delta measurement, when scrolling explicitly + if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) + display.wheelStartX = display.wheelStartY = null; + + // Propagate the scroll position to the actual DOM scroller + if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { + doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); + display.scrollbars.setScrollTop(doc.scrollTop); + display.scroller.scrollTop = doc.scrollTop; + } + if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); + display.scrollbars.setScrollLeft(doc.scrollLeft); + display.scroller.scrollLeft = doc.scrollLeft; + alignHorizontally(cm); + } + // If we need to scroll a specific position into view, do so. + if (op.scrollToPos) { + var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); + if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); + } + + // Fire events for markers that are hidden/unidden by editing or + // undoing + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + if (hidden) for (var i = 0; i < hidden.length; ++i) + if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + + if (display.wrapper.offsetHeight) + doc.scrollTop = cm.display.scroller.scrollTop; + + // Fire change events, and delayed event handlers + if (op.changeObjs) + signal(cm, "changes", cm, op.changeObjs); + if (op.update) + op.update.finish(); + } + + // Run the given function in an operation + function runInOp(cm, f) { + if (cm.curOp) return f(); + startOperation(cm); + try { return f(); } + finally { endOperation(cm); } + } + // Wraps a function in an operation. Returns the wrapped function. + function operation(cm, f) { + return function () { + if (cm.curOp) return f.apply(cm, arguments); + startOperation(cm); + try { return f.apply(cm, arguments); } + finally { endOperation(cm); } + }; + } + // Used to add methods to editor and doc instances, wrapping them in + // operations. + function methodOp(f) { + return function () { + if (this.curOp) return f.apply(this, arguments); + startOperation(this); + try { return f.apply(this, arguments); } + finally { endOperation(this); } + }; + } + function docMethodOp(f) { + return function () { + var cm = this.cm; + if (!cm || cm.curOp) return f.apply(this, arguments); + startOperation(cm); + try { return f.apply(this, arguments); } + finally { endOperation(cm); } + }; + } + + // VIEW TRACKING + + // These objects are used to represent the visible (currently drawn) + // part of the document. A LineView may correspond to multiple + // logical lines, if those are connected by collapsed ranges. + function LineView(doc, line, lineN) { + // The starting line + this.line = line; + // Continuing lines, if any + this.rest = visualLineContinued(line); + // Number of logical lines in this visual line + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; + this.node = this.text = null; + this.hidden = lineIsHidden(doc, line); + } + + // Create a range of LineView objects for the given lines. + function buildViewArray(cm, from, to) { + var array = [], nextPos; + for (var pos = from; pos < to; pos = nextPos) { + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); + nextPos = pos + view.size; + array.push(view); + } + return array; + } + + // Updates the display.view data structure for a given change to the + // document. From and to are in pre-change coordinates. Lendiff is + // the amount of lines added or subtracted by the change. This is + // used for changes that span multiple lines, or change the way + // lines are divided into visual lines. regLineChange (below) + // registers single-line changes. + function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; + if (!lendiff) lendiff = 0; + + var display = cm.display; + if (lendiff && to < display.viewTo && + (display.updateLineNumbers == null || display.updateLineNumbers > from)) + display.updateLineNumbers = from; + + cm.curOp.viewChanged = true; + + if (from >= display.viewTo) { // Change after + if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) + resetView(cm); + } else if (to <= display.viewFrom) { // Change before + if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { + resetView(cm); + } else { + display.viewFrom += lendiff; + display.viewTo += lendiff; + } + } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap + resetView(cm); + } else if (from <= display.viewFrom) { // Top overlap + var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cut) { + display.view = display.view.slice(cut.index); + display.viewFrom = cut.lineN; + display.viewTo += lendiff; + } else { + resetView(cm); + } + } else if (to >= display.viewTo) { // Bottom overlap + var cut = viewCuttingPoint(cm, from, from, -1); + if (cut) { + display.view = display.view.slice(0, cut.index); + display.viewTo = cut.lineN; + } else { + resetView(cm); + } + } else { // Gap in the middle + var cutTop = viewCuttingPoint(cm, from, from, -1); + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + if (cutTop && cutBot) { + display.view = display.view.slice(0, cutTop.index) + .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) + .concat(display.view.slice(cutBot.index)); + display.viewTo += lendiff; + } else { + resetView(cm); + } + } + + var ext = display.externalMeasured; + if (ext) { + if (to < ext.lineN) + ext.lineN += lendiff; + else if (from < ext.lineN + ext.size) + display.externalMeasured = null; + } + } + + // Register a change to a single line. Type must be one of "text", + // "gutter", "class", "widget" + function regLineChange(cm, line, type) { + cm.curOp.viewChanged = true; + var display = cm.display, ext = cm.display.externalMeasured; + if (ext && line >= ext.lineN && line < ext.lineN + ext.size) + display.externalMeasured = null; + + if (line < display.viewFrom || line >= display.viewTo) return; + var lineView = display.view[findViewIndex(cm, line)]; + if (lineView.node == null) return; + var arr = lineView.changes || (lineView.changes = []); + if (indexOf(arr, type) == -1) arr.push(type); + } + + // Clear the view. + function resetView(cm) { + cm.display.viewFrom = cm.display.viewTo = cm.doc.first; + cm.display.view = []; + cm.display.viewOffset = 0; + } + + // Find the view element corresponding to a given line. Return null + // when the line isn't visible. + function findViewIndex(cm, n) { + if (n >= cm.display.viewTo) return null; + n -= cm.display.viewFrom; + if (n < 0) return null; + var view = cm.display.view; + for (var i = 0; i < view.length; i++) { + n -= view[i].size; + if (n < 0) return i; + } + } + + function viewCuttingPoint(cm, oldN, newN, dir) { + var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) + return { index: index, lineN: newN }; + for (var i = 0, n = cm.display.viewFrom; i < index; i++) + n += view[i].size; + if (n != oldN) { + if (dir > 0) { + if (index == view.length - 1) return null; + diff = (n + view[index].size) - oldN; + index++; + } else { + diff = n - oldN; + } + oldN += diff; newN += diff; + } + while (visualLineNo(cm.doc, newN) != newN) { + if (index == (dir < 0 ? 0 : view.length - 1)) return null; + newN += dir * view[index - (dir < 0 ? 1 : 0)].size; + index += dir; + } + return { index: index, lineN: newN }; + } + + // Force the view to cover a given range, adding empty view element + // or clipping off existing ones as needed. + function adjustView(cm, from, to) { + var display = cm.display, view = display.view; + if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { + display.view = buildViewArray(cm, from, to); + display.viewFrom = from; + } else { + if (display.viewFrom > from) + display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); + else if (display.viewFrom < from) + display.view = display.view.slice(findViewIndex(cm, from)); + display.viewFrom = from; + if (display.viewTo < to) + display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); + else if (display.viewTo > to) + display.view = display.view.slice(0, findViewIndex(cm, to)); + } + display.viewTo = to; + } + + // Count the number of lines in the view whose DOM representation is + // out of date (or nonexistent). + function countDirtyView(cm) { + var view = cm.display.view, dirty = 0; + for (var i = 0; i < view.length; i++) { + var lineView = view[i]; + if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; + } + return dirty; + } + + // EVENT HANDLERS + + // Attach the necessary event handlers when initializing the editor + function registerEventHandlers(cm) { + var d = cm.display; + on(d.scroller, "mousedown", operation(cm, onMouseDown)); + // Older IE's will not fire a second mousedown for a double click + if (ie && ie_version < 11) + on(d.scroller, "dblclick", operation(cm, function (e) { + if (signalDOMEvent(cm, e)) return; + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = cm.findWordAt(pos); + extendSelection(cm.doc, word.anchor, word.head); + })); + else + on(d.scroller, "dblclick", function (e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + // Some browsers fire contextmenu *after* opening the menu, at + // which point we can't mess with it anymore. Context menu is + // handled in onMouseDown for these browsers. + if (!captureRightClick) on(d.scroller, "contextmenu", function (e) { onContextMenu(cm, e); }); + + // Used to suppress mouse event handling when a touch happens + var touchFinished, prevTouch = { end: 0 }; + function finishTouch() { + if (d.activeTouch) { + touchFinished = setTimeout(function () { d.activeTouch = null; }, 1000); + prevTouch = d.activeTouch; + prevTouch.end = +new Date; + } + }; + function isMouseLikeTouchEvent(e) { + if (e.touches.length != 1) return false; + var touch = e.touches[0]; + return touch.radiusX <= 1 && touch.radiusY <= 1; + } + function farAway(touch, other) { + if (other.left == null) return true; + var dx = other.left - touch.left, dy = other.top - touch.top; + return dx * dx + dy * dy > 20 * 20; + } + on(d.scroller, "touchstart", function (e) { + if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { + clearTimeout(touchFinished); + var now = +new Date; + d.activeTouch = { + start: now, moved: false, + prev: now - prevTouch.end <= 300 ? prevTouch : null + }; + if (e.touches.length == 1) { + d.activeTouch.left = e.touches[0].pageX; + d.activeTouch.top = e.touches[0].pageY; + } + } + }); + on(d.scroller, "touchmove", function () { + if (d.activeTouch) d.activeTouch.moved = true; + }); + on(d.scroller, "touchend", function (e) { + var touch = d.activeTouch; + if (touch && !eventInWidget(d, e) && touch.left != null && + !touch.moved && new Date - touch.start < 300) { + var pos = cm.coordsChar(d.activeTouch, "page"), range; + if (!touch.prev || farAway(touch, touch.prev)) // Single tap + range = new Range(pos, pos); + else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap + range = cm.findWordAt(pos); + else // Triple tap + range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); + cm.setSelection(range.anchor, range.head); + cm.focus(); + e_preventDefault(e); + } + finishTouch(); + }); + on(d.scroller, "touchcancel", finishTouch); + + // Sync scrolling between fake scrollbars and real scrollable + // area, ensure viewport is updated when scrolling. + on(d.scroller, "scroll", function () { + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } + }); + + // Listen to wheel events in order to try and update the viewport on time. + on(d.scroller, "mousewheel", function (e) { onScrollWheel(cm, e); }); + on(d.scroller, "DOMMouseScroll", function (e) { onScrollWheel(cm, e); }); + + // Prevent wrapper from ever scrolling + on(d.wrapper, "scroll", function () { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + + d.dragFunctions = { + enter: function (e) { if (!signalDOMEvent(cm, e)) e_stop(e); }, + over: function (e) { if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); } }, + start: function (e) { onDragStart(cm, e); }, + drop: operation(cm, onDrop), + leave: function (e) { if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); } } + }; + + var inp = d.input.getField(); + on(inp, "keyup", function (e) { onKeyUp.call(cm, e); }); + on(inp, "keydown", operation(cm, onKeyDown)); + on(inp, "keypress", operation(cm, onKeyPress)); + on(inp, "focus", bind(onFocus, cm)); + on(inp, "blur", bind(onBlur, cm)); + } + + function dragDropChanged(cm, value, old) { + var wasOn = old && old != CodeMirror.Init; + if (!value != !wasOn) { + var funcs = cm.display.dragFunctions; + var toggle = value ? on : off; + toggle(cm.display.scroller, "dragstart", funcs.start); + toggle(cm.display.scroller, "dragenter", funcs.enter); + toggle(cm.display.scroller, "dragover", funcs.over); + toggle(cm.display.scroller, "dragleave", funcs.leave); + toggle(cm.display.scroller, "drop", funcs.drop); + } + } + + // Called when the window resizes + function onResize(cm) { + var d = cm.display; + if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) + return; + // Might be a text scaling operation, clear size caches. + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + d.scrollbarsClipped = false; + cm.setSize(); + } + + // MOUSE EVENTS + + // Return true when the given mouse event happened in a widget + function eventInWidget(display, e) { + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || + (n.parentNode == display.sizer && n != display.mover)) + return true; + } + } + + // Given a mouse event, find the corresponding position. If liberal + // is false, it checks whether a gutter or scrollbar was clicked, + // and returns null if it was. forRect is used by rectangular + // selections, and tries to estimate a character position even for + // coordinates beyond the right of the text. + function posFromMouse(cm, e, liberal, forRect) { + var display = cm.display; + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; + + var x, y, space = display.lineSpace.getBoundingClientRect(); + // Fails unpredictably on IE[67] when mouse is dragged around quickly. + try { x = e.clientX - space.left; y = e.clientY - space.top; } + catch (e) { return null; } + var coords = coordsChar(cm, x, y), line; + if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + } + return coords; + } + + // A mouse down can be a single click, double click, triple click, + // start of selection drag, start of text drag, new cursor + // (ctrl-click), rectangle drag (alt-drag), or xwin + // middle-click-paste. Or it might be a click on something we should + // not interfere with, such as a scrollbar or widget. + function onMouseDown(e) { + var cm = this, display = cm.display; + if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return; + display.shift = e.shiftKey; + + if (eventInWidget(display, e)) { + if (!webkit) { + // Briefly turn off draggability, to allow widgets to do + // normal dragging things. + display.scroller.draggable = false; + setTimeout(function () { display.scroller.draggable = true; }, 100); + } + return; + } + if (clickInGutter(cm, e)) return; + var start = posFromMouse(cm, e); + window.focus(); + + switch (e_button(e)) { + case 1: + // #3261: make sure, that we're not starting a second selection + if (cm.state.selectingText) + cm.state.selectingText(e); + else if (start) + leftButtonDown(cm, e, start); + else if (e_target(e) == display.scroller) + e_preventDefault(e); + break; + case 2: + if (webkit) cm.state.lastMiddleDown = +new Date; + if (start) extendSelection(cm.doc, start); + setTimeout(function () { display.input.focus(); }, 20); + e_preventDefault(e); + break; + case 3: + if (captureRightClick) onContextMenu(cm, e); + else delayBlurEvent(cm); + break; + } + } + + var lastClick, lastDoubleClick; + function leftButtonDown(cm, e, start) { + if (ie) setTimeout(bind(ensureFocus, cm), 0); + else cm.curOp.focus = activeElt(); + + var now = +new Date, type; + if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { + type = "triple"; + } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { + type = "double"; + lastDoubleClick = { time: now, pos: start }; + } else { + type = "single"; + lastClick = { time: now, pos: start }; + } + + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; + if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && + type == "single" && (contained = sel.contains(start)) > -1 && + (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && + (cmp(contained.to(), start) > 0 || start.xRel < 0)) + leftButtonStartDrag(cm, e, start, modifier); + else + leftButtonSelect(cm, e, start, type, modifier); + } + + // Start a text drag. When it ends, see if any dragging actually + // happen, and treat as a click if it didn't. + function leftButtonStartDrag(cm, e, start, modifier) { + var display = cm.display, startTime = +new Date; + var dragEnd = operation(cm, function (e2) { + if (webkit) display.scroller.draggable = false; + cm.state.draggingText = false; + off(document, "mouseup", dragEnd); + off(display.scroller, "drop", dragEnd); + if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { + e_preventDefault(e2); + if (!modifier && +new Date - 200 < startTime) + extendSelection(cm.doc, start); + // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) + if (webkit || ie && ie_version == 9) + setTimeout(function () { document.body.focus(); display.input.focus(); }, 20); + else + display.input.focus(); + } + }); + // Let the drag handler handle this. + if (webkit) display.scroller.draggable = true; + cm.state.draggingText = dragEnd; + dragEnd.copy = mac ? e.altKey : e.ctrlKey + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop(); + on(document, "mouseup", dragEnd); + on(display.scroller, "drop", dragEnd); + } + + // Normal selection, as opposed to text dragging. + function leftButtonSelect(cm, e, start, type, addNew) { + var display = cm.display, doc = cm.doc; + e_preventDefault(e); + + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + if (addNew && !e.shiftKey) { + ourIndex = doc.sel.contains(start); + if (ourIndex > -1) + ourRange = ranges[ourIndex]; + else + ourRange = new Range(start, start); + } else { + ourRange = doc.sel.primary(); + ourIndex = doc.sel.primIndex; + } + + if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) { + type = "rect"; + if (!addNew) ourRange = new Range(start, start); + start = posFromMouse(cm, e, true, true); + ourIndex = -1; + } else if (type == "double") { + var word = cm.findWordAt(start); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, word.anchor, word.head); + else + ourRange = word; + } else if (type == "triple") { + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); + if (cm.display.shift || doc.extend) + ourRange = extendRange(doc, ourRange, line.anchor, line.head); + else + ourRange = line; + } else { + ourRange = extendRange(doc, ourRange, start); + } + + if (!addNew) { + ourIndex = 0; + setSelection(doc, new Selection([ourRange], 0), sel_mouse); + startSel = doc.sel; + } else if (ourIndex == -1) { + ourIndex = ranges.length; + setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), + { scroll: false, origin: "*mouse" }); + } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { + setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), + { scroll: false, origin: "*mouse" }); + startSel = doc.sel; + } else { + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + } + + var lastPos = start; + function extendTo(pos) { + if (cmp(lastPos, pos) == 0) return; + lastPos = pos; + + if (type == "rect") { + var ranges = [], tabSize = cm.options.tabSize; + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + line <= end; line++) { + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + if (left == right) + ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); + else if (text.length > leftPos) + ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); + } + if (!ranges.length) ranges.push(new Range(start, start)); + setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), + { origin: "*mouse", scroll: false }); + cm.scrollIntoView(pos); + } else { + var oldRange = ourRange; + var anchor = oldRange.anchor, head = pos; + if (type != "single") { + if (type == "double") + var range = cm.findWordAt(pos); + else + var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); + if (cmp(range.anchor, anchor) > 0) { + head = range.head; + anchor = minPos(oldRange.from(), range.anchor); + } else { + head = range.anchor; + anchor = maxPos(oldRange.to(), range.head); + } + } + var ranges = startSel.ranges.slice(0); + ranges[ourIndex] = new Range(clipPos(doc, anchor), head); + setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); + } + } + + var editorSize = display.wrapper.getBoundingClientRect(); + // Used to ensure timeout re-tries don't fire when another extend + // happened in the meantime (clearTimeout isn't reliable -- at + // least on Chrome, the timeouts still happen even when cleared, + // if the clear happens after their scheduled firing time). + var counter = 0; + + function extend(e) { + var curCount = ++counter; + var cur = posFromMouse(cm, e, true, type == "rect"); + if (!cur) return; + if (cmp(cur, lastPos) != 0) { + cm.curOp.focus = activeElt(); + extendTo(cur); + var visible = visibleLines(display, doc); + if (cur.line >= visible.to || cur.line < visible.from) + setTimeout(operation(cm, function () { if (counter == curCount) extend(e); }), 150); + } else { + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + if (outside) setTimeout(operation(cm, function () { + if (counter != curCount) return; + display.scroller.scrollTop += outside; + extend(e); + }), 50); + } + } + + function done(e) { + cm.state.selectingText = false; + counter = Infinity; + e_preventDefault(e); + display.input.focus(); + off(document, "mousemove", move); + off(document, "mouseup", up); + doc.history.lastSelOrigin = null; + } + + var move = operation(cm, function (e) { + if (!e_button(e)) done(e); + else extend(e); + }); + var up = operation(cm, done); + cm.state.selectingText = up; + on(document, "mousemove", move); + on(document, "mouseup", up); + } + + // Determines whether an event happened in the gutter, and fires the + // handlers for the corresponding event. + function gutterEvent(cm, e, type, prevent) { + try { var mX = e.clientX, mY = e.clientY; } + catch (e) { return false; } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; + if (prevent) e_preventDefault(e); + + var display = cm.display; + var lineBox = display.lineDiv.getBoundingClientRect(); + + if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && g.getBoundingClientRect().right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signal(cm, type, cm, line, gutter, e); + return e_defaultPrevented(e); + } + } + } + + function clickInGutter(cm, e) { + return gutterEvent(cm, e, "gutterClick", true); + } + + // Kludge to work around strange IE behavior where it'll sometimes + // re-fire a series of drag-related events right after the drop (#1551) + var lastDrop = 0; + + function onDrop(e) { + var cm = this; + clearDragCursor(cm); + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) + return; + e_preventDefault(e); + if (ie) lastDrop = +new Date; + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; + if (!pos || cm.isReadOnly()) return; + // Might be a file drop, in which case we simply extract the text + // and insert it. + if (files && files.length && window.FileReader && window.File) { + var n = files.length, text = Array(n), read = 0; + var loadFile = function (file, i) { + if (cm.options.allowDropFileTypes && + indexOf(cm.options.allowDropFileTypes, file.type) == -1) + return; + + var reader = new FileReader; + reader.onload = operation(cm, function () { + var content = reader.result; + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = ""; + text[i] = content; + if (++read == n) { + pos = clipPos(cm.doc, pos); + var change = { + from: pos, to: pos, + text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), + origin: "paste" + }; + makeChange(cm.doc, change); + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + } + }); + reader.readAsText(file); + }; + for (var i = 0; i < n; ++i) loadFile(files[i], i); + } else { // Normal drop + // Don't do a replace if the drop happened inside of the selected text. + if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { + cm.state.draggingText(e); + // Ensure the editor is re-focused + setTimeout(function () { cm.display.input.focus(); }, 20); + return; + } + try { + var text = e.dataTransfer.getData("Text"); + if (text) { + if (cm.state.draggingText && !cm.state.draggingText.copy) + var selected = cm.listSelections(); + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + if (selected) for (var i = 0; i < selected.length; ++i) + replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); + cm.replaceSelection(text, "around", "paste"); + cm.display.input.focus(); + } + } + catch (e) { } + } + } + + function onDragStart(cm, e) { + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + + e.dataTransfer.setData("Text", cm.getSelection()); + e.dataTransfer.effectAllowed = "copyMove" + + // Use dummy image instead of default browsers image. + // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + if (presto) { + img.width = img.height = 1; + cm.display.wrapper.appendChild(img); + // Force a relayout, or Opera won't use our image for some obscure reason + img._top = img.offsetTop; + } + e.dataTransfer.setDragImage(img, 0, 0); + if (presto) img.parentNode.removeChild(img); + } + } + + function onDragOver(cm, e) { + var pos = posFromMouse(cm, e); + if (!pos) return; + var frag = document.createDocumentFragment(); + drawSelectionCursor(cm, pos, frag); + if (!cm.display.dragCursor) { + cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors"); + cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv); + } + removeChildrenAndAdd(cm.display.dragCursor, frag); + } + + function clearDragCursor(cm) { + if (cm.display.dragCursor) { + cm.display.lineSpace.removeChild(cm.display.dragCursor); + cm.display.dragCursor = null; + } + } + + // SCROLL EVENTS + + // Sync the scrollable area and scrollbars, ensure the viewport + // covers the visible area. + function setScrollTop(cm, val) { + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; + if (!gecko) updateDisplaySimple(cm, { top: val }); + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; + cm.display.scrollbars.setScrollTop(val); + if (gecko) updateDisplaySimple(cm); + startWorker(cm, 100); + } + // Sync scroller and scrollbar, ensure the gutter elements are + // aligned. + function setScrollLeft(cm, val, isScroller) { + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); + cm.doc.scrollLeft = val; + alignHorizontally(cm); + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; + cm.display.scrollbars.setScrollLeft(val); + } + + // Since the delta values reported on mouse wheel events are + // unstandardized between browsers and even browser versions, and + // generally horribly unpredictable, this code starts by measuring + // the scroll effect that the first few mouse wheel events have, + // and, from that, detects the way it can convert deltas to pixel + // offsets afterwards. + // + // The reason we want to know the amount a wheel event will scroll + // is that it gives us a chance to update the display before the + // actual scrolling happens, reducing flickering. + + var wheelSamples = 0, wheelPixelsPerUnit = null; + // Fill in a browser-detected starting value on browsers where we + // know one. These don't have to be accurate -- the result of them + // being wrong would just be a slight flicker on the first wheel + // scroll (if it is large enough). + if (ie) wheelPixelsPerUnit = -.53; + else if (gecko) wheelPixelsPerUnit = 15; + else if (chrome) wheelPixelsPerUnit = -.7; + else if (safari) wheelPixelsPerUnit = -1 / 3; + + var wheelEventDelta = function (e) { + var dx = e.wheelDeltaX, dy = e.wheelDeltaY; + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; + else if (dy == null) dy = e.wheelDelta; + return { x: dx, y: dy }; + }; + CodeMirror.wheelEventPixels = function (e) { + var delta = wheelEventDelta(e); + delta.x *= wheelPixelsPerUnit; + delta.y *= wheelPixelsPerUnit; + return delta; + }; + + function onScrollWheel(cm, e) { + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + + var display = cm.display, scroll = display.scroller; + // Quit if there's nothing to scroll here + var canScrollX = scroll.scrollWidth > scroll.clientWidth; + var canScrollY = scroll.scrollHeight > scroll.clientHeight; + if (!(dx && canScrollX || dy && canScrollY)) return; + + // Webkit browsers on OS X abort momentum scrolls when the target + // of the scroll event is removed from the scrollable element. + // This hack (see related code in patchDisplay) makes sure the + // element is kept around. + if (dy && mac && webkit) { + outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (var i = 0; i < view.length; i++) { + if (view[i].node == cur) { + cm.display.currentWheelTarget = cur; + break outer; + } + } + } + } + + // On some browsers, horizontal scrolling will cause redraws to + // happen before the gutter has been realigned, causing it to + // wriggle around in a most unseemly way. When we have an + // estimated pixels/delta value, we just handle horizontal + // scrolling entirely here. It'll be slightly off from native, but + // better than glitching out. + if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { + if (dy && canScrollY) + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + // Only prevent default scrolling if vertical scrolling is + // actually possible. Otherwise, it causes vertical scroll + // jitter on OSX trackpads when deltaX is small and deltaY + // is large (issue #3579) + if (!dy || (dy && canScrollY)) + e_preventDefault(e); + display.wheelStartX = null; // Abort measurement, if in progress + return; + } + + // 'Project' the visible viewport to cover the area that is being + // scrolled into view (if we know enough to estimate it). + if (dy && wheelPixelsPerUnit != null) { + var pixels = dy * wheelPixelsPerUnit; + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; + if (pixels < 0) top = Math.max(0, top + pixels - 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); + updateDisplaySimple(cm, { top: top, bottom: bot }); + } + + if (wheelSamples < 20) { + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; + setTimeout(function () { + if (display.wheelStartX == null) return; + var movedX = scroll.scrollLeft - display.wheelStartX; + var movedY = scroll.scrollTop - display.wheelStartY; + var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + (movedX && display.wheelDX && movedX / display.wheelDX); + display.wheelStartX = display.wheelStartY = null; + if (!sample) return; + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); + ++wheelSamples; + }, 200); + } else { + display.wheelDX += dx; display.wheelDY += dy; + } + } + } + + // KEY EVENTS + + // Run a handler that was bound to a key. + function doHandleBinding(cm, bound, dropShift) { + if (typeof bound == "string") { + bound = commands[bound]; + if (!bound) return false; + } + // Ensure previous input has been read, so that the handler sees a + // consistent view of the document + cm.display.input.ensurePolled(); + var prevShift = cm.display.shift, done = false; + try { + if (cm.isReadOnly()) cm.state.suppressEdits = true; + if (dropShift) cm.display.shift = false; + done = bound(cm) != Pass; + } finally { + cm.display.shift = prevShift; + cm.state.suppressEdits = false; + } + return done; + } + + function lookupKeyForEditor(cm, name, handle) { + for (var i = 0; i < cm.state.keyMaps.length; i++) { + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); + if (result) return result; + } + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm); + } + + var stopSeq = new Delayed; + function dispatchKey(cm, name, e, handle) { + var seq = cm.state.keySeq; + if (seq) { + if (isModifierKey(name)) return "handled"; + stopSeq.set(50, function () { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null; + cm.display.input.reset(); + } + }); + name = seq + " " + name; + } + var result = lookupKeyForEditor(cm, name, handle); + + if (result == "multi") + cm.state.keySeq = name; + if (result == "handled") + signalLater(cm, "keyHandled", cm, name, e); + + if (result == "handled" || result == "multi") { + e_preventDefault(e); + restartBlink(cm); + } + + if (seq && !result && /\'$/.test(name)) { + e_preventDefault(e); + return true; + } + return !!result; + } + + // Handle a key from the keydown event. + function handleKeyBinding(cm, e) { + var name = keyName(e, true); + if (!name) return false; + + if (e.shiftKey && !cm.state.keySeq) { + // First try to resolve full name (including 'Shift-'). Failing + // that, see if there is a cursor-motion command (starting with + // 'go') bound to the keyname without 'Shift-'. + return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); }) + || dispatchKey(cm, name, e, function (b) { + if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) + return doHandleBinding(cm, b); + }); + } else { + return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); }); + } + } + + // Handle a key from the keypress event + function handleCharBinding(cm, e, ch) { + return dispatchKey(cm, "'" + ch + "'", e, + function (b) { return doHandleBinding(cm, b, true); }); + } + + var lastStoppedKey = null; + function onKeyDown(e) { + var cm = this; + cm.curOp.focus = activeElt(); + if (signalDOMEvent(cm, e)) return; + // IE does strange things with escape. + if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; + var code = e.keyCode; + cm.display.shift = code == 16 || e.shiftKey; + var handled = handleKeyBinding(cm, e); + if (presto) { + lastStoppedKey = handled ? code : null; + // Opera has no cut event... we try to at least catch the key combo + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) + cm.replaceSelection("", null, "cut"); + } + + // Turn mouse into crosshair when Alt is held on Mac. + if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) + showCrossHair(cm); + } + + function showCrossHair(cm) { + var lineDiv = cm.display.lineDiv; + addClass(lineDiv, "CodeMirror-crosshair"); + + function up(e) { + if (e.keyCode == 18 || !e.altKey) { + rmClass(lineDiv, "CodeMirror-crosshair"); + off(document, "keyup", up); + off(document, "mouseover", up); + } + } + on(document, "keyup", up); + on(document, "mouseover", up); + } + + function onKeyUp(e) { + if (e.keyCode == 16) this.doc.sel.shift = false; + signalDOMEvent(this, e); + } + + function onKeyPress(e) { + var cm = this; + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; + var keyCode = e.keyCode, charCode = e.charCode; + if (presto && keyCode == lastStoppedKey) { lastStoppedKey = null; e_preventDefault(e); return; } + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; + var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + if (handleCharBinding(cm, e, ch)) return; + cm.display.input.onKeyPress(e); + } + + // FOCUS/BLUR EVENTS + + function delayBlurEvent(cm) { + cm.state.delayingBlurEvent = true; + setTimeout(function () { + if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false; + onBlur(cm); + } + }, 100); + } + + function onFocus(cm) { + if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; + + if (cm.options.readOnly == "nocursor") return; + if (!cm.state.focused) { + signal(cm, "focus", cm); + cm.state.focused = true; + addClass(cm.display.wrapper, "CodeMirror-focused"); + // This test prevents this from firing when a context + // menu is closed (since the input reset would kill the + // select-all detection hack) + if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { + cm.display.input.reset(); + if (webkit) setTimeout(function () { cm.display.input.reset(true); }, 20); // Issue #1730 + } + cm.display.input.receivedFocus(); + } + restartBlink(cm); + } + function onBlur(cm) { + if (cm.state.delayingBlurEvent) return; + + if (cm.state.focused) { + signal(cm, "blur", cm); + cm.state.focused = false; + rmClass(cm.display.wrapper, "CodeMirror-focused"); + } + clearInterval(cm.display.blinker); + setTimeout(function () { if (!cm.state.focused) cm.display.shift = false; }, 150); + } + + // CONTEXT MENU HANDLING + + // To make the context menu work, we need to briefly unhide the + // textarea (making it as unobtrusive as possible) to let the + // right-click take effect on it. + function onContextMenu(cm, e) { + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; + if (signalDOMEvent(cm, e, "contextmenu")) return; + cm.display.input.onContextMenu(e); + } + + function contextMenuInGutter(cm, e) { + if (!hasHandler(cm, "gutterContextMenu")) return false; + return gutterEvent(cm, e, "gutterContextMenu", false); + } + + // UPDATING + + // Compute the position of the end of a change (its 'to' property + // refers to the pre-change end). + var changeEnd = CodeMirror.changeEnd = function (change) { + if (!change.text) return change.to; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + }; + + // Adjust a position to refer to the post-change position of the + // same text, or the end of the change if the change covers it. + function adjustForChange(pos, change) { + if (cmp(pos, change.from) < 0) return pos; + if (cmp(pos, change.to) <= 0) return changeEnd(change); + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; + return Pos(line, ch); + } + + function computeSelAfterChange(doc, change) { + var out = []; + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + out.push(new Range(adjustForChange(range.anchor, change), + adjustForChange(range.head, change))); + } + return normalizeSelection(out, doc.sel.primIndex); + } + + function offsetPos(pos, old, nw) { + if (pos.line == old.line) + return Pos(nw.line, pos.ch - old.ch + nw.ch); + else + return Pos(nw.line + (pos.line - old.line), pos.ch); + } + + // Used by replaceSelections to allow moving the selection to the + // start or around the replaced test. Hint may be "start" or "around". + function computeReplacedSel(doc, changes, hint) { + var out = []; + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + var from = offsetPos(change.from, oldPrev, newPrev); + var to = offsetPos(changeEnd(change), oldPrev, newPrev); + oldPrev = change.to; + newPrev = to; + if (hint == "around") { + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; + out[i] = new Range(inv ? to : from, inv ? from : to); + } else { + out[i] = new Range(from, from); + } + } + return new Selection(out, doc.sel.primIndex); + } + + // Allow "beforeChange" event handlers to influence a change + function filterChange(doc, change, update) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + cancel: function () { this.canceled = true; } + }; + if (update) obj.update = function (from, to, text, origin) { + if (from) this.from = clipPos(doc, from); + if (to) this.to = clipPos(doc, to); + if (text) this.text = text; + if (origin !== undefined) this.origin = origin; + }; + signal(doc, "beforeChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); + + if (obj.canceled) return null; + return { from: obj.from, to: obj.to, text: obj.text, origin: obj.origin }; + } + + // Apply a change to a document, and add it to the document's + // history, and propagating it to all linked documents. + function makeChange(doc, change, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change, true); + if (!change) return; + } + + // Possibly split or suppress the update based on the presence + // of read-only spans in its range. + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + if (split) { + for (var i = split.length - 1; i >= 0; --i) + makeChangeInner(doc, { from: split[i].from, to: split[i].to, text: i ? [""] : change.text }); + } else { + makeChangeInner(doc, change); + } + } + + function makeChangeInner(doc, change) { + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; + var selAfter = computeSelAfterChange(doc, change); + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + var rebased = []; + + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); + }); + } + + // Revert a change stored in a document's history. + function makeChangeFromHistory(doc, type, allowSelectionOnly) { + if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) return; + + var hist = doc.history, event, selAfter = doc.sel; + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + + // Verify that there is a useable event (so that ctrl-z won't + // needlessly clear selection events) + for (var i = 0; i < source.length; i++) { + event = source[i]; + if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) + break; + } + if (i == source.length) return; + hist.lastOrigin = hist.lastSelOrigin = null; + + for (; ;) { + event = source.pop(); + if (event.ranges) { + pushSelectionToHistory(event, dest); + if (allowSelectionOnly && !event.equals(doc.sel)) { + setSelection(doc, event, { clearRedo: false }); + return; + } + selAfter = event; + } + else break; + } + + // Build up a reverse change object to add to the opposite history + // stack (redo when undoing, and vice versa). + var antiChanges = []; + pushSelectionToHistory(selAfter, dest); + dest.push({ changes: antiChanges, generation: hist.generation }); + hist.generation = event.generation || ++hist.maxGeneration; + + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + if (filter && !filterChange(doc, change, false)) { + source.length = 0; + return; + } + + antiChanges.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc, change) : lst(source); + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); + if (!i && doc.cm) doc.cm.scrollIntoView({ from: change.from, to: changeEnd(change) }); + var rebased = []; + + // Propagate to the linked documents + linkedDocs(doc, function (doc, sharedHist) { + if (!sharedHist && indexOf(rebased, doc.history) == -1) { + rebaseHist(doc.history, change); + rebased.push(doc.history); + } + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); + }); + } + } + + // Sub-views need their line numbers shifted when text is added + // above or below them in the parent document. + function shiftDoc(doc, distance) { + if (distance == 0) return; + doc.first += distance; + doc.sel = new Selection(map(doc.sel.ranges, function (range) { + return new Range(Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch)); + }), doc.sel.primIndex); + if (doc.cm) { + regChange(doc.cm, doc.first, doc.first - distance, distance); + for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + regLineChange(doc.cm, l, "gutter"); + } + } + + // More lower-level change function, handling only a single document + // (not linked ones). + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + + if (change.to.line < doc.first) { + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); + return; + } + if (change.from.line > doc.lastLine()) return; + + // Clip the change to the size of this doc + if (change.from.line < doc.first) { + var shift = change.text.length - 1 - (doc.first - change.from.line); + shiftDoc(doc, shift); + change = { + from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), + text: [lst(change.text)], origin: change.origin + }; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = { + from: change.from, to: Pos(last, getLine(doc, last).text.length), + text: [change.text[0]], origin: change.origin + }; + } + + change.removed = getBetween(doc, change.from, change.to); + + if (!selAfter) selAfter = computeSelAfterChange(doc, change); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); + else updateDoc(doc, change, spans); + setSelectionNoUndo(doc, selAfter, sel_dontScroll); + } + + // Handle the interaction of a change to a document with the editor + // that this document is part of. + function makeChangeSingleDocInEditor(cm, change, spans) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + + var recomputeMaxLength = false, checkWidthStart = from.line; + if (!cm.options.lineWrapping) { + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + doc.iter(checkWidthStart, to.line + 1, function (line) { + if (line == display.maxLine) { + recomputeMaxLength = true; + return true; + } + }); + } + + if (doc.sel.contains(change.from, change.to) > -1) + signalCursorActivity(cm); + + updateDoc(doc, change, spans, estimateHeight(cm)); + + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function (line) { + var len = lineLength(line); + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; + recomputeMaxLength = false; + } + }); + if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + } + + // Adjust frontier, schedule worker + doc.frontier = Math.min(doc.frontier, from.line); + startWorker(cm, 400); + + var lendiff = change.text.length - (to.line - from.line) - 1; + // Remember that these lines changed, for updating the display + if (change.full) + regChange(cm); + else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) + regLineChange(cm, from.line, "text"); + else + regChange(cm, from.line, to.line + 1, lendiff); + + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + if (changeHandler || changesHandler) { + var obj = { + from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin + }; + if (changeHandler) signalLater(cm, "change", cm, obj); + if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); + } + cm.display.selForContextMenu = null; + } + + function replaceRange(doc, code, from, to, origin) { + if (!to) to = from; + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } + if (typeof code == "string") code = doc.splitLines(code); + makeChange(doc, { from: from, to: to, text: code, origin: origin }); + } + + // SCROLLING THINGS INTO VIEW + + // If an editor sits on the top or bottom of the window, partially + // scrolled out of view, this ensures that the cursor is visible. + function maybeScrollWindow(cm, coords) { + if (signalDOMEvent(cm, "scrollCursorIntoView")) return; + + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + if (coords.top + box.top < 0) doScroll = true; + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + if (doScroll != null && !phantom) { + var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + + coords.left + "px; width: 2px;"); + cm.display.lineSpace.appendChild(scrollNode); + scrollNode.scrollIntoView(doScroll); + cm.display.lineSpace.removeChild(scrollNode); + } + } + + // Scroll a given position into view (immediately), verifying that + // it actually became visible (as line heights are accurately + // measured, the position of something may 'drift' during drawing). + function scrollPosIntoView(cm, pos, end, margin) { + if (margin == null) margin = 0; + for (var limit = 0; limit < 5; limit++) { + var changed = false, coords = cursorCoords(cm, pos); + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), + Math.min(coords.top, endCoords.top) - margin, + Math.max(coords.left, endCoords.left), + Math.max(coords.bottom, endCoords.bottom) + margin); + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + if (scrollPos.scrollTop != null) { + setScrollTop(cm, scrollPos.scrollTop); + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + } + if (scrollPos.scrollLeft != null) { + setScrollLeft(cm, scrollPos.scrollLeft); + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + } + if (!changed) break; + } + return coords; + } + + // Scroll a given set of coordinates into view (immediately). + function scrollIntoView(cm, x1, y1, x2, y2) { + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + } + + // Calculate a new scroll position needed to scroll the given + // rectangle into view. Returns an object with scrollTop and + // scrollLeft properties. When these are undefined, the + // vertical/horizontal position does not need to be adjusted. + function calculateScrollPos(cm, x1, y1, x2, y2) { + var display = cm.display, snapMargin = textHeight(cm.display); + if (y1 < 0) y1 = 0; + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; + var screen = displayHeight(cm), result = {}; + if (y2 - y1 > screen) y2 = y1 + screen; + var docBottom = cm.doc.height + paddingVert(display); + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + if (y1 < screentop) { + result.scrollTop = atTop ? 0 : y1; + } else if (y2 > screentop + screen) { + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); + if (newTop != screentop) result.scrollTop = newTop; + } + + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); + var tooWide = x2 - x1 > screenw; + if (tooWide) x2 = x1 + screenw; + if (x1 < 10) + result.scrollLeft = 0; + else if (x1 < screenleft) + result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); + else if (x2 > screenw + screenleft - 3) + result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; + return result; + } + + // Store a relative adjustment to the scroll position in the current + // operation (to be applied when the operation finishes). + function addToScrollPos(cm, left, top) { + if (left != null || top != null) resolveScrollToPos(cm); + if (left != null) + cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; + if (top != null) + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + } + + // Make sure that at the end of the operation the current cursor is + // shown. + function ensureCursorVisible(cm) { + resolveScrollToPos(cm); + var cur = cm.getCursor(), from = cur, to = cur; + if (!cm.options.lineWrapping) { + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; + to = Pos(cur.line, cur.ch + 1); + } + cm.curOp.scrollToPos = { from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true }; + } + + // When an operation has its scrollToPos property set, and another + // scroll action is applied before the end of the operation, this + // 'simulates' scrolling that position into view in a cheap way, so + // that the effect of intermediate scroll commands is not ignored. + function resolveScrollToPos(cm) { + var range = cm.curOp.scrollToPos; + if (range) { + cm.curOp.scrollToPos = null; + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), + Math.min(from.top, to.top) - range.margin, + Math.max(from.right, to.right), + Math.max(from.bottom, to.bottom) + range.margin); + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + } + + // API UTILITIES + + // Indent the given line. The how parameter can be "smart", + // "add"/null, "subtract", or "prev". When aggressive is false + // (typically set to true for forced single-line indents), empty + // lines are not indented, and places where the mode returns Pass + // are left alone. + function indentLine(cm, n, how, aggressive) { + var doc = cm.doc, state; + if (how == null) how = "add"; + if (how == "smart") { + // Fall back to "prev" when the mode doesn't have an indentation + // method. + if (!doc.mode.indent) how = "prev"; + else state = getStateBefore(cm, n); + } + + var tabSize = cm.options.tabSize; + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) line.stateAfter = null; + var curSpaceString = line.text.match(/^\s*/)[0], indentation; + if (!aggressive && !/\S/.test(line.text)) { + indentation = 0; + how = "not"; + } else if (how == "smart") { + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + if (indentation == Pass || indentation > 150) { + if (!aggressive) return; + how = "prev"; + } + } + if (how == "prev") { + if (n > doc.first) indentation = countColumn(getLine(doc, n - 1).text, null, tabSize); + else indentation = 0; + } else if (how == "add") { + indentation = curSpace + cm.options.indentUnit; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; + } else if (typeof how == "number") { + indentation = curSpace + how; + } + indentation = Math.max(0, indentation); + + var indentString = "", pos = 0; + if (cm.options.indentWithTabs) + for (var i = Math.floor(indentation / tabSize); i; --i) { pos += tabSize; indentString += "\t"; } + if (pos < indentation) indentString += spaceStr(indentation - pos); + + if (indentString != curSpaceString) { + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + line.stateAfter = null; + return true; + } else { + // Ensure that, if the cursor was in the whitespace at the start + // of the line, it is moved to the end of that space. + for (var i = 0; i < doc.sel.ranges.length; i++) { + var range = doc.sel.ranges[i]; + if (range.head.line == n && range.head.ch < curSpaceString.length) { + var pos = Pos(n, curSpaceString.length); + replaceOneSelection(doc, i, new Range(pos, pos)); + break; + } + } + } + } + + // Utility for applying a change to a line by handle or number, + // returning the number and optionally registering the line as + // changed. + function changeLine(doc, handle, changeType, op) { + var no = handle, line = handle; + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); + else no = lineNo(handle); + if (no == null) return null; + if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); + return line; + } + + // Helper for deleting text near the selection(s), used to implement + // backspace, delete, and similar functionality. + function deleteNearSelection(cm, compute) { + var ranges = cm.doc.sel.ranges, kill = []; + // Build up a set of ranges to kill first, merging overlapping + // ranges. + for (var i = 0; i < ranges.length; i++) { + var toKill = compute(ranges[i]); + while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { + var replaced = kill.pop(); + if (cmp(replaced.from, toKill.from) < 0) { + toKill.from = replaced.from; + break; + } + } + kill.push(toKill); + } + // Next, remove those actual ranges. + runInOp(cm, function () { + for (var i = kill.length - 1; i >= 0; i--) + replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); + ensureCursorVisible(cm); + }); + } + + // Used for horizontal relative motion. Dir is -1 or 1 (left or + // right), unit can be "char", "column" (like char, but doesn't + // cross line boundaries), "word" (across next word), or "group" (to + // the start of next group of word or non-word-non-whitespace + // chars). The visually param controls whether, in right-to-left + // text, direction 1 means to move towards the next index in the + // string, or towards the character to the right of the current + // position. The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch, origDir = dir; + var lineObj = getLine(doc, line); + function findNextLine() { + var l = line + dir; + if (l < doc.first || l >= doc.first + doc.size) return false + line = l; + return lineObj = getLine(doc, l); + } + function moveOnce(boundToLine) { + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + if (next == null) { + if (!boundToLine && findNextLine()) { + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); + else ch = dir < 0 ? lineObj.text.length : 0; + } else return false + } else ch = next; + return true; + } + + if (unit == "char") { + moveOnce() + } else if (unit == "column") { + moveOnce(true) + } else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + for (var first = true; ; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur, helper) ? "w" + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null + : "p"; + if (group && !first && !type) type = "s"; + if (sawType && sawType != type) { + if (dir < 0) { dir = 1; moveOnce(); } + break; + } + + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; + } + } + var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true); + if (!cmp(pos, result)) result.hitSide = true; + return result; + } + + // For relative vertical movement. Dir may be -1 or 1. Unit can be + // "page" or "line". The resulting position will have a hitSide=true + // property if it reached the end of the document. + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, x = pos.left, y; + if (unit == "page") { + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + } else if (unit == "line") { + y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + } + for (; ;) { + var target = coordsChar(cm, x, y); + if (!target.outside) break; + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } + y += dir * 5; + } + return target; + } + + // EDITOR METHODS + + // The publicly visible API. Note that methodOp(f) means + // 'wrap f in an operation, performed on its `this` parameter'. + + // This is not the complete set of editor methods. Most of the + // methods defined on the Doc type are also injected into + // CodeMirror.prototype, for backwards compatibility and + // convenience. + + CodeMirror.prototype = { + constructor: CodeMirror, + focus: function () { window.focus(); this.display.input.focus(); }, + + setOption: function (option, value) { + var options = this.options, old = options[option]; + if (options[option] == value && option != "mode") return; + options[option] = value; + if (optionHandlers.hasOwnProperty(option)) + operation(this, optionHandlers[option])(this, value, old); + }, + + getOption: function (option) { return this.options[option]; }, + getDoc: function () { return this.doc; }, + + addKeyMap: function (map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); + }, + removeKeyMap: function (map) { + var maps = this.state.keyMaps; + for (var i = 0; i < maps.length; ++i) + if (maps[i] == map || maps[i].name == map) { + maps.splice(i, 1); + return true; + } + }, + + addOverlay: methodOp(function (spec, options) { + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); + if (mode.startState) throw new Error("Overlays may not be stateful."); + this.state.overlays.push({ mode: mode, modeSpec: spec, opaque: options && options.opaque }); + this.state.modeGen++; + regChange(this); + }), + removeOverlay: methodOp(function (spec) { + var overlays = this.state.overlays; + for (var i = 0; i < overlays.length; ++i) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { + overlays.splice(i, 1); + this.state.modeGen++; + regChange(this); + return; + } + } + }), + + indentLine: methodOp(function (n, dir, aggressive) { + if (typeof dir != "string" && typeof dir != "number") { + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; + else dir = dir ? "add" : "subtract"; + } + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + }), + indentSelection: methodOp(function (how) { + var ranges = this.doc.sel.ranges, end = -1; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i]; + if (!range.empty()) { + var from = range.from(), to = range.to(); + var start = Math.max(end, from.line); + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + for (var j = start; j < end; ++j) + indentLine(this, j, how); + var newRanges = this.doc.sel.ranges; + if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) + replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); + } else if (range.head.line > end) { + indentLine(this, range.head.line, how, true); + end = range.head.line; + if (i == this.doc.sel.primIndex) ensureCursorVisible(this); + } + } + }), + + // Fetch the parser token for a given character. Useful for hacks + // that want to inspect the mode state (say, for completion). + getTokenAt: function (pos, precise) { + return takeToken(this, pos, precise); + }, + + getLineTokens: function (line, precise) { + return takeToken(this, Pos(line), precise, true); + }, + + getTokenTypeAt: function (pos) { + pos = clipPos(this.doc, pos); + var styles = getLineStyles(this, getLine(this.doc, pos.line)); + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; + var type; + if (ch == 0) type = styles[2]; + else for (; ;) { + var mid = (before + after) >> 1; + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; + else if (styles[mid * 2 + 1] < ch) before = mid + 1; + else { type = styles[mid * 2 + 2]; break; } + } + var cut = type ? type.indexOf("cm-overlay ") : -1; + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); + }, + + getModeAt: function (pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + + getHelper: function (pos, type) { + return this.getHelpers(pos, type)[0]; + }, + + getHelpers: function (pos, type) { + var found = []; + if (!helpers.hasOwnProperty(type)) return found; + var help = helpers[type], mode = this.getModeAt(pos); + if (typeof mode[type] == "string") { + if (help[mode[type]]) found.push(help[mode[type]]); + } else if (mode[type]) { + for (var i = 0; i < mode[type].length; i++) { + var val = help[mode[type][i]]; + if (val) found.push(val); + } + } else if (mode.helperType && help[mode.helperType]) { + found.push(help[mode.helperType]); + } else if (help[mode.name]) { + found.push(help[mode.name]); + } + for (var i = 0; i < help._global.length; i++) { + var cur = help._global[i]; + if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) + found.push(cur.val); + } + return found; + }, + + getStateAfter: function (line, precise) { + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1 : line); + return getStateBefore(this, line + 1, precise); + }, + + cursorCoords: function (start, mode) { + var pos, range = this.doc.sel.primary(); + if (start == null) pos = range.head; + else if (typeof start == "object") pos = clipPos(this.doc, start); + else pos = start ? range.from() : range.to(); + return cursorCoords(this, pos, mode || "page"); + }, + + charCoords: function (pos, mode) { + return charCoords(this, clipPos(this.doc, pos), mode || "page"); + }, + + coordsChar: function (coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); + }, + + lineAtHeight: function (height, mode) { + height = fromCoordSystem(this, { top: height, left: 0 }, mode || "page").top; + return lineAtHeight(this.doc, height + this.display.viewOffset); + }, + heightAtLine: function (line, mode) { + var end = false, lineObj; + if (typeof line == "number") { + var last = this.doc.first + this.doc.size - 1; + if (line < this.doc.first) line = this.doc.first; + else if (line > last) { line = last; end = true; } + lineObj = getLine(this.doc, line); + } else { + lineObj = line; + } + return intoCoordSystem(this, lineObj, { top: 0, left: 0 }, mode || "page").top + + (end ? this.doc.height - heightAtLine(lineObj) : 0); + }, + + defaultTextHeight: function () { return textHeight(this.display); }, + defaultCharWidth: function () { return charWidth(this.display); }, + + setGutterMarker: methodOp(function (line, gutterID, value) { + return changeLine(this.doc, line, "gutter", function (line) { + var markers = line.gutterMarkers || (line.gutterMarkers = {}); + markers[gutterID] = value; + if (!value && isEmpty(markers)) line.gutterMarkers = null; + return true; + }); + }), + + clearGutter: methodOp(function (gutterID) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function (line) { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + line.gutterMarkers[gutterID] = null; + regLineChange(cm, i, "gutter"); + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + } + ++i; + }); + }), + + lineInfo: function (line) { + if (typeof line == "number") { + if (!isLine(this.doc, line)) return null; + var n = line; + line = getLine(this.doc, line); + if (!line) return null; + } else { + var n = lineNo(line); + if (n == null) return null; + } + return { + line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets + }; + }, + + getViewport: function () { return { from: this.display.viewFrom, to: this.display.viewTo }; }, + + addWidget: function (pos, node, scroll, vert, horiz) { + var display = this.display; + pos = cursorCoords(this, clipPos(this.doc, pos)); + var top = pos.bottom, left = pos.left; + node.style.position = "absolute"; + node.setAttribute("cm-ignore-events", "true"); + this.display.input.setUneditable(node); + display.sizer.appendChild(node); + if (vert == "over") { + top = pos.top; + } else if (vert == "above" || vert == "near") { + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + // Default to positioning above (if specified and possible); otherwise default to positioning below + if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) + top = pos.top - node.offsetHeight; + else if (pos.bottom + node.offsetHeight <= vspace) + top = pos.bottom; + if (left + node.offsetWidth > hspace) + left = hspace - node.offsetWidth; + } + node.style.top = top + "px"; + node.style.left = node.style.right = ""; + if (horiz == "right") { + left = display.sizer.clientWidth - node.offsetWidth; + node.style.right = "0px"; + } else { + if (horiz == "left") left = 0; + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; + node.style.left = left + "px"; + } + if (scroll) + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + }, + + triggerOnKeyDown: methodOp(onKeyDown), + triggerOnKeyPress: methodOp(onKeyPress), + triggerOnKeyUp: onKeyUp, + + execCommand: function (cmd) { + if (commands.hasOwnProperty(cmd)) + return commands[cmd].call(null, this); + }, + + triggerElectric: methodOp(function (text) { triggerElectric(this, text); }), + + findPosH: function (from, amount, unit, visually) { + var dir = 1; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + cur = findPosH(this.doc, cur, dir, unit, visually); + if (cur.hitSide) break; + } + return cur; + }, + + moveH: methodOp(function (dir, unit) { + var cm = this; + cm.extendSelectionsBy(function (range) { + if (cm.display.shift || cm.doc.extend || range.empty()) + return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); + else + return dir < 0 ? range.from() : range.to(); + }, sel_move); + }), + + deleteH: methodOp(function (dir, unit) { + var sel = this.doc.sel, doc = this.doc; + if (sel.somethingSelected()) + doc.replaceSelection("", null, "+delete"); + else + deleteNearSelection(this, function (range) { + var other = findPosH(doc, range.head, dir, unit, false); + return dir < 0 ? { from: other, to: range.head } : { from: range.head, to: other }; + }); + }), + + findPosV: function (from, amount, unit, goalColumn) { + var dir = 1, x = goalColumn; + if (amount < 0) { dir = -1; amount = -amount; } + for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + var coords = cursorCoords(this, cur, "div"); + if (x == null) x = coords.left; + else coords.left = x; + cur = findPosV(this, coords, dir, unit); + if (cur.hitSide) break; + } + return cur; + }, + + moveV: methodOp(function (dir, unit) { + var cm = this, doc = this.doc, goals = []; + var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); + doc.extendSelectionsBy(function (range) { + if (collapse) + return dir < 0 ? range.from() : range.to(); + var headPos = cursorCoords(cm, range.head, "div"); + if (range.goalColumn != null) headPos.left = range.goalColumn; + goals.push(headPos.left); + var pos = findPosV(cm, headPos, dir, unit); + if (unit == "page" && range == doc.sel.primary()) + addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); + return pos; + }, sel_move); + if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) + doc.sel.ranges[i].goalColumn = goals[i]; + }), + + // Find the word at the given position (as returned by coordsChar). + findWordAt: function (pos) { + var doc = this.doc, line = getLine(doc, pos.line).text; + var start = pos.ch, end = pos.ch; + if (line) { + var helper = this.getHelper(pos, "wordChars"); + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; + var startChar = line.charAt(start); + var check = isWordChar(startChar, helper) + ? function (ch) { return isWordChar(ch, helper); } + : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); } + : function (ch) { return !/\s/.test(ch) && !isWordChar(ch); }; + while (start > 0 && check(line.charAt(start - 1))) --start; + while (end < line.length && check(line.charAt(end))) ++end; + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)); + }, + + toggleOverwrite: function (value) { + if (value != null && value == this.state.overwrite) return; + if (this.state.overwrite = !this.state.overwrite) + addClass(this.display.cursorDiv, "CodeMirror-overwrite"); + else + rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); + + signal(this, "overwriteToggle", this, this.state.overwrite); + }, + hasFocus: function () { return this.display.input.getField() == activeElt(); }, + isReadOnly: function () { return !!(this.options.readOnly || this.doc.cantEdit); }, + + scrollTo: methodOp(function (x, y) { + if (x != null || y != null) resolveScrollToPos(this); + if (x != null) this.curOp.scrollLeft = x; + if (y != null) this.curOp.scrollTop = y; + }), + getScrollInfo: function () { + var scroller = this.display.scroller; + return { + left: scroller.scrollLeft, top: scroller.scrollTop, + height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, + width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, + clientHeight: displayHeight(this), clientWidth: displayWidth(this) + }; + }, + + scrollIntoView: methodOp(function (range, margin) { + if (range == null) { + range = { from: this.doc.sel.primary().head, to: null }; + if (margin == null) margin = this.options.cursorScrollMargin; + } else if (typeof range == "number") { + range = { from: Pos(range, 0), to: null }; + } else if (range.from == null) { + range = { from: range, to: null }; + } + if (!range.to) range.to = range.from; + range.margin = margin || 0; + + if (range.from.line != null) { + resolveScrollToPos(this); + this.curOp.scrollToPos = range; + } else { + var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), + Math.min(range.from.top, range.to.top) - range.margin, + Math.max(range.from.right, range.to.right), + Math.max(range.from.bottom, range.to.bottom) + range.margin); + this.scrollTo(sPos.scrollLeft, sPos.scrollTop); + } + }), + + setSize: methodOp(function (width, height) { + var cm = this; + function interpret(val) { + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + } + if (width != null) cm.display.wrapper.style.width = interpret(width); + if (height != null) cm.display.wrapper.style.height = interpret(height); + if (cm.options.lineWrapping) clearLineMeasurementCache(this); + var lineNo = cm.display.viewFrom; + cm.doc.iter(lineNo, cm.display.viewTo, function (line) { + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) + if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } + ++lineNo; + }); + cm.curOp.forceUpdate = true; + signal(cm, "refresh", this); + }), + + operation: function (f) { return runInOp(this, f); }, + + refresh: methodOp(function () { + var oldHeight = this.display.cachedTextHeight; + regChange(this); + this.curOp.forceUpdate = true; + clearCaches(this); + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); + updateGutterSpace(this); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + estimateLineHeights(this); + signal(this, "refresh", this); + }), + + swapDoc: methodOp(function (doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + this.display.input.reset(); + this.scrollTo(doc.scrollLeft, doc.scrollTop); + this.curOp.forceScroll = true; + signalLater(this, "swapDoc", this, old); + return old; + }), + + getInputField: function () { return this.display.input.getField(); }, + getWrapperElement: function () { return this.display.wrapper; }, + getScrollerElement: function () { return this.display.scroller; }, + getGutterElement: function () { return this.display.gutters; } + }; + eventMixin(CodeMirror); + + // OPTION DEFAULTS + + // The default configuration options. + var defaults = CodeMirror.defaults = {}; + // Functions to run when options are changed. + var optionHandlers = CodeMirror.optionHandlers = {}; + + function option(name, deflt, handle, notOnInit) { + CodeMirror.defaults[name] = deflt; + if (handle) optionHandlers[name] = + notOnInit ? function (cm, val, old) { if (old != Init) handle(cm, val, old); } : handle; + } + + // Passed to option handlers when there is no old value. + var Init = CodeMirror.Init = { toString: function () { return "CodeMirror.Init"; } }; + + // These two are, on init, called from the constructor because they + // have to be initialized before the editor can start at all. + option("value", "", function (cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function (cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); + + option("indentUnit", 2, loadMode, true); + option("indentWithTabs", false); + option("smartIndent", true); + option("tabSize", 4, function (cm) { + resetModeState(cm); + clearCaches(cm); + regChange(cm); + }, true); + option("lineSeparator", null, function (cm, val) { + cm.doc.lineSep = val; + if (!val) return; + var newBreaks = [], lineNo = cm.doc.first; + cm.doc.iter(function (line) { + for (var pos = 0; ;) { + var found = line.text.indexOf(val, pos); + if (found == -1) break; + pos = found + val.length; + newBreaks.push(Pos(lineNo, found)); + } + lineNo++; + }); + for (var i = newBreaks.length - 1; i >= 0; i--) + replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) + }); + option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) { + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + if (old != CodeMirror.Init) cm.refresh(); + }); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { cm.refresh(); }, true); + option("electricChars", true); + option("inputStyle", mobile ? "contenteditable" : "textarea", function () { + throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME + }, true); + option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); + + option("theme", "default", function (cm) { + themeChanged(cm); + guttersChanged(cm); + }, true); + option("keyMap", "default", function (cm, val, old) { + var next = getKeyMap(val); + var prev = old != CodeMirror.Init && getKeyMap(old); + if (prev && prev.detach) prev.detach(cm, next); + if (next.attach) next.attach(cm, prev || null); + }); + option("extraKeys", null); + + option("lineWrapping", false, wrappingChanged, true); + option("gutters", [], function (cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("fixedGutter", true, function (cm, val) { + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; + cm.refresh(); + }, true); + option("coverGutterNextToScrollbar", false, function (cm) { updateScrollbars(cm); }, true); + option("scrollbarStyle", "native", function (cm) { + initScrollbars(cm); + updateScrollbars(cm); + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); + }, true); + option("lineNumbers", false, function (cm) { + setGuttersForLineNumbers(cm.options); + guttersChanged(cm); + }, true); + option("firstLineNumber", 1, guttersChanged, true); + option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true); + option("showCursorWhenSelecting", false, updateSelection, true); + + option("resetSelectionOnContextMenu", true); + option("lineWiseCopyCut", true); + + option("readOnly", false, function (cm, val) { + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + } + cm.display.input.readOnlyChanged(val) + }); + option("disableInput", false, function (cm, val) { if (!val) cm.display.input.reset(); }, true); + option("dragDrop", true, dragDropChanged); + option("allowDropFileTypes", null); + + option("cursorBlinkRate", 530); + option("cursorScrollMargin", 0); + option("cursorHeight", 1, updateSelection, true); + option("singleCursorHeightPerLine", true, updateSelection, true); + option("workTime", 100); + option("workDelay", 100); + option("flattenSpans", true, resetModeState, true); + option("addModeClass", false, resetModeState, true); + option("pollInterval", 100); + option("undoDepth", 200, function (cm, val) { cm.doc.history.undoDepth = val; }); + option("historyEventDelay", 1250); + option("viewportMargin", 10, function (cm) { cm.refresh(); }, true); + option("maxHighlightLength", 10000, resetModeState, true); + option("moveInputWithCursor", true, function (cm, val) { + if (!val) cm.display.input.resetPosition(); + }); + + option("tabindex", null, function (cm, val) { + cm.display.input.getField().tabIndex = val || ""; + }); + option("autofocus", null); + + // MODE DEFINITION AND QUERYING + + // Known modes, by name and by MIME + var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; + + // Extra arguments are stored as the mode's dependencies, which is + // used by (legacy) mechanisms like loadmode.js to automatically + // load a mode. (Preferred mechanism is the require/define calls.) + CodeMirror.defineMode = function (name, mode) { + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; + if (arguments.length > 2) + mode.dependencies = Array.prototype.slice.call(arguments, 2); + modes[name] = mode; + }; + + CodeMirror.defineMIME = function (mime, spec) { + mimeModes[mime] = spec; + }; + + // Given a MIME type, a {name, ...options} config object, or a name + // string, return a mode config object. + CodeMirror.resolveMode = function (spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { + spec = mimeModes[spec]; + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + if (typeof found == "string") found = { name: found }; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { + return CodeMirror.resolveMode("application/xml"); + } + if (typeof spec == "string") return { name: spec }; + else return spec || { name: "null" }; + }; + + // Given a mode spec (anything that resolveMode accepts), find and + // initialize an actual mode object. + CodeMirror.getMode = function (options, spec) { + var spec = CodeMirror.resolveMode(spec); + var mfactory = modes[spec.name]; + if (!mfactory) return CodeMirror.getMode(options, "text/plain"); + var modeObj = mfactory(options, spec); + if (modeExtensions.hasOwnProperty(spec.name)) { + var exts = modeExtensions[spec.name]; + for (var prop in exts) { + if (!exts.hasOwnProperty(prop)) continue; + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; + modeObj[prop] = exts[prop]; + } + } + modeObj.name = spec.name; + if (spec.helperType) modeObj.helperType = spec.helperType; + if (spec.modeProps) for (var prop in spec.modeProps) + modeObj[prop] = spec.modeProps[prop]; + + return modeObj; + }; + + // Minimal default mode. + CodeMirror.defineMode("null", function () { + return { token: function (stream) { stream.skipToEnd(); } }; + }); + CodeMirror.defineMIME("text/plain", "null"); + + // This can be used to attach properties to mode objects from + // outside the actual mode definition. + var modeExtensions = CodeMirror.modeExtensions = {}; + CodeMirror.extendMode = function (mode, properties) { + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); + copyObj(properties, exts); + }; + + // EXTENSIONS + + CodeMirror.defineExtension = function (name, func) { + CodeMirror.prototype[name] = func; + }; + CodeMirror.defineDocExtension = function (name, func) { + Doc.prototype[name] = func; + }; + CodeMirror.defineOption = option; + + var initHooks = []; + CodeMirror.defineInitHook = function (f) { initHooks.push(f); }; + + var helpers = CodeMirror.helpers = {}; + CodeMirror.registerHelper = function (type, name, value) { + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = { _global: [] }; + helpers[type][name] = value; + }; + CodeMirror.registerGlobalHelper = function (type, name, predicate, value) { + CodeMirror.registerHelper(type, name, value); + helpers[type]._global.push({ pred: predicate, val: value }); + }; + + // MODE STATE HANDLING + + // Utility functions for working with state. Exported because nested + // modes need to do this for their inner modes. + + var copyState = CodeMirror.copyState = function (mode, state) { + if (state === true) return state; + if (mode.copyState) return mode.copyState(state); + var nstate = {}; + for (var n in state) { + var val = state[n]; + if (val instanceof Array) val = val.concat([]); + nstate[n] = val; + } + return nstate; + }; + + var startState = CodeMirror.startState = function (mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; + }; + + // Given a mode and a state (for that mode), find the inner mode and + // state at the position that the state refers to. + CodeMirror.innerMode = function (mode, state) { + while (mode.innerMode) { + var info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || { mode: mode, state: state }; + }; + + // STANDARD COMMANDS + + // Commands are parameter-less actions that can be performed on an + // editor, mostly used for keybindings. + var commands = CodeMirror.commands = { + selectAll: function (cm) { cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll); }, + singleSelection: function (cm) { + cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); + }, + killLine: function (cm) { + deleteNearSelection(cm, function (range) { + if (range.empty()) { + var len = getLine(cm.doc, range.head.line).text.length; + if (range.head.ch == len && range.head.line < cm.lastLine()) + return { from: range.head, to: Pos(range.head.line + 1, 0) }; + else + return { from: range.head, to: Pos(range.head.line, len) }; + } else { + return { from: range.from(), to: range.to() }; + } + }); + }, + deleteLine: function (cm) { + deleteNearSelection(cm, function (range) { + return { + from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) + }; + }); + }, + delLineLeft: function (cm) { + deleteNearSelection(cm, function (range) { + return { from: Pos(range.from().line, 0), to: range.from() }; + }); + }, + delWrappedLineLeft: function (cm) { + deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5; + var leftPos = cm.coordsChar({ left: 0, top: top }, "div"); + return { from: leftPos, to: range.from() }; + }); + }, + delWrappedLineRight: function (cm) { + deleteNearSelection(cm, function (range) { + var top = cm.charCoords(range.head, "div").top + 5; + var rightPos = cm.coordsChar({ left: cm.display.lineDiv.offsetWidth + 100, top: top }, "div"); + return { from: range.from(), to: rightPos }; + }); + }, + undo: function (cm) { cm.undo(); }, + redo: function (cm) { cm.redo(); }, + undoSelection: function (cm) { cm.undoSelection(); }, + redoSelection: function (cm) { cm.redoSelection(); }, + goDocStart: function (cm) { cm.extendSelection(Pos(cm.firstLine(), 0)); }, + goDocEnd: function (cm) { cm.extendSelection(Pos(cm.lastLine())); }, + goLineStart: function (cm) { + cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); }, + { origin: "+move", bias: 1 }); + }, + goLineStartSmart: function (cm) { + cm.extendSelectionsBy(function (range) { + return lineStartSmart(cm, range.head); + }, { origin: "+move", bias: 1 }); + }, + goLineEnd: function (cm) { + cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); }, + { origin: "+move", bias: -1 }); + }, + goLineRight: function (cm) { + cm.extendSelectionsBy(function (range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({ left: cm.display.lineDiv.offsetWidth + 100, top: top }, "div"); + }, sel_move); + }, + goLineLeft: function (cm) { + cm.extendSelectionsBy(function (range) { + var top = cm.charCoords(range.head, "div").top + 5; + return cm.coordsChar({ left: 0, top: top }, "div"); + }, sel_move); + }, + goLineLeftSmart: function (cm) { + cm.extendSelectionsBy(function (range) { + var top = cm.charCoords(range.head, "div").top + 5; + var pos = cm.coordsChar({ left: 0, top: top }, "div"); + if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); + return pos; + }, sel_move); + }, + goLineUp: function (cm) { cm.moveV(-1, "line"); }, + goLineDown: function (cm) { cm.moveV(1, "line"); }, + goPageUp: function (cm) { cm.moveV(-1, "page"); }, + goPageDown: function (cm) { cm.moveV(1, "page"); }, + goCharLeft: function (cm) { cm.moveH(-1, "char"); }, + goCharRight: function (cm) { cm.moveH(1, "char"); }, + goColumnLeft: function (cm) { cm.moveH(-1, "column"); }, + goColumnRight: function (cm) { cm.moveH(1, "column"); }, + goWordLeft: function (cm) { cm.moveH(-1, "word"); }, + goGroupRight: function (cm) { cm.moveH(1, "group"); }, + goGroupLeft: function (cm) { cm.moveH(-1, "group"); }, + goWordRight: function (cm) { cm.moveH(1, "word"); }, + delCharBefore: function (cm) { cm.deleteH(-1, "char"); }, + delCharAfter: function (cm) { cm.deleteH(1, "char"); }, + delWordBefore: function (cm) { cm.deleteH(-1, "word"); }, + delWordAfter: function (cm) { cm.deleteH(1, "word"); }, + delGroupBefore: function (cm) { cm.deleteH(-1, "group"); }, + delGroupAfter: function (cm) { cm.deleteH(1, "group"); }, + indentAuto: function (cm) { cm.indentSelection("smart"); }, + indentMore: function (cm) { cm.indentSelection("add"); }, + indentLess: function (cm) { cm.indentSelection("subtract"); }, + insertTab: function (cm) { cm.replaceSelection("\t"); }, + insertSoftTab: function (cm) { + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + for (var i = 0; i < ranges.length; i++) { + var pos = ranges[i].from(); + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + spaces.push(spaceStr(tabSize - col % tabSize)); + } + cm.replaceSelections(spaces); + }, + defaultTab: function (cm) { + if (cm.somethingSelected()) cm.indentSelection("add"); + else cm.execCommand("insertTab"); + }, + transposeChars: function (cm) { + runInOp(cm, function () { + var ranges = cm.listSelections(), newSel = []; + for (var i = 0; i < ranges.length; i++) { + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + if (line) { + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1); + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose"); + } else if (cur.line > cm.doc.first) { + var prev = getLine(cm.doc, cur.line - 1).text; + if (prev) + cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); + } + } + newSel.push(new Range(cur, cur)); + } + cm.setSelections(newSel); + }); + }, + newlineAndIndent: function (cm) { + runInOp(cm, function () { + var len = cm.listSelections().length; + for (var i = 0; i < len; i++) { + var range = cm.listSelections()[i]; + cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input"); + cm.indentLine(range.from().line + 1, null, true); + } + ensureCursorVisible(cm); + }); + }, + openLine: function (cm) { cm.replaceSelection("\n", "start") }, + toggleOverwrite: function (cm) { cm.toggleOverwrite(); } + }; + + + // STANDARD KEYMAPS + + var keyMap = CodeMirror.keyMap = {}; + + keyMap.basic = { + "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", + "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", + "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", + "Tab": "defaultTab", "Shift-Tab": "indentAuto", + "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", + "Esc": "singleSelection" + }; + // Note that the save and find-related commands aren't defined by + // default. User code or addons can define them. Unknown commands + // are simply ignored. + keyMap.pcDefault = { + "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", + "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", + "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", + fallthrough: "basic" + }; + // Very basic readline/emacs-style bindings, which are standard on Mac. + keyMap.emacsy = { + "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", + "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", + "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", + "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", + "Ctrl-O": "openLine" + }; + keyMap.macDefault = { + "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", + fallthrough: ["basic", "emacsy"] + }; + keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; + + // KEYMAP DISPATCH + + function normalizeKeyName(name) { + var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; + var alt, ctrl, shift, cmd; + for (var i = 0; i < parts.length - 1; i++) { + var mod = parts[i]; + if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; + else if (/^a(lt)?$/i.test(mod)) alt = true; + else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; + else if (/^s(hift)$/i.test(mod)) shift = true; + else throw new Error("Unrecognized modifier name: " + mod); + } + if (alt) name = "Alt-" + name; + if (ctrl) name = "Ctrl-" + name; + if (cmd) name = "Cmd-" + name; + if (shift) name = "Shift-" + name; + return name; + } + + // This is a kludge to keep keymaps mostly working as raw objects + // (backwards compatibility) while at the same time support features + // like normalization and multi-stroke key bindings. It compiles a + // new normalized keymap, and then updates the old object to reflect + // this. + CodeMirror.normalizeKeyMap = function (keymap) { + var copy = {}; + for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { + var value = keymap[keyname]; + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; + if (value == "...") { delete keymap[keyname]; continue; } + + var keys = map(keyname.split(" "), normalizeKeyName); + for (var i = 0; i < keys.length; i++) { + var val, name; + if (i == keys.length - 1) { + name = keys.join(" "); + val = value; + } else { + name = keys.slice(0, i + 1).join(" "); + val = "..."; + } + var prev = copy[name]; + if (!prev) copy[name] = val; + else if (prev != val) throw new Error("Inconsistent bindings for " + name); + } + delete keymap[keyname]; + } + for (var prop in copy) keymap[prop] = copy[prop]; + return keymap; + }; + + var lookupKey = CodeMirror.lookupKey = function (key, map, handle, context) { + map = getKeyMap(map); + var found = map.call ? map.call(key, context) : map[key]; + if (found === false) return "nothing"; + if (found === "...") return "multi"; + if (found != null && handle(found)) return "handled"; + + if (map.fallthrough) { + if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") + return lookupKey(key, map.fallthrough, handle, context); + for (var i = 0; i < map.fallthrough.length; i++) { + var result = lookupKey(key, map.fallthrough[i], handle, context); + if (result) return result; + } + } + }; + + // Modifier key presses don't count as 'real' key presses for the + // purpose of keymap fallthrough. + var isModifierKey = CodeMirror.isModifierKey = function (value) { + var name = typeof value == "string" ? value : keyNames[value.keyCode]; + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + }; + + // Look up the name of a key as indicated by an event object. + var keyName = CodeMirror.keyName = function (event, noShift) { + if (presto && event.keyCode == 34 && event["char"]) return false; + var base = keyNames[event.keyCode], name = base; + if (name == null || event.altGraphKey) return false; + if (event.altKey && base != "Alt") name = "Alt-" + name; + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; + if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; + return name; + }; + + function getKeyMap(val) { + return typeof val == "string" ? keyMap[val] : val; + } + + // FROMTEXTAREA + + CodeMirror.fromTextArea = function (textarea, options) { + options = options ? copyObj(options) : {}; + options.value = textarea.value; + if (!options.tabindex && textarea.tabIndex) + options.tabindex = textarea.tabIndex; + if (!options.placeholder && textarea.placeholder) + options.placeholder = textarea.placeholder; + // Set autofocus to true if this textarea is focused, or if it has + // autofocus and no other element is focused. + if (options.autofocus == null) { + var hasFocus = activeElt(); + options.autofocus = hasFocus == textarea || + textarea.getAttribute("autofocus") != null && hasFocus == document.body; + } + + function save() { textarea.value = cm.getValue(); } + if (textarea.form) { + on(textarea.form, "submit", save); + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function () { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch (e) { } + } + } + + options.finishInit = function (cm) { + cm.save = save; + cm.getTextArea = function () { return textarea; }; + cm.toTextArea = function () { + cm.toTextArea = isNaN; // Prevent this from being ran twice + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + }; + + textarea.style.display = "none"; + var cm = CodeMirror(function (node) { + textarea.parentNode.insertBefore(node, textarea.nextSibling); + }, options); + return cm; + }; + + // STRING STREAM + + // Fed to the mode parsers, provides helper functions to make + // parsers more succinct. + + var StringStream = CodeMirror.StringStream = function (string, tabSize) { + this.pos = this.start = 0; + this.string = string; + this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; + this.lineStart = 0; + }; + + StringStream.prototype = { + eol: function () { return this.pos >= this.string.length; }, + sol: function () { return this.pos == this.lineStart; }, + peek: function () { return this.string.charAt(this.pos) || undefined; }, + next: function () { + if (this.pos < this.string.length) + return this.string.charAt(this.pos++); + }, + eat: function (match) { + var ch = this.string.charAt(this.pos); + if (typeof match == "string") var ok = ch == match; + else var ok = ch && (match.test ? match.test(ch) : match(ch)); + if (ok) { ++this.pos; return ch; } + }, + eatWhile: function (match) { + var start = this.pos; + while (this.eat(match)) { } + return this.pos > start; + }, + eatSpace: function () { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; + return this.pos > start; + }, + skipToEnd: function () { this.pos = this.string.length; }, + skipTo: function (ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) { this.pos = found; return true; } + }, + backUp: function (n) { this.pos -= n; }, + column: function () { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + indentation: function () { + return countColumn(this.string, null, this.tabSize) - + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + }, + match: function (pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }; + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && match.index > 0) return null; + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function () { return this.string.slice(this.start, this.pos); }, + hideFirstChars: function (n, inner) { + this.lineStart += n; + try { return inner(); } + finally { this.lineStart -= n; } + } + }; + + // TEXTMARKERS + + // Created with markText and setBookmark methods. A TextMarker is a + // handle that can be used to clear or find a marked position in the + // document. Line objects hold arrays (markedSpans) containing + // {from, to, marker} object pointing to such marker objects, and + // indicating that such a marker is present on that line. Multiple + // lines may point to the same marker when it spans across lines. + // The spans will have null for their from/to properties when the + // marker continues beyond the start/end of the line. Markers have + // links back to the lines they currently touch. + + var nextMarkerId = 0; + + var TextMarker = CodeMirror.TextMarker = function (doc, type) { + this.lines = []; + this.type = type; + this.doc = doc; + this.id = ++nextMarkerId; + }; + eventMixin(TextMarker); + + // Clear the marker. + TextMarker.prototype.clear = function () { + if (this.explicitlyCleared) return; + var cm = this.doc.cm, withOp = cm && !cm.curOp; + if (withOp) startOperation(cm); + if (hasHandler(this, "clear")) { + var found = this.find(); + if (found) signalLater(this, "clear", found.from, found.to); + } + var min = null, max = null; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); + else if (cm) { + if (span.to != null) max = lineNo(line); + if (span.from != null) min = lineNo(line); + } + line.markedSpans = removeMarkedSpan(line.markedSpans, span); + if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) + updateLineHeight(line, textHeight(cm.display)); + } + if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(this.lines[i]), len = lineLength(visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; + } + } + + if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); + this.lines.length = 0; + this.explicitlyCleared = true; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm.doc); + } + if (cm) signalLater(cm, "markerCleared", cm, this); + if (withOp) endOperation(cm); + if (this.parent) this.parent.clear(); + }; + + // Find the position of the marker in the document. Returns a {from, + // to} object by default. Side can be passed to get a specific side + // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the + // Pos objects returned contain a line object, rather than a line + // number (used to prevent looking up the same line twice). + TextMarker.prototype.find = function (side, lineObj) { + if (side == null && this.type == "bookmark") side = 1; + var from, to; + for (var i = 0; i < this.lines.length; ++i) { + var line = this.lines[i]; + var span = getMarkedSpanFor(line.markedSpans, this); + if (span.from != null) { + from = Pos(lineObj ? line : lineNo(line), span.from); + if (side == -1) return from; + } + if (span.to != null) { + to = Pos(lineObj ? line : lineNo(line), span.to); + if (side == 1) return to; + } + } + return from && { from: from, to: to }; + }; + + // Signals that the marker's widget changed, and surrounding layout + // should be recomputed. + TextMarker.prototype.changed = function () { + var pos = this.find(-1, true), widget = this, cm = this.doc.cm; + if (!pos || !cm) return; + runInOp(cm, function () { + var line = pos.line, lineN = lineNo(pos.line); + var view = findViewForLine(cm, lineN); + if (view) { + clearLineMeasurementCacheFor(view); + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + } + cm.curOp.updateMaxLine = true; + if (!lineIsHidden(widget.doc, line) && widget.height != null) { + var oldHeight = widget.height; + widget.height = null; + var dHeight = widgetHeight(widget) - oldHeight; + if (dHeight) + updateLineHeight(line, line.height + dHeight); + } + }); + }; + + TextMarker.prototype.attachLine = function (line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(line); + }; + TextMarker.prototype.detachLine = function (line) { + this.lines.splice(indexOf(this.lines, line), 1); + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + + // Collapsed markers have unique ids, in order to be able to order + // them, which is needed for uniquely determining an outer marker + // when they overlap (they may nest, but not partially overlap). + var nextMarkerId = 0; + + // Create a marker, wire it up to the right lines, and + function markText(doc, from, to, options, type) { + // Shared markers (across linked documents) are handled separately + // (markTextShared will call out to this again, once per + // document). + if (options && options.shared) return markTextShared(doc, from, to, options, type); + // Ensure we are in an operation. + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + + var marker = new TextMarker(doc, type), diff = cmp(from, to); + if (options) copyObj(options, marker, false); + // Don't connect empty markers unless clearWhenEmpty is false + if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) + return marker; + if (marker.replacedWith) { + // Showing up as a widget implies collapsed (widget replaces text) + marker.collapsed = true; + marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); + if (options.insertLeft) marker.widgetNode.insertLeft = true; + } + if (marker.collapsed) { + if (conflictingCollapsedRange(doc, from.line, from, to, marker) || + from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) + throw new Error("Inserting collapsed marker partially overlapping an existing one"); + sawCollapsedSpans = true; + } + + if (marker.addToHistory) + addChangeToHistory(doc, { from: from, to: to, origin: "markText" }, doc.sel, NaN); + + var curLine = from.line, cm = doc.cm, updateMaxLine; + doc.iter(curLine, to.line + 1, function (line) { + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) + updateMaxLine = true; + if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); + addMarkedSpan(line, new MarkedSpan(marker, + curLine == from.line ? from.ch : null, + curLine == to.line ? to.ch : null)); + ++curLine; + }); + // lineIsHidden depends on the presence of the spans, so needs a second pass + if (marker.collapsed) doc.iter(from.line, to.line + 1, function (line) { + if (lineIsHidden(doc, line)) updateLineHeight(line, 0); + }); + + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function () { marker.clear(); }); + + if (marker.readOnly) { + sawReadOnlySpans = true; + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); + } + if (marker.collapsed) { + marker.id = ++nextMarkerId; + marker.atomic = true; + } + if (cm) { + // Sync editor state + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.collapsed) + regChange(cm, from.line, to.line + 1); + else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) + for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); + if (marker.atomic) reCheckSelection(cm.doc); + signalLater(cm, "markerAdded", cm, marker); + } + return marker; + } + + // SHARED TEXTMARKERS + + // A shared marker spans multiple linked documents. It is + // implemented as a meta-marker-object controlling multiple normal + // markers. + var SharedTextMarker = CodeMirror.SharedTextMarker = function (markers, primary) { + this.markers = markers; + this.primary = primary; + for (var i = 0; i < markers.length; ++i) + markers[i].parent = this; + }; + eventMixin(SharedTextMarker); + + SharedTextMarker.prototype.clear = function () { + if (this.explicitlyCleared) return; + this.explicitlyCleared = true; + for (var i = 0; i < this.markers.length; ++i) + this.markers[i].clear(); + signalLater(this, "clear"); + }; + SharedTextMarker.prototype.find = function (side, lineObj) { + return this.primary.find(side, lineObj); + }; + + function markTextShared(doc, from, to, options, type) { + options = copyObj(options); + options.shared = false; + var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.widgetNode; + linkedDocs(doc, function (doc) { + if (widget) options.widgetNode = widget.cloneNode(true); + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + for (var i = 0; i < doc.linked.length; ++i) + if (doc.linked[i].isParent) return; + primary = lst(markers); + }); + return new SharedTextMarker(markers, primary); + } + + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), + function (m) { return m.parent; }); + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], linked = [marker.primary.doc];; + linkedDocs(marker.primary.doc, function (d) { linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + } + } + + // TEXTMARKER SPANS + + function MarkedSpan(marker, from, to) { + this.marker = marker; + this.from = from; this.to = to; + } + + // Search an array of spans for a span matching the given marker. + function getMarkedSpanFor(spans, marker) { + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.marker == marker) return span; + } + } + // Remove a span from an array, returning undefined if no spans are + // left (we don't store arrays for lines without spans). + function removeMarkedSpan(spans, span) { + for (var r, i = 0; i < spans.length; ++i) + if (spans[i] != span) (r || (r = [])).push(spans[i]); + return r; + } + // Add a span to a line. + function addMarkedSpan(line, span) { + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; + span.marker.attachLine(line); + } + + // Used for the algorithm that adjusts markers for a change in the + // document. These functions cut an array of spans at a given + // character position, returning an array of remaining chunks (or + // undefined if nothing remains). + function markedSpansBefore(old, startCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); + if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); + (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + } + } + return nw; + } + function markedSpansAfter(old, endCh, isInsert) { + if (old) for (var i = 0, nw; i < old.length; ++i) { + var span = old[i], marker = span.marker; + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); + (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)); + } + } + return nw; + } + + // Given a change object, compute the new set of marker spans that + // cover the line in which the change took place. Removes spans + // entirely within the change, reconnects spans belonging to the + // same marker that appear on both sides of the change, and cuts off + // spans partially within the change. Returns an array of span + // arrays with one element for each line in (after) the change. + function stretchSpansOverChange(doc, change) { + if (change.full) return null; + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; + if (!oldFirst && !oldLast) return null; + + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + // Get the spans that 'stick out' on both sides + var first = markedSpansBefore(oldFirst, startCh, isInsert); + var last = markedSpansAfter(oldLast, endCh, isInsert); + + // Next, merge those two ends + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + if (first) { + // Fix up .to properties of first + for (var i = 0; i < first.length; ++i) { + var span = first[i]; + if (span.to == null) { + var found = getMarkedSpanFor(last, span.marker); + if (!found) span.to = startCh; + else if (sameLine) span.to = found.to == null ? null : found.to + offset; + } + } + } + if (last) { + // Fix up .from in last (or move them into first in case of sameLine) + for (var i = 0; i < last.length; ++i) { + var span = last[i]; + if (span.to != null) span.to += offset; + if (span.from == null) { + var found = getMarkedSpanFor(first, span.marker); + if (!found) { + span.from = offset; + if (sameLine) (first || (first = [])).push(span); + } + } else { + span.from += offset; + if (sameLine) (first || (first = [])).push(span); + } + } + } + // Make sure we didn't create any zero-length spans + if (first) first = clearEmptySpans(first); + if (last && last != first) last = clearEmptySpans(last); + + var newMarkers = [first]; + if (!sameLine) { + // Fill gap with whole-line-spans + var gap = change.text.length - 2, gapMarkers; + if (gap > 0 && first) + for (var i = 0; i < first.length; ++i) + if (first[i].to == null) + (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); + for (var i = 0; i < gap; ++i) + newMarkers.push(gapMarkers); + newMarkers.push(last); + } + return newMarkers; + } + + // Remove spans that are empty and don't have a clearWhenEmpty + // option of false. + function clearEmptySpans(spans) { + for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) + spans.splice(i--, 1); + } + if (!spans.length) return null; + return spans; + } + + // Used for un/re-doing changes from the history. Combines the + // result of computing the existing spans with the set of spans that + // existed in the history (so that deleting around a span and then + // undoing brings back the span). + function mergeOldSpans(doc, change) { + var old = getOldSpans(doc, change); + var stretched = stretchSpansOverChange(doc, change); + if (!old) return stretched; + if (!stretched) return old; + + for (var i = 0; i < old.length; ++i) { + var oldCur = old[i], stretchCur = stretched[i]; + if (oldCur && stretchCur) { + spans: for (var j = 0; j < stretchCur.length; ++j) { + var span = stretchCur[j]; + for (var k = 0; k < oldCur.length; ++k) + if (oldCur[k].marker == span.marker) continue spans; + oldCur.push(span); + } + } else if (stretchCur) { + old[i] = stretchCur; + } + } + return old; + } + + // Used to 'clip' out readOnly ranges when making a change. + function removeReadOnlyRanges(doc, from, to) { + var markers = null; + doc.iter(from.line, to.line + 1, function (line) { + if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { + var mark = line.markedSpans[i].marker; + if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) + (markers || (markers = [])).push(mark); + } + }); + if (!markers) return null; + var parts = [{ from: from, to: to }]; + for (var i = 0; i < markers.length; ++i) { + var mk = markers[i], m = mk.find(0); + for (var j = 0; j < parts.length; ++j) { + var p = parts[j]; + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) + newParts.push({ from: p.from, to: m.from }); + if (dto > 0 || !mk.inclusiveRight && !dto) + newParts.push({ from: m.to, to: p.to }); + parts.splice.apply(parts, newParts); + j += newParts.length - 1; + } + } + return parts; + } + + // Connect or disconnect spans from a line. + function detachMarkedSpans(line) { + var spans = line.markedSpans; + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); + line.markedSpans = null; + } + function attachMarkedSpans(line, spans) { + if (!spans) return; + for (var i = 0; i < spans.length; ++i) + spans[i].marker.attachLine(line); + line.markedSpans = spans; + } + + // Helpers used when computing which overlapping collapsed span + // counts as the larger one. + function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } + function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } + + // Returns a number indicating which of two overlapping collapsed + // spans is larger (and thus includes the other). Falls back to + // comparing ids when the spans cover exactly the same range. + function compareCollapsedMarkers(a, b) { + var lenDiff = a.lines.length - b.lines.length; + if (lenDiff != 0) return lenDiff; + var aPos = a.find(), bPos = b.find(); + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); + if (fromCmp) return -fromCmp; + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); + if (toCmp) return toCmp; + return b.id - a.id; + } + + // Find out whether a line ends or starts in a collapsed span. If + // so, return the marker for that span. + function collapsedSpanAtSide(line, start) { + var sps = sawCollapsedSpans && line.markedSpans, found; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && + (!found || compareCollapsedMarkers(found, sp.marker) < 0)) + found = sp.marker; + } + return found; + } + function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } + function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } + + // Test whether there exists a collapsed span that partially + // overlaps (covers the start or end, but not both) of a new span. + // Such overlap is not allowed. + function conflictingCollapsedRange(doc, lineNo, from, to, marker) { + var line = getLine(doc, lineNo); + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) { + var sp = sps[i]; + if (!sp.marker.collapsed) continue; + var found = sp.marker.find(0); + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; + if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || + fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) + return true; + } + } + + // A visual line is a line as drawn on the screen. Folding, for + // example, can cause multiple logical lines to appear on the same + // visual line. This finds the start of the visual line that the + // given line is part of (usually that is the line itself). + function visualLine(line) { + var merged; + while (merged = collapsedSpanAtStart(line)) + line = merged.find(-1, true).line; + return line; + } + + // Returns an array of logical lines that continue the visual line + // started by the argument, or undefined if there are no such lines. + function visualLineContinued(line) { + var merged, lines; + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + (lines || (lines = [])).push(line); + } + return lines; + } + + // Get the line number of the start of the visual line that the + // given line number is part of. + function visualLineNo(doc, lineN) { + var line = getLine(doc, lineN), vis = visualLine(line); + if (line == vis) return lineN; + return lineNo(vis); + } + // Get the line number of the start of the next visual line after + // the given line. + function visualLineEndNo(doc, lineN) { + if (lineN > doc.lastLine()) return lineN; + var line = getLine(doc, lineN), merged; + if (!lineIsHidden(doc, line)) return lineN; + while (merged = collapsedSpanAtEnd(line)) + line = merged.find(1, true).line; + return lineNo(line) + 1; + } + + // Compute whether a line is hidden. Lines count as hidden when they + // are part of a visual line that starts with another line, or when + // they are entirely covered by collapsed, non-widget span. + function lineIsHidden(doc, line) { + var sps = sawCollapsedSpans && line.markedSpans; + if (sps) for (var sp, i = 0; i < sps.length; ++i) { + sp = sps[i]; + if (!sp.marker.collapsed) continue; + if (sp.from == null) return true; + if (sp.marker.widgetNode) continue; + if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) + return true; + } + } + function lineIsHiddenInner(doc, line, span) { + if (span.to == null) { + var end = span.marker.find(1, true); + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) + return true; + for (var sp, i = 0; i < line.markedSpans.length; ++i) { + sp = line.markedSpans[i]; + if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && + (sp.to == null || sp.to != span.from) && + (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && + lineIsHiddenInner(doc, line, sp)) return true; + } + } + + // LINE WIDGETS + + // Line widgets are block elements displayed above or below a line. + + var LineWidget = CodeMirror.LineWidget = function (doc, node, options) { + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.doc = doc; + this.node = node; + }; + eventMixin(LineWidget); + + function adjustScrollWhenAboveVisible(cm, line, diff) { + if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) + addToScrollPos(cm, null, diff); + } + + LineWidget.prototype.clear = function () { + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + if (!ws.length) line.widgets = null; + var height = widgetHeight(this); + updateLineHeight(line, Math.max(0, line.height - height)); + if (cm) runInOp(cm, function () { + adjustScrollWhenAboveVisible(cm, line, -height); + regLineChange(cm, no, "widget"); + }); + }; + LineWidget.prototype.changed = function () { + var oldH = this.height, cm = this.doc.cm, line = this.line; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + updateLineHeight(line, line.height + diff); + if (cm) runInOp(cm, function () { + cm.curOp.forceUpdate = true; + adjustScrollWhenAboveVisible(cm, line, diff); + }); + }; + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + var cm = widget.doc.cm; + if (!cm) return 0; + if (!contains(document.body, widget.node)) { + var parentStyle = "position: relative;"; + if (widget.coverGutter) + parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; + if (widget.noHScroll) + parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); + } + return widget.height = widget.node.parentNode.offsetHeight; + } + + function addLineWidget(doc, handle, node, options) { + var widget = new LineWidget(doc, node, options); + var cm = doc.cm; + if (cm && widget.noHScroll) cm.display.alignWidgets = true; + changeLine(doc, handle, "widget", function (line) { + var widgets = line.widgets || (line.widgets = []); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); + widget.line = line; + if (cm && !lineIsHidden(doc, line)) { + var aboveVisible = heightAtLine(line) < doc.scrollTop; + updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) addToScrollPos(cm, null, widget.height); + cm.curOp.forceUpdate = true; + } + return true; + }); + return widget; + } + + // LINE DATA STRUCTURE + + // Line objects. These hold state related to a line, including + // highlighting info (the styles array). + var Line = CodeMirror.Line = function (text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; + }; + eventMixin(Line); + Line.prototype.lineNo = function () { return lineNo(this); }; + + // Change the content (text, markers) of a line. Automatically + // invalidates cached information and tries to re-estimate the + // line's height. + function updateLine(line, text, markedSpans, estimateHeight) { + line.text = text; + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + if (line.order != null) line.order = null; + detachMarkedSpans(line); + attachMarkedSpans(line, markedSpans); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + } + + // Detach a line from the document tree and its markers. + function cleanUpLine(line) { + line.parent = null; + detachMarkedSpans(line); + } + + function extractLineClasses(type, output) { + if (type) for (; ;) { + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); + if (!lineClass) break; + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (output[prop] == null) + output[prop] = lineClass[2]; + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) + output[prop] += " " + lineClass[2]; + } + return type; + } + + function callBlankLine(mode, state) { + if (mode.blankLine) return mode.blankLine(state); + if (!mode.innerMode) return; + var inner = CodeMirror.innerMode(mode, state); + if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); + } + + function readToken(mode, stream, state, inner) { + for (var i = 0; i < 10; i++) { + if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; + var style = mode.token(stream, state); + if (stream.pos > stream.start) return style; + } + throw new Error("Mode " + mode.name + " failed to advance stream."); + } + + // Utility for getTokenAt and getLineTokens + function takeToken(cm, pos, precise, asArray) { + function getObj(copy) { + return { + start: stream.start, end: stream.pos, + string: stream.current(), + type: style || null, + state: copy ? copyState(doc.mode, state) : state + }; + } + + var doc = cm.doc, mode = doc.mode, style; + pos = clipPos(doc, pos); + var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); + var stream = new StringStream(line.text, cm.options.tabSize), tokens; + if (asArray) tokens = []; + while ((asArray || stream.pos < pos.ch) && !stream.eol()) { + stream.start = stream.pos; + style = readToken(mode, stream, state); + if (asArray) tokens.push(getObj(true)); + } + return asArray ? tokens : getObj(); + } + + // Run the given mode's parser over a line, calling f for each token. + function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { + var flattenSpans = mode.flattenSpans; + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; + var curStart = 0, curStyle = null; + var stream = new StringStream(text, cm.options.tabSize), style; + var inner = cm.options.addModeClass && [null]; + if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); + while (!stream.eol()) { + if (stream.pos > cm.options.maxHighlightLength) { + flattenSpans = false; + if (forceToEnd) processLine(cm, text, state, stream.pos); + stream.pos = text.length; + style = null; + } else { + style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); + } + if (inner) { + var mName = inner[0].name; + if (mName) style = "m-" + (style ? mName + " " + style : mName); + } + if (!flattenSpans || curStyle != style) { + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 50000); + f(curStart, curStyle); + } + curStyle = style; + } + stream.start = stream.pos; + } + while (curStart < stream.pos) { + // Webkit seems to refuse to render text nodes longer than 57444 characters + var pos = Math.min(stream.pos, curStart + 50000); + f(pos, curStyle); + curStart = pos; + } + } + + // Compute a style array (an array starting with a mode generation + // -- for invalidation -- followed by pairs of end positions and + // style strings), which is used to highlight the tokens on the + // line. + function highlightLine(cm, line, state, forceToEnd) { + // A styles array always starts with a number identifying the + // mode/overlays that it is based on (for easy invalidation). + var st = [cm.state.modeGen], lineClasses = {}; + // Compute the base array of styles + runMode(cm, line.text, cm.doc.mode, state, function (end, style) { + st.push(end, style); + }, lineClasses, forceToEnd); + + // Run overlays, adjust style array. + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1, at = 0; + runMode(cm, line.text, overlay.mode, true, function (end, style) { + var start = i; + // Ensure there's a token end at the current position, and that i points at it + while (at < end) { + var i_end = st[i]; + if (i_end > end) + st.splice(i, 1, end, st[i + 1], i_end); + i += 2; + at = Math.min(end, i_end); + } + if (!style) return; + if (overlay.opaque) { + st.splice(start, i - start, end, "cm-overlay " + style); + i = start + 2; + } else { + for (; start < i; start += 2) { + var cur = st[start + 1]; + st[start + 1] = (cur ? cur + " " : "") + "cm-overlay " + style; + } + } + }, lineClasses); + } + + return { styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null }; + } + + function getLineStyles(cm, line, updateFrontier) { + if (!line.styles || line.styles[0] != cm.state.modeGen) { + var state = getStateBefore(cm, lineNo(line)); + var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state); + line.stateAfter = state; + line.styles = result.styles; + if (result.classes) line.styleClasses = result.classes; + else if (line.styleClasses) line.styleClasses = null; + if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; + } + return line.styles; + } + + // Lightweight form of highlight -- proceed over this line and + // update state, but don't save a style array. Used for lines that + // aren't currently visible. + function processLine(cm, text, state, startAt) { + var mode = cm.doc.mode; + var stream = new StringStream(text, cm.options.tabSize); + stream.start = stream.pos = startAt || 0; + if (text == "") callBlankLine(mode, state); + while (!stream.eol()) { + readToken(mode, stream, state); + stream.start = stream.pos; + } + } + + // Convert a style as returned by a mode (either null, or a string + // containing one or more styles) to a CSS style. This is cached, + // and also looks for line-wide styles. + var styleToClassCache = {}, styleToClassCacheWithMode = {}; + function interpretTokenStyle(style, options) { + if (!style || /^\s*$/.test(style)) return null; + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + return cache[style] || + (cache[style] = style.replace(/\S+/g, "cm-$&")); + } + + // Render the DOM representation of the text of a line. Also builds + // up a 'line map', which points at the DOM nodes that represent + // specific stretches of text, and is used by the measuring code. + // The returned object contains the DOM node, this map, and + // information about line-wide styles that were set by the mode. + function buildLineContent(cm, lineView) { + // The padding-right forces the element to have a 'border', which + // is needed on Webkit to be able to get line-level bounding + // rectangles for it (in measureChar). + var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); + var builder = { + pre: elt("pre", [content], "CodeMirror-line"), content: content, + col: 0, pos: 0, cm: cm, + trailingSpace: false, + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping") + }; + lineView.measure = {}; + + // Iterate over the logical lines that make up this visual line. + for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + var line = i ? lineView.rest[i - 1] : lineView.line, order; + builder.pos = 0; + builder.addToken = buildToken; + // Optionally wire in some hacks into the token-rendering + // algorithm, to deal with browser quirks. + if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) + builder.addToken = buildTokenBadBidi(builder.addToken, order); + builder.map = []; + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); + if (line.styleClasses) { + if (line.styleClasses.bgClass) + builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); + if (line.styleClasses.textClass) + builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); + } + + // Ensure at least a single node is present, for measuring. + if (builder.map.length == 0) + builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); + + // Store the map and a cache object for the current logical line + if (i == 0) { + lineView.measure.map = builder.map; + lineView.measure.cache = {}; + } else { + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); + (lineView.measure.caches || (lineView.measure.caches = [])).push({}); + } + } + + // See issue #2901 + if (webkit) { + var last = builder.content.lastChild + if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) + builder.content.className = "cm-tab-wrap-hack"; + } + + signal(cm, "renderLine", cm, lineView.line, builder.pre); + if (builder.pre.className) + builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); + + return builder; + } + + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.charCodeAt(0).toString(16); + token.setAttribute("aria-label", token.title); + return token; + } + + // Build up the DOM representation for a single token, and add it to + // the line map. Takes care to render special characters separately. + function buildToken(builder, text, style, startStyle, endStyle, title, css) { + if (!text) return; + var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text + var special = builder.cm.state.specialChars, mustWrap = false; + if (!special.test(text)) { + builder.col += text.length; + var content = document.createTextNode(displayText); + builder.map.push(builder.pos, builder.pos + text.length, content); + if (ie && ie_version < 9) mustWrap = true; + builder.pos += text.length; + } else { + var content = document.createDocumentFragment(), pos = 0; + while (true) { + special.lastIndex = pos; + var m = special.exec(text); + var skipped = m ? m.index - pos : text.length - pos; + if (skipped) { + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.map.push(builder.pos, builder.pos + skipped, txt); + builder.col += skipped; + builder.pos += skipped; + } + if (!m) break; + pos += skipped + 1; + if (m[0] == "\t") { + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; + var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + txt.setAttribute("role", "presentation"); + txt.setAttribute("cm-text", "\t"); + builder.col += tabWidth; + } else if (m[0] == "\r" || m[0] == "\n") { + var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")); + txt.setAttribute("cm-text", m[0]); + builder.col += 1; + } else { + var txt = builder.cm.options.specialCharPlaceholder(m[0]); + txt.setAttribute("cm-text", m[0]); + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); + else content.appendChild(txt); + builder.col += 1; + } + builder.map.push(builder.pos, builder.pos + 1, txt); + builder.pos++; + } + } + builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 + if (style || startStyle || endStyle || mustWrap || css) { + var fullStyle = style || ""; + if (startStyle) fullStyle += startStyle; + if (endStyle) fullStyle += endStyle; + var token = elt("span", [content], fullStyle, css); + if (title) token.title = title; + return builder.content.appendChild(token); + } + builder.content.appendChild(content); + } + + function splitSpaces(text, trailingBefore) { + if (text.length > 1 && !/ /.test(text)) return text + var spaceBefore = trailingBefore, result = "" + for (var i = 0; i < text.length; i++) { + var ch = text.charAt(i) + if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) + ch = "\u00a0" + result += ch + spaceBefore = ch == " " + } + return result + } + + // Work around nonsense dimensions being reported for stretches of + // right-to-left text. + function buildTokenBadBidi(inner, order) { + return function (builder, text, style, startStyle, endStyle, title, css) { + style = style ? style + " cm-force-border" : "cm-force-border"; + var start = builder.pos, end = start + text.length; + for (; ;) { + // Find the part that overlaps with the start of this text + for (var i = 0; i < order.length; i++) { + var part = order[i]; + if (part.to > start && part.from <= start) break; + } + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); + startStyle = null; + text = text.slice(part.to - start); + start = part.to; + } + }; + } + + function buildCollapsedSpan(builder, size, marker, ignoreWidget) { + var widget = !ignoreWidget && marker.widgetNode; + if (widget) builder.map.push(builder.pos, builder.pos + size, widget); + if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { + if (!widget) + widget = builder.content.appendChild(document.createElement("span")); + widget.setAttribute("cm-marker", marker.id); + } + if (widget) { + builder.cm.display.input.setUneditable(widget); + builder.content.appendChild(widget); + } + builder.pos += size; + builder.trailingSpace = false + } + + // Outputs a number of spans to make up a line, taking highlighting + // and marked text into account. + function insertLineContent(line, builder, styles) { + var spans = line.markedSpans, allText = line.text, at = 0; + if (!spans) { + for (var i = 1; i < styles.length; i += 2) + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i + 1], builder.cm.options)); + return; + } + + var len = allText.length, pos = 0, i = 1, text = "", style, css; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + for (; ;) { + if (nextChange == pos) { // Update current marker set + spanStyle = spanEndStyle = spanStartStyle = title = css = ""; + collapsed = null; nextChange = Infinity; + var foundBookmarks = [], endStyles + for (var j = 0; j < spans.length; ++j) { + var sp = spans[j], m = sp.marker; + if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { + foundBookmarks.push(m); + } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { + if (sp.to != null && sp.to != pos && nextChange > sp.to) { + nextChange = sp.to; + spanEndStyle = ""; + } + if (m.className) spanStyle += " " + m.className; + if (m.css) css = (css ? css + ";" : "") + m.css; + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to) + if (m.title && !title) title = m.title; + if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) + collapsed = sp; + } else if (sp.from > pos && nextChange > sp.from) { + nextChange = sp.from; + } + } + if (endStyles) for (var j = 0; j < endStyles.length; j += 2) + if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j] + + if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j) + buildCollapsedSpan(builder, 0, foundBookmarks[j]); + if (collapsed && (collapsed.from || 0) == pos) { + buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, + collapsed.marker, collapsed.from == null); + if (collapsed.to == null) return; + if (collapsed.to == pos) collapsed = false; + } + } + if (pos >= len) break; + + var upto = Math.min(len, nextChange); + while (true) { + if (text) { + var end = pos + text.length; + if (!collapsed) { + var tokenText = end > upto ? text.slice(0, upto - pos) : text; + builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); + } + if (end >= upto) { text = text.slice(upto - pos); pos = upto; break; } + pos = end; + spanStartStyle = ""; + } + text = allText.slice(at, at = styles[i++]); + style = interpretTokenStyle(styles[i++], builder.cm.options); + } + } + } + + // DOCUMENT DATA STRUCTURE + + // By default, updates that start and end at the beginning of a line + // are treated specially, in order to make the association of line + // widgets and marker elements with the text behave more intuitive. + function isWholeLineUpdate(doc, change) { + return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore); + } + + // Perform a change on the document data structure. + function updateDoc(doc, change, markedSpans, estimateHeight) { + function spansFor(n) { return markedSpans ? markedSpans[n] : null; } + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } + function linesFor(start, end) { + for (var i = start, result = []; i < end; ++i) + result.push(new Line(text[i], spansFor(i), estimateHeight)); + return result; + } + + var from = change.from, to = change.to, text = change.text; + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + + // Adjust the line structure + if (change.full) { + doc.insert(0, linesFor(0, text.length)); + doc.remove(text.length, doc.size - text.length); + } else if (isWholeLineUpdate(doc, change)) { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + var added = linesFor(0, text.length - 1); + update(lastLine, lastLine.text, lastSpans); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + } else { + var added = linesFor(1, text.length - 1); + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); + doc.remove(from.line + 1, nlines); + } else { + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); + var added = linesFor(1, text.length - 1); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + signalLater(doc, "change", doc, change); + } + + // The document is represented as a BTree consisting of leaves, with + // chunk of lines in them, and branches, with up to ten leaves or + // other branch nodes below them. The top node is always a branch + // node, and is the document object itself (meaning it has + // additional methods and properties). + // + // All nodes have parent links. The tree is used both to go from + // line numbers to line objects, and to go from objects to numbers. + // It also indexes by height, and is used to convert between height + // and line object, and to find the total height of the document. + // + // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html + + function LeafChunk(lines) { + this.lines = lines; + this.parent = null; + for (var i = 0, height = 0; i < lines.length; ++i) { + lines[i].parent = this; + height += lines[i].height; + } + this.height = height; + } + + LeafChunk.prototype = { + chunkSize: function () { return this.lines.length; }, + // Remove the n lines at offset 'at'. + removeInner: function (at, n) { + for (var i = at, e = at + n; i < e; ++i) { + var line = this.lines[i]; + this.height -= line.height; + cleanUpLine(line); + signalLater(line, "delete"); + } + this.lines.splice(at, n); + }, + // Helper used to collapse a small branch into a single leaf. + collapse: function (lines) { + lines.push.apply(lines, this.lines); + }, + // Insert the given array of lines at offset 'at', count them as + // having the given height. + insertInner: function (at, lines, height) { + this.height += height; + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); + for (var i = 0; i < lines.length; ++i) lines[i].parent = this; + }, + // Used to iterate over a part of the tree. + iterN: function (at, n, op) { + for (var e = at + n; at < e; ++at) + if (op(this.lines[at])) return true; + } + }; + + function BranchChunk(children) { + this.children = children; + var size = 0, height = 0; + for (var i = 0; i < children.length; ++i) { + var ch = children[i]; + size += ch.chunkSize(); height += ch.height; + ch.parent = this; + } + this.size = size; + this.height = height; + this.parent = null; + } + + BranchChunk.prototype = { + chunkSize: function () { return this.size; }, + removeInner: function (at, n) { + this.size -= n; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var rm = Math.min(n, sz - at), oldHeight = child.height; + child.removeInner(at, rm); + this.height -= oldHeight - child.height; + if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } + if ((n -= rm) == 0) break; + at = 0; + } else at -= sz; + } + // If the result is smaller than 25 lines, ensure that it is a + // single leaf node. + if (this.size - n < 25 && + (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { + var lines = []; + this.collapse(lines); + this.children = [new LeafChunk(lines)]; + this.children[0].parent = this; + } + }, + collapse: function (lines) { + for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); + }, + insertInner: function (at, lines, height) { + this.size += lines.length; + this.height += height; + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at <= sz) { + child.insertInner(at, lines, height); + if (child.lines && child.lines.length > 50) { + // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. + // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. + var remaining = child.lines.length % 25 + 25 + for (var pos = remaining; pos < child.lines.length;) { + var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); + child.height -= leaf.height; + this.children.splice(++i, 0, leaf); + leaf.parent = this; + } + child.lines = child.lines.slice(0, remaining); + this.maybeSpill(); + } + break; + } + at -= sz; + } + }, + // When a node has grown, check whether it should be split. + maybeSpill: function () { + if (this.children.length <= 10) return; + var me = this; + do { + var spilled = me.children.splice(me.children.length - 5, 5); + var sibling = new BranchChunk(spilled); + if (!me.parent) { // Become the parent node + var copy = new BranchChunk(me.children); + copy.parent = me; + me.children = [copy, sibling]; + me = copy; + } else { + me.size -= sibling.size; + me.height -= sibling.height; + var myIndex = indexOf(me.parent.children, me); + me.parent.children.splice(myIndex + 1, 0, sibling); + } + sibling.parent = me.parent; + } while (me.children.length > 10); + me.parent.maybeSpill(); + }, + iterN: function (at, n, op) { + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i], sz = child.chunkSize(); + if (at < sz) { + var used = Math.min(n, sz - at); + if (child.iterN(at, used, op)) return true; + if ((n -= used) == 0) break; + at = 0; + } else at -= sz; + } + } + }; + + var nextDocId = 0; + var Doc = CodeMirror.Doc = function (text, mode, firstLine, lineSep) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.cleanGeneration = 1; + this.frontier = firstLine; + var start = Pos(firstLine, 0); + this.sel = simpleSelection(start); + this.history = new History(null); + this.id = ++nextDocId; + this.modeOption = mode; + this.lineSep = lineSep; + this.extend = false; + + if (typeof text == "string") text = this.splitLines(text); + updateDoc(this, { from: start, to: start, text: text }); + setSelection(this, simpleSelection(start), sel_dontScroll); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, + // Iterate over the document. Supports two forms -- with only one + // argument, it calls that for each line in the document. With + // three, it iterates over the range given by the first two (with + // the second being non-inclusive). + iter: function (from, to, op) { + if (op) this.iterN(from - this.first, to - from, op); + else this.iterN(this.first, this.first + this.size, from); + }, + + // Non-public interface for adding and removing lines. + insert: function (at, lines) { + var height = 0; + for (var i = 0; i < lines.length; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function (at, n) { this.removeInner(at - this.first, n); }, + + // From here, the methods are part of the public interface. Most + // are also available from CodeMirror (editor) instances. + + getValue: function (lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || this.lineSeparator()); + }, + setValue: docMethodOp(function (code) { + var top = Pos(this.first, 0), last = this.first + this.size - 1; + makeChange(this, { + from: top, to: Pos(last, getLine(this, last).text.length), + text: this.splitLines(code), origin: "setValue", full: true + }, true); + setSelection(this, simpleSelection(top)); + }), + replaceRange: function (code, from, to, origin) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to, origin); + }, + getRange: function (from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || this.lineSeparator()); + }, + + getLine: function (line) { var l = this.getLineHandle(line); return l && l.text; }, + + getLineHandle: function (line) { if (isLine(this, line)) return getLine(this, line); }, + getLineNumber: function (line) { return lineNo(line); }, + + getLineHandleVisualStart: function (line) { + if (typeof line == "number") line = getLine(this, line); + return visualLine(line); + }, + + lineCount: function () { return this.size; }, + firstLine: function () { return this.first; }, + lastLine: function () { return this.first + this.size - 1; }, + + clipPos: function (pos) { return clipPos(this, pos); }, + + getCursor: function (start) { + var range = this.sel.primary(), pos; + if (start == null || start == "head") pos = range.head; + else if (start == "anchor") pos = range.anchor; + else if (start == "end" || start == "to" || start === false) pos = range.to(); + else pos = range.from(); + return pos; + }, + listSelections: function () { return this.sel.ranges; }, + somethingSelected: function () { return this.sel.somethingSelected(); }, + + setCursor: docMethodOp(function (line, ch, options) { + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + }), + setSelection: docMethodOp(function (anchor, head, options) { + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + }), + extendSelection: docMethodOp(function (head, other, options) { + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + }), + extendSelections: docMethodOp(function (heads, options) { + extendSelections(this, clipPosArray(this, heads), options); + }), + extendSelectionsBy: docMethodOp(function (f, options) { + var heads = map(this.sel.ranges, f); + extendSelections(this, clipPosArray(this, heads), options); + }), + setSelections: docMethodOp(function (ranges, primary, options) { + if (!ranges.length) return; + for (var i = 0, out = []; i < ranges.length; i++) + out[i] = new Range(clipPos(this, ranges[i].anchor), + clipPos(this, ranges[i].head)); + if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); + setSelection(this, normalizeSelection(out, primary), options); + }), + addSelection: docMethodOp(function (anchor, head, options) { + var ranges = this.sel.ranges.slice(0); + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); + }), + + getSelection: function (lineSep) { + var ranges = this.sel.ranges, lines; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + lines = lines ? lines.concat(sel) : sel; + } + if (lineSep === false) return lines; + else return lines.join(lineSep || this.lineSeparator()); + }, + getSelections: function (lineSep) { + var parts = [], ranges = this.sel.ranges; + for (var i = 0; i < ranges.length; i++) { + var sel = getBetween(this, ranges[i].from(), ranges[i].to()); + if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()); + parts[i] = sel; + } + return parts; + }, + replaceSelection: function (code, collapse, origin) { + var dup = []; + for (var i = 0; i < this.sel.ranges.length; i++) + dup[i] = code; + this.replaceSelections(dup, collapse, origin || "+input"); + }, + replaceSelections: docMethodOp(function (code, collapse, origin) { + var changes = [], sel = this.sel; + for (var i = 0; i < sel.ranges.length; i++) { + var range = sel.ranges[i]; + changes[i] = { from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin }; + } + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + for (var i = changes.length - 1; i >= 0; i--) + makeChange(this, changes[i]); + if (newSel) setSelectionReplaceHistory(this, newSel); + else if (this.cm) ensureCursorVisible(this.cm); + }), + undo: docMethodOp(function () { makeChangeFromHistory(this, "undo"); }), + redo: docMethodOp(function () { makeChangeFromHistory(this, "redo"); }), + undoSelection: docMethodOp(function () { makeChangeFromHistory(this, "undo", true); }), + redoSelection: docMethodOp(function () { makeChangeFromHistory(this, "redo", true); }), + + setExtending: function (val) { this.extend = val; }, + getExtending: function () { return this.extend; }, + + historySize: function () { + var hist = this.history, done = 0, undone = 0; + for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; + for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; + return { undo: done, redo: undone }; + }, + clearHistory: function () { this.history = new History(this.history.maxGeneration); }, + + markClean: function () { + this.cleanGeneration = this.changeGeneration(true); + }, + changeGeneration: function (forceSplit) { + if (forceSplit) + this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; + return this.history.generation; + }, + isClean: function (gen) { + return this.history.generation == (gen || this.cleanGeneration); + }, + + getHistory: function () { + return { + done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone) + }; + }, + setHistory: function (histData) { + var hist = this.history = new History(this.history.maxGeneration); + hist.done = copyHistoryArray(histData.done.slice(0), null, true); + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + }, + + addLineClass: docMethodOp(function (handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + if (!line[prop]) line[prop] = cls; + else if (classTest(cls).test(line[prop])) return false; + else line[prop] += " " + cls; + return true; + }); + }), + removeLineClass: docMethodOp(function (handle, where, cls) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) { + var prop = where == "text" ? "textClass" + : where == "background" ? "bgClass" + : where == "gutter" ? "gutterClass" : "wrapClass"; + var cur = line[prop]; + if (!cur) return false; + else if (cls == null) line[prop] = null; + else { + var found = cur.match(classTest(cls)); + if (!found) return false; + var end = found.index + found[0].length; + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + } + return true; + }); + }), + + addLineWidget: docMethodOp(function (handle, node, options) { + return addLineWidget(this, handle, node, options); + }), + removeLineWidget: function (widget) { widget.clear(); }, + + markText: function (from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range"); + }, + setBookmark: function (pos, options) { + var realOpts = { + replacedWith: options && (options.nodeType == null ? options.widget : options), + insertLeft: options && options.insertLeft, + clearWhenEmpty: false, shared: options && options.shared, + handleMouseEvents: options && options.handleMouseEvents + }; + pos = clipPos(this, pos); + return markText(this, pos, pos, realOpts, "bookmark"); + }, + findMarksAt: function (pos) { + pos = clipPos(this, pos); + var markers = [], spans = getLine(this, pos.line).markedSpans; + if (spans) for (var i = 0; i < spans.length; ++i) { + var span = spans[i]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker.parent || span.marker); + } + return markers; + }, + findMarks: function (from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo = from.line; + this.iter(from.line, to.line + 1, function (line) { + var spans = line.markedSpans; + if (spans) for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(span.to != null && lineNo == from.line && from.ch >= span.to || + span.from == null && lineNo != from.line || + span.from != null && lineNo == to.line && span.from >= to.ch) && + (!filter || filter(span.marker))) + found.push(span.marker.parent || span.marker); + } + ++lineNo; + }); + return found; + }, + getAllMarks: function () { + var markers = []; + this.iter(function (line) { + var sps = line.markedSpans; + if (sps) for (var i = 0; i < sps.length; ++i) + if (sps[i].from != null) markers.push(sps[i].marker); + }); + return markers; + }, + + posFromIndex: function (off) { + var ch, lineNo = this.first, sepSize = this.lineSeparator().length; + this.iter(function (line) { + var sz = line.text.length + sepSize; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, Pos(lineNo, ch)); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + var sepSize = this.lineSeparator().length; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + sepSize; + }); + return index; + }, + + copy: function (copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), + this.modeOption, this.first, this.lineSep); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = this.sel; + doc.extend = false; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + return doc; + }, + + linkedDoc: function (options) { + if (!options) options = {}; + var from = this.first, to = this.first + this.size; + if (options.from != null && options.from > from) from = options.from; + if (options.to != null && options.to < to) to = options.to; + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep); + if (options.sharedHist) copy.history = this.history; + (this.linked || (this.linked = [])).push({ doc: copy, sharedHist: options.sharedHist }); + copy.linked = [{ doc: this, isParent: true, sharedHist: options.sharedHist }]; + copySharedMarkers(copy, findSharedMarkers(this)); + return copy; + }, + unlinkDoc: function (other) { + if (other instanceof CodeMirror) other = other.doc; + if (this.linked) for (var i = 0; i < this.linked.length; ++i) { + var link = this.linked[i]; + if (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); + break; + } + // If the histories were shared, split them again + if (other.history == this.history) { + var splitIds = [other.id]; + linkedDocs(other, function (doc) { splitIds.push(doc.id); }, true); + other.history = new History(null); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function (f) { linkedDocs(this, f); }, + + getMode: function () { return this.mode; }, + getEditor: function () { return this.cm; }, + + splitLines: function (str) { + if (this.lineSep) return str.split(this.lineSep); + return splitLinesAuto(str); + }, + lineSeparator: function () { return this.lineSep || "\n"; } + }); + + // Public alias. + Doc.prototype.eachLine = Doc.prototype.iter; + + // Set up methods on CodeMirror's prototype to redirect to the editor's document. + var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); + for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) + CodeMirror.prototype[prop] = (function (method) { + return function () { return method.apply(this.doc, arguments); }; + })(Doc.prototype[prop]); + + eventMixin(Doc); + + // Call f for all linked documents. + function linkedDocs(doc, f, sharedHistOnly) { + function propagate(doc, skip, sharedHist) { + if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { + var rel = doc.linked[i]; + if (rel.doc == skip) continue; + var shared = sharedHist && rel.sharedHist; + if (sharedHistOnly && !shared) continue; + f(rel.doc, shared); + propagate(rel.doc, doc, shared); + } + } + propagate(doc, null, true); + } + + // Attach a document to an editor. + function attachDoc(cm, doc) { + if (doc.cm) throw new Error("This document is already in use."); + cm.doc = doc; + doc.cm = cm; + estimateLineHeights(cm); + loadMode(cm); + if (!cm.options.lineWrapping) findMaxLine(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + + // LINE UTILITIES + + // Find the line object corresponding to the given line number. + function getLine(doc, n) { + n -= doc.first; + if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); + for (var chunk = doc; !chunk.lines;) { + for (var i = 0; ; ++i) { + var child = chunk.children[i], sz = child.chunkSize(); + if (n < sz) { chunk = child; break; } + n -= sz; + } + } + return chunk.lines[n]; + } + + // Get the part of a document between two positions, as an array of + // strings. + function getBetween(doc, start, end) { + var out = [], n = start.line; + doc.iter(start.line, end.line + 1, function (line) { + var text = line.text; + if (n == end.line) text = text.slice(0, end.ch); + if (n == start.line) text = text.slice(start.ch); + out.push(text); + ++n; + }); + return out; + } + // Get the lines between from and to, as array of strings. + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function (line) { out.push(line.text); }); + return out; + } + + // Update the height of a line, propagating the height change + // upwards to parent nodes. + function updateLineHeight(line, height) { + var diff = height - line.height; + if (diff) for (var n = line; n; n = n.parent) n.height += diff; + } + + // Given a line object, find its line number by walking up through + // its parent links. + function lineNo(line) { + if (line.parent == null) return null; + var cur = line.parent, no = indexOf(cur.lines, line); + for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (var i = 0; ; ++i) { + if (chunk.children[i] == cur) break; + no += chunk.children[i].chunkSize(); + } + } + return no + cur.first; + } + + // Find the line at the given vertical position, using the height + // information in the document tree. + function lineAtHeight(chunk, h) { + var n = chunk.first; + outer: do { + for (var i = 0; i < chunk.children.length; ++i) { + var child = chunk.children[i], ch = child.height; + if (h < ch) { chunk = child; continue outer; } + h -= ch; + n += child.chunkSize(); + } + return n; + } while (!chunk.lines); + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i], lh = line.height; + if (h < lh) break; + h -= lh; + } + return n + i; + } + + + // Find the height above the given line. + function heightAtLine(lineObj) { + lineObj = visualLine(lineObj); + + var h = 0, chunk = lineObj.parent; + for (var i = 0; i < chunk.lines.length; ++i) { + var line = chunk.lines[i]; + if (line == lineObj) break; + else h += line.height; + } + for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (var i = 0; i < p.children.length; ++i) { + var cur = p.children[i]; + if (cur == chunk) break; + else h += cur.height; + } + } + return h; + } + + // Get the bidi ordering for the given line (and cache it). Returns + // false for lines that are fully left-to-right, and an array of + // BidiSpan objects otherwise. + function getOrder(line) { + var order = line.order; + if (order == null) order = line.order = bidiOrdering(line.text); + return order; + } + + // HISTORY + + function History(startGen) { + // Arrays of change events and selections. Doing something adds an + // event to done and clears undo. Undoing moves events from done + // to undone, redoing moves them in the other direction. + this.done = []; this.undone = []; + this.undoDepth = Infinity; + // Used to track when changes can be merged into a single undo + // event + this.lastModTime = this.lastSelTime = 0; + this.lastOp = this.lastSelOp = null; + this.lastOrigin = this.lastSelOrigin = null; + // Used by the isClean() method + this.generation = this.maxGeneration = startGen || 1; + } + + // Create a history change event from an updateDoc-style change + // object. + function historyChangeFromChange(doc, change) { + var histChange = { from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to) }; + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); + linkedDocs(doc, function (doc) { attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true); + return histChange; + } + + // Pop all selection events off the end of a history array. Stop at + // a change event. + function clearSelectionEvents(array) { + while (array.length) { + var last = lst(array); + if (last.ranges) array.pop(); + else break; + } + } + + // Find the top change event in the history. Pop off selection + // events that are in the way. + function lastChangeEvent(hist, force) { + if (force) { + clearSelectionEvents(hist.done); + return lst(hist.done); + } else if (hist.done.length && !lst(hist.done).ranges) { + return lst(hist.done); + } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { + hist.done.pop(); + return lst(hist.done); + } + } + + // Register a change in the history. Merges changes that are within + // a single operation, ore are close together with an origin that + // allows merging (starting with "+") into a single event. + function addChangeToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur; + + if ((hist.lastOp == opId || + hist.lastOrigin == change.origin && change.origin && + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*")) && + (cur = lastChangeEvent(hist, hist.lastOp == opId))) { + // Merge this change into the last event + var last = lst(cur.changes); + if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); + } else { + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); + } + } else { + // Can not be merged, start a new event. + var before = lst(hist.done); + if (!before || !before.ranges) + pushSelectionToHistory(doc.sel, hist.done); + cur = { + changes: [historyChangeFromChange(doc, change)], + generation: hist.generation + }; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) { + hist.done.shift(); + if (!hist.done[0].ranges) hist.done.shift(); + } + } + hist.done.push(selAfter); + hist.generation = ++hist.maxGeneration; + hist.lastModTime = hist.lastSelTime = time; + hist.lastOp = hist.lastSelOp = opId; + hist.lastOrigin = hist.lastSelOrigin = change.origin; + + if (!last) signal(doc, "historyAdded"); + } + + function selectionEventCanBeMerged(doc, origin, prev, sel) { + var ch = origin.charAt(0); + return ch == "*" || + ch == "+" && + prev.ranges.length == sel.ranges.length && + prev.somethingSelected() == sel.somethingSelected() && + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); + } + + // Called whenever the selection changes, sets the new selection as + // the pending selection in the history, and pushes the old pending + // selection into the 'done' array when it was significantly + // different (in number of selected ranges, emptiness, or time). + function addSelectionToHistory(doc, sel, opId, options) { + var hist = doc.history, origin = options && options.origin; + + // A new event is started when the previous origin does not match + // the current, or the origins don't allow matching. Origins + // starting with * are always merged, those starting with + are + // merged when similar and close together in time. + if (opId == hist.lastSelOp || + (origin && hist.lastSelOrigin == origin && + (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || + selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) + hist.done[hist.done.length - 1] = sel; + else + pushSelectionToHistory(sel, hist.done); + + hist.lastSelTime = +new Date; + hist.lastSelOrigin = origin; + hist.lastSelOp = opId; + if (options && options.clearRedo !== false) + clearSelectionEvents(hist.undone); + } + + function pushSelectionToHistory(sel, dest) { + var top = lst(dest); + if (!(top && top.ranges && top.equals(sel))) + dest.push(sel); + } + + // Used to store marked span information in the history. + function attachLocalSpans(doc, change, from, to) { + var existing = change["spans_" + doc.id], n = 0; + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) { + if (line.markedSpans) + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; + ++n; + }); + } + + // When un/re-doing restores text containing marked spans, those + // that have been explicitly cleared should not be restored. + function removeClearedSpans(spans) { + if (!spans) return null; + for (var i = 0, out; i < spans.length; ++i) { + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } + else if (out) out.push(spans[i]); + } + return !out ? spans : out.length ? out : null; + } + + // Retrieve and filter the old marked spans stored in a change event. + function getOldSpans(doc, change) { + var found = change["spans_" + doc.id]; + if (!found) return null; + for (var i = 0, nw = []; i < change.text.length; ++i) + nw.push(removeClearedSpans(found[i])); + return nw; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup, instantiateSel) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i]; + if (event.ranges) { + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); + continue; + } + var changes = event.changes, newChanges = []; + copy.push({ changes: newChanges }); + for (var j = 0; j < changes.length; ++j) { + var change = changes[j], m; + newChanges.push({ from: change.from, to: change.to, text: change.text }); + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (indexOf(newGroup, Number(m[1])) > -1) { + lst(newChanges)[prop] = change[prop]; + delete change[prop]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSelSingle(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // reallocate them all on every rebase, but also avoid problems with + // shared position objects being unsafely updated. + function rebaseHistArray(array, from, to, diff) { + for (var i = 0; i < array.length; ++i) { + var sub = array[i], ok = true; + if (sub.ranges) { + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + for (var j = 0; j < sub.ranges.length; j++) { + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + } + continue; + } + for (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (to < cur.from.line) { + cur.from = Pos(cur.from.line + diff, cur.from.ch); + cur.to = Pos(cur.to.line + diff, cur.to.ch); + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } + } + } + + function rebaseHist(hist, change) { + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; + rebaseHistArray(hist.done, from, to, diff); + rebaseHistArray(hist.undone, from, to, diff); + } + + // EVENT UTILITIES + + // Due to the fact that we still support jurassic IE versions, some + // compatibility wrappers are needed. + + var e_preventDefault = CodeMirror.e_preventDefault = function (e) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + }; + var e_stopPropagation = CodeMirror.e_stopPropagation = function (e) { + if (e.stopPropagation) e.stopPropagation(); + else e.cancelBubble = true; + }; + function e_defaultPrevented(e) { + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + } + var e_stop = CodeMirror.e_stop = function (e) { e_preventDefault(e); e_stopPropagation(e); }; + + function e_target(e) { return e.target || e.srcElement; } + function e_button(e) { + var b = e.which; + if (b == null) { + if (e.button & 1) b = 1; + else if (e.button & 2) b = 3; + else if (e.button & 4) b = 2; + } + if (mac && e.ctrlKey && b == 1) b = 3; + return b; + } + + // EVENT HANDLING + + // Lightweight event framework. on/off also work on DOM nodes, + // registering native DOM handlers. + + var on = CodeMirror.on = function (emitter, type, f) { + if (emitter.addEventListener) + emitter.addEventListener(type, f, false); + else if (emitter.attachEvent) + emitter.attachEvent("on" + type, f); + else { + var map = emitter._handlers || (emitter._handlers = {}); + var arr = map[type] || (map[type] = []); + arr.push(f); + } + }; + + var noHandlers = [] + function getHandlers(emitter, type, copy) { + var arr = emitter._handlers && emitter._handlers[type] + if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers + else return arr || noHandlers + } + + var off = CodeMirror.off = function (emitter, type, f) { + if (emitter.removeEventListener) + emitter.removeEventListener(type, f, false); + else if (emitter.detachEvent) + emitter.detachEvent("on" + type, f); + else { + var handlers = getHandlers(emitter, type, false) + for (var i = 0; i < handlers.length; ++i) + if (handlers[i] == f) { handlers.splice(i, 1); break; } + } + }; + + var signal = CodeMirror.signal = function (emitter, type /*, values...*/) { + var handlers = getHandlers(emitter, type, true) + if (!handlers.length) return; + var args = Array.prototype.slice.call(arguments, 2); + for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args); + }; + + var orphanDelayedCallbacks = null; + + // Often, we want to signal events at a point where we are in the + // middle of some work, but don't want the handler to start calling + // other methods on the editor, which might be in an inconsistent + // state or simply not expect any other events to happen. + // signalLater looks whether there are any handlers, and schedules + // them to be executed when the last operation ends, or, if no + // operation is active, when a timeout fires. + function signalLater(emitter, type /*, values...*/) { + var arr = getHandlers(emitter, type, false) + if (!arr.length) return; + var args = Array.prototype.slice.call(arguments, 2), list; + if (operationGroup) { + list = operationGroup.delayedCallbacks; + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks; + } else { + list = orphanDelayedCallbacks = []; + setTimeout(fireOrphanDelayed, 0); + } + function bnd(f) { return function () { f.apply(null, args); }; }; + for (var i = 0; i < arr.length; ++i) + list.push(bnd(arr[i])); + } + + function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks; + orphanDelayedCallbacks = null; + for (var i = 0; i < delayed.length; ++i) delayed[i](); + } + + // The DOM events that CodeMirror handles can be overridden by + // registering a (non-DOM) handler on the editor for the event name, + // and preventDefault-ing the event in that handler. + function signalDOMEvent(cm, e, override) { + if (typeof e == "string") + e = { type: e, preventDefault: function () { this.defaultPrevented = true; } }; + signal(cm, override || e.type, cm, e); + return e_defaultPrevented(e) || e.codemirrorIgnore; + } + + function signalCursorActivity(cm) { + var arr = cm._handlers && cm._handlers.cursorActivity; + if (!arr) return; + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) + set.push(arr[i]); + } + + function hasHandler(emitter, type) { + return getHandlers(emitter, type).length > 0 + } + + // Add on and off methods to a constructor's prototype, to make + // registering events on such objects more convenient. + function eventMixin(ctor) { + ctor.prototype.on = function (type, f) { on(this, type, f); }; + ctor.prototype.off = function (type, f) { off(this, type, f); }; + } + + // MISC UTILITIES + + // Number of pixels added to scroller and sizer to hide scrollbar + var scrollerGap = 30; + + // Returned or thrown by various protocols to signal 'I'm not + // handling this'. + var Pass = CodeMirror.Pass = { toString: function () { return "CodeMirror.Pass"; } }; + + // Reused option objects for setSelection & friends + var sel_dontScroll = { scroll: false }, sel_mouse = { origin: "*mouse" }, sel_move = { origin: "+move" }; + + function Delayed() { this.id = null; } + Delayed.prototype.set = function (ms, f) { + clearTimeout(this.id); + this.id = setTimeout(f, ms); + }; + + // Counts the column offset in a string, taking tabs into account. + // Used mostly to find indentation. + var countColumn = CodeMirror.countColumn = function (string, end, tabSize, startIndex, startValue) { + if (end == null) { + end = string.search(/[^\s\u00a0]/); + if (end == -1) end = string.length; + } + for (var i = startIndex || 0, n = startValue || 0; ;) { + var nextTab = string.indexOf("\t", i); + if (nextTab < 0 || nextTab >= end) + return n + (end - i); + n += nextTab - i; + n += tabSize - (n % tabSize); + i = nextTab + 1; + } + }; + + // The inverse of countColumn -- find the offset that corresponds to + // a particular column. + var findColumn = CodeMirror.findColumn = function (string, goal, tabSize) { + for (var pos = 0, col = 0; ;) { + var nextTab = string.indexOf("\t", pos); + if (nextTab == -1) nextTab = string.length; + var skipped = nextTab - pos; + if (nextTab == string.length || col + skipped >= goal) + return pos + Math.min(skipped, goal - col); + col += nextTab - pos; + col += tabSize - (col % tabSize); + pos = nextTab + 1; + if (col >= goal) return pos; + } + } + + var spaceStrs = [""]; + function spaceStr(n) { + while (spaceStrs.length <= n) + spaceStrs.push(lst(spaceStrs) + " "); + return spaceStrs[n]; + } + + function lst(arr) { return arr[arr.length - 1]; } + + var selectInput = function (node) { node.select(); }; + if (ios) // Mobile Safari apparently has a bug where select() is broken. + selectInput = function (node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; + else if (ie) // Suppress mysterious IE10 errors + selectInput = function (node) { try { node.select(); } catch (_e) { } }; + + function indexOf(array, elt) { + for (var i = 0; i < array.length; ++i) + if (array[i] == elt) return i; + return -1; + } + function map(array, f) { + var out = []; + for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); + return out; + } + + function nothing() { } + + function createObj(base, props) { + var inst; + if (Object.create) { + inst = Object.create(base); + } else { + nothing.prototype = base; + inst = new nothing(); + } + if (props) copyObj(props, inst); + return inst; + }; + + function copyObj(obj, target, overwrite) { + if (!target) target = {}; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; + return target; + } + + function bind(f) { + var args = Array.prototype.slice.call(arguments, 1); + return function () { return f.apply(null, args); }; + } + + var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var isWordCharBasic = CodeMirror.isWordChar = function (ch) { + return /\w/.test(ch) || ch > "\x80" && + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + }; + function isWordChar(ch, helper) { + if (!helper) return isWordCharBasic(ch); + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; + return helper.test(ch); + } + + function isEmpty(obj) { + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; + return true; + } + + // Extending unicode characters. A series of a non-extending char + + // any number of extending chars is treated as a single unit as far + // as editing and measuring is concerned. This is not fully correct, + // since some scripts/fonts/browsers also treat other configurations + // of code points as a group. + var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; + function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } + + // DOM UTILITIES + + function elt(tag, content, className, style) { + var e = document.createElement(tag); + if (className) e.className = className; + if (style) e.style.cssText = style; + if (typeof content == "string") e.appendChild(document.createTextNode(content)); + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); + return e; + } + + var range; + if (document.createRange) range = function (node, start, end, endNode) { + var r = document.createRange(); + r.setEnd(endNode || node, end); + r.setStart(node, start); + return r; + }; + else range = function (node, start, end) { + var r = document.body.createTextRange(); + try { r.moveToElementText(node.parentNode); } + catch (e) { return r; } + r.collapse(true); + r.moveEnd("character", end); + r.moveStart("character", start); + return r; + }; + + function removeChildren(e) { + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); + return e; + } + + function removeChildrenAndAdd(parent, e) { + return removeChildren(parent).appendChild(e); + } + + var contains = CodeMirror.contains = function (parent, child) { + if (child.nodeType == 3) // Android browser always returns false when child is a textnode + child = child.parentNode; + if (parent.contains) + return parent.contains(child); + do { + if (child.nodeType == 11) child = child.host; + if (child == parent) return true; + } while (child = child.parentNode); + }; + + function activeElt() { + var activeElement = document.activeElement; + while (activeElement && activeElement.root && activeElement.root.activeElement) + activeElement = activeElement.root.activeElement; + return activeElement; + } + // Older versions of IE throws unspecified error when touching + // document.activeElement in some cases (during loading, in iframe) + if (ie && ie_version < 11) activeElt = function () { + try { return document.activeElement; } + catch (e) { return document.body; } + }; + + function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } + var rmClass = CodeMirror.rmClass = function (node, cls) { + var current = node.className; + var match = classTest(cls).exec(current); + if (match) { + var after = current.slice(match.index + match[0].length); + node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); + } + }; + var addClass = CodeMirror.addClass = function (node, cls) { + var current = node.className; + if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; + }; + function joinClasses(a, b) { + var as = a.split(" "); + for (var i = 0; i < as.length; i++) + if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; + return b; + } + + // WINDOW-WIDE EVENTS + + // These must be handled carefully, because naively registering a + // handler for each editor will cause the editors to never be + // garbage collected. + + function forEachCodeMirror(f) { + if (!document.body.getElementsByClassName) return; + var byClass = document.body.getElementsByClassName("CodeMirror"); + for (var i = 0; i < byClass.length; i++) { + var cm = byClass[i].CodeMirror; + if (cm) f(cm); + } + } + + var globalsRegistered = false; + function ensureGlobalHandlers() { + if (globalsRegistered) return; + registerGlobalHandlers(); + globalsRegistered = true; + } + function registerGlobalHandlers() { + // When the window resizes, we need to refresh active editors. + var resizeTimer; + on(window, "resize", function () { + if (resizeTimer == null) resizeTimer = setTimeout(function () { + resizeTimer = null; + forEachCodeMirror(onResize); + }, 100); + }); + // When the window loses focus, we want to show the editor as blurred + on(window, "blur", function () { + forEachCodeMirror(onBlur); + }); + } + + // FEATURE DETECTION + + // Detect drag-and-drop + var dragAndDrop = function () { + // There is *some* kind of drag-and-drop support in IE6-8, but I + // couldn't get it to work yet. + if (ie && ie_version < 9) return false; + var div = elt('div'); + return "draggable" in div || "dragDrop" in div; + }(); + + var zwspSupported; + function zeroWidthElement(measure) { + if (zwspSupported == null) { + var test = elt("span", "\u200b"); + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + if (measure.firstChild.offsetHeight != 0) + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); + } + var node = zwspSupported ? elt("span", "\u200b") : + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); + node.setAttribute("cm-text", ""); + return node; + } + + // Feature-detect IE's crummy client rect reporting for bidi text + var badBidiRects; + function hasBadBidiRects(measure) { + if (badBidiRects != null) return badBidiRects; + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); + var r0 = range(txt, 0, 1).getBoundingClientRect(); + var r1 = range(txt, 1, 2).getBoundingClientRect(); + removeChildren(measure); + if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) + return badBidiRects = (r1.right - r0.right < 3); + } + + // See if "".split is the broken IE version, if so, provide an + // alternative way to split lines. + var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function (string) { + var pos = 0, result = [], l = string.length; + while (pos <= l) { + var nl = string.indexOf("\n", pos); + if (nl == -1) nl = string.length; + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); + var rt = line.indexOf("\r"); + if (rt != -1) { + result.push(line.slice(0, rt)); + pos += rt + 1; + } else { + result.push(line); + pos = nl + 1; + } + } + return result; + } : function (string) { return string.split(/\r\n?|\n/); }; + + var hasSelection = window.getSelection ? function (te) { + try { return te.selectionStart != te.selectionEnd; } + catch (e) { return false; } + } : function (te) { + try { var range = te.ownerDocument.selection.createRange(); } + catch (e) { } + if (!range || range.parentElement() != te) return false; + return range.compareEndPoints("StartToEnd", range) != 0; + }; + + var hasCopyEvent = (function () { + var e = elt("div"); + if ("oncopy" in e) return true; + e.setAttribute("oncopy", "return;"); + return typeof e.oncopy == "function"; + })(); + + var badZoomedRects = null; + function hasBadZoomedRects(measure) { + if (badZoomedRects != null) return badZoomedRects; + var node = removeChildrenAndAdd(measure, elt("span", "x")); + var normal = node.getBoundingClientRect(); + var fromRange = range(node, 0, 1).getBoundingClientRect(); + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; + } + + // KEY NAMES + + var keyNames = CodeMirror.keyNames = { + 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", + 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", + 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", + 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", + 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", + 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", + 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" + }; + (function () { + // Number keys + for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); + // Alphabetic keys + for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); + // Function keys + for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; + })(); + + // BIDI HELPERS + + function iterateBidiSections(order, from, to, f) { + if (!order) return f(from, to, "ltr"); + var found = false; + for (var i = 0; i < order.length; ++i) { + var part = order[i]; + if (part.from < to && part.to > from || from == to && part.to == from) { + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); + found = true; + } + } + if (!found) f(from, to, "ltr"); + } + + function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } + function bidiRight(part) { return part.level % 2 ? part.from : part.to; } + + function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } + function lineRight(line) { + var order = getOrder(line); + if (!order) return line.text.length; + return bidiRight(lst(order)); + } + + function lineStart(cm, lineN) { + var line = getLine(cm.doc, lineN); + var visual = visualLine(line); + if (visual != line) lineN = lineNo(visual); + var order = getOrder(visual); + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); + return Pos(lineN, ch); + } + function lineEnd(cm, lineN) { + var merged, line = getLine(cm.doc, lineN); + while (merged = collapsedSpanAtEnd(line)) { + line = merged.find(1, true).line; + lineN = null; + } + var order = getOrder(line); + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); + return Pos(lineN == null ? lineNo(line) : lineN, ch); + } + function lineStartSmart(cm, pos) { + var start = lineStart(cm, pos.line); + var line = getLine(cm.doc, start.line); + var order = getOrder(line); + if (!order || order[0].level == 0) { + var firstNonWS = Math.max(0, line.text.search(/\S/)); + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; + return Pos(start.line, inWS ? 0 : firstNonWS); + } + return start; + } + + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + bidiOther = null; + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) return i; + if ((cur.from == pos || cur.to == pos)) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + if (cur.from != cur.to) bidiOther = found; + return i; + } else { + if (cur.from != cur.to) bidiOther = i; + return found; + } + } + } + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar(line.text.charAt(pos))); + return pos; + } + + // This is needed in order to move 'visually' through bi-directional + // text -- i.e., pressing left should make the cursor go left, even + // when in RTL text. The tricky part is the 'jumps', where RTL and + // LTR text touch each other. This often requires the cursor offset + // to move more than one unit, in order to visually move one unit. + function moveVisually(line, start, dir, byUnit) { + var bidi = getOrder(line); + if (!bidi) return moveLogically(line, start, dir, byUnit); + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (; ;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; + } else { + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); + } + } + } + + function moveLogically(line, start, dir, byUnit) { + var target = start + dir; + if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; + return target < 0 || target > line.text.length ? null : target; + } + + // Bidirectional ordering algorithm + // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm + // that this (partially) implements. + + // One-char codes used for character types: + // L (L): Left-to-Right + // R (R): Right-to-Left + // r (AL): Right-to-Left Arabic + // 1 (EN): European Number + // + (ES): European Number Separator + // % (ET): European Number Terminator + // n (AN): Arabic Number + // , (CS): Common Number Separator + // m (NSM): Non-Spacing Mark + // b (BN): Boundary Neutral + // s (B): Paragraph Separator + // t (S): Segment Separator + // w (WS): Whitespace + // N (ON): Other Neutrals + + // Returns null if characters are ordered as they appear + // (left-to-right), or an array of sections ({from, to, level} + // objects) in the order in which they occur visually. + var bidiOrdering = (function () { + // Character types for codepoints 0 to 0xff + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + // Character types for codepoints 0x600 to 0x6ff + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; + function charType(code) { + if (code <= 0xf7) return lowTypes.charAt(code); + else if (0x590 <= code && code <= 0x5f4) return "R"; + else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); + else if (0x6ee <= code && code <= 0x8ac) return "r"; + else if (0x2000 <= code && code <= 0x200b) return "w"; + else if (code == 0x200c) return "b"; + else return "L"; + } + + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + // Browsers seem to always treat the boundaries of block elements as being L. + var outerType = "L"; + + function BidiSpan(level, from, to) { + this.level = level; + this.from = from; this.to = to; + } + + return function (str) { + if (!bidiRE.test(str)) return false; + var len = str.length, types = []; + for (var i = 0, type; i < len; ++i) + types.push(type = charType(str.charCodeAt(i))); + + // W1. Examine each non-spacing mark (NSM) in the level run, and + // change the type of the NSM to the type of the previous + // character. If the NSM is at the start of the level run, it will + // get the type of sor. + for (var i = 0, prev = outerType; i < len; ++i) { + var type = types[i]; + if (type == "m") types[i] = prev; + else prev = type; + } + + // W2. Search backwards from each instance of a European number + // until the first strong type (R, L, AL, or sor) is found. If an + // AL is found, change the type of the European number to Arabic + // number. + // W3. Change all ALs to R. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (type == "1" && cur == "r") types[i] = "n"; + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + } + + // W4. A single European separator between two European numbers + // changes to a European number. A single common separator between + // two numbers of the same type changes to that type. + for (var i = 1, prev = types[0]; i < len - 1; ++i) { + var type = types[i]; + if (type == "+" && prev == "1" && types[i + 1] == "1") types[i] = "1"; + else if (type == "," && prev == types[i + 1] && + (prev == "1" || prev == "n")) types[i] = prev; + prev = type; + } + + // W5. A sequence of European terminators adjacent to European + // numbers changes to all European numbers. + // W6. Otherwise, separators and terminators change to Other + // Neutral. + for (var i = 0; i < len; ++i) { + var type = types[i]; + if (type == ",") types[i] = "N"; + else if (type == "%") { + for (var end = i + 1; end < len && types[end] == "%"; ++end) { } + var replace = (i && types[i - 1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // W7. Search backwards from each instance of a European number + // until the first strong type (R, L, or sor) is found. If an L is + // found, then change the type of the European number to L. + for (var i = 0, cur = outerType; i < len; ++i) { + var type = types[i]; + if (cur == "L" && type == "1") types[i] = "L"; + else if (isStrong.test(type)) cur = type; + } + + // N1. A sequence of neutrals takes the direction of the + // surrounding strong text if the text on both sides has the same + // direction. European and Arabic numbers act as if they were R in + // terms of their influence on neutrals. Start-of-level-run (sor) + // and end-of-level-run (eor) are used at level run boundaries. + // N2. Any remaining neutrals take the embedding direction. + for (var i = 0; i < len; ++i) { + if (isNeutral.test(types[i])) { + for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) { } + var before = (i ? types[i - 1] : outerType) == "L"; + var after = (end < len ? types[end] : outerType) == "L"; + var replace = before || after ? "L" : "R"; + for (var j = i; j < end; ++j) types[j] = replace; + i = end - 1; + } + } + + // Here we depart from the documented algorithm, in order to avoid + // building up an actual levels array. Since there are only three + // levels (0, 1, 2) in an implementation that doesn't take + // explicit embedding into account, we can build up the order on + // the fly, without following the level-based algorithm. + var order = [], m; + for (var i = 0; i < len;) { + if (countsAsLeft.test(types[i])) { + var start = i; + for (++i; i < len && countsAsLeft.test(types[i]); ++i) { } + order.push(new BidiSpan(0, start, i)); + } else { + var pos = i, at = order.length; + for (++i; i < len && types[i] != "L"; ++i) { } + for (var j = pos; j < i;) { + if (countsAsNum.test(types[j])) { + if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); + var nstart = j; + for (++j; j < i && countsAsNum.test(types[j]); ++j) { } + order.splice(at, 0, new BidiSpan(2, nstart, j)); + pos = j; + } else ++j; + } + if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); + } + } + if (order[0].level == 1 && (m = str.match(/^\s+/))) { + order[0].from = m[0].length; + order.unshift(new BidiSpan(0, 0, m[0].length)); + } + if (lst(order).level == 1 && (m = str.match(/\s+$/))) { + lst(order).to -= m[0].length; + order.push(new BidiSpan(0, len - m[0].length, len)); + } + if (order[0].level == 2) + order.unshift(new BidiSpan(1, order[0].to, order[0].to)); + if (order[0].level != lst(order).level) + order.push(new BidiSpan(order[0].level, len, len)); + + return order; + }; + })(); + + // THE END + + CodeMirror.version = "5.17.0"; + + return CodeMirror; +})(); + +// @ts-ignore +window.CodeMirror = CodeMirror; + +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// TODO actually recognize syntax of TypeScript constructs + +(function () { + "use strict"; + + function expressionAllowed(stream, state, backUp) { + return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) || + (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) + } + + CodeMirror.defineMode("javascript", function (config, parserConfig) { + var indentUnit = config.indentUnit; + var statementIndent = parserConfig.statementIndent; + var jsonldMode = parserConfig.jsonld; + var jsonMode = parserConfig.json || jsonldMode; + var isTS = parserConfig.typescript; + var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; + + // Tokenizer + + var keywords = function () { + function kw(type) { return { type: type, style: "keyword" }; } + var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); + var operator = kw("operator"), atom = { type: "atom", style: "atom" }; + + var jsKeywords = { + "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C, + "var": kw("var"), "const": kw("var"), "let": kw("var"), + "function": kw("function"), "catch": kw("catch"), + "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), + "in": operator, "typeof": operator, "instanceof": operator, + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, + "this": kw("this"), "class": kw("class"), "super": kw("atom"), + "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, + "await": C, "async": kw("async") + }; + + // Extend the 'normal' keywords with the TypeScript language extensions + if (isTS) { + var type = { type: "variable", style: "variable-3" }; + var tsKeywords = { + // object-like things + "interface": kw("class"), + "implements": C, + "namespace": C, + "module": kw("module"), + "enum": kw("module"), + + // scope modifiers + "public": kw("modifier"), + "private": kw("modifier"), + "protected": kw("modifier"), + "abstract": kw("modifier"), + + // operators + "as": operator, + + // types + "string": type, "number": type, "boolean": type, "any": type + }; + + for (var attr in tsKeywords) { + jsKeywords[attr] = tsKeywords[attr]; + } + } + + return jsKeywords; + }(); + + var isOperatorChar = /[+\-*&%=<>!?|~^]/; + var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/; + + function readRegexp(stream) { + var escaped = false, next, inSet = false; + while ((next = stream.next()) != null) { + if (!escaped) { + if (next == "/" && !inSet) return; + if (next == "[") inSet = true; + else if (inSet && next == "]") inSet = false; + } + escaped = !escaped && next == "\\"; + } + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + function ret(tp, style, cont) { + type = tp; content = cont; + return style; + } + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) { + return ret("number", "number"); + } else if (ch == "." && stream.match("..")) { + return ret("spread", "meta"); + } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + return ret(ch); + } else if (ch == "=" && stream.eat(">")) { + return ret("=>", "operator"); + } else if (ch == "0" && stream.eat(/x/i)) { + stream.eatWhile(/[\da-f]/i); + return ret("number", "number"); + } else if (ch == "0" && stream.eat(/o/i)) { + stream.eatWhile(/[0-7]/i); + return ret("number", "number"); + } else if (ch == "0" && stream.eat(/b/i)) { + stream.eatWhile(/[01]/i); + return ret("number", "number"); + } else if (/\d/.test(ch)) { + stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); + return ret("number", "number"); + } else if (ch == "/") { + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } else if (stream.eat("/")) { + stream.skipToEnd(); + return ret("comment", "comment"); + } else if (expressionAllowed(stream, state, 1)) { + readRegexp(stream); + stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); + return ret("regexp", "string-2"); + } else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } + } else if (ch == "`") { + state.tokenize = tokenQuasi; + return tokenQuasi(stream, state); + } else if (ch == "#") { + stream.skipToEnd(); + return ret("error", "error"); + } else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator", stream.current()); + } else if (wordRE.test(ch)) { + stream.eatWhile(wordRE); + var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; + return (known && state.lastType != ".") ? ret(known.type, known.style, word) : + ret("variable", "variable", word); + } + } + + function tokenString(quote) { + return function (stream, state) { + var escaped = false, next; + if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)) { + state.tokenize = tokenBase; + return ret("jsonld-keyword", "meta"); + } + while ((next = stream.next()) != null) { + if (next == quote && !escaped) break; + escaped = !escaped && next == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenQuasi(stream, state) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && next == "\\"; + } + return ret("quasi", "string-2", stream.current()); + } + + var brackets = "([{}])"; + // This is a crude lookahead trick to try and notice that we're + // parsing the argument patterns for a fat-arrow function before we + // actually hit the arrow token. It only works if the arrow is on + // the same line as the arguments and there's no strange noise + // (comments) in between. Fallback is to only notice when we hit the + // arrow, and not declare the arguments as locals for the arrow + // body. + function findFatArrow(stream, state) { + if (state.fatArrowAt) state.fatArrowAt = null; + var arrow = stream.string.indexOf("=>", stream.start); + if (arrow < 0) return; + + var depth = 0, sawSomething = false; + for (var pos = arrow - 1; pos >= 0; --pos) { + var ch = stream.string.charAt(pos); + var bracket = brackets.indexOf(ch); + if (bracket >= 0 && bracket < 3) { + if (!depth) { ++pos; break; } + if (--depth == 0) break; + } else if (bracket >= 3 && bracket < 6) { + ++depth; + } else if (wordRE.test(ch)) { + sawSomething = true; + } else if (/["'\/]/.test(ch)) { + return; + } else if (sawSomething && !depth) { + ++pos; + break; + } + } + if (sawSomething && !depth) state.fatArrowAt = pos; + } + + // Parser + + var atomicTypes = { "atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true }; + + function JSLexical(indented, column, type, align, prev, info) { + this.indented = indented; + this.column = column; + this.type = type; + this.prev = prev; + this.info = info; + if (align != null) this.align = align; + } + + function inScope(state, varname) { + for (var v = state.localVars; v; v = v.next) + if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } + } + + function parseJS(state, style, type, content, stream) { + var cc = state.cc; + // Communicate our context to the combinators. + // (Less wasteful than consing up a hundred closures on every call.) + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; + + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = true; + + while (true) { + var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement; + if (combinator(type, content)) { + while (cc.length && cc[cc.length - 1].lex) + cc.pop()(); + if (cx.marked) return cx.marked; + if (type == "variable" && inScope(state, content)) return "variable-2"; + return style; + } + } + } + + // Combinator utils + + var cx = { state: null, column: null, marked: null, cc: null }; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]); + } + function cont() { + pass.apply(null, arguments); + return true; + } + function register(varname) { + function inList(list) { + for (var v = list; v; v = v.next) + if (v.name == varname) return true; + return false; + } + var state = cx.state; + cx.marked = "def"; + if (state.context) { + if (inList(state.localVars)) return; + state.localVars = { name: varname, next: state.localVars }; + } else { + if (inList(state.globalVars)) return; + if (parserConfig.globalVars) + state.globalVars = { name: varname, next: state.globalVars }; + } + } + + // Combinators + + var defaultVars = { name: "this", next: { name: "arguments" } }; + function pushcontext() { + cx.state.context = { prev: cx.state.context, vars: cx.state.localVars }; + cx.state.localVars = defaultVars; + } + function popcontext() { + cx.state.localVars = cx.state.context.vars; + cx.state.context = cx.state.context.prev; + } + function pushlex(type, info) { + var result = function () { + var state = cx.state, indent = state.indented; + if (state.lexical.type == "stat") indent = state.lexical.indented; + else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) + indent = outer.indented; + state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); + }; + result.lex = true; + return result; + } + function poplex() { + var state = cx.state; + if (state.lexical.prev) { + if (state.lexical.type == ")") + state.indented = state.lexical.indented; + state.lexical = state.lexical.prev; + } + } + poplex.lex = true; + + function expect(wanted) { + function exp(type) { + if (type == wanted) return cont(); + else if (wanted == ";") return pass(); + else return cont(exp); + }; + return exp; + } + + function statement(type, value) { + if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); + if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); + if (type == "keyword b") return cont(pushlex("form"), statement, poplex); + if (type == "{") return cont(pushlex("}"), block, poplex); + if (type == ";") return cont(); + if (type == "if") { + if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) + cx.state.cc.pop()(); + return cont(pushlex("form"), expression, statement, poplex, maybeelse); + } + if (type == "function") return cont(functiondef); + if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "variable") return cont(pushlex("stat"), maybelabel); + if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), + block, poplex, poplex); + if (type == "case") return cont(expression, expect(":")); + if (type == "default") return cont(expect(":")); + if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), + statement, poplex, popcontext); + if (type == "class") return cont(pushlex("form"), className, poplex); + if (type == "export") return cont(pushlex("stat"), afterExport, poplex); + if (type == "import") return cont(pushlex("stat"), afterImport, poplex); + if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex) + if (type == "async") return cont(statement) + return pass(pushlex("stat"), expression, expect(";"), poplex); + } + function expression(type) { + return expressionInner(type, false); + } + function expressionNoComma(type) { + return expressionInner(type, true); + } + function expressionInner(type, noComma) { + if (cx.state.fatArrowAt == cx.stream.start) { + var body = noComma ? arrowBodyNoComma : arrowBody; + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext); + else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext); + } + + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); + if (type == "function") return cont(functiondef, maybeop); + if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression); + if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); + if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); + if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop); + if (type == "{") return contCommasep(objprop, "}", null, maybeop); + if (type == "quasi") return pass(quasi, maybeop); + if (type == "new") return cont(maybeTarget(noComma)); + return cont(); + } + function maybeexpression(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expression); + } + function maybeexpressionNoComma(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expressionNoComma); + } + + function maybeoperatorComma(type, value) { + if (type == ",") return cont(expression); + return maybeoperatorNoComma(type, value, false); + } + function maybeoperatorNoComma(type, value, noComma) { + var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; + var expr = noComma == false ? expression : expressionNoComma; + if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "operator") { + if (/\+\+|--/.test(value)) return cont(me); + if (value == "?") return cont(expression, expect(":"), expr); + return cont(expr); + } + if (type == "quasi") { return pass(quasi, me); } + if (type == ";") return; + if (type == "(") return contCommasep(expressionNoComma, ")", "call", me); + if (type == ".") return cont(property, me); + if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); + } + function quasi(type, value) { + if (type != "quasi") return pass(); + if (value.slice(value.length - 2) != "${") return cont(quasi); + return cont(expression, continueQuasi); + } + function continueQuasi(type) { + if (type == "}") { + cx.marked = "string-2"; + cx.state.tokenize = tokenQuasi; + return cont(quasi); + } + } + function arrowBody(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expression); + } + function arrowBodyNoComma(type) { + findFatArrow(cx.stream, cx.state); + return pass(type == "{" ? statement : expressionNoComma); + } + function maybeTarget(noComma) { + return function (type) { + if (type == ".") return cont(noComma ? targetNoComma : target); + else return pass(noComma ? expressionNoComma : expression); + }; + } + function target(_, value) { + if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); } + } + function targetNoComma(_, value) { + if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); } + } + function maybelabel(type) { + if (type == ":") return cont(poplex, statement); + return pass(maybeoperatorComma, expect(";"), poplex); + } + function property(type) { + if (type == "variable") { cx.marked = "property"; return cont(); } + } + function objprop(type, value) { + if (type == "async") return cont(objprop); + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(getterSetter); + return cont(afterprop); + } else if (type == "number" || type == "string") { + cx.marked = jsonldMode ? "property" : (cx.style + " property"); + return cont(afterprop); + } else if (type == "jsonld-keyword") { + return cont(afterprop); + } else if (type == "modifier") { + return cont(objprop) + } else if (type == "[") { + return cont(expression, expect("]"), afterprop); + } else if (type == "spread") { + return cont(expression); + } + } + function getterSetter(type) { + if (type != "variable") return pass(afterprop); + cx.marked = "property"; + return cont(functiondef); + } + function afterprop(type) { + if (type == ":") return cont(expressionNoComma); + if (type == "(") return pass(functiondef); + } + function commasep(what, end) { + function proceed(type, value) { + if (type == ",") { + var lex = cx.state.lexical; + if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; + return cont(function (type, value) { + if (type == end || value == end) return pass() + return pass(what) + }, proceed); + } + if (type == end || value == end) return cont(); + return cont(expect(end)); + } + return function (type, value) { + if (type == end || value == end) return cont(); + return pass(what, proceed); + }; + } + function contCommasep(what, end, info) { + for (var i = 3; i < arguments.length; i++) + cx.cc.push(arguments[i]); + return cont(pushlex(end, info), commasep(what, end), poplex); + } + function block(type) { + if (type == "}") return cont(); + return pass(statement, block); + } + function maybetype(type) { + if (isTS && type == ":") return cont(typeexpr); + } + function maybedefault(_, value) { + if (value == "=") return cont(expressionNoComma); + } + function typeexpr(type) { + if (type == "variable") { cx.marked = "variable-3"; return cont(afterType); } + } + function afterType(type, value) { + if (value == "<") return cont(commasep(typeexpr, ">"), afterType) + if (type == "[") return cont(expect("]"), afterType) + } + function vardef() { + return pass(pattern, maybetype, maybeAssign, vardefCont); + } + function pattern(type, value) { + if (type == "modifier") return cont(pattern) + if (type == "variable") { register(value); return cont(); } + if (type == "spread") return cont(pattern); + if (type == "[") return contCommasep(pattern, "]"); + if (type == "{") return contCommasep(proppattern, "}"); + } + function proppattern(type, value) { + if (type == "variable" && !cx.stream.match(/^\s*:/, false)) { + register(value); + return cont(maybeAssign); + } + if (type == "variable") cx.marked = "property"; + if (type == "spread") return cont(pattern); + if (type == "}") return pass(); + return cont(expect(":"), pattern, maybeAssign); + } + function maybeAssign(_type, value) { + if (value == "=") return cont(expressionNoComma); + } + function vardefCont(type) { + if (type == ",") return cont(vardef); + } + function maybeelse(type, value) { + if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex); + } + function forspec(type) { + if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex); + } + function forspec1(type) { + if (type == "var") return cont(vardef, expect(";"), forspec2); + if (type == ";") return cont(forspec2); + if (type == "variable") return cont(formaybeinof); + return pass(expression, expect(";"), forspec2); + } + function formaybeinof(_type, value) { + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return cont(maybeoperatorComma, forspec2); + } + function forspec2(type, value) { + if (type == ";") return cont(forspec3); + if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); } + return pass(expression, expect(";"), forspec3); + } + function forspec3(type) { + if (type != ")") cont(expression); + } + function functiondef(type, value) { + if (value == "*") { cx.marked = "keyword"; return cont(functiondef); } + if (type == "variable") { register(value); return cont(functiondef); } + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext); + } + function funarg(type) { + if (type == "spread") return cont(funarg); + return pass(pattern, maybetype, maybedefault); + } + function className(type, value) { + if (type == "variable") { register(value); return cont(classNameAfter); } + } + function classNameAfter(type, value) { + if (value == "extends") return cont(expression, classNameAfter); + if (type == "{") return cont(pushlex("}"), classBody, poplex); + } + function classBody(type, value) { + if (type == "variable" || cx.style == "keyword") { + if (value == "static") { + cx.marked = "keyword"; + return cont(classBody); + } + cx.marked = "property"; + if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); + return cont(functiondef, classBody); + } + if (value == "*") { + cx.marked = "keyword"; + return cont(classBody); + } + if (type == ";") return cont(classBody); + if (type == "}") return cont(); + } + function classGetterSetter(type) { + if (type != "variable") return pass(); + cx.marked = "property"; + return cont(); + } + function afterExport(_type, value) { + if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } + if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } + return pass(statement); + } + function afterImport(type) { + if (type == "string") return cont(); + return pass(importSpec, maybeFrom); + } + function importSpec(type, value) { + if (type == "{") return contCommasep(importSpec, "}"); + if (type == "variable") register(value); + if (value == "*") cx.marked = "keyword"; + return cont(maybeAs); + } + function maybeAs(_type, value) { + if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } + } + function maybeFrom(_type, value) { + if (value == "from") { cx.marked = "keyword"; return cont(expression); } + } + function arrayLiteral(type) { + if (type == "]") return cont(); + return pass(expressionNoComma, commasep(expressionNoComma, "]")); + } + + function isContinuedStatement(state, textAfter) { + return state.lastType == "operator" || state.lastType == "," || + isOperatorChar.test(textAfter.charAt(0)) || + /[,.]/.test(textAfter.charAt(0)); + } + + // Interface + + return { + startState: function (basecolumn) { + var state = { + tokenize: tokenBase, + lastType: "sof", + cc: [], + lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), + localVars: parserConfig.localVars, + context: parserConfig.localVars && { vars: parserConfig.localVars }, + indented: basecolumn || 0 + }; + if (parserConfig.globalVars && typeof parserConfig.globalVars == "object") + state.globalVars = parserConfig.globalVars; + return state; + }, + + token: function (stream, state) { + if (stream.sol()) { + if (!state.lexical.hasOwnProperty("align")) + state.lexical.align = false; + state.indented = stream.indentation(); + findFatArrow(stream, state); + } + if (state.tokenize != tokenComment && stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + if (type == "comment") return style; + state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; + return parseJS(state, style, type, content, stream); + }, + + indent: function (state, textAfter) { + if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize != tokenBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + // Kludge to prevent 'maybelse' from blocking lexical scope pops + if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { + var c = state.cc[i]; + if (c == poplex) lexical = lexical.prev; + else if (c != maybeelse) break; + } + if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; + if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") + lexical = lexical.prev; + var type = lexical.type, closing = firstChar == type; + + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0); + else if (type == "form" && firstChar == "{") return lexical.indented; + else if (type == "form") return lexical.indented + indentUnit; + else if (type == "stat") + return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0); + else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false) + return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit); + else if (lexical.align) return lexical.column + (closing ? 0 : 1); + else return lexical.indented + (closing ? 0 : indentUnit); + }, + + electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + lineComment: jsonMode ? null : "//", + fold: "brace", + closeBrackets: "()[]{}''\"\"``", + + helperType: jsonMode ? "json" : "javascript", + jsonldMode: jsonldMode, + jsonMode: jsonMode, + + expressionAllowed: expressionAllowed, + skipExpression: function (state) { + var top = state.cc[state.cc.length - 1] + if (top == expression || top == expressionNoComma) state.cc.pop() + } + }; + }); + + CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); + + CodeMirror.defineMIME("text/javascript", "javascript"); + CodeMirror.defineMIME("text/ecmascript", "javascript"); + CodeMirror.defineMIME("application/javascript", "javascript"); + CodeMirror.defineMIME("application/x-javascript", "javascript"); + CodeMirror.defineMIME("application/ecmascript", "javascript"); + CodeMirror.defineMIME("application/json", { name: "javascript", json: true }); + CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true }); + CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true }); + CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); + CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); + +})(); + +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function () { + var defaults = { + pairs: "()[]{}''\"\"", + triples: "", + explode: "[]{}" + }; + + var Pos = CodeMirror.Pos; + + CodeMirror.defineOption("autoCloseBrackets", false, function (cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.removeKeyMap(keyMap); + cm.state.closeBrackets = null; + } + if (val) { + cm.state.closeBrackets = val; + cm.addKeyMap(keyMap); + } + }); + + function getOption(conf, name) { + if (name == "pairs" && typeof conf == "string") return conf; + if (typeof conf == "object" && conf[name] != null) return conf[name]; + return defaults[name]; + } + + var bind = defaults.pairs + "`"; + var keyMap = { Backspace: handleBackspace, Enter: handleEnter }; + for (var i = 0; i < bind.length; i++) + keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i)); + + function handler(ch) { + return function (cm) { return handleChar(cm, ch); }; + } + + function getConfig(cm) { + var deflt = cm.state.closeBrackets; + if (!deflt) return null; + var mode = cm.getModeAt(cm.getCursor()); + return mode.closeBrackets || deflt; + } + + function handleBackspace(cm) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + for (var i = ranges.length - 1; i >= 0; i--) { + var cur = ranges[i].head; + cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); + } + } + + function handleEnter(cm) { + var conf = getConfig(cm); + var explode = conf && getOption(conf, "explode"); + if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; + + var ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) return CodeMirror.Pass; + var around = charsAround(cm, ranges[i].head); + if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; + } + cm.operation(function () { + cm.replaceSelection("\n\n", null); + cm.execCommand("goCharLeft"); + ranges = cm.listSelections(); + for (var i = 0; i < ranges.length; i++) { + var line = ranges[i].head.line; + cm.indentLine(line, null, true); + cm.indentLine(line + 1, null, true); + } + }); + } + + function contractSelection(sel) { + var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; + return { + anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), + head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1)) + }; + } + + function handleChar(cm, ch) { + var conf = getConfig(cm); + if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; + + var pairs = getOption(conf, "pairs"); + var pos = pairs.indexOf(ch); + if (pos == -1) return CodeMirror.Pass; + var triples = getOption(conf, "triples"); + + var identical = pairs.charAt(pos + 1) == ch; + var ranges = cm.listSelections(); + var opening = pos % 2 == 0; + + var type; + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i], cur = range.head, curType; + var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); + if (opening && !range.empty()) { + curType = "surround"; + } else if ((identical || !opening) && next == ch) { + if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) + curType = "skipThree"; + else + curType = "skip"; + } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch && + (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) { + curType = "addFour"; + } else if (identical) { + if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both"; + else return CodeMirror.Pass; + } else if (opening && (cm.getLine(cur.line).length == cur.ch || + isClosingBracket(next, pairs) || + /\s/.test(next))) { + curType = "both"; + } else { + return CodeMirror.Pass; + } + if (!type) type = curType; + else if (type != curType) return CodeMirror.Pass; + } + + var left = pos % 2 ? pairs.charAt(pos - 1) : ch; + var right = pos % 2 ? ch : pairs.charAt(pos + 1); + cm.operation(function () { + if (type == "skip") { + cm.execCommand("goCharRight"); + } else if (type == "skipThree") { + for (var i = 0; i < 3; i++) + cm.execCommand("goCharRight"); + } else if (type == "surround") { + var sels = cm.getSelections(); + for (var i = 0; i < sels.length; i++) + sels[i] = left + sels[i] + right; + cm.replaceSelections(sels, "around"); + sels = cm.listSelections().slice(); + for (var i = 0; i < sels.length; i++) + sels[i] = contractSelection(sels[i]); + cm.setSelections(sels); + } else if (type == "both") { + cm.replaceSelection(left + right, null); + cm.triggerElectric(left + right); + cm.execCommand("goCharLeft"); + } else if (type == "addFour") { + cm.replaceSelection(left + left + left + left, "before"); + cm.execCommand("goCharRight"); + } + }); + } + + function isClosingBracket(ch, pairs) { + var pos = pairs.lastIndexOf(ch); + return pos > -1 && pos % 2 == 1; + } + + function charsAround(cm, pos) { + var str = cm.getRange(Pos(pos.line, pos.ch - 1), + Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + + // Project the token type that will exists after the given char is + // typed, and use it to determine whether it would cause the start + // of a string token. + function enteringString(cm, pos, ch) { + var line = cm.getLine(pos.line); + var token = cm.getTokenAt(pos); + if (/\bstring2?\b/.test(token.type)) return false; + var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); + stream.pos = stream.start = token.start; + for (; ;) { + var type1 = cm.getMode().token(stream, token.state); + if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1); + stream.start = stream.pos; + } + } +})(); + +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: https://codemirror.net/LICENSE + +// declare global: DOMRect + +(function () { + "use strict"; + + var HINT_ELEMENT_CLASS = "CodeMirror-hint"; + var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; + + // This is the old interface, kept around for now to stay + // backwards-compatible. + CodeMirror.showHint = function (cm, getHints, options) { + if (!getHints) return cm.showHint(options); + if (options && options.async) getHints.async = true; + var newOpts = { hint: getHints }; + if (options) for (var prop in options) newOpts[prop] = options[prop]; + return cm.showHint(newOpts); + }; + + CodeMirror.defineExtension("showHint", function (options) { + options = parseOptions(this, this.getCursor("start"), options); + var selections = this.listSelections() + if (selections.length > 1) return; + // By default, don't allow completion when something is selected. + // A hint function can have a `supportsSelection` property to + // indicate that it can handle selections. + if (this.somethingSelected()) { + if (!options.hint.supportsSelection) return; + // Don't try with cross-line selections + for (var i = 0; i < selections.length; i++) + if (selections[i].head.line != selections[i].anchor.line) return; + } + + if (this.state.completionActive) this.state.completionActive.close(); + var completion = this.state.completionActive = new Completion(this, options); + if (!completion.options.hint) return; + + CodeMirror.signal(this, "startCompletion", this); + completion.update(true); + }); + + CodeMirror.defineExtension("closeHint", function () { + if (this.state.completionActive) this.state.completionActive.close() + }) + + function Completion(cm, options) { + this.cm = cm; + this.options = options; + this.widget = null; + this.debounce = 0; + this.tick = 0; + this.startPos = this.cm.getCursor("start"); + this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; + + if (this.options.updateOnCursorActivity) { + var self = this; + cm.on("cursorActivity", this.activityFunc = function () { self.cursorActivity(); }); + } + } + + var requestAnimationFrame = window.requestAnimationFrame || function (fn) { + return setTimeout(fn, 1000 / 60); + }; + var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; + + Completion.prototype = { + close: function () { + if (!this.active()) return; + this.cm.state.completionActive = null; + this.tick = null; + if (this.options.updateOnCursorActivity) { + this.cm.off("cursorActivity", this.activityFunc); + } + + if (this.widget && this.data) CodeMirror.signal(this.data, "close"); + if (this.widget) this.widget.close(); + CodeMirror.signal(this.cm, "endCompletion", this.cm); + }, + + active: function () { + return this.cm.state.completionActive == this; + }, + + pick: function (data, i) { + var completion = data.list[i], self = this; + this.cm.operation(function () { + if (completion.hint) + completion.hint(self.cm, data, completion); + else + self.cm.replaceRange(getText(completion), completion.from || data.from, + completion.to || data.to, "complete"); + CodeMirror.signal(data, "pick", completion); + self.cm.scrollIntoView(); + }); + if (this.options.closeOnPick) { + this.close(); + } + }, + + cursorActivity: function () { + if (this.debounce) { + cancelAnimationFrame(this.debounce); + this.debounce = 0; + } + + var identStart = this.startPos; + if (this.data) { + identStart = this.data.from; + } + + var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); + if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || + pos.ch < identStart.ch || this.cm.somethingSelected() || + (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { + this.close(); + } else { + var self = this; + this.debounce = requestAnimationFrame(function () { self.update(); }); + if (this.widget) this.widget.disable(); + } + }, + + update: function (first) { + if (this.tick == null) return + var self = this, myTick = ++this.tick + fetchHints(this.options.hint, this.cm, this.options, function (data) { + if (self.tick == myTick) self.finishUpdate(data, first) + }) + }, + + finishUpdate: function (data, first) { + if (this.data) CodeMirror.signal(this.data, "update"); + + var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); + if (this.widget) this.widget.close(); + + this.data = data; + + if (data && data.list.length) { + if (picked && data.list.length == 1) { + this.pick(data, 0); + } else { + this.widget = new Widget(this, data); + CodeMirror.signal(data, "shown"); + } + } + } + }; + + function parseOptions(cm, pos, options) { + var editor = cm.options.hintOptions; + var out = {}; + for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; + if (editor) for (var prop in editor) + if (editor[prop] !== undefined) out[prop] = editor[prop]; + if (options) for (var prop in options) + if (options[prop] !== undefined) out[prop] = options[prop]; + if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) + return out; + } + + function getText(completion) { + if (typeof completion == "string") return completion; + else return completion.text; + } + + function buildKeyMap(completion, handle) { + var baseMap = { + Up: function () { handle.moveFocus(-1); }, + Down: function () { handle.moveFocus(1); }, + PageUp: function () { handle.moveFocus(-handle.menuSize() + 1, true); }, + PageDown: function () { handle.moveFocus(handle.menuSize() - 1, true); }, + Home: function () { handle.setFocus(0); }, + End: function () { handle.setFocus(handle.length - 1); }, + Enter: handle.pick, + Tab: handle.pick, + Esc: handle.close + }; + + var mac = /Mac/.test(navigator.platform); + + if (mac) { + baseMap["Ctrl-P"] = function () { handle.moveFocus(-1); }; + baseMap["Ctrl-N"] = function () { handle.moveFocus(1); }; + } + + var custom = completion.options.customKeys; + var ourMap = custom ? {} : baseMap; + function addBinding(key, val) { + var bound; + if (typeof val != "string") + bound = function (cm) { return val(cm, handle); }; + // This mechanism is deprecated + else if (baseMap.hasOwnProperty(val)) + bound = baseMap[val]; + else + bound = val; + ourMap[key] = bound; + } + if (custom) + for (var key in custom) if (custom.hasOwnProperty(key)) + addBinding(key, custom[key]); + var extra = completion.options.extraKeys; + if (extra) + for (var key in extra) if (extra.hasOwnProperty(key)) + addBinding(key, extra[key]); + return ourMap; + } + + function getHintElement(hintsElement, el) { + while (el && el != hintsElement) { + if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; + el = el.parentNode; + } + } + + function Widget(completion, data) { + this.completion = completion; + this.data = data; + this.picked = false; + var widget = this, cm = completion.cm; + var ownerDocument = cm.getInputField().ownerDocument; + var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow; + var hints = this.hints = ownerDocument.createElement("ul"); + var theme = completion.cm.options.theme; + hints.className = "CodeMirror-hints " + theme; + this.selectedHint = data.selectedHint || 0; + + var completions = data.list; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i]; + var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); + if (cur.className != null) className = cur.className + " " + className; + elt.className = className; + if (cur.render) cur.render(elt, data, cur); + else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur))); + elt.hintId = i; + CodeMirror.on(elt, "mouseover", function (e) { + widget.changeActive(this.hintId); + }); + CodeMirror.on(elt, "touchstart", function (e) { + widget.changeActive(this.hintId); + }); + CodeMirror.on(elt, "touchend", function (e) { + var cur = cm.getCursor(); + var self = this; + setTimeout(function () { + cm.focus(); + var cur2 = cm.getCursor(); + if (cur2.line == cur.line && cur2.ch == 0) { + var textLen = self.innerText.length; + cm.setCursor({ line: cur.line, ch: cur.ch + textLen }); + } + }, 10); + }); + } + + var container = completion.options.container || ownerDocument.body; + var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); + var left = pos.left, top = pos.bottom, below = true; + var offsetLeft = 0, offsetTop = 0; + if (container !== ownerDocument.body) { + // We offset the cursor position because left and top are relative to the offsetParent's top left corner. + var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1; + var offsetParent = isContainerPositioned ? container : container.offsetParent; + var offsetParentPosition = offsetParent.getBoundingClientRect(); + var bodyPosition = ownerDocument.body.getBoundingClientRect(); + offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft); + offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop); + } + var documentZoom = getDocumentZoom(); + hints.style.fontSize = 16 / documentZoom * 0.9 + "px"; + hints.style.left = (left - offsetLeft) / documentZoom + "px"; + hints.style.top = (top - offsetTop) / documentZoom + "px"; + + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); + var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); + container.appendChild(hints); + + var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect(); + var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false; + + // Compute in the timeout to avoid reflow on init + var startScroll; + setTimeout(function () { startScroll = cm.getScrollInfo(); }); + + var overlapY = box.bottom - winH; + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = pos.top - height - offsetTop) / documentZoom + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) / documentZoom + "px"; + hints.style.top = (top = pos.bottom - box.top - offsetTop) / documentZoom + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left - offsetLeft) / documentZoom + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.right - winW; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) / documentZoom + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (left = pos.left - overlapX - offsetLeft) / documentZoom + "px"; + } + if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) + node.style.paddingRight = cm.display.nativeBarWidth / documentZoom + "px" + + cm.addKeyMap(this.keyMap = buildKeyMap(completion, { + moveFocus: function (n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, + setFocus: function (n) { widget.changeActive(n); }, + menuSize: function () { return widget.screenAmount(); }, + length: completions.length, + close: function () { completion.close(); }, + pick: function () { widget.pick(); }, + data: data + })); + + if (completion.options.closeOnUnfocus) { + var closingOnBlur; + cm.on("blur", this.onBlur = function () { closingOnBlur = setTimeout(function () { completion.close(); }, 100); }); + cm.on("focus", this.onFocus = function () { clearTimeout(closingOnBlur); }); + } + + cm.on("scroll", this.onScroll = function () { + // fix "startScroll == undfined" + if (!startScroll) return; + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top; + var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop); + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return completion.close(); + hints.style.top = newTop / documentZoom + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) / documentZoom + "px"; + }); + + CodeMirror.on(hints, "dblclick", function (e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { widget.changeActive(t.hintId); widget.pick(); } + }); + + CodeMirror.on(hints, "click", function (e) { + var t = getHintElement(hints, e.target || e.srcElement); + if (t && t.hintId != null) { + widget.changeActive(t.hintId); + if (completion.options.completeOnSingleClick) widget.pick(); + } + }); + + CodeMirror.on(hints, "mousedown", function () { + setTimeout(function () { cm.focus(); }, 20); + }); + + //滑动修复 + CodeMirror.on(hints, "touchmove", function (event) { + if (ios && this.scrollHeight <= this.offsetHeight + 5 && this.scrollWidth <= this.offsetWidth + 5) { + event.preventDefault(); + } + else { + event.stopPropagation(); + } + }); + hints.style.WebkitOverflowScrolling = 'touch'; + + // The first hint doesn't need to be scrolled to on init + var selectedHintRange = this.getSelectedHintRange(); + if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) { + this.scrollToActive(); + } + + CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); + return true; + } + + Widget.prototype = { + close: function () { + if (this.completion.widget != this) return; + this.completion.widget = null; + this.hints.parentNode.removeChild(this.hints); + this.completion.cm.removeKeyMap(this.keyMap); + + var cm = this.completion.cm; + if (this.completion.options.closeOnUnfocus) { + cm.off("blur", this.onBlur); + cm.off("focus", this.onFocus); + } + cm.off("scroll", this.onScroll); + }, + + disable: function () { + this.completion.cm.removeKeyMap(this.keyMap); + var widget = this; + this.keyMap = { Enter: function () { widget.picked = true; } }; + this.completion.cm.addKeyMap(this.keyMap); + }, + + pick: function () { + this.completion.pick(this.data, this.selectedHint); + }, + + changeActive: function (i, avoidWrap) { + if (i >= this.data.list.length) + i = avoidWrap ? this.data.list.length - 1 : 0; + else if (i < 0) + i = avoidWrap ? 0 : this.data.list.length - 1; + if (this.selectedHint == i) return; + var node = this.hints.childNodes[this.selectedHint]; + if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); + node = this.hints.childNodes[this.selectedHint = i]; + node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; + this.scrollToActive() + CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); + }, + + scrollToActive: function () { + var selectedHintRange = this.getSelectedHintRange(); + var node1 = this.hints.childNodes[selectedHintRange.from]; + var node2 = this.hints.childNodes[selectedHintRange.to]; + var firstNode = this.hints.firstChild; + if (node1.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop; + else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop; + }, + + screenAmount: function () { + return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + }, + + getSelectedHintRange: function () { + var margin = this.completion.options.scrollMargin || 0; + return { + from: Math.max(0, this.selectedHint - margin), + to: Math.min(this.data.list.length - 1, this.selectedHint + margin), + }; + } + }; + + function applicableHelpers(cm, helpers) { + if (!cm.somethingSelected()) return helpers + var result = [] + for (var i = 0; i < helpers.length; i++) + if (helpers[i].supportsSelection) result.push(helpers[i]) + return result + } + + function fetchHints(hint, cm, options, callback) { + if (hint.async) { + hint(cm, callback, options) + } else { + var result = hint(cm, options) + if (result && result.then) result.then(callback) + else callback(result) + } + } + + function resolveAutoHints(cm, pos) { + var helpers = cm.getHelpers(pos, "hint"), words + if (helpers.length) { + var resolved = function (cm, callback, options) { + var app = applicableHelpers(cm, helpers); + function run(i) { + if (i == app.length) return callback(null) + fetchHints(app[i], cm, options, function (result) { + if (result && result.list.length > 0) callback(result) + else run(i + 1) + }) + } + run(0) + } + resolved.async = true + resolved.supportsSelection = true + return resolved + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { + return function (cm) { return CodeMirror.hint.fromList(cm, { words: words }) } + } else if (CodeMirror.hint.anyword) { + return function (cm, options) { return CodeMirror.hint.anyword(cm, options) } + } else { + return function () { } + } + } + + CodeMirror.registerHelper("hint", "auto", { + resolve: resolveAutoHints + }); + + CodeMirror.registerHelper("hint", "fromList", function (cm, options) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur) + var term, from = CodeMirror.Pos(cur.line, token.start), to = cur + if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) { + term = token.string.substr(0, cur.ch - token.start) + } else { + term = "" + from = cur + } + var found = []; + for (var i = 0; i < options.words.length; i++) { + var word = options.words[i]; + if (word.slice(0, term.length) == term) + found.push(word); + } + + if (found.length) return { list: found, from: from, to: to }; + }); + + CodeMirror.commands.autocomplete = CodeMirror.showHint; + + var defaultOptions = { + hint: CodeMirror.hint.auto, + completeSingle: true, + alignWithWord: true, + closeCharacters: /[\s()\[\]{};:>,]/, + closeOnPick: true, + closeOnUnfocus: true, + updateOnCursorActivity: true, + completeOnSingleClick: true, + container: null, + customKeys: null, + extraKeys: null, + paddingForScrollbar: true, + moveOnOverlap: true, + }; + + CodeMirror.defineOption("hintOptions", null); +})(); + +export default CodeMirror; diff --git a/game/config.js b/game/config.js index c343c0109..064b67daa 100644 --- a/game/config.js +++ b/game/config.js @@ -1,249 +1,410 @@ -window.config={ - extension_sources:{ - 'GitHub Proxy':'https://mirror.ghproxy.com/https://raw.githubusercontent.com/libccy/noname-extension/master/', - FastGit:'https://raw.fgit.cf/libccy/noname-extension/master/', - GitHub:'https://raw.githubusercontent.com/libccy/noname-extension/master/' +window.config = { + extension_sources: { + "GitHub Proxy": + "https://mirror.ghproxy.com/https://raw.githubusercontent.com/libccy/noname-extension/master/", + FastGit: "https://raw.fgit.cf/libccy/noname-extension/master/", + GitHub: "https://raw.githubusercontent.com/libccy/noname-extension/master/", }, - extension_source:'GitHub Proxy', - forbidai:['ns_liuzhang'], - forbidai_user:[], - forbidall:[], - forbidstone:['zhugedan','pal_xuanxiao','hs_malfurion','lusu','chenlin','hs_siwangzhiyi', - 'gjqt_bailitusu','yuanshao','swd_anka','swd_nicole','daqiao','re_daqiao','hs_xuanzhuanjijia', - 'zhuran','huatuo','swd_tuwei','hs_guldan','wangyi','caoang','swd_guyue','swd_rongshuang', - 'swd_jiangziya','guojia','re_guojia','shen_caocao','swd_qiner','caopi','hs_yngvar','guansuo', - 'gjqt_aruan','swd_hanluo','hs_anduin','swd_huanglei','yxs_yujix','yxs_luzhishen','swd_muyun','ow_tianshi', - 'pal_yuejinzhao','hs_antonidas','xushi','hs_lreno' + extension_source: "GitHub Proxy", + forbidai: ["ns_liuzhang"], + forbidai_user: [], + forbidall: [], + forbidstone: [ + "zhugedan", + "pal_xuanxiao", + "hs_malfurion", + "lusu", + "chenlin", + "hs_siwangzhiyi", + "gjqt_bailitusu", + "yuanshao", + "swd_anka", + "swd_nicole", + "daqiao", + "re_daqiao", + "hs_xuanzhuanjijia", + "zhuran", + "huatuo", + "swd_tuwei", + "hs_guldan", + "wangyi", + "caoang", + "swd_guyue", + "swd_rongshuang", + "swd_jiangziya", + "guojia", + "re_guojia", + "shen_caocao", + "swd_qiner", + "caopi", + "hs_yngvar", + "guansuo", + "gjqt_aruan", + "swd_hanluo", + "hs_anduin", + "swd_huanglei", + "yxs_yujix", + "yxs_luzhishen", + "swd_muyun", + "ow_tianshi", + "pal_yuejinzhao", + "hs_antonidas", + "xushi", + "hs_lreno", ], - forbidchess:['hetaihou','swd_kangnalishi'], - forbidboss:['caiwenji','gjqt_aruan','pal_xuanxiao','swd_hupo'], - forbiddouble:['zhugedan','swd_kangnalishi','dongzhuo','wutugu','hs_siwangzhiyi','hs_ronghejuren','hs_shanlingjuren'], - forbidthreecard:['qiankunbiao','shenhuofeiya','gw_ciguhanshuang','gw_birinongwu','gw_qinpendayu','gw_poxiao'], - zhinang_tricks:['guohe','wuxie','wuzhong','dongzhuxianji'], - connect_zhinang_tricks:['guohe','wuxie','wuzhong','dongzhuxianji'], - all:{ - sgscharacters:['standard','shenhua','xinghuoliaoyuan','refresh','yijiang','sp','sp2','xianding','huicui','extra','old','mobile','shiji','tw','yingbian','offline','jsrg','sb','clan','collab','onlyOL'], - sgscards:['standard','extra','sp','guozhan','zhulu','yingbian','yongjian'], - sgsmodes:['identity','guozhan','versus','doudizhu','single','brawl','connect'], - stockmode:['identity','guozhan','versus','boss','doudizhu','single','chess','stone','connect','brawl','tafang'], - stockextension:['boss','cardpile','coin','wuxing'], - layout:['default','newlayout'], - theme:['woodden','music','simple'], - card_font:['xiaozhuan','huangcao','caoshu','xingshu'], - double_hp:['hejiansan','pingjun','zuidazhi','zuixiaozhi','zonghe'], - image_background_filter:['default','blur','gray','sepia','invert','saturate','contrast','hue','brightness'], + forbidchess: ["hetaihou", "swd_kangnalishi"], + forbidboss: ["caiwenji", "gjqt_aruan", "pal_xuanxiao", "swd_hupo"], + forbiddouble: [ + "zhugedan", + "swd_kangnalishi", + "dongzhuo", + "wutugu", + "hs_siwangzhiyi", + "hs_ronghejuren", + "hs_shanlingjuren", + ], + forbidthreecard: [ + "qiankunbiao", + "shenhuofeiya", + "gw_ciguhanshuang", + "gw_birinongwu", + "gw_qinpendayu", + "gw_poxiao", + ], + zhinang_tricks: ["guohe", "wuxie", "wuzhong", "dongzhuxianji"], + connect_zhinang_tricks: ["guohe", "wuxie", "wuzhong", "dongzhuxianji"], + all: { + sgscharacters: [ + "standard", + "shenhua", + "xinghuoliaoyuan", + "refresh", + "yijiang", + "sp", + "sp2", + "xianding", + "huicui", + "extra", + "old", + "mobile", + "shiji", + "tw", + "yingbian", + "offline", + "jsrg", + "sb", + "clan", + "collab", + "onlyOL", + ], + sgscards: [ + "standard", + "extra", + "sp", + "guozhan", + "zhulu", + "yingbian", + "yongjian", + ], + sgsmodes: [ + "identity", + "guozhan", + "versus", + "doudizhu", + "single", + "brawl", + "connect", + ], + stockmode: [ + "identity", + "guozhan", + "versus", + "boss", + "doudizhu", + "single", + "chess", + "stone", + "connect", + "brawl", + "tafang", + ], + stockextension: ["boss", "cardpile", "coin", "wuxing"], + layout: ["default", "newlayout"], + theme: ["woodden", "music", "simple"], + card_font: ["xiaozhuan", "huangcao", "caoshu", "xingshu"], + double_hp: ["hejiansan", "pingjun", "zuidazhi", "zuixiaozhi", "zonghe"], + image_background_filter: [ + "default", + "blur", + "gray", + "sepia", + "invert", + "saturate", + "contrast", + "hue", + "brightness", + ], }, - game:'sgs', - duration:500, - hoveration:1000, - doubleclick_intro:true, - cheat:false, - volumn_background:8, - volumn_audio:8, + game: "sgs", + duration: 500, + hoveration: 1000, + doubleclick_intro: true, + cheat: false, + volumn_background: 8, + volumn_audio: 8, - connect_avatar:'caocao', - connect_nickname:'无名玩家', - config_menu:true, - auto_popped_config:true, - auto_popped_history:false, - auto_skill:true, - auto_confirm:true, - enable_drag:true, - enable_pressure:false, - pressure_taptic:true, - hover_handcard:true, - hover_all:true, - right_info:true, - longpress_info:true, - long_info:true, - background_music:'music_default', - background_audio:true, - background_speak:true, - glow_phase:'yellow', - die_move:'flip', + connect_avatar: "caocao", + connect_nickname: "无名玩家", + config_menu: true, + auto_popped_config: true, + auto_popped_history: false, + auto_skill: true, + auto_confirm: true, + enable_drag: true, + enable_pressure: false, + pressure_taptic: true, + hover_handcard: true, + hover_all: true, + right_info: true, + longpress_info: true, + long_info: true, + background_music: "music_default", + background_audio: true, + background_speak: true, + glow_phase: "yellow", + die_move: "flip", - skin:{}, - gameRecord:{}, - extensionInfo:{}, - autoskilllist:[], - hiddenModePack:[], - hiddenCharacterPack:[], - hiddenCardPack:[], - hiddenPlayPack:[], - hiddenBackgroundPack:[], - customBackgroundPack:[], - favouriteCharacter:[], - favouriteMode:[], - recentIP:[], - vintageSkills:[], - alteredSkills:[], - brokenFile:[], + skin: {}, + gameRecord: {}, + extensionInfo: {}, + autoskilllist: [], + hiddenModePack: [], + hiddenCharacterPack: [], + hiddenCardPack: [], + hiddenPlayPack: [], + hiddenBackgroundPack: [], + customBackgroundPack: [], + favouriteCharacter: [], + favouriteMode: [], + recentIP: [], + vintageSkills: [], + alteredSkills: [], + brokenFile: [], - theme:'woodden', - layout:'mobile', - card_style:'default', - cardback_style:'default', - hp_style:'default', + theme: "woodden", + layout: "mobile", + card_style: "default", + cardback_style: "default", + hp_style: "default", - image_character:'default', - image_background:'default', + image_character: "default", + image_background: "default", - asset_image:true, - asset_font:true, + asset_image: true, + asset_font: true, - card_font:'xiaozhuan', - show_statusbar_ios:'off', - show_statusbar_android:false, - show_name:true, - show_replay:false, - show_round_menu:true, - show_pause:true, - show_auto:true, - show_volumn:true, - show_cardpile:true, - only_fullskin:true, - show_connect:true, - show_wuxie:false, - show_wuxie_self:true, - show_stat:true, - show_playerids:true, - show_scrollbar:false, - mousewheel:true, - fold_card:true, - threed_card:false, - vertical_scroll:false, - handcard_scroll:0, - animation:true, - skill_animation_type:'default', - paused:false, - title:false, - button_press:true, - damage_shake:true, - log_highlight:true, - player_border:'normal', - radius_size:'default', + card_font: "xiaozhuan", + show_statusbar_ios: "off", + show_statusbar_android: false, + show_name: true, + show_replay: false, + show_round_menu: true, + show_pause: true, + show_auto: true, + show_volumn: true, + show_cardpile: true, + only_fullskin: true, + show_connect: true, + show_wuxie: false, + show_wuxie_self: true, + show_stat: true, + show_playerids: true, + show_scrollbar: false, + mousewheel: true, + fold_card: true, + threed_card: false, + vertical_scroll: false, + handcard_scroll: 0, + animation: true, + skill_animation_type: "default", + paused: false, + title: false, + button_press: true, + damage_shake: true, + log_highlight: true, + player_border: "normal", + radius_size: "default", - modeconfig:false, - gameconfig:false, - appearence:false, - video:'20', - coin:0, + modeconfig: false, + gameconfig: false, + appearence: false, + video: "20", + coin: 0, - intro:'i', - right_click:'pause', - sort:'type_sort', + intro: "i", + right_click: "pause", + sort: "type_sort", - cards:['standard','extra'], - characters:['standard','shenhua','sp','sp2','yijiang','refresh','xinghuoliaoyuan','mobile','extra','yingbian','sb','tw','offline','clan','collab','xianding','huicui','shiji','jsrg','onlyOL'], - connect_characters:['diy'], - connect_cards:['huanlekapai','guozhan','sp','zhulu','yingbian','yongjian'], - plays:[], - extensions:[], - banned:[], - bannedcards:[], - forbidlist:[], - bannedpile:{}, - customcardpile:{}, - addedpile:{}, + cards: ["standard", "extra"], + characters: [ + "standard", + "shenhua", + "sp", + "sp2", + "yijiang", + "refresh", + "xinghuoliaoyuan", + "mobile", + "extra", + "yingbian", + "sb", + "tw", + "offline", + "clan", + "collab", + "xianding", + "huicui", + "shiji", + "jsrg", + "onlyOL", + ], + connect_characters: ["diy"], + connect_cards: [ + "huanlekapai", + "guozhan", + "sp", + "zhulu", + "yingbian", + "yongjian", + ], + plays: [], + extensions: [], + banned: [], + bannedcards: [], + forbidlist: [], + bannedpile: {}, + customcardpile: {}, + addedpile: {}, - mode:'identity', - mode_config:{ - global:{ - player_number:8, - auto_identity:'off', - double_character:false, - save_progress:true, - free_choose:true, - swap:true, - change_identity:true, - battle_number:3, - double_hp:'pingjun', + mode: "identity", + mode_config: { + global: { + player_number: 8, + auto_identity: "off", + double_character: false, + save_progress: true, + free_choose: true, + swap: true, + change_identity: true, + battle_number: 3, + double_hp: "pingjun", }, - identity:{ - identity:[ - ['zhu','fan'], - ['zhu','nei','fan'], - ['zhu','zhong','nei','fan'], - ['zhu','zhong','nei','fan','fan'], - ['zhu','zhong','nei','fan','fan','fan'], - ['zhu','zhong','zhong','nei','fan','fan','fan'], - ['zhu','zhong','zhong','nei','fan','fan','fan','fan'], - ['zhu','zhong','zhong','zhong','nei','fan','fan','fan','fan'], - ['zhu','zhong','zhong','zhong','nei','nei','fan','fan','fan','fan'], + identity: { + identity: [ + ["zhu", "fan"], + ["zhu", "nei", "fan"], + ["zhu", "zhong", "nei", "fan"], + ["zhu", "zhong", "nei", "fan", "fan"], + ["zhu", "zhong", "nei", "fan", "fan", "fan"], + ["zhu", "zhong", "zhong", "nei", "fan", "fan", "fan"], + ["zhu", "zhong", "zhong", "nei", "fan", "fan", "fan", "fan"], + [ + "zhu", + "zhong", + "zhong", + "zhong", + "nei", + "fan", + "fan", + "fan", + "fan", + ], + [ + "zhu", + "zhong", + "zhong", + "zhong", + "nei", + "nei", + "fan", + "fan", + "fan", + "fan", + ], ], - choice:{ - zhu:3, - zhong:4, - nei:5, - fan:3, + choice: { + zhu: 3, + zhong: 4, + nei: 5, + fan: 3, }, - show_identity:true, - difficulty:'normal', - dierestart:true + show_identity: true, + difficulty: "normal", + dierestart: true, }, - guozhan:{ - difficulty:'normal', - initshow_draw:'mark', - dierestart:true + guozhan: { + difficulty: "normal", + initshow_draw: "mark", + dierestart: true, }, }, - current_mode:{}, - customforbid:[], - forbid:[ - ['huashen'], - ['rehuashen'], - ['xinmanjuan'], + current_mode: {}, + customforbid: [], + forbid: [ + ["huashen"], + ["rehuashen"], + ["xinmanjuan"], //['xinleiji','fuji'], - ['xinleiji','xinfu_jijun'], - ['reluanji','jueqing'], - ['lianying','rende'], - ['lianying','anxian'], - ['lianying','yinguo'], - ['lianying','qingjian'], - ['boss_juejing','rende'], - ['boss_juejing','anxian'], - ['boss_juejing','yinguo'], - ['boss_juejing','qingjian'], - ['shangshi','rende'], - ['shangshi','anxian'], - ['shangshi','yinguo'], - ['shangshi','qingjian'], - ['rende','relianying'], - ['anxian','relianying'], - ['yinguo','relianying'], - ['shenxing','relianying'], - ['qingjian','relianying'], - ['rende','yuling'], - ['anxian','yuling'], - ['yinguo','yuling'], - ['qingjian','yuling'], + ["xinleiji", "xinfu_jijun"], + ["reluanji", "jueqing"], + ["lianying", "rende"], + ["lianying", "anxian"], + ["lianying", "yinguo"], + ["lianying", "qingjian"], + ["boss_juejing", "rende"], + ["boss_juejing", "anxian"], + ["boss_juejing", "yinguo"], + ["boss_juejing", "qingjian"], + ["shangshi", "rende"], + ["shangshi", "anxian"], + ["shangshi", "yinguo"], + ["shangshi", "qingjian"], + ["rende", "relianying"], + ["anxian", "relianying"], + ["yinguo", "relianying"], + ["shenxing", "relianying"], + ["qingjian", "relianying"], + ["rende", "yuling"], + ["anxian", "yuling"], + ["yinguo", "yuling"], + ["qingjian", "yuling"], //['qingnang','yiji'], //['qingnang','reyiji'], //['qingjian','tuntian'], // ['yiji','tuntian'], // ['reyiji','tuntian'], - ['tuntian','guidao'], - ['tuntian','tiandao'], - ['tuntian','huanshi'], + ["tuntian", "guidao"], + ["tuntian", "tiandao"], + ["tuntian", "huanshi"], // ['tuntian','guicai'], // ['jiang','chongzhen'], // ['fenji','yuling'], - ['jiushi','guixin'], - ['xiuhua','qiaoxie'], - ['xiuhua','xuanfeng'], - ['xiuhua','duanxing'], - ['xiuhua','xiaoji'], - ['xiuhua','xiaoji'], + ["jiushi", "guixin"], + ["xiuhua", "qiaoxie"], + ["xiuhua", "xuanfeng"], + ["xiuhua", "duanxing"], + ["xiuhua", "xiaoji"], + ["xiuhua", "xiaoji"], // ['jiushi','jushou'], // ['jiushi','kuiwei'], - ['zishu','xinfu_songsang'], - ['zishu','shenxing'], - ['minishendao','luoshen'], - ['minishendao','reluoshen'], - ['akane_quanqing','lianying'], - ['akane_quanqing','relianying'], - ['akane_quanqing','shangshi'], - ['dcruyi','cxliushi'], - ] + ["zishu", "xinfu_songsang"], + ["zishu", "shenxing"], + ["minishendao", "luoshen"], + ["minishendao", "reluoshen"], + ["akane_quanqing", "lianying"], + ["akane_quanqing", "relianying"], + ["akane_quanqing", "shangshi"], + ["dcruyi", "cxliushi"], + ], }; diff --git a/game/directory.js b/game/directory.js index cdabbb940..bca4a4b84 100644 --- a/game/directory.js +++ b/game/directory.js @@ -1,176 +1,198 @@ -var fs=require('fs'); -var path=require('path'); -var exec = require('child_process').exec; -global.window=global; -require(__dirname+'/update.js'); -require(__dirname+'/asset.js'); - -var updates=window.noname_update; -var newversion=false; -var commit=false -if(process.argv[2]){ - if(/[0-9]/.test(process.argv[2][0])){ - newversion=true; - updates.update = updates.version; - updates.version = '1.9.' + process.argv[2]; - commit=updates.version; - } - else{ - commit=process.argv[2]; - } -} -var assetlist=''; -var skinlist='window.noname_skin_list={\n'; -var entrylist=[]; -var entrymap={}; -var get = function(dir,callback){ - fs.readdir(dir,function(err,list){ - var shift=function(){ - if(list.length){ - var filename=list.shift(); - var delay=false; - if(!/\.|~|_/.test(filename[0])){ - var url=dir+'/'+filename; - var stat=fs.statSync(url); - if(stat.isFile()){ - if(['.jpg','.png','.mp3','.ttf'].indexOf(path.extname(url))!=-1){ - var assetentry=path.relative(path.dirname(__dirname),url); - assetlist+=',\n\t\''+assetentry+'\''; - entrylist.push(assetentry); - } - } - else if(stat.isDirectory()){ - if(dir==path.dirname(__dirname)+'/image/skin'){ - fs.readdir(url,function(err,list){ - var num=0; - for(var i=0;i { - var updatelist='window.noname_update={\n\tversion:\''+updates.version+'\','; - updatelist+='\n\tupdate:\''+(updates.update||'')+'\','; - var apply=function(name,list){ - updatelist+='\n\t'+name+':[\n'; - for(var i=0;ib) return 1; - if (a { + var updatelist = + "window.noname_update={\n\tversion:'" + updates.version + "',"; + updatelist += "\n\tupdate:'" + (updates.update || "") + "',"; + var apply = function (name, list) { + updatelist += "\n\t" + name + ":[\n"; + for (var i = 0; i < list.length; i++) { + updatelist += "\t\t'" + list[i] + "'"; + if (i < list.length - 1) { + updatelist += ","; + } + updatelist += "\n"; + } + updatelist += "\t]"; + }; + if (updates.changeLog) { + apply("changeLog", updates.changeLog); + updatelist += ","; + } + if (updates.players) { + apply("players", updates.players); + updatelist += ","; + } + if (updates.cards) { + apply("cards", updates.cards); + updatelist += ","; + } + var changes = stdout.split("\n"); + for (var i = 0; i < changes.length; i++) { + var extname = path.extname(changes[i]); + if ( + !changes[i] || + (extname != ".js" && extname != ".css") || + changes[i] == "game/update.js" + ) { + changes.splice(i--, 1); + } + } + var files; + if (newversion) { + files = []; + } else { + files = updates.files || []; + } + for (var i = 0; i < changes.length; i++) { + if (files.indexOf(changes[i]) === -1) { + files.push(changes[i]); + } + } + files.sort(function (a, b) { + if (a > b) return 1; + if (a < b) return -1; + return 0; + }); + apply("files", files); + fs.writeFile( + "game/update.js", + updatelist + "\n};", + "utf-8", + function () { + console.log("updated update.js"); + if (commit && typeof commit === "string") { + exec("git add . && git commit -am " + commit); + console.log("committed " + commit); + } + } + ); + }); + }; + if (diff) { + var assetversion = + "window.noname_asset_list=[\n\t'" + updates.version + "'"; + fs.writeFile( + "game/asset.js", + assetversion + + assetlist + + "\n];\n" + + skinlist.slice(0, skinlist.length - 2) + + "\n};", + "utf-8", + function () { + console.log("udpated asset.js"); + next(); + } + ); + } else { + next(); + } +}); diff --git a/game/entry.js b/game/entry.js index 6678ac740..c4cae30cc 100644 --- a/game/entry.js +++ b/game/entry.js @@ -1,137 +1,171 @@ -import { game, get, lib, boot } from "../noname.js"; -import { canUseHttpProtocol, sendUpdate } from "../noname/init/index.js"; -import { userAgent } from "../noname/util/index.js"; - -const coreAndVersion = get.coreInfo(); -const core = coreAndVersion[0], version = coreAndVersion[1]; -//@todo: 77 -> 80 -if (core === 'chrome' && !isNaN(version) && version < 77) { - const tip = '检测到您的浏览器内核版本小于77,请及时升级浏览器或手机webview内核!'; - console.warn(tip); - game.print(tip); - const redirect_tip = `您使用的浏览器或无名杀客户端内核版本过低,将在未来的版本被废弃!\n目前使用的浏览器UA信息为:\n${userAgent}\n点击“确认”以前往GitHub下载最新版无名杀客户端(可能需要科学上网)。`; - if (confirm(redirect_tip)) { - window.open('https://github.com/libccy/noname/releases/tag/chromium77-client'); - } -} - -boot().then(() => { - // 判断是否从file协议切换到http/s协议 - if (canUseHttpProtocol()) { - /* - 升级方法: - 1. 游戏启动后导出数据,然后以http/s协议重启 - 2. 以http/s协议导入数据 - 3. 保存http/s协议的状态,以后不再以file协议启动 - */ - // 导出数据到根目录的noname.config.txt - let data; - let export_data = function (data) { - game.promises.writeFile(lib.init.encode(JSON.stringify(data)), './', 'noname.config.txt') - .then(saveProtocol) - .catch(e => { - console.error('升级失败:', e); - }); - }; - // @ts-ignore - if (!lib.db) { - data = {}; - for (let i in localStorage) { - if (i.startsWith(lib.configprefix)) { - data[i] = localStorage[i]; - } - } - export_data(data); - } - else { - game.getDB('config', null, function (data1) { - game.getDB('data', null, function (data2) { - export_data({ - config: data1, - data: data2 - }); - }); - }); - } - // 保存协议的切换状态 - function saveProtocol() { - const url = sendUpdate(); - if (typeof url == 'string') { - if (typeof window.require == 'function' && typeof window.process == 'object') { - // @ts-ignore - const remote = require('@electron/remote'); - const thisWindow = remote.getCurrentWindow(); - thisWindow.loadURL(url); - } else { - location.href = url; - } - } - } - } else { - // 成功导入后删除noname.config.txt - let searchParams = new URLSearchParams(location.search); - for (let [key, value] of searchParams) { - if (key === 'sendUpdate' && value === 'true') { - game.promises.readFileAsText('noname.config.txt').then(data => { - return /** @type {Promise} */(new Promise(async (resolve, reject) => { - if (!data) return reject('!data'); - try { - data = JSON.parse(lib.init.decode(data)); - if (!data || typeof data != 'object') { - throw ('err'); - } - // @ts-ignore - if (lib.db && (!data.config || !data.data)) { - throw ('err'); - } - } - catch (e) { - console.log(e); - if (e == 'err') { - alert('导入文件格式不正确'); - reject('导入文件格式不正确'); - } else { - alert('导入失败: ' + e.message); - reject('导入失败: ' + e.message); - } - return; - } - alert('导入成功, 即将自动重启'); - // @ts-ignore - if (!lib.db) { - const noname_inited = localStorage.getItem('noname_inited'); - const onlineKey = localStorage.getItem(lib.configprefix + 'key'); - localStorage.clear(); - if (noname_inited) { - localStorage.setItem('noname_inited', noname_inited); - } - if (onlineKey) { - localStorage.setItem(lib.configprefix + 'key', onlineKey); - } - for (let i in data) { - localStorage.setItem(i, data[i]); - } - } - else { - for (let i in data.config) { - await game.putDB('config', i, data.config[i]); - lib.config[i] = data.config[i]; - } - for (let i in data.data) { - await game.putDB('data', i, data.data[i]); - } - } - lib.init.background(); - resolve(); - })); - }).then(() => { - return game.promises.removeFile('noname.config.txt'); - }).then(() => { - const url = new URL(location.href); - location.href = url.origin + url.pathname; - }); - } - } - } -}); - +import { game, get, lib, boot } from "../noname.js"; +import { canUseHttpProtocol, sendUpdate } from "../noname/init/index.js"; +import { userAgent } from "../noname/util/index.js"; + +const coreAndVersion = get.coreInfo(); +const core = coreAndVersion[0], + version = coreAndVersion[1]; +//@todo: 77 -> 80 +if (core === "chrome" && !isNaN(version) && version < 77) { + const tip = + "检测到您的浏览器内核版本小于77,请及时升级浏览器或手机webview内核!"; + console.warn(tip); + game.print(tip); + const redirect_tip = `您使用的浏览器或无名杀客户端内核版本过低,将在未来的版本被废弃!\n目前使用的浏览器UA信息为:\n${userAgent}\n点击“确认”以前往GitHub下载最新版无名杀客户端(可能需要科学上网)。`; + if (confirm(redirect_tip)) { + window.open( + "https://github.com/libccy/noname/releases/tag/chromium77-client" + ); + } +} + +boot().then(() => { + // 判断是否从file协议切换到http/s协议 + if (canUseHttpProtocol()) { + /* + 升级方法: + 1. 游戏启动后导出数据,然后以http/s协议重启 + 2. 以http/s协议导入数据 + 3. 保存http/s协议的状态,以后不再以file协议启动 + */ + // 导出数据到根目录的noname.config.txt + let data; + let export_data = function (data) { + game.promises + .writeFile( + lib.init.encode(JSON.stringify(data)), + "./", + "noname.config.txt" + ) + .then(saveProtocol) + .catch((e) => { + console.error("升级失败:", e); + }); + }; + // @ts-ignore + if (!lib.db) { + data = {}; + for (let i in localStorage) { + if (i.startsWith(lib.configprefix)) { + data[i] = localStorage[i]; + } + } + export_data(data); + } else { + game.getDB("config", null, function (data1) { + game.getDB("data", null, function (data2) { + export_data({ + config: data1, + data: data2, + }); + }); + }); + } + // 保存协议的切换状态 + function saveProtocol() { + const url = sendUpdate(); + if (typeof url == "string") { + if ( + typeof window.require == "function" && + typeof window.process == "object" + ) { + // @ts-ignore + const remote = require("@electron/remote"); + const thisWindow = remote.getCurrentWindow(); + thisWindow.loadURL(url); + } else { + location.href = url; + } + } + } + } else { + // 成功导入后删除noname.config.txt + let searchParams = new URLSearchParams(location.search); + for (let [key, value] of searchParams) { + if (key === "sendUpdate" && value === "true") { + game.promises + .readFileAsText("noname.config.txt") + .then((data) => { + return /** @type {Promise} */ ( + new Promise(async (resolve, reject) => { + if (!data) return reject("!data"); + try { + data = JSON.parse(lib.init.decode(data)); + if (!data || typeof data != "object") { + throw "err"; + } + // @ts-ignore + if ( + lib.db && + (!data.config || !data.data) + ) { + throw "err"; + } + } catch (e) { + console.log(e); + if (e == "err") { + alert("导入文件格式不正确"); + reject("导入文件格式不正确"); + } else { + alert("导入失败: " + e.message); + reject("导入失败: " + e.message); + } + return; + } + alert("导入成功, 即将自动重启"); + // @ts-ignore + if (!lib.db) { + const noname_inited = + localStorage.getItem("noname_inited"); + const onlineKey = localStorage.getItem( + lib.configprefix + "key" + ); + localStorage.clear(); + if (noname_inited) { + localStorage.setItem( + "noname_inited", + noname_inited + ); + } + if (onlineKey) { + localStorage.setItem( + lib.configprefix + "key", + onlineKey + ); + } + for (let i in data) { + localStorage.setItem(i, data[i]); + } + } else { + for (let i in data.config) { + await game.putDB( + "config", + i, + data.config[i] + ); + lib.config[i] = data.config[i]; + } + for (let i in data.data) { + await game.putDB( + "data", + i, + data.data[i] + ); + } + } + lib.init.background(); + resolve(); + }) + ); + }) + .then(() => { + return game.promises.removeFile("noname.config.txt"); + }) + .then(() => { + const url = new URL(location.href); + location.href = url.origin + url.pathname; + }); + } + } + } +}); diff --git a/game/game.js b/game/game.js index f071cb26e..eb688d35e 100644 --- a/game/game.js +++ b/game/game.js @@ -1,232 +1,301 @@ -"use strict"; - -new Promise(resolve => { - // 客户端自带core.js的请注意跟进core.js版本 - if ('__core-js_shared__' in window) resolve(null); - else { - const nonameInitialized = localStorage.getItem('noname_inited'); - const assetURL = location.protocol.startsWith('http') || typeof nonameInitialized != 'string' || nonameInitialized == 'nodejs' ? '' : nonameInitialized; - const coreJSBundle = document.createElement('script'); - coreJSBundle.onerror = coreJSBundle.onload = resolve; - coreJSBundle.src = `${assetURL}game/core-js-bundle.js`; - document.head.appendChild(coreJSBundle); - } -}).then(() => { - const nonameInitialized = localStorage.getItem('noname_inited'); - const assetURL = location.protocol.startsWith('http') || typeof nonameInitialized != 'string' || nonameInitialized == 'nodejs' ? '' : nonameInitialized; - const userAgent = navigator.userAgent.toLowerCase(); - - const exit = () => { - const ios = userAgent.includes('iphone') || userAgent.includes('ipad') || userAgent.includes('macintosh'); - //electron - if (typeof window.process == 'object' && typeof window.require == 'function') { - const versions = window.process.versions; - // @ts-ignore - const electronVersion = parseFloat(versions.electron); - let remote; - if (electronVersion >= 14) { - // @ts-ignore - remote = require('@electron/remote'); - } else { - // @ts-ignore - remote = require('electron').remote; - } - const thisWindow = remote.getCurrentWindow(); - thisWindow.destroy(); - window.process.exit(); - } - //android-cordova环境 - //ios-cordova环境或ios浏览器环境 - //非ios的网页版 - else if (!ios) { - window.close(); - } - }; - - // 这个弹窗,在升级到http协议下的客户端不应该进行提示。 - if (!localStorage.getItem('gplv3_noname_alerted')) { - const nonameInitialized = localStorage.getItem('noname_inited'); - const callback = () => { - if (confirm('①无名杀是一款基于GPLv3协议的开源软件!\n你可以在遵守GPLv3协议的基础上任意使用,修改并转发《无名杀》,以及所有基于《无名杀》开发的拓展。\n点击“确定”即代表您认可并接受GPLv3协议↓️\nhttps://www.gnu.org/licenses/gpl-3.0.html\n②无名杀官方发布地址仅有GitHub仓库!\n其他所有的所谓“无名杀”社群(包括但不限于绝大多数“官方”QQ群、QQ频道等)均为玩家自发组织,与无名杀官方无关!')) { - // @ts-ignore - localStorage.setItem('gplv3_noname_alerted', true); - } - else { - exit(); - } - }; - if (location.protocol.startsWith('http')) { - if (!nonameInitialized || nonameInitialized.length == 0) { - callback(); - } else { - // @ts-ignore - localStorage.setItem('gplv3_noname_alerted', true); - } - } else callback(); - - } - window['b' + 'ann' + 'e' + 'dE' + 'x' + 'ten' + 's' + 'i' + 'o' + 'ns'] = ['\u4fa0\u4e49', '\u5168\u6559\u7a0b']; - - /** - * - * @returns {["firefox" | "chrome" | "safari" | "other", number, number, number]} - */ - function coreInfo() { - const regex = /(firefox|chrome|safari)\/(\d+(?:\.\d+)+)/ - let result - if (!(result = userAgent.match(regex))) return ["other", NaN, NaN, NaN] - if (result[1] != "safari") { - const [major, minor, patch] = result[2].split(".") - // @ts-ignore - return [result[1], parseInt(major), parseInt(minor), parseInt(patch)] - } - result = userAgent.match(/version\/(\d+(?:\.\d+)+).*safari/) - // @ts-ignore - const [major, minor, patch] = result[1].split(".") - return ["safari", parseInt(major), parseInt(minor), parseInt(patch)] - } - const [core, major, minor, patch] = coreInfo(); - const supportMap = { - "firefox": [60, 0, 0], - "chrome": [61, 0, 0], - "safari": [14, 5, 0] - } - const versions = [major, minor, patch] - // require是需求的版本号,current是浏览器环境本身的版本号 - const check = (require, current) => { - // 防止不存在的意外,提前截断当前版本号的长度 - if (current.length > require.length) current.length = require.length - - // 考虑到玄学的NaN情况,记录是否存在NaN - let flag = false - // 从主版本号遍历到修订版本号,只考虑当前版本号的长度 - for (let i = 0; i < current.length; ++i) { - // 当前环境版本号当前位若是NaN,则记录后直接到下一位 - if (isNaN(current[i])) { - flag = true - continue - } - // 如果此时flag为true且current[i]不为NaN,版本号则不合法,直接否 - if (flag) return false - // 上位版本号未达到要求,直接否决 - if (require[i] > current[i]) return false - // 上位版本号已超过要求,直接可行 - if (current[i] > require[i]) return true - } - return true - } - - if (core in supportMap && !check(supportMap[core], versions)) { - const tip = '检测到您的浏览器内核版本无法支持当前无名杀所需的功能,请立即升级浏览器或手机webview内核!'; - console.error(tip); - let redirect_tip = `您使用的浏览器或无名杀客户端内核版本过低,已经无法正常运行无名杀!\n目前使用的浏览器UA信息为:\n${userAgent}\n点击“确认”以前往GitHub下载最新版无名杀客户端(可能需要科学上网)。\n稍后您的无名杀将自动退出(可能的话)`; - if (core === 'safari') { - alert(`您使用的safari浏览器无法支持当前无名杀所需的功能,请至少升级至14.5.0!\n稍后您的无名杀将自动退出(可能的话)`); - } else { - if (confirm(redirect_tip)) { - window.open('https://github.com/libccy/noname/releases/tag/chromium77-client'); - } - } - exit(); - } - else { - // node环境下 - if (typeof window.require == 'function' && - typeof window.process == 'object' && - typeof window.__dirname == 'string') { - // 在http环境下修改__dirname和require的逻辑 - if (location.protocol.startsWith('http') && - window.__dirname.endsWith('electron.asar\\renderer')) { - const path = require('path'); - window.__dirname = path.join(path.resolve(), 'resources/app'); - const oldData = Object.entries(window.require); - // @ts-ignore - window.require = function (moduleId) { - try { - return module.require(moduleId); - } catch { - return module.require(path.join(window.__dirname, moduleId)); - } - }; - oldData.forEach(([key, value]) => { - window.require[key] = value; - }); - } - // 增加导入ts的逻辑 - window.require.extensions['.ts'] = function (module, filename) { - // @ts-ignore - const _compile = module._compile; - // @ts-ignore - module._compile = function (code, fileName) { - /** - * @type { import('typescript') } - */ - // @ts-ignore - const ts = require('./game/typescript.js'); - // 使用ts compiler对ts文件进行编译 - const result = ts.transpile(code, { - module: ts.ModuleKind.CommonJS, - //@todo: ES2019 -> ES2020 - target: ts.ScriptTarget.ES2019, - inlineSourceMap: true, - resolveJsonModule: true, - esModuleInterop: true, - }, fileName); - // 使用默认的js编译函数获取返回值 - return _compile.call(this, result, fileName); - } - // @ts-ignore - module._compile(require('fs').readFileSync(filename, 'utf8'), filename); - }; - } - // 使serviceWorker加载完成后,再加载entry.js - const loadEntryJs = () => { - const script = document.createElement('script') - script.type = "module"; - script.src = `${assetURL}game/entry.js`; - script.async = true; - script.onerror = event => { - console.error(event); - const message = `您使用的浏览器或《无名杀》客户端加载内容失败!\n请检查是否缺少游戏文件!隔版本更新请下载完整包而不是离线包!\n目前使用的浏览器UA信息为:\n${userAgent}\n若您使用的客户端为自带内核的旧版“兼容版”,请及时更新客户端版本!\n若您使用的客户端为手机端的非兼容版《无名杀》,请尝试更新手机的WebView内核,或者更换为1.8.2版本及以上的兼容版!\n若您是直接使用浏览器加载index.html进行游戏,请改为运行文件夹内的“noname-server.exe”(或使用VSCode等工具启动Live Server),以动态服务器的方式启动《无名杀》!\n若您使用的是苹果端,请至少将Safari升级至14.5.0!`; - console.error(message); - alert(message); - exit(); - } - document.head.appendChild(script); - }; - - if (location.protocol.startsWith('http') && 'serviceWorker' in navigator) { - let scope = window.location.protocol + '//' + window.location.host + '/'; - navigator.serviceWorker.getRegistrations() - .then(async registrations => { - let findServiceWorker = registrations.find(registration => { - return registration && registration.active && registration.active.scriptURL == `${scope}service-worker.js`; - }); - try { - const registration_1 = await navigator.serviceWorker.register(`${scope}service-worker.js`, { - type: 'module', - updateViaCache: "all", - scope, - }); - // 初次加载worker,需要重新启动一次 - if (!findServiceWorker) location.reload(); - // 接收消息,暂时没用到 - navigator.serviceWorker.addEventListener('message', e => { - console.log(e); - }); - registration_1.update().catch(e => console.error('worker update失败', e)); - if (!sessionStorage.getItem('canUseTs')) { - await import('./canUse.ts').then(({ text }) => console.log(text)).catch(() => { - sessionStorage.setItem('canUseTs', '1'); - location.reload(); - }); - } - } catch (e_1) { - console.log('serviceWorker加载失败: ', e_1); - } - }).finally(loadEntryJs); - } else { - loadEntryJs(); - } - } -}); +"use strict"; + +new Promise((resolve) => { + // 客户端自带core.js的请注意跟进core.js版本 + if ("__core-js_shared__" in window) resolve(null); + else { + const nonameInitialized = localStorage.getItem("noname_inited"); + const assetURL = + location.protocol.startsWith("http") || + typeof nonameInitialized != "string" || + nonameInitialized == "nodejs" + ? "" + : nonameInitialized; + const coreJSBundle = document.createElement("script"); + coreJSBundle.onerror = coreJSBundle.onload = resolve; + coreJSBundle.src = `${assetURL}game/core-js-bundle.js`; + document.head.appendChild(coreJSBundle); + } +}).then(() => { + const nonameInitialized = localStorage.getItem("noname_inited"); + const assetURL = + location.protocol.startsWith("http") || + typeof nonameInitialized != "string" || + nonameInitialized == "nodejs" + ? "" + : nonameInitialized; + const userAgent = navigator.userAgent.toLowerCase(); + + const exit = () => { + const ios = + userAgent.includes("iphone") || + userAgent.includes("ipad") || + userAgent.includes("macintosh"); + //electron + if ( + typeof window.process == "object" && + typeof window.require == "function" + ) { + const versions = window.process.versions; + // @ts-ignore + const electronVersion = parseFloat(versions.electron); + let remote; + if (electronVersion >= 14) { + // @ts-ignore + remote = require("@electron/remote"); + } else { + // @ts-ignore + remote = require("electron").remote; + } + const thisWindow = remote.getCurrentWindow(); + thisWindow.destroy(); + window.process.exit(); + } + //android-cordova环境 + //ios-cordova环境或ios浏览器环境 + //非ios的网页版 + else if (!ios) { + window.close(); + } + }; + + // 这个弹窗,在升级到http协议下的客户端不应该进行提示。 + if (!localStorage.getItem("gplv3_noname_alerted")) { + const nonameInitialized = localStorage.getItem("noname_inited"); + const callback = () => { + if ( + confirm( + "①无名杀是一款基于GPLv3协议的开源软件!\n你可以在遵守GPLv3协议的基础上任意使用,修改并转发《无名杀》,以及所有基于《无名杀》开发的拓展。\n点击“确定”即代表您认可并接受GPLv3协议↓️\nhttps://www.gnu.org/licenses/gpl-3.0.html\n②无名杀官方发布地址仅有GitHub仓库!\n其他所有的所谓“无名杀”社群(包括但不限于绝大多数“官方”QQ群、QQ频道等)均为玩家自发组织,与无名杀官方无关!" + ) + ) { + // @ts-ignore + localStorage.setItem("gplv3_noname_alerted", true); + } else { + exit(); + } + }; + if (location.protocol.startsWith("http")) { + if (!nonameInitialized || nonameInitialized.length == 0) { + callback(); + } else { + // @ts-ignore + localStorage.setItem("gplv3_noname_alerted", true); + } + } else callback(); + } + window["b" + "ann" + "e" + "dE" + "x" + "ten" + "s" + "i" + "o" + "ns"] = [ + "\u4fa0\u4e49", + "\u5168\u6559\u7a0b", + ]; + + /** + * + * @returns {["firefox" | "chrome" | "safari" | "other", number, number, number]} + */ + function coreInfo() { + const regex = /(firefox|chrome|safari)\/(\d+(?:\.\d+)+)/; + let result; + if (!(result = userAgent.match(regex))) return ["other", NaN, NaN, NaN]; + if (result[1] != "safari") { + const [major, minor, patch] = result[2].split("."); + // @ts-ignore + return [ + result[1], + parseInt(major), + parseInt(minor), + parseInt(patch), + ]; + } + result = userAgent.match(/version\/(\d+(?:\.\d+)+).*safari/); + // @ts-ignore + const [major, minor, patch] = result[1].split("."); + return ["safari", parseInt(major), parseInt(minor), parseInt(patch)]; + } + const [core, major, minor, patch] = coreInfo(); + const supportMap = { + firefox: [60, 0, 0], + chrome: [61, 0, 0], + safari: [14, 5, 0], + }; + const versions = [major, minor, patch]; + // require是需求的版本号,current是浏览器环境本身的版本号 + const check = (require, current) => { + // 防止不存在的意外,提前截断当前版本号的长度 + if (current.length > require.length) current.length = require.length; + + // 考虑到玄学的NaN情况,记录是否存在NaN + let flag = false; + // 从主版本号遍历到修订版本号,只考虑当前版本号的长度 + for (let i = 0; i < current.length; ++i) { + // 当前环境版本号当前位若是NaN,则记录后直接到下一位 + if (isNaN(current[i])) { + flag = true; + continue; + } + // 如果此时flag为true且current[i]不为NaN,版本号则不合法,直接否 + if (flag) return false; + // 上位版本号未达到要求,直接否决 + if (require[i] > current[i]) return false; + // 上位版本号已超过要求,直接可行 + if (current[i] > require[i]) return true; + } + return true; + }; + + if (core in supportMap && !check(supportMap[core], versions)) { + const tip = + "检测到您的浏览器内核版本无法支持当前无名杀所需的功能,请立即升级浏览器或手机webview内核!"; + console.error(tip); + let redirect_tip = `您使用的浏览器或无名杀客户端内核版本过低,已经无法正常运行无名杀!\n目前使用的浏览器UA信息为:\n${userAgent}\n点击“确认”以前往GitHub下载最新版无名杀客户端(可能需要科学上网)。\n稍后您的无名杀将自动退出(可能的话)`; + if (core === "safari") { + alert( + `您使用的safari浏览器无法支持当前无名杀所需的功能,请至少升级至14.5.0!\n稍后您的无名杀将自动退出(可能的话)` + ); + } else { + if (confirm(redirect_tip)) { + window.open( + "https://github.com/libccy/noname/releases/tag/chromium77-client" + ); + } + } + exit(); + } else { + // node环境下 + if ( + typeof window.require == "function" && + typeof window.process == "object" && + typeof window.__dirname == "string" + ) { + // 在http环境下修改__dirname和require的逻辑 + if ( + location.protocol.startsWith("http") && + window.__dirname.endsWith("electron.asar\\renderer") + ) { + const path = require("path"); + window.__dirname = path.join(path.resolve(), "resources/app"); + const oldData = Object.entries(window.require); + // @ts-ignore + window.require = function (moduleId) { + try { + return module.require(moduleId); + } catch { + return module.require( + path.join(window.__dirname, moduleId) + ); + } + }; + oldData.forEach(([key, value]) => { + window.require[key] = value; + }); + } + // 增加导入ts的逻辑 + window.require.extensions[".ts"] = function (module, filename) { + // @ts-ignore + const _compile = module._compile; + // @ts-ignore + module._compile = function (code, fileName) { + /** + * @type { import('typescript') } + */ + // @ts-ignore + const ts = require("./game/typescript.js"); + // 使用ts compiler对ts文件进行编译 + const result = ts.transpile( + code, + { + module: ts.ModuleKind.CommonJS, + //@todo: ES2019 -> ES2020 + target: ts.ScriptTarget.ES2019, + inlineSourceMap: true, + resolveJsonModule: true, + esModuleInterop: true, + }, + fileName + ); + // 使用默认的js编译函数获取返回值 + return _compile.call(this, result, fileName); + }; + // @ts-ignore + module._compile( + require("fs").readFileSync(filename, "utf8"), + filename + ); + }; + } + // 使serviceWorker加载完成后,再加载entry.js + const loadEntryJs = () => { + const script = document.createElement("script"); + script.type = "module"; + script.src = `${assetURL}game/entry.js`; + script.async = true; + script.onerror = (event) => { + console.error(event); + const message = `您使用的浏览器或《无名杀》客户端加载内容失败!\n请检查是否缺少游戏文件!隔版本更新请下载完整包而不是离线包!\n目前使用的浏览器UA信息为:\n${userAgent}\n若您使用的客户端为自带内核的旧版“兼容版”,请及时更新客户端版本!\n若您使用的客户端为手机端的非兼容版《无名杀》,请尝试更新手机的WebView内核,或者更换为1.8.2版本及以上的兼容版!\n若您是直接使用浏览器加载index.html进行游戏,请改为运行文件夹内的“noname-server.exe”(或使用VSCode等工具启动Live Server),以动态服务器的方式启动《无名杀》!\n若您使用的是苹果端,请至少将Safari升级至14.5.0!`; + console.error(message); + alert(message); + exit(); + }; + document.head.appendChild(script); + }; + + if ( + location.protocol.startsWith("http") && + "serviceWorker" in navigator + ) { + let scope = + window.location.protocol + "//" + window.location.host + "/"; + navigator.serviceWorker + .getRegistrations() + .then(async (registrations) => { + let findServiceWorker = registrations.find( + (registration) => { + return ( + registration && + registration.active && + registration.active.scriptURL == + `${scope}service-worker.js` + ); + } + ); + try { + const registration_1 = + await navigator.serviceWorker.register( + `${scope}service-worker.js`, + { + type: "module", + updateViaCache: "all", + scope, + } + ); + // 初次加载worker,需要重新启动一次 + if (!findServiceWorker) location.reload(); + // 接收消息,暂时没用到 + navigator.serviceWorker.addEventListener( + "message", + (e) => { + console.log(e); + } + ); + registration_1 + .update() + .catch((e) => + console.error("worker update失败", e) + ); + if (!sessionStorage.getItem("canUseTs")) { + await import("./canUse.ts") + .then(({ text }) => console.log(text)) + .catch(() => { + sessionStorage.setItem("canUseTs", "1"); + location.reload(); + }); + } + } catch (e_1) { + console.log("serviceWorker加载失败: ", e_1); + } + }) + .finally(loadEntryJs); + } else { + loadEntryJs(); + } + } +}); diff --git a/game/http.js b/game/http.js index 95ed6fd41..b0bee2db9 100644 --- a/game/http.js +++ b/game/http.js @@ -1,87 +1,111 @@ -var http = require('http'); -var fs = require('fs'); -var server = new http.Server(); -server.listen(80); -server.on('request', function(request, response) { - var url = require('url').parse(request.url); - switch(url.pathname) { - case ''||'/' : - fs.readFile('./index.html', function(err, content){ - if(err) { - response.writeHead(404, { 'Content-Type':'text/plain; charset="UTF-8"' }); - response.write(err.message); - response.end(); - } else { - response.writeHead(200, { 'Content-Type' : 'text/html; charset=UTF-8' }); - response.write(content); - response.end(); - } - }); - break; - case '/test/delay': - var delay = parseInt(url.query) || 2000; - response.writeHead(200, {'Content-type':'text/plain; charset=UTF-8'}); - response.write('Sleeping for' + delay + ' milliseconds...'); - setTimeout(function(){ - response.write('done.'); - response.end(); - }, delay); - break; - case '/test/mirror': - response.writeHead(200, {'Content-type':'text/plain; charset=UTF-8'}); - response.write(request.mothod + ' ' + request.url + ' HTTP/' + request.httpVersion + '\r\n'); - for (var h in request.headers) { - response.write(h + ':' + request.headers[h] + '\r\n'); - } - response.write('\r\n'); - request.on('data', function(chunk) { response.write(chunk); }); - request.on('end', function(chunk){ response.end(); }); - break; - case '/json' : - response.writeHead(200, {'Content-type':'application/json; charset=UTF-8'}); - response.write(JSON.stringify({test:'success'})); - response.end(); - break; - default: - var filename = url.pathname.substring(1); - var type = getType(filename.substring(filename.lastIndexOf('.')+1)); - fs.readFile(filename, function(err, content){ - if(err) { - response.writeHead(404, { 'Content-Type':'text/plain; charset="UTF-8"' }); - response.write(err.message); - response.end(); - } else { - response.writeHead(200, { 'Content-Type' : type }); - response.write(content); - response.end(); - } - }); - break; - } - -}); -function getType(endTag){ - var type=null; - switch(endTag){ - case 'html' : - case 'htm' : - type = 'text/html; charset=UTF-8'; - break; - case 'js' : - type = 'application/javascript; charset="UTF-8"'; - break; - case 'css' : - type = 'text/css; charset="UTF-8"'; - break; - case 'txt' : - type = 'text/plain; charset="UTF-8"'; - break; - case 'manifest' : - type = 'text/cache-manifest; charset="UTF-8"'; - break; - default : - type = 'application/octet-stream'; - break; - } - return type; -} +var http = require("http"); +var fs = require("fs"); +var server = new http.Server(); +server.listen(80); +server.on("request", function (request, response) { + var url = require("url").parse(request.url); + switch (url.pathname) { + case "" || "/": + fs.readFile("./index.html", function (err, content) { + if (err) { + response.writeHead(404, { + "Content-Type": 'text/plain; charset="UTF-8"', + }); + response.write(err.message); + response.end(); + } else { + response.writeHead(200, { + "Content-Type": "text/html; charset=UTF-8", + }); + response.write(content); + response.end(); + } + }); + break; + case "/test/delay": + var delay = parseInt(url.query) || 2000; + response.writeHead(200, { + "Content-type": "text/plain; charset=UTF-8", + }); + response.write("Sleeping for" + delay + " milliseconds..."); + setTimeout(function () { + response.write("done."); + response.end(); + }, delay); + break; + case "/test/mirror": + response.writeHead(200, { + "Content-type": "text/plain; charset=UTF-8", + }); + response.write( + request.mothod + + " " + + request.url + + " HTTP/" + + request.httpVersion + + "\r\n" + ); + for (var h in request.headers) { + response.write(h + ":" + request.headers[h] + "\r\n"); + } + response.write("\r\n"); + request.on("data", function (chunk) { + response.write(chunk); + }); + request.on("end", function (chunk) { + response.end(); + }); + break; + case "/json": + response.writeHead(200, { + "Content-type": "application/json; charset=UTF-8", + }); + response.write(JSON.stringify({ test: "success" })); + response.end(); + break; + default: + var filename = url.pathname.substring(1); + var type = getType( + filename.substring(filename.lastIndexOf(".") + 1) + ); + fs.readFile(filename, function (err, content) { + if (err) { + response.writeHead(404, { + "Content-Type": 'text/plain; charset="UTF-8"', + }); + response.write(err.message); + response.end(); + } else { + response.writeHead(200, { "Content-Type": type }); + response.write(content); + response.end(); + } + }); + break; + } +}); +function getType(endTag) { + var type = null; + switch (endTag) { + case "html": + case "htm": + type = "text/html; charset=UTF-8"; + break; + case "js": + type = 'application/javascript; charset="UTF-8"'; + break; + case "css": + type = 'text/css; charset="UTF-8"'; + break; + case "txt": + type = 'text/plain; charset="UTF-8"'; + break; + case "manifest": + type = 'text/cache-manifest; charset="UTF-8"'; + break; + default: + type = "application/octet-stream"; + break; + } + return type; +} diff --git a/game/jszip.js b/game/jszip.js index 84a63d2e3..86efd905a 100644 --- a/game/jszip.js +++ b/game/jszip.js @@ -1,9720 +1,11690 @@ -// @ts-nocheck -/*! - -JSZip - A Javascript class for generating and reading zip files - - -(c) 2009-2014 Stuart Knightley -Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. - -JSZip uses the library pako released under the MIT license : -https://github.com/nodeca/pako/blob/master/LICENSE -*/ -/** - * @type { typeof import('@types/jszip') } - */ -(function (f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.JSZip = f() } })(function () { - var define, module, exports; 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 < r.length; o++)s(r[o]); return s })({ - 1: [function (require, module, exports) { - 'use strict'; - var DataReader = require('./dataReader'); - - function ArrayReader(data) { - if (data) { - this.data = data; - this.length = this.data.length; - this.index = 0; - this.zero = 0; - - for (var i = 0; i < this.data.length; i++) { - data[i] = data[i] & 0xFF; - } - } - } - ArrayReader.prototype = new DataReader(); - /** - * @see DataReader.byteAt - */ - ArrayReader.prototype.byteAt = function (i) { - return this.data[this.zero + i]; - }; - /** - * @see DataReader.lastIndexOfSignature - */ - ArrayReader.prototype.lastIndexOfSignature = function (sig) { - var sig0 = sig.charCodeAt(0), - sig1 = sig.charCodeAt(1), - sig2 = sig.charCodeAt(2), - sig3 = sig.charCodeAt(3); - for (var i = this.length - 4; i >= 0; --i) { - if (this.data[i] === sig0 && this.data[i + 1] === sig1 && this.data[i + 2] === sig2 && this.data[i + 3] === sig3) { - return i - this.zero; - } - } - - return -1; - }; - /** - * @see DataReader.readData - */ - ArrayReader.prototype.readData = function (size) { - this.checkOffset(size); - if (size === 0) { - return []; - } - var result = this.data.slice(this.zero + this.index, this.zero + this.index + size); - this.index += size; - return result; - }; - module.exports = ArrayReader; - - }, { "./dataReader": 6 }], 2: [function (require, module, exports) { - 'use strict'; - // private property - var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - - - // public method for encoding - exports.encode = function (input, utf8) { - var output = ""; - var chr1, chr2, chr3, enc1, enc2, enc3, enc4; - var i = 0; - - while (i < input.length) { - - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } - else if (isNaN(chr3)) { - enc4 = 64; - } - - output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); - - } - - return output; - }; - - // public method for decoding - exports.decode = function (input, utf8) { - var output = ""; - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0; - - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - while (i < input.length) { - - enc1 = _keyStr.indexOf(input.charAt(i++)); - enc2 = _keyStr.indexOf(input.charAt(i++)); - enc3 = _keyStr.indexOf(input.charAt(i++)); - enc4 = _keyStr.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - - } - - return output; - - }; - - }, {}], 3: [function (require, module, exports) { - 'use strict'; - function CompressedObject() { - this.compressedSize = 0; - this.uncompressedSize = 0; - this.crc32 = 0; - this.compressionMethod = null; - this.compressedContent = null; - } - - CompressedObject.prototype = { - /** - * Return the decompressed content in an unspecified format. - * The format will depend on the decompressor. - * @return {Object} the decompressed content. - */ - getContent: function () { - return null; // see implementation - }, - /** - * Return the compressed content in an unspecified format. - * The format will depend on the compressed conten source. - * @return {Object} the compressed content. - */ - getCompressedContent: function () { - return null; // see implementation - } - }; - module.exports = CompressedObject; - - }, {}], 4: [function (require, module, exports) { - 'use strict'; - exports.STORE = { - magic: "\x00\x00", - compress: function (content, compressionOptions) { - return content; // no compression - }, - uncompress: function (content) { - return content; // no compression - }, - compressInputType: null, - uncompressInputType: null - }; - exports.DEFLATE = require('./flate'); - - }, { "./flate": 9 }], 5: [function (require, module, exports) { - 'use strict'; - - var utils = require('./utils'); - - var table = [ - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, - 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, - 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, - 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, - 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, - 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, - 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, - 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, - 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, - 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, - 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, - 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, - 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, - 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, - 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, - 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, - 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, - 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, - 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, - 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, - 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, - 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, - 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, - 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, - 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, - 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, - 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - ]; - - /** - * - * Javascript crc32 - * http://www.webtoolkit.info/ - * - */ - module.exports = function crc32(input, crc) { - if (typeof input === "undefined" || !input.length) { - return 0; - } - - var isArray = utils.getTypeOf(input) !== "string"; - - if (typeof (crc) == "undefined") { - crc = 0; - } - var x = 0; - var y = 0; - var b = 0; - - crc = crc ^ (-1); - for (var i = 0, iTop = input.length; i < iTop; i++) { - b = isArray ? input[i] : input.charCodeAt(i); - y = (crc ^ b) & 0xFF; - x = table[y]; - crc = (crc >>> 8) ^ x; - } - - return crc ^ (-1); - }; - // vim: set shiftwidth=4 softtabstop=4: - - }, { "./utils": 22 }], 6: [function (require, module, exports) { - 'use strict'; - var utils = require('./utils'); - - function DataReader(data) { - this.data = null; // type : see implementation - this.length = 0; - this.index = 0; - this.zero = 0; - } - DataReader.prototype = { - /** - * Check that the offset will not go too far. - * @param {string} offset the additional offset to check. - * @throws {Error} an Error if the offset is out of bounds. - */ - checkOffset: function (offset) { - this.checkIndex(this.index + offset); - }, - /** - * Check that the specifed index will not be too far. - * @param {string} newIndex the index to check. - * @throws {Error} an Error if the index is out of bounds. - */ - checkIndex: function (newIndex) { - if (this.length < this.zero + newIndex || newIndex < 0) { - throw new Error("End of data reached (data length = " + this.length + ", asked index = " + (newIndex) + "). Corrupted zip ?"); - } - }, - /** - * Change the index. - * @param {number} newIndex The new index. - * @throws {Error} if the new index is out of the data. - */ - setIndex: function (newIndex) { - this.checkIndex(newIndex); - this.index = newIndex; - }, - /** - * Skip the next n bytes. - * @param {number} n the number of bytes to skip. - * @throws {Error} if the new index is out of the data. - */ - skip: function (n) { - this.setIndex(this.index + n); - }, - /** - * Get the byte at the specified index. - * @param {number} i the index to use. - * @return {number} a byte. - */ - byteAt: function (i) { - // see implementations - }, - /** - * Get the next number with a given byte size. - * @param {number} size the number of bytes to read. - * @return {number} the corresponding number. - */ - readInt: function (size) { - var result = 0, - i; - this.checkOffset(size); - for (i = this.index + size - 1; i >= this.index; i--) { - result = (result << 8) + this.byteAt(i); - } - this.index += size; - return result; - }, - /** - * Get the next string with a given byte size. - * @param {number} size the number of bytes to read. - * @return {string} the corresponding string. - */ - readString: function (size) { - return utils.transformTo("string", this.readData(size)); - }, - /** - * Get raw data without conversion, bytes. - * @param {number} size the number of bytes to read. - * @return {Object} the raw data, implementation specific. - */ - readData: function (size) { - // see implementations - }, - /** - * Find the last occurence of a zip signature (4 bytes). - * @param {string} sig the signature to find. - * @return {number} the index of the last occurence, -1 if not found. - */ - lastIndexOfSignature: function (sig) { - // see implementations - }, - /** - * Get the next date. - * @return {Date} the date. - */ - readDate: function () { - var dostime = this.readInt(4); - return new Date( - ((dostime >> 25) & 0x7f) + 1980, // year - ((dostime >> 21) & 0x0f) - 1, // month - (dostime >> 16) & 0x1f, // day - (dostime >> 11) & 0x1f, // hour - (dostime >> 5) & 0x3f, // minute - (dostime & 0x1f) << 1); // second - } - }; - module.exports = DataReader; - - }, { "./utils": 22 }], 7: [function (require, module, exports) { - 'use strict'; - exports.base64 = false; - exports.binary = false; - exports.dir = false; - exports.createFolders = false; - exports.date = null; - exports.compression = null; - exports.compressionOptions = null; - exports.comment = null; - exports.unixPermissions = null; - exports.dosPermissions = null; - - }, {}], 8: [function (require, module, exports) { - 'use strict'; - var utils = require('./utils'); - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.string2binary = function (str) { - return utils.string2binary(str); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.string2Uint8Array = function (str) { - return utils.transformTo("uint8array", str); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.uint8Array2String = function (array) { - return utils.transformTo("string", array); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.string2Blob = function (str) { - var buffer = utils.transformTo("arraybuffer", str); - return utils.arrayBuffer2Blob(buffer); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.arrayBuffer2Blob = function (buffer) { - return utils.arrayBuffer2Blob(buffer); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.transformTo = function (outputType, input) { - return utils.transformTo(outputType, input); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.getTypeOf = function (input) { - return utils.getTypeOf(input); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.checkSupport = function (type) { - return utils.checkSupport(type); - }; - - /** - * @deprecated - * This value will be removed in a future version without replacement. - */ - exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS; - - /** - * @deprecated - * This value will be removed in a future version without replacement. - */ - exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS; - - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.pretty = function (str) { - return utils.pretty(str); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.findCompression = function (compressionMethod) { - return utils.findCompression(compressionMethod); - }; - - /** - * @deprecated - * This function will be removed in a future version without replacement. - */ - exports.isRegExp = function (object) { - return utils.isRegExp(object); - }; - - - }, { "./utils": 22 }], 9: [function (require, module, exports) { - 'use strict'; - var USE_TYPEDARRAY = (typeof Uint8Array !== 'undefined') && (typeof Uint16Array !== 'undefined') && (typeof Uint32Array !== 'undefined'); - - var pako = require("pako"); - exports.uncompressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; - exports.compressInputType = USE_TYPEDARRAY ? "uint8array" : "array"; - - exports.magic = "\x08\x00"; - exports.compress = function (input, compressionOptions) { - return pako.deflateRaw(input, { - level: compressionOptions.level || -1 // default compression - }); - }; - exports.uncompress = function (input) { - return pako.inflateRaw(input); - }; - - }, { "pako": 25 }], 10: [function (require, module, exports) { - 'use strict'; - - var base64 = require('./base64'); - - /** - Usage: - zip = new JSZip(); - zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing"); - zip.folder("images").file("smile.gif", base64Data, {base64: true}); - zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")}); - zip.remove("tempfile"); - - base64zip = zip.generate(); - - **/ - - /** - * Representation a of zip file in js - * @constructor - * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional). - * @param {Object=} options the options for creating this objects (optional). - */ - function JSZip(data, options) { - // if this constructor is used without `new`, it adds `new` before itself: - if (!(this instanceof JSZip)) return new JSZip(data, options); - - // object containing the files : - // { - // "folder/" : {...}, - // "folder/data.txt" : {...} - // } - // NOTE: we use a null prototype because we do not - // want filenames like "toString" coming from a zip file - // to overwrite methods and attributes in a normal Object. - this.files = Object.create(null); - - this.comment = null; - - // Where we are in the hierarchy - this.root = ""; - if (data) { - this.load(data, options); - } - this.clone = function () { - var newObj = new JSZip(); - for (var i in this) { - if (typeof this[i] !== "function") { - newObj[i] = this[i]; - } - } - return newObj; - }; - } - JSZip.prototype = require('./object'); - JSZip.prototype.load = require('./load'); - JSZip.support = require('./support'); - JSZip.defaults = require('./defaults'); - - /** - * @deprecated - * This namespace will be removed in a future version without replacement. - */ - JSZip.utils = require('./deprecatedPublicUtils'); - - JSZip.base64 = { - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - encode: function (input) { - return base64.encode(input); - }, - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - decode: function (input) { - return base64.decode(input); - } - }; - JSZip.compressions = require('./compressions'); - module.exports = JSZip; - - }, { "./base64": 2, "./compressions": 4, "./defaults": 7, "./deprecatedPublicUtils": 8, "./load": 11, "./object": 14, "./support": 18 }], 11: [function (require, module, exports) { - 'use strict'; - var base64 = require('./base64'); - var utf8 = require('./utf8'); - var utils = require('./utils'); - var ZipEntries = require('./zipEntries'); - module.exports = function (data, options) { - var files, zipEntries, i, input; - options = utils.extend(options || {}, { - base64: false, - checkCRC32: false, - optimizedBinaryString: false, - createFolders: false, - decodeFileName: utf8.utf8decode - }); - if (options.base64) { - data = base64.decode(data); - } - - zipEntries = new ZipEntries(data, options); - files = zipEntries.files; - for (i = 0; i < files.length; i++) { - input = files[i]; - this.file(input.fileNameStr, input.decompressed, { - binary: true, - optimizedBinaryString: true, - date: input.date, - dir: input.dir, - comment: input.fileCommentStr.length ? input.fileCommentStr : null, - unixPermissions: input.unixPermissions, - dosPermissions: input.dosPermissions, - createFolders: options.createFolders - }); - } - if (zipEntries.zipComment.length) { - this.comment = zipEntries.zipComment; - } - - return this; - }; - - }, { "./base64": 2, "./utf8": 21, "./utils": 22, "./zipEntries": 23 }], 12: [function (require, module, exports) { - (function (Buffer) { - 'use strict'; - module.exports = function (data, encoding) { - return new Buffer(data, encoding); - }; - module.exports.test = function (b) { - return Buffer.isBuffer(b); - }; - - }).call(this, (typeof Buffer !== "undefined" ? Buffer : undefined)) - }, {}], 13: [function (require, module, exports) { - 'use strict'; - var Uint8ArrayReader = require('./uint8ArrayReader'); - - function NodeBufferReader(data) { - this.data = data; - this.length = this.data.length; - this.index = 0; - this.zero = 0; - } - NodeBufferReader.prototype = new Uint8ArrayReader(); - - /** - * @see DataReader.readData - */ - NodeBufferReader.prototype.readData = function (size) { - this.checkOffset(size); - var result = this.data.slice(this.zero + this.index, this.zero + this.index + size); - this.index += size; - return result; - }; - module.exports = NodeBufferReader; - - }, { "./uint8ArrayReader": 19 }], 14: [function (require, module, exports) { - 'use strict'; - var support = require('./support'); - var utils = require('./utils'); - var crc32 = require('./crc32'); - var signature = require('./signature'); - var defaults = require('./defaults'); - var base64 = require('./base64'); - var compressions = require('./compressions'); - var CompressedObject = require('./compressedObject'); - var nodeBuffer = require('./nodeBuffer'); - var utf8 = require('./utf8'); - var StringWriter = require('./stringWriter'); - var Uint8ArrayWriter = require('./uint8ArrayWriter'); - - /** - * Returns the raw data of a ZipObject, decompress the content if necessary. - * @param {ZipObject} file the file to use. - * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. - */ - var getRawData = function (file) { - if (file._data instanceof CompressedObject) { - file._data = file._data.getContent(); - file.options.binary = true; - file.options.base64 = false; - - if (utils.getTypeOf(file._data) === "uint8array") { - var copy = file._data; - // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array. - // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file). - file._data = new Uint8Array(copy.length); - // with an empty Uint8Array, Opera fails with a "Offset larger than array size" - if (copy.length !== 0) { - file._data.set(copy, 0); - } - } - } - return file._data; - }; - - /** - * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it. - * @param {ZipObject} file the file to use. - * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. - */ - var getBinaryData = function (file) { - var result = getRawData(file), - type = utils.getTypeOf(result); - if (type === "string") { - if (!file.options.binary) { - // unicode text ! - // unicode string => binary string is a painful process, check if we can avoid it. - if (support.nodebuffer) { - return nodeBuffer(result, "utf-8"); - } - } - return file.asBinary(); - } - return result; - }; - - /** - * Transform this._data into a string. - * @param {function} filter a function String -> String, applied if not null on the result. - * @return {String} the string representing this._data. - */ - var dataToString = function (asUTF8) { - var result = getRawData(this); - if (result === null || typeof result === "undefined") { - return ""; - } - // if the data is a base64 string, we decode it before checking the encoding ! - if (this.options.base64) { - result = base64.decode(result); - } - if (asUTF8 && this.options.binary) { - // JSZip.prototype.utf8decode supports arrays as input - // skip to array => string step, utf8decode will do it. - result = out.utf8decode(result); - } - else { - // no utf8 transformation, do the array => string step. - result = utils.transformTo("string", result); - } - - if (!asUTF8 && !this.options.binary) { - result = utils.transformTo("string", out.utf8encode(result)); - } - return result; - }; - /** - * A simple object representing a file in the zip file. - * @constructor - * @param {string} name the name of the file - * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data - * @param {Object} options the options of the file - */ - var ZipObject = function (name, data, options) { - this.name = name; - this.dir = options.dir; - this.date = options.date; - this.comment = options.comment; - this.unixPermissions = options.unixPermissions; - this.dosPermissions = options.dosPermissions; - - this._data = data; - this.options = options; - - /* - * This object contains initial values for dir and date. - * With them, we can check if the user changed the deprecated metadata in - * `ZipObject#options` or not. - */ - this._initialMetadata = { - dir: options.dir, - date: options.date - }; - }; - - ZipObject.prototype = { - /** - * Return the content as UTF8 string. - * @return {string} the UTF8 string. - */ - asText: function () { - return dataToString.call(this, true); - }, - /** - * Returns the binary content. - * @return {string} the content as binary. - */ - asBinary: function () { - return dataToString.call(this, false); - }, - /** - * Returns the content as a nodejs Buffer. - * @return {Buffer} the content as a Buffer. - */ - asNodeBuffer: function () { - var result = getBinaryData(this); - return utils.transformTo("nodebuffer", result); - }, - /** - * Returns the content as an Uint8Array. - * @return {Uint8Array} the content as an Uint8Array. - */ - asUint8Array: function () { - var result = getBinaryData(this); - return utils.transformTo("uint8array", result); - }, - /** - * Returns the content as an ArrayBuffer. - * @return {ArrayBuffer} the content as an ArrayBufer. - */ - asArrayBuffer: function () { - return this.asUint8Array().buffer; - } - }; - - /** - * Transform an integer into a string in hexadecimal. - * @private - * @param {number} dec the number to convert. - * @param {number} bytes the number of bytes to generate. - * @returns {string} the result. - */ - var decToHex = function (dec, bytes) { - var hex = "", - i; - for (i = 0; i < bytes; i++) { - hex += String.fromCharCode(dec & 0xff); - dec = dec >>> 8; - } - return hex; - }; - - /** - * Transforms the (incomplete) options from the user into the complete - * set of options to create a file. - * @private - * @param {Object} o the options from the user. - * @return {Object} the complete set of options. - */ - var prepareFileAttrs = function (o) { - o = o || {}; - if (o.base64 === true && (o.binary === null || o.binary === undefined)) { - o.binary = true; - } - o = utils.extend(o, defaults); - o.date = o.date || new Date(); - if (o.compression !== null) o.compression = o.compression.toUpperCase(); - - return o; - }; - - /** - * Add a file in the current folder. - * @private - * @param {string} name the name of the file - * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file - * @param {Object} o the options of the file - * @return {Object} the new file. - */ - var fileAdd = function (name, data, o) { - // be sure sub folders exist - var dataType = utils.getTypeOf(data), - parent; - - o = prepareFileAttrs(o); - - if (typeof o.unixPermissions === "string") { - o.unixPermissions = parseInt(o.unixPermissions, 8); - } - - // UNX_IFDIR 0040000 see zipinfo.c - if (o.unixPermissions && (o.unixPermissions & 0x4000)) { - o.dir = true; - } - // Bit 4 Directory - if (o.dosPermissions && (o.dosPermissions & 0x0010)) { - o.dir = true; - } - - if (o.dir) { - name = forceTrailingSlash(name); - } - - if (o.createFolders && (parent = parentFolder(name))) { - folderAdd.call(this, parent, true); - } - - if (o.dir || data === null || typeof data === "undefined") { - o.base64 = false; - o.binary = false; - data = null; - dataType = null; - } - else if (dataType === "string") { - if (o.binary && !o.base64) { - // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask - if (o.optimizedBinaryString !== true) { - // this is a string, not in a base64 format. - // Be sure that this is a correct "binary string" - data = utils.string2binary(data); - } - } - } - else { // arraybuffer, uint8array, ... - o.base64 = false; - o.binary = true; - - if (!dataType && !(data instanceof CompressedObject)) { - throw new Error("The data of '" + name + "' is in an unsupported format !"); - } - - // special case : it's way easier to work with Uint8Array than with ArrayBuffer - if (dataType === "arraybuffer") { - data = utils.transformTo("uint8array", data); - } - } - - var object = new ZipObject(name, data, o); - this.files[name] = object; - return object; - }; - - /** - * Find the parent folder of the path. - * @private - * @param {string} path the path to use - * @return {string} the parent folder, or "" - */ - var parentFolder = function (path) { - if (path.slice(-1) == '/') { - path = path.substring(0, path.length - 1); - } - var lastSlash = path.lastIndexOf('/'); - return (lastSlash > 0) ? path.substring(0, lastSlash) : ""; - }; - - - /** - * Returns the path with a slash at the end. - * @private - * @param {String} path the path to check. - * @return {String} the path with a trailing slash. - */ - var forceTrailingSlash = function (path) { - // Check the name ends with a / - if (path.slice(-1) != "/") { - path += "/"; // IE doesn't like substr(-1) - } - return path; - }; - /** - * Add a (sub) folder in the current folder. - * @private - * @param {string} name the folder's name - * @param {boolean=} [createFolders] If true, automatically create sub - * folders. Defaults to false. - * @return {Object} the new folder. - */ - var folderAdd = function (name, createFolders) { - createFolders = (typeof createFolders !== 'undefined') ? createFolders : false; - - name = forceTrailingSlash(name); - - // Does this folder already exist? - if (!this.files[name]) { - fileAdd.call(this, name, null, { - dir: true, - createFolders: createFolders - }); - } - return this.files[name]; - }; - - /** - * Generate a JSZip.CompressedObject for a given zipOject. - * @param {ZipObject} file the object to read. - * @param {JSZip.compression} compression the compression to use. - * @param {Object} compressionOptions the options to use when compressing. - * @return {JSZip.CompressedObject} the compressed result. - */ - var generateCompressedObjectFrom = function (file, compression, compressionOptions) { - var result = new CompressedObject(), - content; - - // the data has not been decompressed, we might reuse things ! - if (file._data instanceof CompressedObject) { - result.uncompressedSize = file._data.uncompressedSize; - result.crc32 = file._data.crc32; - - if (result.uncompressedSize === 0 || file.dir) { - compression = compressions['STORE']; - result.compressedContent = ""; - result.crc32 = 0; - } - else if (file._data.compressionMethod === compression.magic) { - result.compressedContent = file._data.getCompressedContent(); - } - else { - content = file._data.getContent(); - // need to decompress / recompress - result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); - } - } - else { - // have uncompressed data - content = getBinaryData(file); - if (!content || content.length === 0 || file.dir) { - compression = compressions['STORE']; - content = ""; - } - result.uncompressedSize = content.length; - result.crc32 = crc32(content); - result.compressedContent = compression.compress(utils.transformTo(compression.compressInputType, content), compressionOptions); - } - - result.compressedSize = result.compressedContent.length; - result.compressionMethod = compression.magic; - - return result; - }; - - - - - /** - * Generate the UNIX part of the external file attributes. - * @param {Object} unixPermissions the unix permissions or null. - * @param {Boolean} isDir true if the entry is a directory, false otherwise. - * @return {Number} a 32 bit integer. - * - * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute : - * - * TTTTsstrwxrwxrwx0000000000ADVSHR - * ^^^^____________________________ file type, see zipinfo.c (UNX_*) - * ^^^_________________________ setuid, setgid, sticky - * ^^^^^^^^^________________ permissions - * ^^^^^^^^^^______ not used ? - * ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only - */ - var generateUnixExternalFileAttr = function (unixPermissions, isDir) { - - var result = unixPermissions; - if (!unixPermissions) { - // I can't use octal values in strict mode, hence the hexa. - // 040775 => 0x41fd - // 0100664 => 0x81b4 - result = isDir ? 0x41fd : 0x81b4; - } - - return (result & 0xFFFF) << 16; - }; - - /** - * Generate the DOS part of the external file attributes. - * @param {Object} dosPermissions the dos permissions or null. - * @param {Boolean} isDir true if the entry is a directory, false otherwise. - * @return {Number} a 32 bit integer. - * - * Bit 0 Read-Only - * Bit 1 Hidden - * Bit 2 System - * Bit 3 Volume Label - * Bit 4 Directory - * Bit 5 Archive - */ - var generateDosExternalFileAttr = function (dosPermissions, isDir) { - - // the dir flag is already set for compatibility - - return (dosPermissions || 0) & 0x3F; - }; - - /** - * Generate the various parts used in the construction of the final zip file. - * @param {string} name the file name. - * @param {ZipObject} file the file content. - * @param {JSZip.CompressedObject} compressedObject the compressed object. - * @param {number} offset the current offset from the start of the zip file. - * @param {String} platform let's pretend we are this platform (change platform dependents fields) - * @param {Function} encodeFileName the function to encode the file name / comment. - * @return {object} the zip parts. - */ - var generateZipParts = function (name, file, compressedObject, offset, platform, encodeFileName) { - var data = compressedObject.compressedContent, - useCustomEncoding = encodeFileName !== utf8.utf8encode, - encodedFileName = utils.transformTo("string", encodeFileName(file.name)), - utfEncodedFileName = utils.transformTo("string", utf8.utf8encode(file.name)), - comment = file.comment || "", - encodedComment = utils.transformTo("string", encodeFileName(comment)), - utfEncodedComment = utils.transformTo("string", utf8.utf8encode(comment)), - useUTF8ForFileName = utfEncodedFileName.length !== file.name.length, - useUTF8ForComment = utfEncodedComment.length !== comment.length, - o = file.options, - dosTime, - dosDate, - extraFields = "", - unicodePathExtraField = "", - unicodeCommentExtraField = "", - dir, date; - - - // handle the deprecated options.dir - if (file._initialMetadata.dir !== file.dir) { - dir = file.dir; - } else { - dir = o.dir; - } - - // handle the deprecated options.date - if (file._initialMetadata.date !== file.date) { - date = file.date; - } else { - date = o.date; - } - - var extFileAttr = 0; - var versionMadeBy = 0; - if (dir) { - // dos or unix, we set the dos dir flag - extFileAttr |= 0x00010; - } - if (platform === "UNIX") { - versionMadeBy = 0x031E; // UNIX, version 3.0 - extFileAttr |= generateUnixExternalFileAttr(file.unixPermissions, dir); - } else { // DOS or other, fallback to DOS - versionMadeBy = 0x0014; // DOS, version 2.0 - extFileAttr |= generateDosExternalFileAttr(file.dosPermissions, dir); - } - - // date - // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html - // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html - // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html - - dosTime = date.getHours(); - dosTime = dosTime << 6; - dosTime = dosTime | date.getMinutes(); - dosTime = dosTime << 5; - dosTime = dosTime | date.getSeconds() / 2; - - dosDate = date.getFullYear() - 1980; - dosDate = dosDate << 4; - dosDate = dosDate | (date.getMonth() + 1); - dosDate = dosDate << 5; - dosDate = dosDate | date.getDate(); - - if (useUTF8ForFileName) { - // set the unicode path extra field. unzip needs at least one extra - // field to correctly handle unicode path, so using the path is as good - // as any other information. This could improve the situation with - // other archive managers too. - // This field is usually used without the utf8 flag, with a non - // unicode path in the header (winrar, winzip). This helps (a bit) - // with the messy Windows' default compressed folders feature but - // breaks on p7zip which doesn't seek the unicode path extra field. - // So for now, UTF-8 everywhere ! - unicodePathExtraField = - // Version - decToHex(1, 1) + - // NameCRC32 - decToHex(crc32(encodedFileName), 4) + - // UnicodeName - utfEncodedFileName; - - extraFields += - // Info-ZIP Unicode Path Extra Field - "\x75\x70" + - // size - decToHex(unicodePathExtraField.length, 2) + - // content - unicodePathExtraField; - } - - if (useUTF8ForComment) { - - unicodeCommentExtraField = - // Version - decToHex(1, 1) + - // CommentCRC32 - decToHex(this.crc32(encodedComment), 4) + - // UnicodeName - utfEncodedComment; - - extraFields += - // Info-ZIP Unicode Path Extra Field - "\x75\x63" + - // size - decToHex(unicodeCommentExtraField.length, 2) + - // content - unicodeCommentExtraField; - } - - var header = ""; - - // version needed to extract - header += "\x0A\x00"; - // general purpose bit flag - // set bit 11 if utf8 - header += !useCustomEncoding && (useUTF8ForFileName || useUTF8ForComment) ? "\x00\x08" : "\x00\x00"; - // compression method - header += compressedObject.compressionMethod; - // last mod file time - header += decToHex(dosTime, 2); - // last mod file date - header += decToHex(dosDate, 2); - // crc-32 - header += decToHex(compressedObject.crc32, 4); - // compressed size - header += decToHex(compressedObject.compressedSize, 4); - // uncompressed size - header += decToHex(compressedObject.uncompressedSize, 4); - // file name length - header += decToHex(encodedFileName.length, 2); - // extra field length - header += decToHex(extraFields.length, 2); - - - var fileRecord = signature.LOCAL_FILE_HEADER + header + encodedFileName + extraFields; - - var dirRecord = signature.CENTRAL_FILE_HEADER + - // version made by (00: DOS) - decToHex(versionMadeBy, 2) + - // file header (common to file and central directory) - header + - // file comment length - decToHex(encodedComment.length, 2) + - // disk number start - "\x00\x00" + - // internal file attributes TODO - "\x00\x00" + - // external file attributes - decToHex(extFileAttr, 4) + - // relative offset of local header - decToHex(offset, 4) + - // file name - encodedFileName + - // extra field - extraFields + - // file comment - encodedComment; - - return { - fileRecord: fileRecord, - dirRecord: dirRecord, - compressedObject: compressedObject - }; - }; - - - // return the actual prototype of JSZip - var out = { - /** - * Read an existing zip and merge the data in the current JSZip object. - * The implementation is in jszip-load.js, don't forget to include it. - * @param {String|ArrayBuffer|Uint8Array|Buffer} stream The stream to load - * @param {Object} options Options for loading the stream. - * options.base64 : is the stream in base64 ? default : false - * @return {JSZip} the current JSZip object - */ - load: function (stream, options) { - throw new Error("Load method is not defined. Is the file jszip-load.js included ?"); - }, - - /** - * Filter nested files/folders with the specified function. - * @param {Function} search the predicate to use : - * function (relativePath, file) {...} - * It takes 2 arguments : the relative path and the file. - * @return {Array} An array of matching elements. - */ - filter: function (search) { - var result = [], - filename, relativePath, file, fileClone; - for (filename in this.files) { - file = this.files[filename]; - // return a new object, don't let the user mess with our internal objects :) - fileClone = new ZipObject(file.name, file._data, utils.extend(file.options)); - relativePath = filename.slice(this.root.length, filename.length); - if (filename.slice(0, this.root.length) === this.root && // the file is in the current root - search(relativePath, fileClone)) { // and the file matches the function - result.push(fileClone); - } - } - return result; - }, - - /** - * Add a file to the zip file, or search a file. - * @param {string|RegExp} name The name of the file to add (if data is defined), - * the name of the file to find (if no data) or a regex to match files. - * @param {String|ArrayBuffer|Uint8Array|Buffer} data The file data, either raw or base64 encoded - * @param {Object} o File options - * @return {JSZip|Object|Array} this JSZip object (when adding a file), - * a file (when searching by string) or an array of files (when searching by regex). - */ - file: function (name, data, o) { - if (arguments.length === 1) { - if (utils.isRegExp(name)) { - var regexp = name; - return this.filter(function (relativePath, file) { - return !file.dir && regexp.test(relativePath); - }); - } - else { // text - return this.filter(function (relativePath, file) { - return !file.dir && relativePath === name; - })[0] || null; - } - } - else { // more than one argument : we have data ! - name = this.root + name; - fileAdd.call(this, name, data, o); - } - return this; - }, - - /** - * Add a directory to the zip file, or search. - * @param {String|RegExp} arg The name of the directory to add, or a regex to search folders. - * @return {JSZip} an object with the new directory as the root, or an array containing matching folders. - */ - folder: function (arg) { - if (!arg) { - return this; - } - - if (utils.isRegExp(arg)) { - return this.filter(function (relativePath, file) { - return file.dir && arg.test(relativePath); - }); - } - - // else, name is a new folder - var name = this.root + arg; - var newFolder = folderAdd.call(this, name); - - // Allow chaining by returning a new object with this folder as the root - var ret = this.clone(); - ret.root = newFolder.name; - return ret; - }, - - /** - * Delete a file, or a directory and all sub-files, from the zip - * @param {string} name the name of the file to delete - * @return {JSZip} this JSZip object - */ - remove: function (name) { - name = this.root + name; - var file = this.files[name]; - if (!file) { - // Look for any folders - if (name.slice(-1) != "/") { - name += "/"; - } - file = this.files[name]; - } - - if (file && !file.dir) { - // file - delete this.files[name]; - } else { - // maybe a folder, delete recursively - var kids = this.filter(function (relativePath, file) { - return file.name.slice(0, name.length) === name; - }); - for (var i = 0; i < kids.length; i++) { - delete this.files[kids[i].name]; - } - } - - return this; - }, - - /** - * Generate the complete zip file - * @param {Object} options the options to generate the zip file : - * - base64, (deprecated, use type instead) true to generate base64. - * - compression, "STORE" by default. - * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob. - * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file - */ - generate: function (options) { - options = utils.extend(options || {}, { - base64: true, - compression: "STORE", - compressionOptions: null, - type: "base64", - platform: "DOS", - comment: null, - mimeType: 'application/zip', - encodeFileName: utf8.utf8encode - }); - - utils.checkSupport(options.type); - - // accept nodejs `process.platform` - if ( - options.platform === 'darwin' || - options.platform === 'freebsd' || - options.platform === 'linux' || - options.platform === 'sunos' - ) { - options.platform = "UNIX"; - } - if (options.platform === 'win32') { - options.platform = "DOS"; - } - - var zipData = [], - localDirLength = 0, - centralDirLength = 0, - writer, i, - encodedComment = utils.transformTo("string", options.encodeFileName(options.comment || this.comment || "")); - - // first, generate all the zip parts. - for (var name in this.files) { - var file = this.files[name]; - - var compressionName = file.options.compression || options.compression.toUpperCase(); - var compression = compressions[compressionName]; - if (!compression) { - throw new Error(compressionName + " is not a valid compression method !"); - } - var compressionOptions = file.options.compressionOptions || options.compressionOptions || {}; - - var compressedObject = generateCompressedObjectFrom.call(this, file, compression, compressionOptions); - - var zipPart = generateZipParts.call(this, name, file, compressedObject, localDirLength, options.platform, options.encodeFileName); - localDirLength += zipPart.fileRecord.length + compressedObject.compressedSize; - centralDirLength += zipPart.dirRecord.length; - zipData.push(zipPart); - } - - var dirEnd = ""; - - // end of central dir signature - dirEnd = signature.CENTRAL_DIRECTORY_END + - // number of this disk - "\x00\x00" + - // number of the disk with the start of the central directory - "\x00\x00" + - // total number of entries in the central directory on this disk - decToHex(zipData.length, 2) + - // total number of entries in the central directory - decToHex(zipData.length, 2) + - // size of the central directory 4 bytes - decToHex(centralDirLength, 4) + - // offset of start of central directory with respect to the starting disk number - decToHex(localDirLength, 4) + - // .ZIP file comment length - decToHex(encodedComment.length, 2) + - // .ZIP file comment - encodedComment; - - - // we have all the parts (and the total length) - // time to create a writer ! - var typeName = options.type.toLowerCase(); - if (typeName === "uint8array" || typeName === "arraybuffer" || typeName === "blob" || typeName === "nodebuffer") { - writer = new Uint8ArrayWriter(localDirLength + centralDirLength + dirEnd.length); - } else { - writer = new StringWriter(localDirLength + centralDirLength + dirEnd.length); - } - - for (i = 0; i < zipData.length; i++) { - writer.append(zipData[i].fileRecord); - writer.append(zipData[i].compressedObject.compressedContent); - } - for (i = 0; i < zipData.length; i++) { - writer.append(zipData[i].dirRecord); - } - - writer.append(dirEnd); - - var zip = writer.finalize(); - - - - switch (options.type.toLowerCase()) { - // case "zip is an Uint8Array" - case "uint8array": - case "arraybuffer": - case "nodebuffer": - return utils.transformTo(options.type.toLowerCase(), zip); - case "blob": - return utils.arrayBuffer2Blob(utils.transformTo("arraybuffer", zip), options.mimeType); - // case "zip is a string" - case "base64": - return (options.base64) ? base64.encode(zip) : zip; - default: // case "string" : - return zip; - } - - }, - - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - crc32: function (input, crc) { - return crc32(input, crc); - }, - - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - utf8encode: function (string) { - return utils.transformTo("string", utf8.utf8encode(string)); - }, - - /** - * @deprecated - * This method will be removed in a future version without replacement. - */ - utf8decode: function (input) { - return utf8.utf8decode(input); - } - }; - module.exports = out; - - }, { "./base64": 2, "./compressedObject": 3, "./compressions": 4, "./crc32": 5, "./defaults": 7, "./nodeBuffer": 12, "./signature": 15, "./stringWriter": 17, "./support": 18, "./uint8ArrayWriter": 20, "./utf8": 21, "./utils": 22 }], 15: [function (require, module, exports) { - 'use strict'; - exports.LOCAL_FILE_HEADER = "PK\x03\x04"; - exports.CENTRAL_FILE_HEADER = "PK\x01\x02"; - exports.CENTRAL_DIRECTORY_END = "PK\x05\x06"; - exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07"; - exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06"; - exports.DATA_DESCRIPTOR = "PK\x07\x08"; - - }, {}], 16: [function (require, module, exports) { - 'use strict'; - var DataReader = require('./dataReader'); - var utils = require('./utils'); - - function StringReader(data, optimizedBinaryString) { - this.data = data; - if (!optimizedBinaryString) { - this.data = utils.string2binary(this.data); - } - this.length = this.data.length; - this.index = 0; - this.zero = 0; - } - StringReader.prototype = new DataReader(); - /** - * @see DataReader.byteAt - */ - StringReader.prototype.byteAt = function (i) { - return this.data.charCodeAt(this.zero + i); - }; - /** - * @see DataReader.lastIndexOfSignature - */ - StringReader.prototype.lastIndexOfSignature = function (sig) { - return this.data.lastIndexOf(sig) - this.zero; - }; - /** - * @see DataReader.readData - */ - StringReader.prototype.readData = function (size) { - this.checkOffset(size); - // this will work because the constructor applied the "& 0xff" mask. - var result = this.data.slice(this.zero + this.index, this.zero + this.index + size); - this.index += size; - return result; - }; - module.exports = StringReader; - - }, { "./dataReader": 6, "./utils": 22 }], 17: [function (require, module, exports) { - 'use strict'; - - var utils = require('./utils'); - - /** - * An object to write any content to a string. - * @constructor - */ - var StringWriter = function () { - this.data = []; - }; - StringWriter.prototype = { - /** - * Append any content to the current string. - * @param {Object} input the content to add. - */ - append: function (input) { - input = utils.transformTo("string", input); - this.data.push(input); - }, - /** - * Finalize the construction an return the result. - * @return {string} the generated string. - */ - finalize: function () { - return this.data.join(""); - } - }; - - module.exports = StringWriter; - - }, { "./utils": 22 }], 18: [function (require, module, exports) { - (function (Buffer) { - 'use strict'; - exports.base64 = true; - exports.array = true; - exports.string = true; - exports.arraybuffer = typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined"; - // contains true if JSZip can read/generate nodejs Buffer, false otherwise. - // Browserify will provide a Buffer implementation for browsers, which is - // an augmented Uint8Array (i.e., can be used as either Buffer or U8). - exports.nodebuffer = typeof Buffer !== "undefined"; - // contains true if JSZip can read/generate Uint8Array, false otherwise. - exports.uint8array = typeof Uint8Array !== "undefined"; - - if (typeof ArrayBuffer === "undefined") { - exports.blob = false; - } - else { - var buffer = new ArrayBuffer(0); - try { - exports.blob = new Blob([buffer], { - type: "application/zip" - }).size === 0; - } - catch (e) { - try { - var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - var builder = new Builder(); - builder.append(buffer); - exports.blob = builder.getBlob('application/zip').size === 0; - } - catch (e) { - exports.blob = false; - } - } - } - - }).call(this, (typeof Buffer !== "undefined" ? Buffer : undefined)) - }, {}], 19: [function (require, module, exports) { - 'use strict'; - var ArrayReader = require('./arrayReader'); - - function Uint8ArrayReader(data) { - if (data) { - this.data = data; - this.length = this.data.length; - this.index = 0; - this.zero = 0; - } - } - Uint8ArrayReader.prototype = new ArrayReader(); - /** - * @see DataReader.readData - */ - Uint8ArrayReader.prototype.readData = function (size) { - this.checkOffset(size); - if (size === 0) { - // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of []. - return new Uint8Array(0); - } - var result = this.data.subarray(this.zero + this.index, this.zero + this.index + size); - this.index += size; - return result; - }; - module.exports = Uint8ArrayReader; - - }, { "./arrayReader": 1 }], 20: [function (require, module, exports) { - 'use strict'; - - var utils = require('./utils'); - - /** - * An object to write any content to an Uint8Array. - * @constructor - * @param {number} length The length of the array. - */ - var Uint8ArrayWriter = function (length) { - this.data = new Uint8Array(length); - this.index = 0; - }; - Uint8ArrayWriter.prototype = { - /** - * Append any content to the current array. - * @param {Object} input the content to add. - */ - append: function (input) { - if (input.length !== 0) { - // with an empty Uint8Array, Opera fails with a "Offset larger than array size" - input = utils.transformTo("uint8array", input); - this.data.set(input, this.index); - this.index += input.length; - } - }, - /** - * Finalize the construction an return the result. - * @return {Uint8Array} the generated array. - */ - finalize: function () { - return this.data; - } - }; - - module.exports = Uint8ArrayWriter; - - }, { "./utils": 22 }], 21: [function (require, module, exports) { - 'use strict'; - - var utils = require('./utils'); - var support = require('./support'); - var nodeBuffer = require('./nodeBuffer'); - - /** - * The following functions come from pako, from pako/lib/utils/strings - * released under the MIT license, see pako https://github.com/nodeca/pako/ - */ - - // Table with utf8 lengths (calculated by first byte of sequence) - // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, - // because max possible codepoint is 0x10ffff - var _utf8len = new Array(256); - for (var i = 0; i < 256; i++) { - _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1); - } - _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start - - // convert string to array (typed, when possible) - var 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 - if (support.uint8array) { - buf = new Uint8Array(buf_len); - } else { - buf = new Array(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; - }; - - // 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); - var 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; - }; - - // convert array to string - var buf2string = function (buf) { - var str, i, out, c, c_len; - var len = 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); - } - } - - // shrinkBuf(utf16buf, out) - if (utf16buf.length !== out) { - if (utf16buf.subarray) { - utf16buf = utf16buf.subarray(0, out); - } else { - utf16buf.length = out; - } - } - - // return String.fromCharCode.apply(null, utf16buf); - return utils.applyFromCharCode(utf16buf); - }; - - - // That's all for the pako functions. - - - /** - * Transform a javascript string into an array (typed if possible) of bytes, - * UTF-8 encoded. - * @param {String} str the string to encode - * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string. - */ - exports.utf8encode = function utf8encode(str) { - if (support.nodebuffer) { - return nodeBuffer(str, "utf-8"); - } - - return string2buf(str); - }; - - - /** - * Transform a bytes array (or a representation) representing an UTF-8 encoded - * string into a javascript string. - * @param {Array|Uint8Array|Buffer} buf the data de decode - * @return {String} the decoded string. - */ - exports.utf8decode = function utf8decode(buf) { - if (support.nodebuffer) { - return utils.transformTo("nodebuffer", buf).toString("utf-8"); - } - - buf = utils.transformTo(support.uint8array ? "uint8array" : "array", buf); - - // return buf2string(buf); - // Chrome prefers to work with "small" chunks of data - // for the method buf2string. - // Firefox and Chrome has their own shortcut, IE doesn't seem to really care. - var result = [], k = 0, len = buf.length, chunk = 65536; - while (k < len) { - var nextBoundary = utf8border(buf, Math.min(k + chunk, len)); - if (support.uint8array) { - result.push(buf2string(buf.subarray(k, nextBoundary))); - } else { - result.push(buf2string(buf.slice(k, nextBoundary))); - } - k = nextBoundary; - } - return result.join(""); - - }; - // vim: set shiftwidth=4 softtabstop=4: - - }, { "./nodeBuffer": 12, "./support": 18, "./utils": 22 }], 22: [function (require, module, exports) { - 'use strict'; - var support = require('./support'); - var compressions = require('./compressions'); - var nodeBuffer = require('./nodeBuffer'); - /** - * Convert a string to a "binary string" : a string containing only char codes between 0 and 255. - * @param {string} str the string to transform. - * @return {String} the binary string. - */ - exports.string2binary = function (str) { - var result = ""; - for (var i = 0; i < str.length; i++) { - result += String.fromCharCode(str.charCodeAt(i) & 0xff); - } - return result; - }; - exports.arrayBuffer2Blob = function (buffer, mimeType) { - exports.checkSupport("blob"); - mimeType = mimeType || 'application/zip'; - - try { - // Blob constructor - return new Blob([buffer], { - type: mimeType - }); - } - catch (e) { - - try { - // deprecated, browser only, old way - var Builder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder; - var builder = new Builder(); - builder.append(buffer); - return builder.getBlob(mimeType); - } - catch (e) { - - // well, fuck ?! - throw new Error("Bug : can't construct the Blob."); - } - } - - - }; - /** - * The identity function. - * @param {Object} input the input. - * @return {Object} the same input. - */ - function identity(input) { - return input; - } - - /** - * Fill in an array with a string. - * @param {String} str the string to use. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated). - * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array. - */ - function stringToArrayLike(str, array) { - for (var i = 0; i < str.length; ++i) { - array[i] = str.charCodeAt(i) & 0xFF; - } - return array; - } - - /** - * Transform an array-like object to a string. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform. - * @return {String} the result. - */ - function arrayLikeToString(array) { - // Performances notes : - // -------------------- - // String.fromCharCode.apply(null, array) is the fastest, see - // see http://jsperf.com/converting-a-uint8array-to-a-string/2 - // but the stack is limited (and we can get huge arrays !). - // - // result += String.fromCharCode(array[i]); generate too many strings ! - // - // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2 - var chunk = 65536; - var result = [], - len = array.length, - type = exports.getTypeOf(array), - k = 0, - canUseApply = true; - try { - switch (type) { - case "uint8array": - String.fromCharCode.apply(null, new Uint8Array(0)); - break; - case "nodebuffer": - String.fromCharCode.apply(null, nodeBuffer(0)); - break; - } - } catch (e) { - canUseApply = false; - } - - // no apply : slow and painful algorithm - // default browser on android 4.* - if (!canUseApply) { - var resultStr = ""; - for (var i = 0; i < array.length; i++) { - resultStr += String.fromCharCode(array[i]); - } - return resultStr; - } - while (k < len && chunk > 1) { - try { - if (type === "array" || type === "nodebuffer") { - result.push(String.fromCharCode.apply(null, array.slice(k, Math.min(k + chunk, len)))); - } - else { - result.push(String.fromCharCode.apply(null, array.subarray(k, Math.min(k + chunk, len)))); - } - k += chunk; - } - catch (e) { - chunk = Math.floor(chunk / 2); - } - } - return result.join(""); - } - - exports.applyFromCharCode = arrayLikeToString; - - - /** - * Copy the data from an array-like to an other array-like. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array. - * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated. - * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array. - */ - function arrayLikeToArrayLike(arrayFrom, arrayTo) { - for (var i = 0; i < arrayFrom.length; i++) { - arrayTo[i] = arrayFrom[i]; - } - return arrayTo; - } - - // a matrix containing functions to transform everything into everything. - var transform = {}; - - // string to ? - transform["string"] = { - "string": identity, - "array": function (input) { - return stringToArrayLike(input, new Array(input.length)); - }, - "arraybuffer": function (input) { - return transform["string"]["uint8array"](input).buffer; - }, - "uint8array": function (input) { - return stringToArrayLike(input, new Uint8Array(input.length)); - }, - "nodebuffer": function (input) { - return stringToArrayLike(input, nodeBuffer(input.length)); - } - }; - - // array to ? - transform["array"] = { - "string": arrayLikeToString, - "array": identity, - "arraybuffer": function (input) { - return (new Uint8Array(input)).buffer; - }, - "uint8array": function (input) { - return new Uint8Array(input); - }, - "nodebuffer": function (input) { - return nodeBuffer(input); - } - }; - - // arraybuffer to ? - transform["arraybuffer"] = { - "string": function (input) { - return arrayLikeToString(new Uint8Array(input)); - }, - "array": function (input) { - return arrayLikeToArrayLike(new Uint8Array(input), new Array(input.byteLength)); - }, - "arraybuffer": identity, - "uint8array": function (input) { - return new Uint8Array(input); - }, - "nodebuffer": function (input) { - return nodeBuffer(new Uint8Array(input)); - } - }; - - // uint8array to ? - transform["uint8array"] = { - "string": arrayLikeToString, - "array": function (input) { - return arrayLikeToArrayLike(input, new Array(input.length)); - }, - "arraybuffer": function (input) { - return input.buffer; - }, - "uint8array": identity, - "nodebuffer": function (input) { - return nodeBuffer(input); - } - }; - - // nodebuffer to ? - transform["nodebuffer"] = { - "string": arrayLikeToString, - "array": function (input) { - return arrayLikeToArrayLike(input, new Array(input.length)); - }, - "arraybuffer": function (input) { - return transform["nodebuffer"]["uint8array"](input).buffer; - }, - "uint8array": function (input) { - return arrayLikeToArrayLike(input, new Uint8Array(input.length)); - }, - "nodebuffer": identity - }; - - /** - * Transform an input into any type. - * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer. - * If no output type is specified, the unmodified input will be returned. - * @param {String} outputType the output type. - * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert. - * @throws {Error} an Error if the browser doesn't support the requested output type. - */ - exports.transformTo = function (outputType, input) { - if (!input) { - // undefined, null, etc - // an empty string won't harm. - input = ""; - } - if (!outputType) { - return input; - } - exports.checkSupport(outputType); - var inputType = exports.getTypeOf(input); - var result = transform[inputType][outputType](input); - return result; - }; - - /** - * Return the type of the input. - * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer. - * @param {Object} input the input to identify. - * @return {String} the (lowercase) type of the input. - */ - exports.getTypeOf = function (input) { - if (typeof input === "string") { - return "string"; - } - if (Object.prototype.toString.call(input) === "[object Array]") { - return "array"; - } - if (support.nodebuffer && nodeBuffer.test(input)) { - return "nodebuffer"; - } - if (support.uint8array && input instanceof Uint8Array) { - return "uint8array"; - } - if (support.arraybuffer && input instanceof ArrayBuffer) { - return "arraybuffer"; - } - }; - - /** - * Throw an exception if the type is not supported. - * @param {String} type the type to check. - * @throws {Error} an Error if the browser doesn't support the requested type. - */ - exports.checkSupport = function (type) { - var supported = support[type.toLowerCase()]; - if (!supported) { - throw new Error(type + " is not supported by this browser"); - } - }; - exports.MAX_VALUE_16BITS = 65535; - exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1 - - /** - * Prettify a string read as binary. - * @param {string} str the string to prettify. - * @return {string} a pretty string. - */ - exports.pretty = function (str) { - var res = '', - code, i; - for (i = 0; i < (str || "").length; i++) { - code = str.charCodeAt(i); - res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase(); - } - return res; - }; - - /** - * Find a compression registered in JSZip. - * @param {string} compressionMethod the method magic to find. - * @return {Object|null} the JSZip compression object, null if none found. - */ - exports.findCompression = function (compressionMethod) { - for (var method in compressions) { - if (!compressions.hasOwnProperty(method)) { - continue; - } - if (compressions[method].magic === compressionMethod) { - return compressions[method]; - } - } - return null; - }; - /** - * Cross-window, cross-Node-context regular expression detection - * @param {Object} object Anything - * @return {Boolean} true if the object is a regular expression, - * false otherwise - */ - exports.isRegExp = function (object) { - return Object.prototype.toString.call(object) === "[object RegExp]"; - }; - - /** - * Merge the objects passed as parameters into a new one. - * @private - * @param {...Object} var_args All objects to merge. - * @return {Object} a new object with the data of the others. - */ - exports.extend = function () { - var result = {}, i, attr; - for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers - for (attr in arguments[i]) { - if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") { - result[attr] = arguments[i][attr]; - } - } - } - return result; - }; - - - }, { "./compressions": 4, "./nodeBuffer": 12, "./support": 18 }], 23: [function (require, module, exports) { - 'use strict'; - var StringReader = require('./stringReader'); - var NodeBufferReader = require('./nodeBufferReader'); - var Uint8ArrayReader = require('./uint8ArrayReader'); - var ArrayReader = require('./arrayReader'); - var utils = require('./utils'); - var sig = require('./signature'); - var ZipEntry = require('./zipEntry'); - var support = require('./support'); - var jszipProto = require('./object'); - // class ZipEntries {{{ - /** - * All the entries in the zip file. - * @constructor - * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load. - * @param {Object} loadOptions Options for loading the stream. - */ - function ZipEntries(data, loadOptions) { - this.files = []; - this.loadOptions = loadOptions; - if (data) { - this.load(data); - } - } - ZipEntries.prototype = { - /** - * Check that the reader is on the speficied signature. - * @param {string} expectedSignature the expected signature. - * @throws {Error} if it is an other signature. - */ - checkSignature: function (expectedSignature) { - var signature = this.reader.readString(4); - if (signature !== expectedSignature) { - throw new Error("Corrupted zip or bug : unexpected signature " + "(" + utils.pretty(signature) + ", expected " + utils.pretty(expectedSignature) + ")"); - } - }, - /** - * Check if the given signature is at the given index. - * @param {number} askedIndex the index to check. - * @param {string} expectedSignature the signature to expect. - * @return {boolean} true if the signature is here, false otherwise. - */ - isSignature: function (askedIndex, expectedSignature) { - var currentIndex = this.reader.index; - this.reader.setIndex(askedIndex); - var signature = this.reader.readString(4); - var result = signature === expectedSignature; - this.reader.setIndex(currentIndex); - return result; - }, - /** - * Read the end of the central directory. - */ - readBlockEndOfCentral: function () { - this.diskNumber = this.reader.readInt(2); - this.diskWithCentralDirStart = this.reader.readInt(2); - this.centralDirRecordsOnThisDisk = this.reader.readInt(2); - this.centralDirRecords = this.reader.readInt(2); - this.centralDirSize = this.reader.readInt(4); - this.centralDirOffset = this.reader.readInt(4); - - this.zipCommentLength = this.reader.readInt(2); - // warning : the encoding depends of the system locale - // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded. - // On a windows machine, this field is encoded with the localized windows code page. - var zipComment = this.reader.readData(this.zipCommentLength); - var decodeParamType = support.uint8array ? "uint8array" : "array"; - // To get consistent behavior with the generation part, we will assume that - // this is utf8 encoded unless specified otherwise. - var decodeContent = utils.transformTo(decodeParamType, zipComment); - this.zipComment = this.loadOptions.decodeFileName(decodeContent); - }, - /** - * Read the end of the Zip 64 central directory. - * Not merged with the method readEndOfCentral : - * The end of central can coexist with its Zip64 brother, - * I don't want to read the wrong number of bytes ! - */ - readBlockZip64EndOfCentral: function () { - this.zip64EndOfCentralSize = this.reader.readInt(8); - this.versionMadeBy = this.reader.readString(2); - this.versionNeeded = this.reader.readInt(2); - this.diskNumber = this.reader.readInt(4); - this.diskWithCentralDirStart = this.reader.readInt(4); - this.centralDirRecordsOnThisDisk = this.reader.readInt(8); - this.centralDirRecords = this.reader.readInt(8); - this.centralDirSize = this.reader.readInt(8); - this.centralDirOffset = this.reader.readInt(8); - - this.zip64ExtensibleData = {}; - var extraDataSize = this.zip64EndOfCentralSize - 44, - index = 0, - extraFieldId, - extraFieldLength, - extraFieldValue; - while (index < extraDataSize) { - extraFieldId = this.reader.readInt(2); - extraFieldLength = this.reader.readInt(4); - extraFieldValue = this.reader.readString(extraFieldLength); - this.zip64ExtensibleData[extraFieldId] = { - id: extraFieldId, - length: extraFieldLength, - value: extraFieldValue - }; - } - }, - /** - * Read the end of the Zip 64 central directory locator. - */ - readBlockZip64EndOfCentralLocator: function () { - this.diskWithZip64CentralDirStart = this.reader.readInt(4); - this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8); - this.disksCount = this.reader.readInt(4); - if (this.disksCount > 1) { - throw new Error("Multi-volumes zip are not supported"); - } - }, - /** - * Read the local files, based on the offset read in the central part. - */ - readLocalFiles: function () { - var i, file; - for (i = 0; i < this.files.length; i++) { - file = this.files[i]; - this.reader.setIndex(file.localHeaderOffset); - this.checkSignature(sig.LOCAL_FILE_HEADER); - file.readLocalPart(this.reader); - file.handleUTF8(); - file.processAttributes(); - } - }, - /** - * Read the central directory. - */ - readCentralDir: function () { - var file; - - this.reader.setIndex(this.centralDirOffset); - while (this.reader.readString(4) === sig.CENTRAL_FILE_HEADER) { - file = new ZipEntry({ - zip64: this.zip64 - }, this.loadOptions); - file.readCentralPart(this.reader); - this.files.push(file); - } - - if (this.centralDirRecords !== this.files.length) { - if (this.centralDirRecords !== 0 && this.files.length === 0) { - // We expected some records but couldn't find ANY. - // This is really suspicious, as if something went wrong. - throw new Error("Corrupted zip or bug: expected " + this.centralDirRecords + " records in central dir, got " + this.files.length); - } else { - // We found some records but not all. - // Something is wrong but we got something for the user: no error here. - // console.warn("expected", this.centralDirRecords, "records in central dir, got", this.files.length); - } - } - }, - /** - * Read the end of central directory. - */ - readEndOfCentral: function () { - var offset = this.reader.lastIndexOfSignature(sig.CENTRAL_DIRECTORY_END); - if (offset < 0) { - // Check if the content is a truncated zip or complete garbage. - // A "LOCAL_FILE_HEADER" is not required at the beginning (auto - // extractible zip for example) but it can give a good hint. - // If an ajax request was used without responseType, we will also - // get unreadable data. - var isGarbage = !this.isSignature(0, sig.LOCAL_FILE_HEADER); - - if (isGarbage) { - throw new Error("Can't find end of central directory : is this a zip file ? " + - "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html"); - } else { - throw new Error("Corrupted zip : can't find end of central directory"); - } - } - this.reader.setIndex(offset); - var endOfCentralDirOffset = offset; - this.checkSignature(sig.CENTRAL_DIRECTORY_END); - this.readBlockEndOfCentral(); - - - /* extract from the zip spec : - 4) If one of the fields in the end of central directory - record is too small to hold required data, the field - should be set to -1 (0xFFFF or 0xFFFFFFFF) and the - ZIP64 format record should be created. - 5) The end of central directory record and the - Zip64 end of central directory locator record must - reside on the same disk when splitting or spanning - an archive. - */ - if (this.diskNumber === utils.MAX_VALUE_16BITS || this.diskWithCentralDirStart === utils.MAX_VALUE_16BITS || this.centralDirRecordsOnThisDisk === utils.MAX_VALUE_16BITS || this.centralDirRecords === utils.MAX_VALUE_16BITS || this.centralDirSize === utils.MAX_VALUE_32BITS || this.centralDirOffset === utils.MAX_VALUE_32BITS) { - this.zip64 = true; - - /* - Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from - the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents - all numbers as 64-bit double precision IEEE 754 floating point numbers. - So, we have 53bits for integers and bitwise operations treat everything as 32bits. - see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators - and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5 - */ - - // should look for a zip64 EOCD locator - offset = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); - if (offset < 0) { - throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator"); - } - this.reader.setIndex(offset); - this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR); - this.readBlockZip64EndOfCentralLocator(); - - // now the zip64 EOCD record - if (!this.isSignature(this.relativeOffsetEndOfZip64CentralDir, sig.ZIP64_CENTRAL_DIRECTORY_END)) { - // console.warn("ZIP64 end of central directory not where expected."); - this.relativeOffsetEndOfZip64CentralDir = this.reader.lastIndexOfSignature(sig.ZIP64_CENTRAL_DIRECTORY_END); - if (this.relativeOffsetEndOfZip64CentralDir < 0) { - throw new Error("Corrupted zip : can't find the ZIP64 end of central directory"); - } - } - this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir); - this.checkSignature(sig.ZIP64_CENTRAL_DIRECTORY_END); - this.readBlockZip64EndOfCentral(); - } - - var expectedEndOfCentralDirOffset = this.centralDirOffset + this.centralDirSize; - if (this.zip64) { - expectedEndOfCentralDirOffset += 20; // end of central dir 64 locator - expectedEndOfCentralDirOffset += 12 /* should not include the leading 12 bytes */ + this.zip64EndOfCentralSize; - } - - var extraBytes = endOfCentralDirOffset - expectedEndOfCentralDirOffset; - - if (extraBytes > 0) { - // console.warn(extraBytes, "extra bytes at beginning or within zipfile"); - if (this.isSignature(endOfCentralDirOffset, sig.CENTRAL_FILE_HEADER)) { - // The offsets seem wrong, but we have something at the specified offset. - // So… we keep it. - } else { - // the offset is wrong, update the "zero" of the reader - // this happens if data has been prepended (crx files for example) - this.reader.zero = extraBytes; - } - } else if (extraBytes < 0) { - throw new Error("Corrupted zip: missing " + Math.abs(extraBytes) + " bytes."); - } - }, - prepareReader: function (data) { - var type = utils.getTypeOf(data); - utils.checkSupport(type); - if (type === "string" && !support.uint8array) { - this.reader = new StringReader(data, this.loadOptions.optimizedBinaryString); - } - else if (type === "nodebuffer") { - this.reader = new NodeBufferReader(data); - } - else if (support.uint8array) { - this.reader = new Uint8ArrayReader(utils.transformTo("uint8array", data)); - } else if (support.array) { - this.reader = new ArrayReader(utils.transformTo("array", data)); - } else { - throw new Error("Unexpected error: unsupported type '" + type + "'"); - } - }, - /** - * Read a zip file and create ZipEntries. - * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file. - */ - load: function (data) { - this.prepareReader(data); - this.readEndOfCentral(); - this.readCentralDir(); - this.readLocalFiles(); - } - }; - // }}} end of ZipEntries - module.exports = ZipEntries; - - }, { "./arrayReader": 1, "./nodeBufferReader": 13, "./object": 14, "./signature": 15, "./stringReader": 16, "./support": 18, "./uint8ArrayReader": 19, "./utils": 22, "./zipEntry": 24 }], 24: [function (require, module, exports) { - 'use strict'; - var StringReader = require('./stringReader'); - var utils = require('./utils'); - var CompressedObject = require('./compressedObject'); - var jszipProto = require('./object'); - var support = require('./support'); - - var MADE_BY_DOS = 0x00; - var MADE_BY_UNIX = 0x03; - - // class ZipEntry {{{ - /** - * An entry in the zip file. - * @constructor - * @param {Object} options Options of the current file. - * @param {Object} loadOptions Options for loading the stream. - */ - function ZipEntry(options, loadOptions) { - this.options = options; - this.loadOptions = loadOptions; - } - ZipEntry.prototype = { - /** - * say if the file is encrypted. - * @return {boolean} true if the file is encrypted, false otherwise. - */ - isEncrypted: function () { - // bit 1 is set - return (this.bitFlag & 0x0001) === 0x0001; - }, - /** - * say if the file has utf-8 filename/comment. - * @return {boolean} true if the filename/comment is in utf-8, false otherwise. - */ - useUTF8: function () { - // bit 11 is set - return (this.bitFlag & 0x0800) === 0x0800; - }, - /** - * Prepare the function used to generate the compressed content from this ZipFile. - * @param {DataReader} reader the reader to use. - * @param {number} from the offset from where we should read the data. - * @param {number} length the length of the data to read. - * @return {Function} the callback to get the compressed content (the type depends of the DataReader class). - */ - prepareCompressedContent: function (reader, from, length) { - return function () { - var previousIndex = reader.index; - reader.setIndex(from); - var compressedFileData = reader.readData(length); - reader.setIndex(previousIndex); - - return compressedFileData; - }; - }, - /** - * Prepare the function used to generate the uncompressed content from this ZipFile. - * @param {DataReader} reader the reader to use. - * @param {number} from the offset from where we should read the data. - * @param {number} length the length of the data to read. - * @param {JSZip.compression} compression the compression used on this file. - * @param {number} uncompressedSize the uncompressed size to expect. - * @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class). - */ - prepareContent: function (reader, from, length, compression, uncompressedSize) { - return function () { - - var compressedFileData = utils.transformTo(compression.uncompressInputType, this.getCompressedContent()); - var uncompressedFileData = compression.uncompress(compressedFileData); - - if (uncompressedFileData.length !== uncompressedSize) { - throw new Error("Bug : uncompressed data size mismatch"); - } - - return uncompressedFileData; - }; - }, - /** - * Read the local part of a zip file and add the info in this object. - * @param {DataReader} reader the reader to use. - */ - readLocalPart: function (reader) { - var compression, localExtraFieldsLength; - - // we already know everything from the central dir ! - // If the central dir data are false, we are doomed. - // On the bright side, the local part is scary : zip64, data descriptors, both, etc. - // The less data we get here, the more reliable this should be. - // Let's skip the whole header and dash to the data ! - reader.skip(22); - // in some zip created on windows, the filename stored in the central dir contains \ instead of /. - // Strangely, the filename here is OK. - // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes - // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators... - // Search "unzip mismatching "local" filename continuing with "central" filename version" on - // the internet. - // - // I think I see the logic here : the central directory is used to display - // content and the local directory is used to extract the files. Mixing / and \ - // may be used to display \ to windows users and use / when extracting the files. - // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394 - this.fileNameLength = reader.readInt(2); - localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir - this.fileName = reader.readData(this.fileNameLength); - reader.skip(localExtraFieldsLength); - - if (this.compressedSize == -1 || this.uncompressedSize == -1) { - throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory " + "(compressedSize == -1 || uncompressedSize == -1)"); - } - - compression = utils.findCompression(this.compressionMethod); - if (compression === null) { // no compression found - throw new Error("Corrupted zip : compression " + utils.pretty(this.compressionMethod) + " unknown (inner file : " + utils.transformTo("string", this.fileName) + ")"); - } - this.decompressed = new CompressedObject(); - this.decompressed.compressedSize = this.compressedSize; - this.decompressed.uncompressedSize = this.uncompressedSize; - this.decompressed.crc32 = this.crc32; - this.decompressed.compressionMethod = this.compressionMethod; - this.decompressed.getCompressedContent = this.prepareCompressedContent(reader, reader.index, this.compressedSize, compression); - this.decompressed.getContent = this.prepareContent(reader, reader.index, this.compressedSize, compression, this.uncompressedSize); - - // we need to compute the crc32... - if (this.loadOptions.checkCRC32) { - this.decompressed = utils.transformTo("string", this.decompressed.getContent()); - if (jszipProto.crc32(this.decompressed) !== this.crc32) { - throw new Error("Corrupted zip : CRC32 mismatch"); - } - } - }, - - /** - * Read the central part of a zip file and add the info in this object. - * @param {DataReader} reader the reader to use. - */ - readCentralPart: function (reader) { - this.versionMadeBy = reader.readInt(2); - this.versionNeeded = reader.readInt(2); - this.bitFlag = reader.readInt(2); - this.compressionMethod = reader.readString(2); - this.date = reader.readDate(); - this.crc32 = reader.readInt(4); - this.compressedSize = reader.readInt(4); - this.uncompressedSize = reader.readInt(4); - this.fileNameLength = reader.readInt(2); - this.extraFieldsLength = reader.readInt(2); - this.fileCommentLength = reader.readInt(2); - this.diskNumberStart = reader.readInt(2); - this.internalFileAttributes = reader.readInt(2); - this.externalFileAttributes = reader.readInt(4); - this.localHeaderOffset = reader.readInt(4); - - if (this.isEncrypted()) { - throw new Error("Encrypted zip are not supported"); - } - - this.fileName = reader.readData(this.fileNameLength); - this.readExtraFields(reader); - this.parseZIP64ExtraField(reader); - this.fileComment = reader.readData(this.fileCommentLength); - }, - - /** - * Parse the external file attributes and get the unix/dos permissions. - */ - processAttributes: function () { - this.unixPermissions = null; - this.dosPermissions = null; - var madeBy = this.versionMadeBy >> 8; - - // Check if we have the DOS directory flag set. - // We look for it in the DOS and UNIX permissions - // but some unknown platform could set it as a compatibility flag. - this.dir = this.externalFileAttributes & 0x0010 ? true : false; - - if (madeBy === MADE_BY_DOS) { - // first 6 bits (0 to 5) - this.dosPermissions = this.externalFileAttributes & 0x3F; - } - - if (madeBy === MADE_BY_UNIX) { - this.unixPermissions = (this.externalFileAttributes >> 16) & 0xFFFF; - // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8); - } - - // fail safe : if the name ends with a / it probably means a folder - if (!this.dir && this.fileNameStr.slice(-1) === '/') { - this.dir = true; - } - }, - - /** - * Parse the ZIP64 extra field and merge the info in the current ZipEntry. - * @param {DataReader} reader the reader to use. - */ - parseZIP64ExtraField: function (reader) { - - if (!this.extraFields[0x0001]) { - return; - } - - // should be something, preparing the extra reader - var extraReader = new StringReader(this.extraFields[0x0001].value); - - // I really hope that these 64bits integer can fit in 32 bits integer, because js - // won't let us have more. - if (this.uncompressedSize === utils.MAX_VALUE_32BITS) { - this.uncompressedSize = extraReader.readInt(8); - } - if (this.compressedSize === utils.MAX_VALUE_32BITS) { - this.compressedSize = extraReader.readInt(8); - } - if (this.localHeaderOffset === utils.MAX_VALUE_32BITS) { - this.localHeaderOffset = extraReader.readInt(8); - } - if (this.diskNumberStart === utils.MAX_VALUE_32BITS) { - this.diskNumberStart = extraReader.readInt(4); - } - }, - /** - * Read the central part of a zip file and add the info in this object. - * @param {DataReader} reader the reader to use. - */ - readExtraFields: function (reader) { - var start = reader.index, - extraFieldId, - extraFieldLength, - extraFieldValue; - - this.extraFields = this.extraFields || {}; - - while (reader.index < start + this.extraFieldsLength) { - extraFieldId = reader.readInt(2); - extraFieldLength = reader.readInt(2); - extraFieldValue = reader.readString(extraFieldLength); - - this.extraFields[extraFieldId] = { - id: extraFieldId, - length: extraFieldLength, - value: extraFieldValue - }; - } - }, - /** - * Apply an UTF8 transformation if needed. - */ - handleUTF8: function () { - var decodeParamType = support.uint8array ? "uint8array" : "array"; - if (this.useUTF8()) { - this.fileNameStr = jszipProto.utf8decode(this.fileName); - this.fileCommentStr = jszipProto.utf8decode(this.fileComment); - } else { - var upath = this.findExtraFieldUnicodePath(); - if (upath !== null) { - this.fileNameStr = upath; - } else { - var fileNameByteArray = utils.transformTo(decodeParamType, this.fileName); - this.fileNameStr = this.loadOptions.decodeFileName(fileNameByteArray); - } - - var ucomment = this.findExtraFieldUnicodeComment(); - if (ucomment !== null) { - this.fileCommentStr = ucomment; - } else { - var commentByteArray = utils.transformTo(decodeParamType, this.fileComment); - this.fileCommentStr = this.loadOptions.decodeFileName(commentByteArray); - } - } - }, - - /** - * Find the unicode path declared in the extra field, if any. - * @return {String} the unicode path, null otherwise. - */ - findExtraFieldUnicodePath: function () { - var upathField = this.extraFields[0x7075]; - if (upathField) { - var extraReader = new StringReader(upathField.value); - - // wrong version - if (extraReader.readInt(1) !== 1) { - return null; - } - - // the crc of the filename changed, this field is out of date. - if (jszipProto.crc32(this.fileName) !== extraReader.readInt(4)) { - return null; - } - - return jszipProto.utf8decode(extraReader.readString(upathField.length - 5)); - } - return null; - }, - - /** - * Find the unicode comment declared in the extra field, if any. - * @return {String} the unicode comment, null otherwise. - */ - findExtraFieldUnicodeComment: function () { - var ucommentField = this.extraFields[0x6375]; - if (ucommentField) { - var extraReader = new StringReader(ucommentField.value); - - // wrong version - if (extraReader.readInt(1) !== 1) { - return null; - } - - // the crc of the comment changed, this field is out of date. - if (jszipProto.crc32(this.fileComment) !== extraReader.readInt(4)) { - return null; - } - - return jszipProto.utf8decode(extraReader.readString(ucommentField.length - 5)); - } - return null; - } - }; - module.exports = ZipEntry; - - }, { "./compressedObject": 3, "./object": 14, "./stringReader": 16, "./support": 18, "./utils": 22 }], 25: [function (require, module, exports) { - // Top level file is just a mixin of submodules & constants - 'use strict'; - - var assign = require('./lib/utils/common').assign; - - var deflate = require('./lib/deflate'); - var inflate = require('./lib/inflate'); - var constants = require('./lib/zlib/constants'); - - var pako = {}; - - assign(pako, deflate, inflate, constants); - - module.exports = pako; - - }, { "./lib/deflate": 26, "./lib/inflate": 27, "./lib/utils/common": 28, "./lib/zlib/constants": 31 }], 26: [function (require, module, exports) { - 'use strict'; - - - var zlib_deflate = require('./zlib/deflate'); - var utils = require('./utils/common'); - var strings = require('./utils/strings'); - var msg = require('./zlib/messages'); - var ZStream = require('./zlib/zstream'); - - var toString = Object.prototype.toString; - - /* Public constants ==========================================================*/ - /* ===========================================================================*/ - - var Z_NO_FLUSH = 0; - var Z_FINISH = 4; - - var Z_OK = 0; - var Z_STREAM_END = 1; - var Z_SYNC_FLUSH = 2; - - var Z_DEFAULT_COMPRESSION = -1; - - var Z_DEFAULT_STRATEGY = 0; - - var Z_DEFLATED = 8; - - /* ===========================================================================*/ - - - /** - * class Deflate - * - * Generic JS-style wrapper for zlib calls. If you don't need - * streaming behaviour - use more simple functions: [[deflate]], - * [[deflateRaw]] and [[gzip]]. - **/ - - /* internal - * Deflate.chunks -> Array - * - * Chunks of output data, if [[Deflate#onData]] not overridden. - **/ - - /** - * Deflate.result -> Uint8Array|Array - * - * Compressed result, generated by default [[Deflate#onData]] - * and [[Deflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you - * push a chunk with explicit flush (call [[Deflate#push]] with - * `Z_SYNC_FLUSH` param). - **/ - - /** - * Deflate.err -> Number - * - * Error code after deflate finished. 0 (Z_OK) on success. - * You will not need it in real life, because deflate errors - * are possible only on wrong options or bad `onData` / `onEnd` - * custom handlers. - **/ - - /** - * Deflate.msg -> String - * - * Error message, if [[Deflate.err]] != 0 - **/ - - - /** - * new Deflate(options) - * - options (Object): zlib deflate options. - * - * Creates new deflator instance with specified params. Throws exception - * on bad params. Supported options: - * - * - `level` - * - `windowBits` - * - `memLevel` - * - `strategy` - * - `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 deflate - * - `gzip` (Boolean) - create gzip wrapper - * - `to` (String) - if equal to 'string', then result will be "binary string" - * (each char code [0..255]) - * - `header` (Object) - custom header for gzip - * - `text` (Boolean) - true if compressed data believed to be text - * - `time` (Number) - modification time, unix timestamp - * - `os` (Number) - operation system code - * - `extra` (Array) - array of bytes with extra data (max 65536) - * - `name` (String) - file name (binary string) - * - `comment` (String) - comment (binary string) - * - `hcrc` (Boolean) - true if header crc should be added - * - * ##### 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 deflate = new pako.Deflate({ level: 3}); - * - * deflate.push(chunk1, false); - * deflate.push(chunk2, true); // true -> last chunk - * - * if (deflate.err) { throw new Error(deflate.err); } - * - * console.log(deflate.result); - * ``` - **/ - function Deflate(options) { - if (!(this instanceof Deflate)) return new Deflate(options); - - this.options = utils.assign({ - level: Z_DEFAULT_COMPRESSION, - method: Z_DEFLATED, - chunkSize: 16384, - windowBits: 15, - memLevel: 8, - strategy: Z_DEFAULT_STRATEGY, - to: '' - }, options || {}); - - var opt = this.options; - - if (opt.raw && (opt.windowBits > 0)) { - opt.windowBits = -opt.windowBits; - } - - else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { - opt.windowBits += 16; - } - - 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_deflate.deflateInit2( - this.strm, - opt.level, - opt.method, - opt.windowBits, - opt.memLevel, - opt.strategy - ); - - if (status !== Z_OK) { - throw new Error(msg[status]); - } - - if (opt.header) { - zlib_deflate.deflateSetHeader(this.strm, opt.header); - } - - if (opt.dictionary) { - var dict; - // Convert data if needed - if (typeof opt.dictionary === 'string') { - // If we need to compress text, change encoding to utf8. - dict = strings.string2buf(opt.dictionary); - } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') { - dict = new Uint8Array(opt.dictionary); - } else { - dict = opt.dictionary; - } - - status = zlib_deflate.deflateSetDictionary(this.strm, dict); - - if (status !== Z_OK) { - throw new Error(msg[status]); - } - - this._dict_set = true; - } - } - - /** - * Deflate#push(data[, mode]) -> Boolean - * - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be - * converted to utf8 byte sequence. - * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. - * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. - * - * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with - * new compressed chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That will flush internal pending buffers and call - * [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you - * can use mode Z_SYNC_FLUSH, keeping the compression context. - * - * On fail call [[Deflate#onEnd]] with error code and return false. - * - * We strongly recommend to use `Uint8Array` on input for best speed (output - * array 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 - * ``` - **/ - Deflate.prototype.push = function (data, mode) { - var strm = this.strm; - var chunkSize = this.options.chunkSize; - var status, _mode; - - if (this.ended) { return false; } - - _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH); - - // Convert data if needed - if (typeof data === 'string') { - // If we need to compress text, change encoding to utf8. - strm.input = strings.string2buf(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_deflate.deflate(strm, _mode); /* no bad return value */ - - if (status !== Z_STREAM_END && status !== Z_OK) { - this.onEnd(status); - this.ended = true; - return false; - } - if (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) { - if (this.options.to === 'string') { - this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out))); - } else { - this.onData(utils.shrinkBuf(strm.output, strm.next_out)); - } - } - } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END); - - // Finalize on the last chunk. - if (_mode === Z_FINISH) { - status = zlib_deflate.deflateEnd(this.strm); - this.onEnd(status); - this.ended = true; - return status === Z_OK; - } - - // callback interim results if Z_SYNC_FLUSH. - if (_mode === Z_SYNC_FLUSH) { - this.onEnd(Z_OK); - strm.avail_out = 0; - return true; - } - - return true; - }; - - - /** - * Deflate#onData(chunk) -> Void - * - chunk (Uint8Array|Array|String): output 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. - **/ - Deflate.prototype.onData = function (chunk) { - this.chunks.push(chunk); - }; - - - /** - * Deflate#onEnd(status) -> Void - * - status (Number): deflate status. 0 (Z_OK) on success, - * other if not. - * - * Called once after you tell deflate 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. - **/ - Deflate.prototype.onEnd = function (status) { - // On success - join - if (status === Z_OK) { - if (this.options.to === 'string') { - this.result = this.chunks.join(''); - } else { - this.result = utils.flattenChunks(this.chunks); - } - } - this.chunks = []; - this.err = status; - this.msg = this.strm.msg; - }; - - - /** - * deflate(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * Compress `data` with deflate algorithm and `options`. - * - * Supported options are: - * - * - level - * - windowBits - * - memLevel - * - strategy - * - dictionary - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * 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 "binary string" - * (each char code [0..255]) - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , data = Uint8Array([1,2,3,4,5,6,7,8,9]); - * - * console.log(pako.deflate(data)); - * ``` - **/ - function deflate(input, options) { - var deflator = new Deflate(options); - - deflator.push(input, true); - - // That will never happens, if you don't cheat with options :) - if (deflator.err) { throw deflator.msg || msg[deflator.err]; } - - return deflator.result; - } - - - /** - * deflateRaw(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * The same as [[deflate]], but creates raw data, without wrapper - * (header and adler32 crc). - **/ - function deflateRaw(input, options) { - options = options || {}; - options.raw = true; - return deflate(input, options); - } - - - /** - * gzip(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * The same as [[deflate]], but create gzip wrapper instead of - * deflate one. - **/ - function gzip(input, options) { - options = options || {}; - options.gzip = true; - return deflate(input, options); - } - - - exports.Deflate = Deflate; - exports.deflate = deflate; - exports.deflateRaw = deflateRaw; - exports.gzip = gzip; - - }, { "./utils/common": 28, "./utils/strings": 29, "./zlib/deflate": 33, "./zlib/messages": 38, "./zlib/zstream": 40 }], 27: [function (require, module, exports) { - 'use strict'; - - - 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 overridden. - **/ - - /** - * 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); - - // Setup dictionary - if (opt.dictionary) { - // Convert data if needed - if (typeof opt.dictionary === 'string') { - opt.dictionary = strings.string2buf(opt.dictionary); - } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') { - opt.dictionary = new Uint8Array(opt.dictionary); - } - if (opt.raw) { //In raw mode we need to set the dictionary early - status = zlib_inflate.inflateSetDictionary(this.strm, opt.dictionary); - if (status !== c.Z_OK) { - throw new Error(msg[status]); - } - } - } - } - - /** - * 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` means 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; - - // 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) { - status = zlib_inflate.inflateSetDictionary(this.strm, dictionary); - } - - 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): output 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 aligned 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": 28, "./utils/strings": 29, "./zlib/constants": 31, "./zlib/gzheader": 34, "./zlib/inflate": 36, "./zlib/messages": 38, "./zlib/zstream": 40 }], 28: [function (require, module, exports) { - 'use strict'; - - - var TYPED_OK = (typeof Uint8Array !== 'undefined') && - (typeof Uint16Array !== 'undefined') && - (typeof Int32Array !== 'undefined'); - - function _has(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); - } - - exports.assign = function (obj /*from1, from2, from3, ...*/) { - var sources = Array.prototype.slice.call(arguments, 1); - while (sources.length) { - var source = sources.shift(); - if (!source) { continue; } - - if (typeof source !== 'object') { - throw new TypeError(source + 'must be non-object'); - } - - for (var p in source) { - if (_has(source, p)) { - obj[p] = source[p]; - } - } - } - - return obj; - }; - - - // reduce buffer size, avoiding mem copy - exports.shrinkBuf = function (buf, size) { - if (buf.length === size) { return buf; } - if (buf.subarray) { return buf.subarray(0, size); } - buf.length = size; - return buf; - }; - - - var fnTyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - if (src.subarray && dest.subarray) { - dest.set(src.subarray(src_offs, src_offs + len), dest_offs); - return; - } - // Fallback to ordinary array - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - // Join array of chunks to single array. - flattenChunks: function (chunks) { - var i, l, len, pos, chunk, result; - - // calculate data length - len = 0; - for (i = 0, l = chunks.length; i < l; i++) { - len += chunks[i].length; - } - - // join chunks - result = new Uint8Array(len); - pos = 0; - for (i = 0, l = chunks.length; i < l; i++) { - chunk = chunks[i]; - result.set(chunk, pos); - pos += chunk.length; - } - - return result; - } - }; - - var fnUntyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - // Join array of chunks to single array. - flattenChunks: function (chunks) { - return [].concat.apply([], chunks); - } - }; - - - // Enable/Disable typed arrays use, for testing - // - exports.setTyped = function (on) { - if (on) { - exports.Buf8 = Uint8Array; - exports.Buf16 = Uint16Array; - exports.Buf32 = Int32Array; - exports.assign(exports, fnTyped); - } else { - exports.Buf8 = Array; - exports.Buf16 = Array; - exports.Buf32 = Array; - exports.assign(exports, fnUntyped); - } - }; - - exports.setTyped(TYPED_OK); - - }, {}], 29: [function (require, module, exports) { - // String encode/decode helpers - 'use strict'; - - - var utils = require('./common'); - - - // Quick check if we can use fast array to bin string conversion - // - // - apply(Array) can fail on Android 2.2 - // - apply(Uint8Array) can fail on iOS 5.1 Safari - // - var STR_APPLY_OK = true; - var STR_APPLY_UIA_OK = true; - - try { String.fromCharCode.apply(null, [0]); } catch (__) { STR_APPLY_OK = false; } - try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; } - - - // Table with utf8 lengths (calculated by first byte of sequence) - // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, - // because max possible codepoint is 0x10ffff - var _utf8len = new utils.Buf8(256); - for (var q = 0; q < 256; q++) { - _utf8len[q] = (q >= 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) { - // On Chrome, the arguments in a function call that are allowed is `65534`. - // If the length of the buffer is smaller than that, we can use this optimization, - // otherwise we will take a slower path. - if (len < 65534) { - 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--; } - - // 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 buffer is too small, - // return max too. - if (pos === 0) { return max; } - - return (pos + _utf8len[buf[pos]] > max) ? pos : max; - }; - - }, { "./common": 28 }], 30: [function (require, module, exports) { - 'use strict'; - - // Note: adler32 takes 12% for level 0 and 2% for level 6. - // It isn't worth it to make additional optimizations as in original. - // Small size is preferable. - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - 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; - - }, {}], 31: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - 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 - }; - - }, {}], 32: [function (require, module, exports) { - 'use strict'; - - // Note: we can't get significant speed boost here. - // So write code to minimize size - no pregenerated tables - // and array tools dependencies. - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - // 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; - - }, {}], 33: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - var utils = require('../utils/common'); - var trees = require('./trees'); - var adler32 = require('./adler32'); - var crc32 = require('./crc32'); - var msg = require('./messages'); - - /* 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; - - - /* compression levels */ - //var Z_NO_COMPRESSION = 0; - //var Z_BEST_SPEED = 1; - //var Z_BEST_COMPRESSION = 9; - var Z_DEFAULT_COMPRESSION = -1; - - - var Z_FILTERED = 1; - var Z_HUFFMAN_ONLY = 2; - var Z_RLE = 3; - var Z_FIXED = 4; - var Z_DEFAULT_STRATEGY = 0; - - /* Possible values of the data_type field (though see inflate()) */ - //var Z_BINARY = 0; - //var Z_TEXT = 1; - //var Z_ASCII = 1; // = Z_TEXT - var Z_UNKNOWN = 2; - - - /* The deflate compression method */ - var Z_DEFLATED = 8; - - /*============================================================================*/ - - - var MAX_MEM_LEVEL = 9; - /* Maximum value for memLevel in deflateInit2 */ - var MAX_WBITS = 15; - /* 32K LZ77 window */ - var DEF_MEM_LEVEL = 8; - - - var LENGTH_CODES = 29; - /* number of length codes, not counting the special END_BLOCK code */ - var LITERALS = 256; - /* number of literal bytes 0..255 */ - var L_CODES = LITERALS + 1 + LENGTH_CODES; - /* number of Literal or Length codes, including the END_BLOCK code */ - var D_CODES = 30; - /* number of distance codes */ - var BL_CODES = 19; - /* number of codes used to transfer the bit lengths */ - var HEAP_SIZE = 2 * L_CODES + 1; - /* maximum heap size */ - var MAX_BITS = 15; - /* All codes must not exceed MAX_BITS bits */ - - var MIN_MATCH = 3; - var MAX_MATCH = 258; - var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); - - var PRESET_DICT = 0x20; - - var INIT_STATE = 42; - var EXTRA_STATE = 69; - var NAME_STATE = 73; - var COMMENT_STATE = 91; - var HCRC_STATE = 103; - var BUSY_STATE = 113; - var FINISH_STATE = 666; - - var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ - var BS_BLOCK_DONE = 2; /* block flush performed */ - var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ - var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ - - var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. - - function err(strm, errorCode) { - strm.msg = msg[errorCode]; - return errorCode; - } - - function rank(f) { - return ((f) << 1) - ((f) > 4 ? 9 : 0); - } - - function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } - - - /* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->output buffer and copying into it. - * (See also read_buf()). - */ - function flush_pending(strm) { - var s = strm.state; - - //_tr_flush_bits(s); - var len = s.pending; - if (len > strm.avail_out) { - len = strm.avail_out; - } - if (len === 0) { return; } - - utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); - strm.next_out += len; - s.pending_out += len; - strm.total_out += len; - strm.avail_out -= len; - s.pending -= len; - if (s.pending === 0) { - s.pending_out = 0; - } - } - - - function flush_block_only(s, last) { - trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); - s.block_start = s.strstart; - flush_pending(s.strm); - } - - - function put_byte(s, b) { - s.pending_buf[s.pending++] = b; - } - - - /* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ - function putShortMSB(s, b) { - // put_byte(s, (Byte)(b >> 8)); - // put_byte(s, (Byte)(b & 0xff)); - s.pending_buf[s.pending++] = (b >>> 8) & 0xff; - s.pending_buf[s.pending++] = b & 0xff; - } - - - /* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->input buffer and copying from it. - * (See also flush_pending()). - */ - function read_buf(strm, buf, start, size) { - var len = strm.avail_in; - - if (len > size) { len = size; } - if (len === 0) { return 0; } - - strm.avail_in -= len; - - // zmemcpy(buf, strm->next_in, len); - utils.arraySet(buf, strm.input, strm.next_in, len, start); - if (strm.state.wrap === 1) { - strm.adler = adler32(strm.adler, buf, len, start); - } - - else if (strm.state.wrap === 2) { - strm.adler = crc32(strm.adler, buf, len, start); - } - - strm.next_in += len; - strm.total_in += len; - - return len; - } - - - /* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ - function longest_match(s, cur_match) { - var chain_length = s.max_chain_length; /* max hash chain length */ - var scan = s.strstart; /* current string */ - var match; /* matched string */ - var len; /* length of current match */ - var best_len = s.prev_length; /* best match length so far */ - var nice_match = s.nice_match; /* stop if match long enough */ - var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? - s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; - - var _win = s.window; // shortcut - - var wmask = s.w_mask; - var prev = s.prev; - - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - - var strend = s.strstart + MAX_MATCH; - var scan_end1 = _win[scan + best_len - 1]; - var scan_end = _win[scan + best_len]; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s.prev_length >= s.good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if (nice_match > s.lookahead) { nice_match = s.lookahead; } - - // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - // Assert(cur_match < s->strstart, "no future"); - match = cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ - - if (_win[match + best_len] !== scan_end || - _win[match + best_len - 1] !== scan_end1 || - _win[match] !== _win[scan] || - _win[++match] !== _win[scan + 1]) { - continue; - } - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2; - match++; - // Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - /*jshint noempty:false*/ - } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - scan < strend); - - // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) { - s.match_start = cur_match; - best_len = len; - if (len >= nice_match) { - break; - } - scan_end1 = _win[scan + best_len - 1]; - scan_end = _win[scan + best_len]; - } - } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); - - if (best_len <= s.lookahead) { - return best_len; - } - return s.lookahead; - } - - - /* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ - function fill_window(s) { - var _w_size = s.w_size; - var p, n, m, more, str; - - //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = s.window_size - s.lookahead - s.strstart; - - // JS ints have 32 bit, block below not needed - /* Deal with !@#$% 64K limit: */ - //if (sizeof(int) <= 2) { - // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - // more = wsize; - // - // } else if (more == (unsigned)(-1)) { - // /* Very unlikely, but possible on 16 bit machine if - // * strstart == 0 && lookahead == 1 (input done a byte at time) - // */ - // more--; - // } - //} - - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { - - utils.arraySet(s.window, s.window, _w_size, _w_size, 0); - s.match_start -= _w_size; - s.strstart -= _w_size; - /* we now have strstart >= MAX_DIST */ - s.block_start -= _w_size; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - - n = s.hash_size; - p = n; - do { - m = s.head[--p]; - s.head[p] = (m >= _w_size ? m - _w_size : 0); - } while (--n); - - n = _w_size; - p = n; - do { - m = s.prev[--p]; - s.prev[p] = (m >= _w_size ? m - _w_size : 0); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); - - more += _w_size; - } - if (s.strm.avail_in === 0) { - break; - } - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - //Assert(more >= 2, "more < 2"); - n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); - s.lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s.lookahead + s.insert >= MIN_MATCH) { - str = s.strstart - s.insert; - s.ins_h = s.window[str]; - - /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; - //#if MIN_MATCH != 3 - // Call update_hash() MIN_MATCH-3 more times - //#endif - while (s.insert) { - /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; - - s.prev[str & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = str; - str++; - s.insert--; - if (s.lookahead + s.insert < MIN_MATCH) { - break; - } - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ - // if (s.high_water < s.window_size) { - // var curr = s.strstart + s.lookahead; - // var init = 0; - // - // if (s.high_water < curr) { - // /* Previous high water mark below current data -- zero WIN_INIT - // * bytes or up to end of window, whichever is less. - // */ - // init = s.window_size - curr; - // if (init > WIN_INIT) - // init = WIN_INIT; - // zmemzero(s->window + curr, (unsigned)init); - // s->high_water = curr + init; - // } - // else if (s->high_water < (ulg)curr + WIN_INIT) { - // /* High water mark at or above current data, but below current data - // * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up - // * to end of window, whichever is less. - // */ - // init = (ulg)curr + WIN_INIT - s->high_water; - // if (init > s->window_size - s->high_water) - // init = s->window_size - s->high_water; - // zmemzero(s->window + s->high_water, (unsigned)init); - // s->high_water += init; - // } - // } - // - // Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, - // "not enough room for search"); - } - - /* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ - function deflate_stored(s, flush) { - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - var max_block_size = 0xffff; - - if (max_block_size > s.pending_buf_size - 5) { - max_block_size = s.pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (; ;) { - /* Fill the window as much as possible: */ - if (s.lookahead <= 1) { - - //Assert(s->strstart < s->w_size+MAX_DIST(s) || - // s->block_start >= (long)s->w_size, "slide too late"); - // if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || - // s.block_start >= s.w_size)) { - // throw new Error("slide too late"); - // } - - fill_window(s); - if (s.lookahead === 0 && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - - if (s.lookahead === 0) { - break; - } - /* flush the current block */ - } - //Assert(s->block_start >= 0L, "block gone"); - // if (s.block_start < 0) throw new Error("block gone"); - - s.strstart += s.lookahead; - s.lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - var max_start = s.block_start + max_block_size; - - if (s.strstart === 0 || s.strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s.lookahead = s.strstart - max_start; - s.strstart = max_start; - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - - - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - - s.insert = 0; - - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - - if (s.strstart > s.block_start) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - return BS_NEED_MORE; - } - - /* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ - function deflate_fast(s, flush) { - var hash_head; /* head of the hash chain */ - var bflush; /* set if current block must be flushed */ - - for (; ;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; /* flush the current block */ - } - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - } - if (s.match_length >= MIN_MATCH) { - // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only - - /*** _tr_tally_dist(s, s.strstart - s.match_start, - s.match_length - MIN_MATCH, bflush); ***/ - bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); - - s.lookahead -= s.match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { - s.match_length--; /* string at strstart already in table */ - do { - s.strstart++; - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s.match_length !== 0); - s.strstart++; - } else { - s.strstart += s.match_length; - s.match_length = 0; - s.ins_h = s.window[s.strstart]; - /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; - - //#if MIN_MATCH != 3 - // Call UPDATE_HASH() MIN_MATCH-3 more times - //#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s.window[s.strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1); - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; - } - - /* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ - function deflate_slow(s, flush) { - var hash_head; /* head of hash chain */ - var bflush; /* set if current block must be flushed */ - - var max_insert; - - /* Process the input block. */ - for (; ;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - - /* Find the longest match, discarding those <= prev_length. - */ - s.prev_length = s.match_length; - s.prev_match = s.match_start; - s.match_length = MIN_MATCH - 1; - - if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && - s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - - if (s.match_length <= 5 && - (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s.match_length = MIN_MATCH - 1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { - max_insert = s.strstart + s.lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - //check_match(s, s.strstart-1, s.prev_match, s.prev_length); - - /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, - s.prev_length - MIN_MATCH, bflush);***/ - bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s.lookahead -= s.prev_length - 1; - s.prev_length -= 2; - do { - if (++s.strstart <= max_insert) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - } while (--s.prev_length !== 0); - s.match_available = 0; - s.match_length = MIN_MATCH - 1; - s.strstart++; - - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - } else if (s.match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); - - if (bflush) { - /*** FLUSH_BLOCK_ONLY(s, 0) ***/ - flush_block_only(s, false); - /***/ - } - s.strstart++; - s.lookahead--; - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s.match_available = 1; - s.strstart++; - s.lookahead--; - } - } - //Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s.match_available) { - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); - - s.match_available = 0; - } - s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - - return BS_BLOCK_DONE; - } - - - /* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ - function deflate_rle(s, flush) { - var bflush; /* set if current block must be flushed */ - var prev; /* byte at distance one to match */ - var scan, strend; /* scan goes up to strend for length of run */ - - var _win = s.window; - - for (; ;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s.lookahead <= MAX_MATCH) { - fill_window(s); - if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - s.match_length = 0; - if (s.lookahead >= MIN_MATCH && s.strstart > 0) { - scan = s.strstart - 1; - prev = _win[scan]; - if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { - strend = s.strstart + MAX_MATCH; - do { - /*jshint noempty:false*/ - } while (prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - scan < strend); - s.match_length = MAX_MATCH - (strend - scan); - if (s.match_length > s.lookahead) { - s.match_length = s.lookahead; - } - } - //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (s.match_length >= MIN_MATCH) { - //check_match(s, s.strstart, s.strstart - 1, s.match_length); - - /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ - bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); - - s.lookahead -= s.match_length; - s.strstart += s.match_length; - s.match_length = 0; - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; - } - - /* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ - function deflate_huff(s, flush) { - var bflush; /* set if current block must be flushed */ - - for (; ;) { - /* Make sure that we have a literal to write. */ - if (s.lookahead === 0) { - fill_window(s); - if (s.lookahead === 0) { - if (flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - break; /* flush the current block */ - } - } - - /* Output a literal byte */ - s.match_length = 0; - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; - } - - /* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ - function Config(good_length, max_lazy, nice_length, max_chain, func) { - this.good_length = good_length; - this.max_lazy = max_lazy; - this.nice_length = nice_length; - this.max_chain = max_chain; - this.func = func; - } - - var configuration_table; - - configuration_table = [ - /* good lazy nice chain */ - new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ - new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ - new Config(4, 5, 16, 8, deflate_fast), /* 2 */ - new Config(4, 6, 32, 32, deflate_fast), /* 3 */ - - new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ - new Config(8, 16, 32, 32, deflate_slow), /* 5 */ - new Config(8, 16, 128, 128, deflate_slow), /* 6 */ - new Config(8, 32, 128, 256, deflate_slow), /* 7 */ - new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ - new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ - ]; - - - /* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ - function lm_init(s) { - s.window_size = 2 * s.w_size; - - /*** CLEAR_HASH(s); ***/ - zero(s.head); // Fill with NIL (= 0); - - /* Set the default configuration parameters: - */ - s.max_lazy_match = configuration_table[s.level].max_lazy; - s.good_match = configuration_table[s.level].good_length; - s.nice_match = configuration_table[s.level].nice_length; - s.max_chain_length = configuration_table[s.level].max_chain; - - s.strstart = 0; - s.block_start = 0; - s.lookahead = 0; - s.insert = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - s.ins_h = 0; - } - - - function DeflateState() { - this.strm = null; /* pointer back to this zlib stream */ - this.status = 0; /* as the name implies */ - this.pending_buf = null; /* output still pending */ - this.pending_buf_size = 0; /* size of pending_buf */ - this.pending_out = 0; /* next pending byte to output to the stream */ - this.pending = 0; /* nb of bytes in the pending buffer */ - this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ - this.gzhead = null; /* gzip header information to write */ - this.gzindex = 0; /* where in extra, name, or comment */ - this.method = Z_DEFLATED; /* can only be DEFLATED */ - this.last_flush = -1; /* value of flush param for previous deflate call */ - - this.w_size = 0; /* LZ77 window size (32K by default) */ - this.w_bits = 0; /* log2(w_size) (8..16) */ - this.w_mask = 0; /* w_size - 1 */ - - this.window = null; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. - */ - - this.window_size = 0; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - this.prev = null; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - this.head = null; /* Heads of the hash chains or NIL. */ - - this.ins_h = 0; /* hash index of string to be inserted */ - this.hash_size = 0; /* number of elements in hash table */ - this.hash_bits = 0; /* log2(hash_size) */ - this.hash_mask = 0; /* hash_size-1 */ - - this.hash_shift = 0; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - this.block_start = 0; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - this.match_length = 0; /* length of best match */ - this.prev_match = 0; /* previous match */ - this.match_available = 0; /* set if previous match exists */ - this.strstart = 0; /* start of string to insert */ - this.match_start = 0; /* start of matching string */ - this.lookahead = 0; /* number of valid bytes ahead in window */ - - this.prev_length = 0; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - this.max_chain_length = 0; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - this.max_lazy_match = 0; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ - // That's alias to max_lazy_match, don't use directly - //this.max_insert_length = 0; - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - this.level = 0; /* compression level (1..9) */ - this.strategy = 0; /* favor or force Huffman coding*/ - - this.good_match = 0; - /* Use a faster search when the previous match is longer than this */ - - this.nice_match = 0; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - - /* Didn't use ct_data typedef below to suppress compiler warning */ - - // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - // Use flat array of DOUBLE size, with interleaved fata, - // because JS does not support effective - this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); - this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2); - this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2); - zero(this.dyn_ltree); - zero(this.dyn_dtree); - zero(this.bl_tree); - - this.l_desc = null; /* desc. for literal tree */ - this.d_desc = null; /* desc. for distance tree */ - this.bl_desc = null; /* desc. for bit length tree */ - - //ush bl_count[MAX_BITS+1]; - this.bl_count = new utils.Buf16(MAX_BITS + 1); - /* number of codes at each bit length for an optimal tree */ - - //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - this.heap = new utils.Buf16(2 * L_CODES + 1); /* heap used to build the Huffman trees */ - zero(this.heap); - - this.heap_len = 0; /* number of elements in the heap */ - this.heap_max = 0; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; - zero(this.depth); - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - this.l_buf = 0; /* buffer index for literals or lengths */ - - this.lit_bufsize = 0; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - this.last_lit = 0; /* running index in l_buf */ - - this.d_buf = 0; - /* Buffer index for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - this.opt_len = 0; /* bit length of current block with optimal trees */ - this.static_len = 0; /* bit length of current block with static trees */ - this.matches = 0; /* number of string matches in current block */ - this.insert = 0; /* bytes at end of window left to insert */ - - - this.bi_buf = 0; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - this.bi_valid = 0; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - - // Used for window memory init. We safely ignore it for JS. That makes - // sense only for pointers and memory check tools. - //this.high_water = 0; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ - } - - - function deflateResetKeep(strm) { - var s; - - if (!strm || !strm.state) { - return err(strm, Z_STREAM_ERROR); - } - - strm.total_in = strm.total_out = 0; - strm.data_type = Z_UNKNOWN; - - s = strm.state; - s.pending = 0; - s.pending_out = 0; - - if (s.wrap < 0) { - s.wrap = -s.wrap; - /* was made negative by deflate(..., Z_FINISH); */ - } - s.status = (s.wrap ? INIT_STATE : BUSY_STATE); - strm.adler = (s.wrap === 2) ? - 0 // crc32(0, Z_NULL, 0) - : - 1; // adler32(0, Z_NULL, 0) - s.last_flush = Z_NO_FLUSH; - trees._tr_init(s); - return Z_OK; - } - - - function deflateReset(strm) { - var ret = deflateResetKeep(strm); - if (ret === Z_OK) { - lm_init(strm.state); - } - return ret; - } - - - function deflateSetHeader(strm, head) { - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } - strm.state.gzhead = head; - return Z_OK; - } - - - function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { - if (!strm) { // === Z_NULL - return Z_STREAM_ERROR; - } - var wrap = 1; - - if (level === Z_DEFAULT_COMPRESSION) { - level = 6; - } - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } - - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } - - - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return err(strm, Z_STREAM_ERROR); - } - - - if (windowBits === 8) { - windowBits = 9; - } - /* until 256-byte window bug fixed */ - - var s = new DeflateState(); - - strm.state = s; - s.strm = strm; - - s.wrap = wrap; - s.gzhead = null; - s.w_bits = windowBits; - s.w_size = 1 << s.w_bits; - s.w_mask = s.w_size - 1; - - s.hash_bits = memLevel + 7; - s.hash_size = 1 << s.hash_bits; - s.hash_mask = s.hash_size - 1; - s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); - - s.window = new utils.Buf8(s.w_size * 2); - s.head = new utils.Buf16(s.hash_size); - s.prev = new utils.Buf16(s.w_size); - - // Don't need mem init magic for JS. - //s.high_water = 0; /* nothing written to s->window yet */ - - s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - s.pending_buf_size = s.lit_bufsize * 4; - - //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - //s->pending_buf = (uchf *) overlay; - s.pending_buf = new utils.Buf8(s.pending_buf_size); - - // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) - //s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s.d_buf = 1 * s.lit_bufsize; - - //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - s.l_buf = (1 + 2) * s.lit_bufsize; - - s.level = level; - s.strategy = strategy; - s.method = method; - - return deflateReset(strm); - } - - function deflateInit(strm, level) { - return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); - } - - - function deflate(strm, flush) { - var old_flush, s; - var beg, val; // for gzip header write only - - if (!strm || !strm.state || - flush > Z_BLOCK || flush < 0) { - return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; - } - - s = strm.state; - - if (!strm.output || - (!strm.input && strm.avail_in !== 0) || - (s.status === FINISH_STATE && flush !== Z_FINISH)) { - return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); - } - - s.strm = strm; /* just in case */ - old_flush = s.last_flush; - s.last_flush = flush; - - /* Write the header */ - if (s.status === INIT_STATE) { - - if (s.wrap === 2) { // GZIP header - strm.adler = 0; //crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (!s.gzhead) { // s->gzhead == Z_NULL - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s.status = BUSY_STATE; - } - else { - put_byte(s, (s.gzhead.text ? 1 : 0) + - (s.gzhead.hcrc ? 2 : 0) + - (!s.gzhead.extra ? 0 : 4) + - (!s.gzhead.name ? 0 : 8) + - (!s.gzhead.comment ? 0 : 16) - ); - put_byte(s, s.gzhead.time & 0xff); - put_byte(s, (s.gzhead.time >> 8) & 0xff); - put_byte(s, (s.gzhead.time >> 16) & 0xff); - put_byte(s, (s.gzhead.time >> 24) & 0xff); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, s.gzhead.os & 0xff); - if (s.gzhead.extra && s.gzhead.extra.length) { - put_byte(s, s.gzhead.extra.length & 0xff); - put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); - } - if (s.gzhead.hcrc) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); - } - s.gzindex = 0; - s.status = EXTRA_STATE; - } - } - else // DEFLATE header - { - var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; - var level_flags = -1; - - if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { - level_flags = 0; - } else if (s.level < 6) { - level_flags = 1; - } else if (s.level === 6) { - level_flags = 2; - } else { - level_flags = 3; - } - header |= (level_flags << 6); - if (s.strstart !== 0) { header |= PRESET_DICT; } - header += 31 - (header % 31); - - s.status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s.strstart !== 0) { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } - strm.adler = 1; // adler32(0L, Z_NULL, 0); - } - } - - //#ifdef GZIP - if (s.status === EXTRA_STATE) { - if (s.gzhead.extra/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - - while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - break; - } - } - put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); - s.gzindex++; - } - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (s.gzindex === s.gzhead.extra.length) { - s.gzindex = 0; - s.status = NAME_STATE; - } - } - else { - s.status = NAME_STATE; - } - } - if (s.status === NAME_STATE) { - if (s.gzhead.name/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - //int val; - - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.name.length) { - val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.gzindex = 0; - s.status = COMMENT_STATE; - } - } - else { - s.status = COMMENT_STATE; - } - } - if (s.status === COMMENT_STATE) { - if (s.gzhead.comment/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - //int val; - - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.comment.length) { - val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); - - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.status = HCRC_STATE; - } - } - else { - s.status = HCRC_STATE; - } - } - if (s.status === HCRC_STATE) { - if (s.gzhead.hcrc) { - if (s.pending + 2 > s.pending_buf_size) { - flush_pending(strm); - } - if (s.pending + 2 <= s.pending_buf_size) { - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - strm.adler = 0; //crc32(0L, Z_NULL, 0); - s.status = BUSY_STATE; - } - } - else { - s.status = BUSY_STATE; - } - } - //#endif - - /* Flush as much pending output as possible */ - if (s.pending !== 0) { - flush_pending(strm); - if (strm.avail_out === 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s.last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && - flush !== Z_FINISH) { - return err(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s.status === FINISH_STATE && strm.avail_in !== 0) { - return err(strm, Z_BUF_ERROR); - } - - /* Start a new block or continue the current one. - */ - if (strm.avail_in !== 0 || s.lookahead !== 0 || - (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { - var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : - (s.strategy === Z_RLE ? deflate_rle(s, flush) : - configuration_table[s.level].func(s, flush)); - - if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { - s.status = FINISH_STATE; - } - if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { - if (strm.avail_out === 0) { - s.last_flush = -1; - /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate === BS_BLOCK_DONE) { - if (flush === Z_PARTIAL_FLUSH) { - trees._tr_align(s); - } - else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ - - trees._tr_stored_block(s, 0, 0, false); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush === Z_FULL_FLUSH) { - /*** CLEAR_HASH(s); ***/ /* forget history */ - zero(s.head); // Fill with NIL (= 0); - - if (s.lookahead === 0) { - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - } - } - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - //Assert(strm->avail_out > 0, "bug2"); - //if (strm.avail_out <= 0) { throw new Error("bug2");} - - if (flush !== Z_FINISH) { return Z_OK; } - if (s.wrap <= 0) { return Z_STREAM_END; } - - /* Write the trailer */ - if (s.wrap === 2) { - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - put_byte(s, (strm.adler >> 16) & 0xff); - put_byte(s, (strm.adler >> 24) & 0xff); - put_byte(s, strm.total_in & 0xff); - put_byte(s, (strm.total_in >> 8) & 0xff); - put_byte(s, (strm.total_in >> 16) & 0xff); - put_byte(s, (strm.total_in >> 24) & 0xff); - } - else { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } - - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s.wrap > 0) { s.wrap = -s.wrap; } - /* write the trailer only once! */ - return s.pending !== 0 ? Z_OK : Z_STREAM_END; - } - - function deflateEnd(strm) { - var status; - - if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { - return Z_STREAM_ERROR; - } - - status = strm.state.status; - if (status !== INIT_STATE && - status !== EXTRA_STATE && - status !== NAME_STATE && - status !== COMMENT_STATE && - status !== HCRC_STATE && - status !== BUSY_STATE && - status !== FINISH_STATE - ) { - return err(strm, Z_STREAM_ERROR); - } - - strm.state = null; - - return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; - } - - - /* ========================================================================= - * Initializes the compression dictionary from the given byte - * sequence without producing any compressed output. - */ - function deflateSetDictionary(strm, dictionary) { - var dictLength = dictionary.length; - - var s; - var str, n; - var wrap; - var avail; - var next; - var input; - var tmpDict; - - if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { - return Z_STREAM_ERROR; - } - - s = strm.state; - wrap = s.wrap; - - if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) { - return Z_STREAM_ERROR; - } - - /* when using zlib wrappers, compute Adler-32 for provided dictionary */ - if (wrap === 1) { - /* adler32(strm->adler, dictionary, dictLength); */ - strm.adler = adler32(strm.adler, dictionary, dictLength, 0); - } - - s.wrap = 0; /* avoid computing Adler-32 in read_buf */ - - /* if dictionary would fill window, just replace the history */ - if (dictLength >= s.w_size) { - if (wrap === 0) { /* already empty otherwise */ - /*** CLEAR_HASH(s); ***/ - zero(s.head); // Fill with NIL (= 0); - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - /* use the tail */ - // dictionary = dictionary.slice(dictLength - s.w_size); - tmpDict = new utils.Buf8(s.w_size); - utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0); - dictionary = tmpDict; - dictLength = s.w_size; - } - /* insert dictionary into window and hash */ - avail = strm.avail_in; - next = strm.next_in; - input = strm.input; - strm.avail_in = dictLength; - strm.next_in = 0; - strm.input = dictionary; - fill_window(s); - while (s.lookahead >= MIN_MATCH) { - str = s.strstart; - n = s.lookahead - (MIN_MATCH - 1); - do { - /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; - - s.prev[str & s.w_mask] = s.head[s.ins_h]; - - s.head[s.ins_h] = str; - str++; - } while (--n); - s.strstart = str; - s.lookahead = MIN_MATCH - 1; - fill_window(s); - } - s.strstart += s.lookahead; - s.block_start = s.strstart; - s.insert = s.lookahead; - s.lookahead = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - strm.next_in = next; - strm.input = input; - strm.avail_in = avail; - s.wrap = wrap; - return Z_OK; - } - - - exports.deflateInit = deflateInit; - exports.deflateInit2 = deflateInit2; - exports.deflateReset = deflateReset; - exports.deflateResetKeep = deflateResetKeep; - exports.deflateSetHeader = deflateSetHeader; - exports.deflate = deflate; - exports.deflateEnd = deflateEnd; - exports.deflateSetDictionary = deflateSetDictionary; - exports.deflateInfo = 'pako deflate (from Nodeca project)'; - - /* Not implemented - exports.deflateBound = deflateBound; - exports.deflateCopy = deflateCopy; - exports.deflateParams = deflateParams; - exports.deflatePending = deflatePending; - exports.deflatePrime = deflatePrime; - exports.deflateTune = deflateTune; - */ - - }, { "../utils/common": 28, "./adler32": 30, "./crc32": 32, "./messages": 38, "./trees": 39 }], 34: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - 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; - - }, {}], 35: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - // 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 defaults, - // 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; - }; - - }, {}], 36: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - 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 convenient 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 defaults, - // 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 '|' instead 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)) { - state.mode = MEM; - return Z_MEM_ERROR; - } - } - _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": 28, "./adler32": 30, "./crc32": 32, "./inffast": 35, "./inftrees": 37 }], 37: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - 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": 28 }], 38: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - 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) */ - }; - - }, {}], 39: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - /* eslint-disable space-unary-ops */ - - var utils = require('../utils/common'); - - /* Public constants ==========================================================*/ - /* ===========================================================================*/ - - - //var Z_FILTERED = 1; - //var Z_HUFFMAN_ONLY = 2; - //var Z_RLE = 3; - var Z_FIXED = 4; - //var Z_DEFAULT_STRATEGY = 0; - - /* Possible values of the data_type field (though see inflate()) */ - var Z_BINARY = 0; - var Z_TEXT = 1; - //var Z_ASCII = 1; // = Z_TEXT - var Z_UNKNOWN = 2; - - /*============================================================================*/ - - - function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } - - // From zutil.h - - var STORED_BLOCK = 0; - var STATIC_TREES = 1; - var DYN_TREES = 2; - /* The three kinds of block type */ - - var MIN_MATCH = 3; - var MAX_MATCH = 258; - /* The minimum and maximum match lengths */ - - // From deflate.h - /* =========================================================================== - * Internal compression state. - */ - - var LENGTH_CODES = 29; - /* number of length codes, not counting the special END_BLOCK code */ - - var LITERALS = 256; - /* number of literal bytes 0..255 */ - - var L_CODES = LITERALS + 1 + LENGTH_CODES; - /* number of Literal or Length codes, including the END_BLOCK code */ - - var D_CODES = 30; - /* number of distance codes */ - - var BL_CODES = 19; - /* number of codes used to transfer the bit lengths */ - - var HEAP_SIZE = 2 * L_CODES + 1; - /* maximum heap size */ - - var MAX_BITS = 15; - /* All codes must not exceed MAX_BITS bits */ - - var Buf_size = 16; - /* size of bit buffer in bi_buf */ - - - /* =========================================================================== - * Constants - */ - - var MAX_BL_BITS = 7; - /* Bit length codes must not exceed MAX_BL_BITS bits */ - - var END_BLOCK = 256; - /* end of block literal code */ - - var REP_3_6 = 16; - /* repeat previous bit length 3-6 times (2 bits of repeat count) */ - - var REPZ_3_10 = 17; - /* repeat a zero length 3-10 times (3 bits of repeat count) */ - - var REPZ_11_138 = 18; - /* repeat a zero length 11-138 times (7 bits of repeat count) */ - - /* eslint-disable comma-spacing,array-bracket-spacing */ - var extra_lbits = /* extra bits for each length code */ - [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0]; - - var extra_dbits = /* extra bits for each distance code */ - [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13]; - - var extra_blbits = /* extra bits for each bit length code */ - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]; - - var bl_order = - [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; - /* eslint-enable comma-spacing,array-bracket-spacing */ - - /* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - - /* =========================================================================== - * Local data. These are initialized only once. - */ - - // We pre-fill arrays with 0 to avoid uninitialized gaps - - var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ - - // !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 - var static_ltree = new Array((L_CODES + 2) * 2); - zero(static_ltree); - /* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - - var static_dtree = new Array(D_CODES * 2); - zero(static_dtree); - /* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - - var _dist_code = new Array(DIST_CODE_LEN); - zero(_dist_code); - /* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - - var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1); - zero(_length_code); - /* length code for each normalized match length (0 == MIN_MATCH) */ - - var base_length = new Array(LENGTH_CODES); - zero(base_length); - /* First normalized length for each code (0 = MIN_MATCH) */ - - var base_dist = new Array(D_CODES); - zero(base_dist); - /* First normalized distance for each code (0 = distance of 1) */ - - - function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { - - this.static_tree = static_tree; /* static tree or NULL */ - this.extra_bits = extra_bits; /* extra bits for each code or NULL */ - this.extra_base = extra_base; /* base index for extra_bits */ - this.elems = elems; /* max number of elements in the tree */ - this.max_length = max_length; /* max bit length for the codes */ - - // show if `static_tree` has data or dummy - needed for monomorphic objects - this.has_stree = static_tree && static_tree.length; - } - - - var static_l_desc; - var static_d_desc; - var static_bl_desc; - - - function TreeDesc(dyn_tree, stat_desc) { - this.dyn_tree = dyn_tree; /* the dynamic tree */ - this.max_code = 0; /* largest code with non zero frequency */ - this.stat_desc = stat_desc; /* the corresponding static tree */ - } - - - - function d_code(dist) { - return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; - } - - - /* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ - function put_short(s, w) { - // put_byte(s, (uch)((w) & 0xff)); - // put_byte(s, (uch)((ush)(w) >> 8)); - s.pending_buf[s.pending++] = (w) & 0xff; - s.pending_buf[s.pending++] = (w >>> 8) & 0xff; - } - - - /* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ - function send_bits(s, value, length) { - if (s.bi_valid > (Buf_size - length)) { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - put_short(s, s.bi_buf); - s.bi_buf = value >> (Buf_size - s.bi_valid); - s.bi_valid += length - Buf_size; - } else { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - s.bi_valid += length; - } - } - - - function send_code(s, c, tree) { - send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/); - } - - - /* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ - function bi_reverse(code, len) { - var res = 0; - do { - res |= code & 1; - code >>>= 1; - res <<= 1; - } while (--len > 0); - return res >>> 1; - } - - - /* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ - function bi_flush(s) { - if (s.bi_valid === 16) { - put_short(s, s.bi_buf); - s.bi_buf = 0; - s.bi_valid = 0; - - } else if (s.bi_valid >= 8) { - s.pending_buf[s.pending++] = s.bi_buf & 0xff; - s.bi_buf >>= 8; - s.bi_valid -= 8; - } - } - - - /* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ - function gen_bitlen(s, desc) - // deflate_state *s; - // tree_desc *desc; /* the tree descriptor */ - { - var tree = desc.dyn_tree; - var max_code = desc.max_code; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var extra = desc.stat_desc.extra_bits; - var base = desc.stat_desc.extra_base; - var max_length = desc.stat_desc.max_length; - var h; /* heap index */ - var n, m; /* iterate over the tree elements */ - var bits; /* bit length */ - var xbits; /* extra bits */ - var f; /* frequency */ - var overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) { - s.bl_count[bits] = 0; - } - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */ - - for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { - n = s.heap[h]; - bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; - if (bits > max_length) { - bits = max_length; - overflow++; - } - tree[n * 2 + 1]/*.Len*/ = bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) { continue; } /* not a leaf node */ - - s.bl_count[bits]++; - xbits = 0; - if (n >= base) { - xbits = extra[n - base]; - } - f = tree[n * 2]/*.Freq*/; - s.opt_len += f * (bits + xbits); - if (has_stree) { - s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits); - } - } - if (overflow === 0) { return; } - - // Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length - 1; - while (s.bl_count[bits] === 0) { bits--; } - s.bl_count[bits]--; /* move one leaf down the tree */ - s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ - s.bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits !== 0; bits--) { - n = s.bl_count[bits]; - while (n !== 0) { - m = s.heap[--h]; - if (m > max_code) { continue; } - if (tree[m * 2 + 1]/*.Len*/ !== bits) { - // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/; - tree[m * 2 + 1]/*.Len*/ = bits; - } - n--; - } - } - } - - - /* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ - function gen_codes(tree, max_code, bl_count) - // ct_data *tree; /* the tree to decorate */ - // int max_code; /* largest code with non zero frequency */ - // ushf *bl_count; /* number of codes at each bit length */ - { - var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */ - var code = 0; /* running code value */ - var bits; /* bit index */ - var n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits - 1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES - 1; code++) { - base_length[code] = length; - for (n = 0; n < (1 << extra_lbits[code]); n++) { - _length_code[length++] = code; - } - } - //Assert (length == 256, "tr_static_init: length != 256"); - /* Note that the length 255 (match length 258) can be represented - * in two different ways: code 284 + 5 bits or code 285, so we - * overwrite length_code[255] to use the best encoding: - */ - _length_code[length - 1] = code; - - /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ - dist = 0; - for (code = 0; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1 << extra_dbits[code]); n++) { - _dist_code[dist++] = code; - } - } - //Assert (dist == 256, "tr_static_init: dist != 256"); - dist >>= 7; /* from now on, all distances are divided by 128 */ - for (; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { - _dist_code[256 + dist++] = code; - } - } - //Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) { - bl_count[bits] = 0; - } - - n = 0; - while (n <= 143) { - static_ltree[n * 2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - while (n <= 255) { - static_ltree[n * 2 + 1]/*.Len*/ = 9; - n++; - bl_count[9]++; - } - while (n <= 279) { - static_ltree[n * 2 + 1]/*.Len*/ = 7; - n++; - bl_count[7]++; - } - while (n <= 287) { - static_ltree[n * 2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes(static_ltree, L_CODES + 1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n * 2 + 1]/*.Len*/ = 5; - static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5); - } - - // Now data ready and we can init static trees - static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS); - static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); - static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); - - //static_init_done = true; - } - - - /* =========================================================================== - * Initialize a new block. - */ - function init_block(s) { - var n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; } - for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; } - for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; } - - s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1; - s.opt_len = s.static_len = 0; - s.last_lit = s.matches = 0; - } - - - /* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ - function bi_windup(s) { - if (s.bi_valid > 8) { - put_short(s, s.bi_buf); - } else if (s.bi_valid > 0) { - //put_byte(s, (Byte)s->bi_buf); - s.pending_buf[s.pending++] = s.bi_buf; - } - s.bi_buf = 0; - s.bi_valid = 0; - } - - /* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ - function copy_block(s, buf, len, header) - //DeflateState *s; - //charf *buf; /* the input data */ - //unsigned len; /* its length */ - //int header; /* true if block header must be written */ - { - bi_windup(s); /* align on byte boundary */ - - if (header) { - put_short(s, len); - put_short(s, ~len); - } - // while (len--) { - // put_byte(s, *buf++); - // } - utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); - s.pending += len; - } - - /* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ - function smaller(tree, n, m, depth) { - var _n2 = n * 2; - var _m2 = m * 2; - return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || - (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); - } - - /* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ - function pqdownheap(s, tree, k) - // deflate_state *s; - // ct_data *tree; /* the tree to restore */ - // int k; /* node to move down */ - { - var v = s.heap[k]; - var j = k << 1; /* left son of k */ - while (j <= s.heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s.heap_len && - smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s.heap[j], s.depth)) { break; } - - /* Exchange v with the smallest son */ - s.heap[k] = s.heap[j]; - k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s.heap[k] = v; - } - - - // inlined manually - // var SMALLEST = 1; - - /* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ - function compress_block(s, ltree, dtree) - // deflate_state *s; - // const ct_data *ltree; /* literal tree */ - // const ct_data *dtree; /* distance tree */ - { - var dist; /* distance of matched string */ - var lc; /* match length or unmatched char (if dist == 0) */ - var lx = 0; /* running index in l_buf */ - var code; /* the code to send */ - var extra; /* number of extra bits to send */ - - if (s.last_lit !== 0) { - do { - dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]); - lc = s.pending_buf[s.l_buf + lx]; - lx++; - - if (dist === 0) { - send_code(s, lc, ltree); /* send a literal byte */ - //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code + LITERALS + 1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra !== 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - //Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra !== 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - // "pendingBuf overflow"); - - } while (lx < s.last_lit); - } - - send_code(s, END_BLOCK, ltree); - } - - - /* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ - function build_tree(s, desc) - // deflate_state *s; - // tree_desc *desc; /* the tree descriptor */ - { - var tree = desc.dyn_tree; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var elems = desc.stat_desc.elems; - var n, m; /* iterate over heap elements */ - var max_code = -1; /* largest code with non zero frequency */ - var node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s.heap_len = 0; - s.heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n * 2]/*.Freq*/ !== 0) { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - - } else { - tree[n * 2 + 1]/*.Len*/ = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s.heap_len < 2) { - node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); - tree[node * 2]/*.Freq*/ = 1; - s.depth[node] = 0; - s.opt_len--; - - if (has_stree) { - s.static_len -= stree[node * 2 + 1]/*.Len*/; - } - /* node is 0 or 1 so it does not have extra bits */ - } - desc.max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - //pqremove(s, tree, n); /* n = node of least frequency */ - /*** pqremove ***/ - n = s.heap[1/*SMALLEST*/]; - s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; - pqdownheap(s, tree, 1/*SMALLEST*/); - /***/ - - m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ - - s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ - s.heap[--s.heap_max] = m; - - /* Create a new node father of n and m */ - tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; - s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; - tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node; - - /* and insert the new node in the heap */ - s.heap[1/*SMALLEST*/] = node++; - pqdownheap(s, tree, 1/*SMALLEST*/); - - } while (s.heap_len >= 2); - - s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes(tree, max_code, s.bl_count); - } - - - /* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ - function scan_tree(s, tree, max_code) - // deflate_state *s; - // ct_data *tree; /* the tree to be scanned */ - // int max_code; /* and its largest code of non zero frequency */ - { - var n; /* iterates over all tree elements */ - var prevlen = -1; /* last emitted length */ - var curlen; /* length of current code */ - - var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ - - var count = 0; /* repeat count of the current code */ - var max_count = 7; /* max repeat count */ - var min_count = 4; /* min repeat count */ - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; - - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - s.bl_tree[curlen * 2]/*.Freq*/ += count; - - } else if (curlen !== 0) { - - if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } - s.bl_tree[REP_3_6 * 2]/*.Freq*/++; - - } else if (count <= 10) { - s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++; - - } else { - s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++; - } - - count = 0; - prevlen = curlen; - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - - } else { - max_count = 7; - min_count = 4; - } - } - } - - - /* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ - function send_tree(s, tree, max_code) - // deflate_state *s; - // ct_data *tree; /* the tree to be scanned */ - // int max_code; /* and its largest code of non zero frequency */ - { - var n; /* iterates over all tree elements */ - var prevlen = -1; /* last emitted length */ - var curlen; /* length of current code */ - - var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ - - var count = 0; /* repeat count of the current code */ - var max_count = 7; /* max repeat count */ - var min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; - - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); - - } else if (curlen !== 0) { - if (curlen !== prevlen) { - send_code(s, curlen, s.bl_tree); - count--; - } - //Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s.bl_tree); - send_bits(s, count - 3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s.bl_tree); - send_bits(s, count - 3, 3); - - } else { - send_code(s, REPZ_11_138, s.bl_tree); - send_bits(s, count - 11, 7); - } - - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - - } else { - max_count = 7; - min_count = 4; - } - } - } - - - /* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ - function build_bl_tree(s) { - var max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, s.dyn_ltree, s.l_desc.max_code); - scan_tree(s, s.dyn_dtree, s.d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, s.bl_desc); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { - if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) { - break; - } - } - /* Update opt_len to include the bit length tree and counts */ - s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - // s->opt_len, s->static_len)); - - return max_blindex; - } - - - /* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ - function send_all_trees(s, lcodes, dcodes, blcodes) - // deflate_state *s; - // int lcodes, dcodes, blcodes; /* number of codes for each tree */ - { - var rank; /* index in bl_order */ - - //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - // "too many codes"); - //Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes - 1, 5); - send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3); - } - //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */ - //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */ - //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); - } - - - /* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "black list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ - function detect_data_type(s) { - /* black_mask is the bit mask of black-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - var black_mask = 0xf3ffc07f; - var n; - - /* Check for non-textual ("black-listed") bytes. */ - for (n = 0; n <= 31; n++, black_mask >>>= 1) { - if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) { - return Z_BINARY; - } - } - - /* Check for textual ("white-listed") bytes. */ - if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || - s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { - return Z_TEXT; - } - for (n = 32; n < LITERALS; n++) { - if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { - return Z_TEXT; - } - } - - /* There are no "black-listed" or "white-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; - } - - - var static_init_done = false; - - /* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ - function _tr_init(s) { - - if (!static_init_done) { - tr_static_init(); - static_init_done = true; - } - - s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); - s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); - s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); - - s.bi_buf = 0; - s.bi_valid = 0; - - /* Initialize the first block of the first file: */ - init_block(s); - } - - - /* =========================================================================== - * Send a stored block - */ - function _tr_stored_block(s, buf, stored_len, last) - //DeflateState *s; - //charf *buf; /* input block */ - //ulg stored_len; /* length of input block */ - //int last; /* one if this is the last block for a file */ - { - send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */ - copy_block(s, buf, stored_len, true); /* with header */ - } - - - /* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - */ - function _tr_align(s) { - send_bits(s, STATIC_TREES << 1, 3); - send_code(s, END_BLOCK, static_ltree); - bi_flush(s); - } - - - /* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ - function _tr_flush_block(s, buf, stored_len, last) - //DeflateState *s; - //charf *buf; /* input block, or NULL if too old */ - //ulg stored_len; /* length of input block */ - //int last; /* one if this is the last block for a file */ - { - var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - var max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s.level > 0) { - - /* Check if the file is binary or text */ - if (s.strm.data_type === Z_UNKNOWN) { - s.strm.data_type = detect_data_type(s); - } - - /* Construct the literal and distance trees */ - build_tree(s, s.l_desc); - // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); - - build_tree(s, s.d_desc); - // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s.opt_len + 3 + 7) >>> 3; - static_lenb = (s.static_len + 3 + 7) >>> 3; - - // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - // s->last_lit)); - - if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } - - } else { - // Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - - if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) { - /* 4: two words for the lengths */ - - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, last); - - } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { - - send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); - compress_block(s, static_ltree, static_dtree); - - } else { - send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); - send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); - compress_block(s, s.dyn_ltree, s.dyn_dtree); - } - // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (last) { - bi_windup(s); - } - // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - // s->compressed_len-7*last)); - } - - /* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ - function _tr_tally(s, dist, lc) - // deflate_state *s; - // unsigned dist; /* distance of matched string */ - // unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ - { - //var out_length, in_length, dcode; - - s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; - s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; - - s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; - s.last_lit++; - - if (dist === 0) { - /* lc is the unmatched char */ - s.dyn_ltree[lc * 2]/*.Freq*/++; - } else { - s.matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - //Assert((ush)dist < (ush)MAX_DIST(s) && - // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++; - s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; - } - - // (!) This block is disabled in zlib defaults, - // don't enable it for binary compatibility - - //#ifdef TRUNCATE_BLOCK - // /* Try to guess if it is profitable to stop the current block here */ - // if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { - // /* Compute an upper bound for the compressed length */ - // out_length = s.last_lit*8; - // in_length = s.strstart - s.block_start; - // - // for (dcode = 0; dcode < D_CODES; dcode++) { - // out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); - // } - // out_length >>>= 3; - // //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - // // s->last_lit, in_length, out_length, - // // 100L - out_length*100L/in_length)); - // if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { - // return true; - // } - // } - //#endif - - return (s.last_lit === s.lit_bufsize - 1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ - } - - exports._tr_init = _tr_init; - exports._tr_stored_block = _tr_stored_block; - exports._tr_flush_block = _tr_flush_block; - exports._tr_tally = _tr_tally; - exports._tr_align = _tr_align; - - }, { "../utils/common": 28 }], 40: [function (require, module, exports) { - 'use strict'; - - // (C) 1995-2013 Jean-loup Gailly and Mark Adler - // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin - // - // This software is provided 'as-is', without any express or implied - // warranty. In no event will the authors be held liable for any damages - // arising from the use of this software. - // - // Permission is granted to anyone to use this software for any purpose, - // including commercial applications, and to alter it and redistribute it - // freely, subject to the following restrictions: - // - // 1. The origin of this software must not be misrepresented; you must not - // claim that you wrote the original software. If you use this software - // in a product, an acknowledgment in the product documentation would be - // appreciated but is not required. - // 2. Altered source versions must be plainly marked as such, and must not be - // misrepresented as being the original software. - // 3. This notice may not be removed or altered from any source distribution. - - 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; - - }, {}] - }, {}, [10])(10) -}); +// @ts-nocheck +/*! + +JSZip - A Javascript class for generating and reading zip files + + +(c) 2009-2014 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/master/LICENSE +*/ +/** + * @type { typeof import('@types/jszip') } + */ +( + function (f) { + if (typeof exports === "object" && typeof module !== "undefined") { + module.exports = f(); + } else if (typeof define === "function" && define.amd) { + define([], f); + } else { + var g; + if (typeof window !== "undefined") { + g = window; + } else if (typeof global !== "undefined") { + g = global; + } else if (typeof self !== "undefined") { + g = self; + } else { + g = this; + } + g.JSZip = f(); + } + } +)(function () { + var define, module, exports; + 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 < r.length; o++) s(r[o]); + return s; + })( + { + 1: [ + function (require, module, exports) { + "use strict"; + var DataReader = require("./dataReader"); + + function ArrayReader(data) { + if (data) { + this.data = data; + this.length = this.data.length; + this.index = 0; + this.zero = 0; + + for (var i = 0; i < this.data.length; i++) { + data[i] = data[i] & 0xff; + } + } + } + ArrayReader.prototype = new DataReader(); + /** + * @see DataReader.byteAt + */ + ArrayReader.prototype.byteAt = function (i) { + return this.data[this.zero + i]; + }; + /** + * @see DataReader.lastIndexOfSignature + */ + ArrayReader.prototype.lastIndexOfSignature = function ( + sig + ) { + var sig0 = sig.charCodeAt(0), + sig1 = sig.charCodeAt(1), + sig2 = sig.charCodeAt(2), + sig3 = sig.charCodeAt(3); + for (var i = this.length - 4; i >= 0; --i) { + if ( + this.data[i] === sig0 && + this.data[i + 1] === sig1 && + this.data[i + 2] === sig2 && + this.data[i + 3] === sig3 + ) { + return i - this.zero; + } + } + + return -1; + }; + /** + * @see DataReader.readData + */ + ArrayReader.prototype.readData = function (size) { + this.checkOffset(size); + if (size === 0) { + return []; + } + var result = this.data.slice( + this.zero + this.index, + this.zero + this.index + size + ); + this.index += size; + return result; + }; + module.exports = ArrayReader; + }, + { "./dataReader": 6 }, + ], + 2: [ + function (require, module, exports) { + "use strict"; + // private property + var _keyStr = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + // public method for encoding + exports.encode = function (input, utf8) { + var output = ""; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 0; + + while (i < input.length) { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = + output + + _keyStr.charAt(enc1) + + _keyStr.charAt(enc2) + + _keyStr.charAt(enc3) + + _keyStr.charAt(enc4); + } + + return output; + }; + + // public method for decoding + exports.decode = function (input, utf8) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + while (i < input.length) { + enc1 = _keyStr.indexOf(input.charAt(i++)); + enc2 = _keyStr.indexOf(input.charAt(i++)); + enc3 = _keyStr.indexOf(input.charAt(i++)); + enc4 = _keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + } + + return output; + }; + }, + {}, + ], + 3: [ + function (require, module, exports) { + "use strict"; + function CompressedObject() { + this.compressedSize = 0; + this.uncompressedSize = 0; + this.crc32 = 0; + this.compressionMethod = null; + this.compressedContent = null; + } + + CompressedObject.prototype = { + /** + * Return the decompressed content in an unspecified format. + * The format will depend on the decompressor. + * @return {Object} the decompressed content. + */ + getContent: function () { + return null; // see implementation + }, + /** + * Return the compressed content in an unspecified format. + * The format will depend on the compressed conten source. + * @return {Object} the compressed content. + */ + getCompressedContent: function () { + return null; // see implementation + }, + }; + module.exports = CompressedObject; + }, + {}, + ], + 4: [ + function (require, module, exports) { + "use strict"; + exports.STORE = { + magic: "\x00\x00", + compress: function (content, compressionOptions) { + return content; // no compression + }, + uncompress: function (content) { + return content; // no compression + }, + compressInputType: null, + uncompressInputType: null, + }; + exports.DEFLATE = require("./flate"); + }, + { "./flate": 9 }, + ], + 5: [ + function (require, module, exports) { + "use strict"; + + var utils = require("./utils"); + + var table = [ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, + ]; + + /** + * + * Javascript crc32 + * http://www.webtoolkit.info/ + * + */ + module.exports = function crc32(input, crc) { + if (typeof input === "undefined" || !input.length) { + return 0; + } + + var isArray = utils.getTypeOf(input) !== "string"; + + if (typeof crc == "undefined") { + crc = 0; + } + var x = 0; + var y = 0; + var b = 0; + + crc = crc ^ -1; + for (var i = 0, iTop = input.length; i < iTop; i++) { + b = isArray ? input[i] : input.charCodeAt(i); + y = (crc ^ b) & 0xff; + x = table[y]; + crc = (crc >>> 8) ^ x; + } + + return crc ^ -1; + }; + // vim: set shiftwidth=4 softtabstop=4: + }, + { "./utils": 22 }, + ], + 6: [ + function (require, module, exports) { + "use strict"; + var utils = require("./utils"); + + function DataReader(data) { + this.data = null; // type : see implementation + this.length = 0; + this.index = 0; + this.zero = 0; + } + DataReader.prototype = { + /** + * Check that the offset will not go too far. + * @param {string} offset the additional offset to check. + * @throws {Error} an Error if the offset is out of bounds. + */ + checkOffset: function (offset) { + this.checkIndex(this.index + offset); + }, + /** + * Check that the specifed index will not be too far. + * @param {string} newIndex the index to check. + * @throws {Error} an Error if the index is out of bounds. + */ + checkIndex: function (newIndex) { + if ( + this.length < this.zero + newIndex || + newIndex < 0 + ) { + throw new Error( + "End of data reached (data length = " + + this.length + + ", asked index = " + + newIndex + + "). Corrupted zip ?" + ); + } + }, + /** + * Change the index. + * @param {number} newIndex The new index. + * @throws {Error} if the new index is out of the data. + */ + setIndex: function (newIndex) { + this.checkIndex(newIndex); + this.index = newIndex; + }, + /** + * Skip the next n bytes. + * @param {number} n the number of bytes to skip. + * @throws {Error} if the new index is out of the data. + */ + skip: function (n) { + this.setIndex(this.index + n); + }, + /** + * Get the byte at the specified index. + * @param {number} i the index to use. + * @return {number} a byte. + */ + byteAt: function (i) { + // see implementations + }, + /** + * Get the next number with a given byte size. + * @param {number} size the number of bytes to read. + * @return {number} the corresponding number. + */ + readInt: function (size) { + var result = 0, + i; + this.checkOffset(size); + for ( + i = this.index + size - 1; + i >= this.index; + i-- + ) { + result = (result << 8) + this.byteAt(i); + } + this.index += size; + return result; + }, + /** + * Get the next string with a given byte size. + * @param {number} size the number of bytes to read. + * @return {string} the corresponding string. + */ + readString: function (size) { + return utils.transformTo( + "string", + this.readData(size) + ); + }, + /** + * Get raw data without conversion, bytes. + * @param {number} size the number of bytes to read. + * @return {Object} the raw data, implementation specific. + */ + readData: function (size) { + // see implementations + }, + /** + * Find the last occurence of a zip signature (4 bytes). + * @param {string} sig the signature to find. + * @return {number} the index of the last occurence, -1 if not found. + */ + lastIndexOfSignature: function (sig) { + // see implementations + }, + /** + * Get the next date. + * @return {Date} the date. + */ + readDate: function () { + var dostime = this.readInt(4); + return new Date( + ((dostime >> 25) & 0x7f) + 1980, // year + ((dostime >> 21) & 0x0f) - 1, // month + (dostime >> 16) & 0x1f, // day + (dostime >> 11) & 0x1f, // hour + (dostime >> 5) & 0x3f, // minute + (dostime & 0x1f) << 1 + ); // second + }, + }; + module.exports = DataReader; + }, + { "./utils": 22 }, + ], + 7: [ + function (require, module, exports) { + "use strict"; + exports.base64 = false; + exports.binary = false; + exports.dir = false; + exports.createFolders = false; + exports.date = null; + exports.compression = null; + exports.compressionOptions = null; + exports.comment = null; + exports.unixPermissions = null; + exports.dosPermissions = null; + }, + {}, + ], + 8: [ + function (require, module, exports) { + "use strict"; + var utils = require("./utils"); + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.string2binary = function (str) { + return utils.string2binary(str); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.string2Uint8Array = function (str) { + return utils.transformTo("uint8array", str); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.uint8Array2String = function (array) { + return utils.transformTo("string", array); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.string2Blob = function (str) { + var buffer = utils.transformTo("arraybuffer", str); + return utils.arrayBuffer2Blob(buffer); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.arrayBuffer2Blob = function (buffer) { + return utils.arrayBuffer2Blob(buffer); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.transformTo = function (outputType, input) { + return utils.transformTo(outputType, input); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.getTypeOf = function (input) { + return utils.getTypeOf(input); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.checkSupport = function (type) { + return utils.checkSupport(type); + }; + + /** + * @deprecated + * This value will be removed in a future version without replacement. + */ + exports.MAX_VALUE_16BITS = utils.MAX_VALUE_16BITS; + + /** + * @deprecated + * This value will be removed in a future version without replacement. + */ + exports.MAX_VALUE_32BITS = utils.MAX_VALUE_32BITS; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.pretty = function (str) { + return utils.pretty(str); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.findCompression = function (compressionMethod) { + return utils.findCompression(compressionMethod); + }; + + /** + * @deprecated + * This function will be removed in a future version without replacement. + */ + exports.isRegExp = function (object) { + return utils.isRegExp(object); + }; + }, + { "./utils": 22 }, + ], + 9: [ + function (require, module, exports) { + "use strict"; + var USE_TYPEDARRAY = + typeof Uint8Array !== "undefined" && + typeof Uint16Array !== "undefined" && + typeof Uint32Array !== "undefined"; + + var pako = require("pako"); + exports.uncompressInputType = USE_TYPEDARRAY + ? "uint8array" + : "array"; + exports.compressInputType = USE_TYPEDARRAY + ? "uint8array" + : "array"; + + exports.magic = "\x08\x00"; + exports.compress = function (input, compressionOptions) { + return pako.deflateRaw(input, { + level: compressionOptions.level || -1, // default compression + }); + }; + exports.uncompress = function (input) { + return pako.inflateRaw(input); + }; + }, + { pako: 25 }, + ], + 10: [ + function (require, module, exports) { + "use strict"; + + var base64 = require("./base64"); + + /** + Usage: + zip = new JSZip(); + zip.file("hello.txt", "Hello, World!").file("tempfile", "nothing"); + zip.folder("images").file("smile.gif", base64Data, {base64: true}); + zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")}); + zip.remove("tempfile"); + + base64zip = zip.generate(); + + **/ + + /** + * Representation a of zip file in js + * @constructor + * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional). + * @param {Object=} options the options for creating this objects (optional). + */ + function JSZip(data, options) { + // if this constructor is used without `new`, it adds `new` before itself: + if (!(this instanceof JSZip)) + return new JSZip(data, options); + + // object containing the files : + // { + // "folder/" : {...}, + // "folder/data.txt" : {...} + // } + // NOTE: we use a null prototype because we do not + // want filenames like "toString" coming from a zip file + // to overwrite methods and attributes in a normal Object. + this.files = Object.create(null); + + this.comment = null; + + // Where we are in the hierarchy + this.root = ""; + if (data) { + this.load(data, options); + } + this.clone = function () { + var newObj = new JSZip(); + for (var i in this) { + if (typeof this[i] !== "function") { + newObj[i] = this[i]; + } + } + return newObj; + }; + } + JSZip.prototype = require("./object"); + JSZip.prototype.load = require("./load"); + JSZip.support = require("./support"); + JSZip.defaults = require("./defaults"); + + /** + * @deprecated + * This namespace will be removed in a future version without replacement. + */ + JSZip.utils = require("./deprecatedPublicUtils"); + + JSZip.base64 = { + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + encode: function (input) { + return base64.encode(input); + }, + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + decode: function (input) { + return base64.decode(input); + }, + }; + JSZip.compressions = require("./compressions"); + module.exports = JSZip; + }, + { + "./base64": 2, + "./compressions": 4, + "./defaults": 7, + "./deprecatedPublicUtils": 8, + "./load": 11, + "./object": 14, + "./support": 18, + }, + ], + 11: [ + function (require, module, exports) { + "use strict"; + var base64 = require("./base64"); + var utf8 = require("./utf8"); + var utils = require("./utils"); + var ZipEntries = require("./zipEntries"); + module.exports = function (data, options) { + var files, zipEntries, i, input; + options = utils.extend(options || {}, { + base64: false, + checkCRC32: false, + optimizedBinaryString: false, + createFolders: false, + decodeFileName: utf8.utf8decode, + }); + if (options.base64) { + data = base64.decode(data); + } + + zipEntries = new ZipEntries(data, options); + files = zipEntries.files; + for (i = 0; i < files.length; i++) { + input = files[i]; + this.file(input.fileNameStr, input.decompressed, { + binary: true, + optimizedBinaryString: true, + date: input.date, + dir: input.dir, + comment: input.fileCommentStr.length + ? input.fileCommentStr + : null, + unixPermissions: input.unixPermissions, + dosPermissions: input.dosPermissions, + createFolders: options.createFolders, + }); + } + if (zipEntries.zipComment.length) { + this.comment = zipEntries.zipComment; + } + + return this; + }; + }, + { + "./base64": 2, + "./utf8": 21, + "./utils": 22, + "./zipEntries": 23, + }, + ], + 12: [ + function (require, module, exports) { + (function (Buffer) { + "use strict"; + module.exports = function (data, encoding) { + return new Buffer(data, encoding); + }; + module.exports.test = function (b) { + return Buffer.isBuffer(b); + }; + }).call( + this, + typeof Buffer !== "undefined" ? Buffer : undefined + ); + }, + {}, + ], + 13: [ + function (require, module, exports) { + "use strict"; + var Uint8ArrayReader = require("./uint8ArrayReader"); + + function NodeBufferReader(data) { + this.data = data; + this.length = this.data.length; + this.index = 0; + this.zero = 0; + } + NodeBufferReader.prototype = new Uint8ArrayReader(); + + /** + * @see DataReader.readData + */ + NodeBufferReader.prototype.readData = function (size) { + this.checkOffset(size); + var result = this.data.slice( + this.zero + this.index, + this.zero + this.index + size + ); + this.index += size; + return result; + }; + module.exports = NodeBufferReader; + }, + { "./uint8ArrayReader": 19 }, + ], + 14: [ + function (require, module, exports) { + "use strict"; + var support = require("./support"); + var utils = require("./utils"); + var crc32 = require("./crc32"); + var signature = require("./signature"); + var defaults = require("./defaults"); + var base64 = require("./base64"); + var compressions = require("./compressions"); + var CompressedObject = require("./compressedObject"); + var nodeBuffer = require("./nodeBuffer"); + var utf8 = require("./utf8"); + var StringWriter = require("./stringWriter"); + var Uint8ArrayWriter = require("./uint8ArrayWriter"); + + /** + * Returns the raw data of a ZipObject, decompress the content if necessary. + * @param {ZipObject} file the file to use. + * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. + */ + var getRawData = function (file) { + if (file._data instanceof CompressedObject) { + file._data = file._data.getContent(); + file.options.binary = true; + file.options.base64 = false; + + if (utils.getTypeOf(file._data) === "uint8array") { + var copy = file._data; + // when reading an arraybuffer, the CompressedObject mechanism will keep it and subarray() a Uint8Array. + // if we request a file in the same format, we might get the same Uint8Array or its ArrayBuffer (the original zip file). + file._data = new Uint8Array(copy.length); + // with an empty Uint8Array, Opera fails with a "Offset larger than array size" + if (copy.length !== 0) { + file._data.set(copy, 0); + } + } + } + return file._data; + }; + + /** + * Returns the data of a ZipObject in a binary form. If the content is an unicode string, encode it. + * @param {ZipObject} file the file to use. + * @return {String|ArrayBuffer|Uint8Array|Buffer} the data. + */ + var getBinaryData = function (file) { + var result = getRawData(file), + type = utils.getTypeOf(result); + if (type === "string") { + if (!file.options.binary) { + // unicode text ! + // unicode string => binary string is a painful process, check if we can avoid it. + if (support.nodebuffer) { + return nodeBuffer(result, "utf-8"); + } + } + return file.asBinary(); + } + return result; + }; + + /** + * Transform this._data into a string. + * @param {function} filter a function String -> String, applied if not null on the result. + * @return {String} the string representing this._data. + */ + var dataToString = function (asUTF8) { + var result = getRawData(this); + if (result === null || typeof result === "undefined") { + return ""; + } + // if the data is a base64 string, we decode it before checking the encoding ! + if (this.options.base64) { + result = base64.decode(result); + } + if (asUTF8 && this.options.binary) { + // JSZip.prototype.utf8decode supports arrays as input + // skip to array => string step, utf8decode will do it. + result = out.utf8decode(result); + } else { + // no utf8 transformation, do the array => string step. + result = utils.transformTo("string", result); + } + + if (!asUTF8 && !this.options.binary) { + result = utils.transformTo( + "string", + out.utf8encode(result) + ); + } + return result; + }; + /** + * A simple object representing a file in the zip file. + * @constructor + * @param {string} name the name of the file + * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data + * @param {Object} options the options of the file + */ + var ZipObject = function (name, data, options) { + this.name = name; + this.dir = options.dir; + this.date = options.date; + this.comment = options.comment; + this.unixPermissions = options.unixPermissions; + this.dosPermissions = options.dosPermissions; + + this._data = data; + this.options = options; + + /* + * This object contains initial values for dir and date. + * With them, we can check if the user changed the deprecated metadata in + * `ZipObject#options` or not. + */ + this._initialMetadata = { + dir: options.dir, + date: options.date, + }; + }; + + ZipObject.prototype = { + /** + * Return the content as UTF8 string. + * @return {string} the UTF8 string. + */ + asText: function () { + return dataToString.call(this, true); + }, + /** + * Returns the binary content. + * @return {string} the content as binary. + */ + asBinary: function () { + return dataToString.call(this, false); + }, + /** + * Returns the content as a nodejs Buffer. + * @return {Buffer} the content as a Buffer. + */ + asNodeBuffer: function () { + var result = getBinaryData(this); + return utils.transformTo("nodebuffer", result); + }, + /** + * Returns the content as an Uint8Array. + * @return {Uint8Array} the content as an Uint8Array. + */ + asUint8Array: function () { + var result = getBinaryData(this); + return utils.transformTo("uint8array", result); + }, + /** + * Returns the content as an ArrayBuffer. + * @return {ArrayBuffer} the content as an ArrayBufer. + */ + asArrayBuffer: function () { + return this.asUint8Array().buffer; + }, + }; + + /** + * Transform an integer into a string in hexadecimal. + * @private + * @param {number} dec the number to convert. + * @param {number} bytes the number of bytes to generate. + * @returns {string} the result. + */ + var decToHex = function (dec, bytes) { + var hex = "", + i; + for (i = 0; i < bytes; i++) { + hex += String.fromCharCode(dec & 0xff); + dec = dec >>> 8; + } + return hex; + }; + + /** + * Transforms the (incomplete) options from the user into the complete + * set of options to create a file. + * @private + * @param {Object} o the options from the user. + * @return {Object} the complete set of options. + */ + var prepareFileAttrs = function (o) { + o = o || {}; + if ( + o.base64 === true && + (o.binary === null || o.binary === undefined) + ) { + o.binary = true; + } + o = utils.extend(o, defaults); + o.date = o.date || new Date(); + if (o.compression !== null) + o.compression = o.compression.toUpperCase(); + + return o; + }; + + /** + * Add a file in the current folder. + * @private + * @param {string} name the name of the file + * @param {String|ArrayBuffer|Uint8Array|Buffer} data the data of the file + * @param {Object} o the options of the file + * @return {Object} the new file. + */ + var fileAdd = function (name, data, o) { + // be sure sub folders exist + var dataType = utils.getTypeOf(data), + parent; + + o = prepareFileAttrs(o); + + if (typeof o.unixPermissions === "string") { + o.unixPermissions = parseInt(o.unixPermissions, 8); + } + + // UNX_IFDIR 0040000 see zipinfo.c + if (o.unixPermissions && o.unixPermissions & 0x4000) { + o.dir = true; + } + // Bit 4 Directory + if (o.dosPermissions && o.dosPermissions & 0x0010) { + o.dir = true; + } + + if (o.dir) { + name = forceTrailingSlash(name); + } + + if (o.createFolders && (parent = parentFolder(name))) { + folderAdd.call(this, parent, true); + } + + if ( + o.dir || + data === null || + typeof data === "undefined" + ) { + o.base64 = false; + o.binary = false; + data = null; + dataType = null; + } else if (dataType === "string") { + if (o.binary && !o.base64) { + // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask + if (o.optimizedBinaryString !== true) { + // this is a string, not in a base64 format. + // Be sure that this is a correct "binary string" + data = utils.string2binary(data); + } + } + } else { + // arraybuffer, uint8array, ... + o.base64 = false; + o.binary = true; + + if ( + !dataType && + !(data instanceof CompressedObject) + ) { + throw new Error( + "The data of '" + + name + + "' is in an unsupported format !" + ); + } + + // special case : it's way easier to work with Uint8Array than with ArrayBuffer + if (dataType === "arraybuffer") { + data = utils.transformTo("uint8array", data); + } + } + + var object = new ZipObject(name, data, o); + this.files[name] = object; + return object; + }; + + /** + * Find the parent folder of the path. + * @private + * @param {string} path the path to use + * @return {string} the parent folder, or "" + */ + var parentFolder = function (path) { + if (path.slice(-1) == "/") { + path = path.substring(0, path.length - 1); + } + var lastSlash = path.lastIndexOf("/"); + return lastSlash > 0 + ? path.substring(0, lastSlash) + : ""; + }; + + /** + * Returns the path with a slash at the end. + * @private + * @param {String} path the path to check. + * @return {String} the path with a trailing slash. + */ + var forceTrailingSlash = function (path) { + // Check the name ends with a / + if (path.slice(-1) != "/") { + path += "/"; // IE doesn't like substr(-1) + } + return path; + }; + /** + * Add a (sub) folder in the current folder. + * @private + * @param {string} name the folder's name + * @param {boolean=} [createFolders] If true, automatically create sub + * folders. Defaults to false. + * @return {Object} the new folder. + */ + var folderAdd = function (name, createFolders) { + createFolders = + typeof createFolders !== "undefined" + ? createFolders + : false; + + name = forceTrailingSlash(name); + + // Does this folder already exist? + if (!this.files[name]) { + fileAdd.call(this, name, null, { + dir: true, + createFolders: createFolders, + }); + } + return this.files[name]; + }; + + /** + * Generate a JSZip.CompressedObject for a given zipOject. + * @param {ZipObject} file the object to read. + * @param {JSZip.compression} compression the compression to use. + * @param {Object} compressionOptions the options to use when compressing. + * @return {JSZip.CompressedObject} the compressed result. + */ + var generateCompressedObjectFrom = function ( + file, + compression, + compressionOptions + ) { + var result = new CompressedObject(), + content; + + // the data has not been decompressed, we might reuse things ! + if (file._data instanceof CompressedObject) { + result.uncompressedSize = + file._data.uncompressedSize; + result.crc32 = file._data.crc32; + + if (result.uncompressedSize === 0 || file.dir) { + compression = compressions["STORE"]; + result.compressedContent = ""; + result.crc32 = 0; + } else if ( + file._data.compressionMethod === + compression.magic + ) { + result.compressedContent = + file._data.getCompressedContent(); + } else { + content = file._data.getContent(); + // need to decompress / recompress + result.compressedContent = compression.compress( + utils.transformTo( + compression.compressInputType, + content + ), + compressionOptions + ); + } + } else { + // have uncompressed data + content = getBinaryData(file); + if (!content || content.length === 0 || file.dir) { + compression = compressions["STORE"]; + content = ""; + } + result.uncompressedSize = content.length; + result.crc32 = crc32(content); + result.compressedContent = compression.compress( + utils.transformTo( + compression.compressInputType, + content + ), + compressionOptions + ); + } + + result.compressedSize = result.compressedContent.length; + result.compressionMethod = compression.magic; + + return result; + }; + + /** + * Generate the UNIX part of the external file attributes. + * @param {Object} unixPermissions the unix permissions or null. + * @param {Boolean} isDir true if the entry is a directory, false otherwise. + * @return {Number} a 32 bit integer. + * + * adapted from http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute : + * + * TTTTsstrwxrwxrwx0000000000ADVSHR + * ^^^^____________________________ file type, see zipinfo.c (UNX_*) + * ^^^_________________________ setuid, setgid, sticky + * ^^^^^^^^^________________ permissions + * ^^^^^^^^^^______ not used ? + * ^^^^^^ DOS attribute bits : Archive, Directory, Volume label, System file, Hidden, Read only + */ + var generateUnixExternalFileAttr = function ( + unixPermissions, + isDir + ) { + var result = unixPermissions; + if (!unixPermissions) { + // I can't use octal values in strict mode, hence the hexa. + // 040775 => 0x41fd + // 0100664 => 0x81b4 + result = isDir ? 0x41fd : 0x81b4; + } + + return (result & 0xffff) << 16; + }; + + /** + * Generate the DOS part of the external file attributes. + * @param {Object} dosPermissions the dos permissions or null. + * @param {Boolean} isDir true if the entry is a directory, false otherwise. + * @return {Number} a 32 bit integer. + * + * Bit 0 Read-Only + * Bit 1 Hidden + * Bit 2 System + * Bit 3 Volume Label + * Bit 4 Directory + * Bit 5 Archive + */ + var generateDosExternalFileAttr = function ( + dosPermissions, + isDir + ) { + // the dir flag is already set for compatibility + + return (dosPermissions || 0) & 0x3f; + }; + + /** + * Generate the various parts used in the construction of the final zip file. + * @param {string} name the file name. + * @param {ZipObject} file the file content. + * @param {JSZip.CompressedObject} compressedObject the compressed object. + * @param {number} offset the current offset from the start of the zip file. + * @param {String} platform let's pretend we are this platform (change platform dependents fields) + * @param {Function} encodeFileName the function to encode the file name / comment. + * @return {object} the zip parts. + */ + var generateZipParts = function ( + name, + file, + compressedObject, + offset, + platform, + encodeFileName + ) { + var data = compressedObject.compressedContent, + useCustomEncoding = + encodeFileName !== utf8.utf8encode, + encodedFileName = utils.transformTo( + "string", + encodeFileName(file.name) + ), + utfEncodedFileName = utils.transformTo( + "string", + utf8.utf8encode(file.name) + ), + comment = file.comment || "", + encodedComment = utils.transformTo( + "string", + encodeFileName(comment) + ), + utfEncodedComment = utils.transformTo( + "string", + utf8.utf8encode(comment) + ), + useUTF8ForFileName = + utfEncodedFileName.length !== file.name.length, + useUTF8ForComment = + utfEncodedComment.length !== comment.length, + o = file.options, + dosTime, + dosDate, + extraFields = "", + unicodePathExtraField = "", + unicodeCommentExtraField = "", + dir, + date; + + // handle the deprecated options.dir + if (file._initialMetadata.dir !== file.dir) { + dir = file.dir; + } else { + dir = o.dir; + } + + // handle the deprecated options.date + if (file._initialMetadata.date !== file.date) { + date = file.date; + } else { + date = o.date; + } + + var extFileAttr = 0; + var versionMadeBy = 0; + if (dir) { + // dos or unix, we set the dos dir flag + extFileAttr |= 0x00010; + } + if (platform === "UNIX") { + versionMadeBy = 0x031e; // UNIX, version 3.0 + extFileAttr |= generateUnixExternalFileAttr( + file.unixPermissions, + dir + ); + } else { + // DOS or other, fallback to DOS + versionMadeBy = 0x0014; // DOS, version 2.0 + extFileAttr |= generateDosExternalFileAttr( + file.dosPermissions, + dir + ); + } + + // date + // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html + // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html + // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html + + dosTime = date.getHours(); + dosTime = dosTime << 6; + dosTime = dosTime | date.getMinutes(); + dosTime = dosTime << 5; + dosTime = dosTime | (date.getSeconds() / 2); + + dosDate = date.getFullYear() - 1980; + dosDate = dosDate << 4; + dosDate = dosDate | (date.getMonth() + 1); + dosDate = dosDate << 5; + dosDate = dosDate | date.getDate(); + + if (useUTF8ForFileName) { + // set the unicode path extra field. unzip needs at least one extra + // field to correctly handle unicode path, so using the path is as good + // as any other information. This could improve the situation with + // other archive managers too. + // This field is usually used without the utf8 flag, with a non + // unicode path in the header (winrar, winzip). This helps (a bit) + // with the messy Windows' default compressed folders feature but + // breaks on p7zip which doesn't seek the unicode path extra field. + // So for now, UTF-8 everywhere ! + unicodePathExtraField = + // Version + decToHex(1, 1) + + // NameCRC32 + decToHex(crc32(encodedFileName), 4) + + // UnicodeName + utfEncodedFileName; + + extraFields += + // Info-ZIP Unicode Path Extra Field + "\x75\x70" + + // size + decToHex(unicodePathExtraField.length, 2) + + // content + unicodePathExtraField; + } + + if (useUTF8ForComment) { + unicodeCommentExtraField = + // Version + decToHex(1, 1) + + // CommentCRC32 + decToHex(this.crc32(encodedComment), 4) + + // UnicodeName + utfEncodedComment; + + extraFields += + // Info-ZIP Unicode Path Extra Field + "\x75\x63" + + // size + decToHex(unicodeCommentExtraField.length, 2) + + // content + unicodeCommentExtraField; + } + + var header = ""; + + // version needed to extract + header += "\x0A\x00"; + // general purpose bit flag + // set bit 11 if utf8 + header += + !useCustomEncoding && + (useUTF8ForFileName || useUTF8ForComment) + ? "\x00\x08" + : "\x00\x00"; + // compression method + header += compressedObject.compressionMethod; + // last mod file time + header += decToHex(dosTime, 2); + // last mod file date + header += decToHex(dosDate, 2); + // crc-32 + header += decToHex(compressedObject.crc32, 4); + // compressed size + header += decToHex(compressedObject.compressedSize, 4); + // uncompressed size + header += decToHex( + compressedObject.uncompressedSize, + 4 + ); + // file name length + header += decToHex(encodedFileName.length, 2); + // extra field length + header += decToHex(extraFields.length, 2); + + var fileRecord = + signature.LOCAL_FILE_HEADER + + header + + encodedFileName + + extraFields; + + var dirRecord = + signature.CENTRAL_FILE_HEADER + + // version made by (00: DOS) + decToHex(versionMadeBy, 2) + + // file header (common to file and central directory) + header + + // file comment length + decToHex(encodedComment.length, 2) + + // disk number start + "\x00\x00" + + // internal file attributes TODO + "\x00\x00" + + // external file attributes + decToHex(extFileAttr, 4) + + // relative offset of local header + decToHex(offset, 4) + + // file name + encodedFileName + + // extra field + extraFields + + // file comment + encodedComment; + + return { + fileRecord: fileRecord, + dirRecord: dirRecord, + compressedObject: compressedObject, + }; + }; + + // return the actual prototype of JSZip + var out = { + /** + * Read an existing zip and merge the data in the current JSZip object. + * The implementation is in jszip-load.js, don't forget to include it. + * @param {String|ArrayBuffer|Uint8Array|Buffer} stream The stream to load + * @param {Object} options Options for loading the stream. + * options.base64 : is the stream in base64 ? default : false + * @return {JSZip} the current JSZip object + */ + load: function (stream, options) { + throw new Error( + "Load method is not defined. Is the file jszip-load.js included ?" + ); + }, + + /** + * Filter nested files/folders with the specified function. + * @param {Function} search the predicate to use : + * function (relativePath, file) {...} + * It takes 2 arguments : the relative path and the file. + * @return {Array} An array of matching elements. + */ + filter: function (search) { + var result = [], + filename, + relativePath, + file, + fileClone; + for (filename in this.files) { + file = this.files[filename]; + // return a new object, don't let the user mess with our internal objects :) + fileClone = new ZipObject( + file.name, + file._data, + utils.extend(file.options) + ); + relativePath = filename.slice( + this.root.length, + filename.length + ); + if ( + filename.slice(0, this.root.length) === + this.root && // the file is in the current root + search(relativePath, fileClone) + ) { + // and the file matches the function + result.push(fileClone); + } + } + return result; + }, + + /** + * Add a file to the zip file, or search a file. + * @param {string|RegExp} name The name of the file to add (if data is defined), + * the name of the file to find (if no data) or a regex to match files. + * @param {String|ArrayBuffer|Uint8Array|Buffer} data The file data, either raw or base64 encoded + * @param {Object} o File options + * @return {JSZip|Object|Array} this JSZip object (when adding a file), + * a file (when searching by string) or an array of files (when searching by regex). + */ + file: function (name, data, o) { + if (arguments.length === 1) { + if (utils.isRegExp(name)) { + var regexp = name; + return this.filter(function ( + relativePath, + file + ) { + return ( + !file.dir && + regexp.test(relativePath) + ); + }); + } else { + // text + return ( + this.filter(function ( + relativePath, + file + ) { + return ( + !file.dir && + relativePath === name + ); + })[0] || null + ); + } + } else { + // more than one argument : we have data ! + name = this.root + name; + fileAdd.call(this, name, data, o); + } + return this; + }, + + /** + * Add a directory to the zip file, or search. + * @param {String|RegExp} arg The name of the directory to add, or a regex to search folders. + * @return {JSZip} an object with the new directory as the root, or an array containing matching folders. + */ + folder: function (arg) { + if (!arg) { + return this; + } + + if (utils.isRegExp(arg)) { + return this.filter(function ( + relativePath, + file + ) { + return file.dir && arg.test(relativePath); + }); + } + + // else, name is a new folder + var name = this.root + arg; + var newFolder = folderAdd.call(this, name); + + // Allow chaining by returning a new object with this folder as the root + var ret = this.clone(); + ret.root = newFolder.name; + return ret; + }, + + /** + * Delete a file, or a directory and all sub-files, from the zip + * @param {string} name the name of the file to delete + * @return {JSZip} this JSZip object + */ + remove: function (name) { + name = this.root + name; + var file = this.files[name]; + if (!file) { + // Look for any folders + if (name.slice(-1) != "/") { + name += "/"; + } + file = this.files[name]; + } + + if (file && !file.dir) { + // file + delete this.files[name]; + } else { + // maybe a folder, delete recursively + var kids = this.filter(function ( + relativePath, + file + ) { + return ( + file.name.slice(0, name.length) === name + ); + }); + for (var i = 0; i < kids.length; i++) { + delete this.files[kids[i].name]; + } + } + + return this; + }, + + /** + * Generate the complete zip file + * @param {Object} options the options to generate the zip file : + * - base64, (deprecated, use type instead) true to generate base64. + * - compression, "STORE" by default. + * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob. + * @return {String|Uint8Array|ArrayBuffer|Buffer|Blob} the zip file + */ + generate: function (options) { + options = utils.extend(options || {}, { + base64: true, + compression: "STORE", + compressionOptions: null, + type: "base64", + platform: "DOS", + comment: null, + mimeType: "application/zip", + encodeFileName: utf8.utf8encode, + }); + + utils.checkSupport(options.type); + + // accept nodejs `process.platform` + if ( + options.platform === "darwin" || + options.platform === "freebsd" || + options.platform === "linux" || + options.platform === "sunos" + ) { + options.platform = "UNIX"; + } + if (options.platform === "win32") { + options.platform = "DOS"; + } + + var zipData = [], + localDirLength = 0, + centralDirLength = 0, + writer, + i, + encodedComment = utils.transformTo( + "string", + options.encodeFileName( + options.comment || this.comment || "" + ) + ); + + // first, generate all the zip parts. + for (var name in this.files) { + var file = this.files[name]; + + var compressionName = + file.options.compression || + options.compression.toUpperCase(); + var compression = compressions[compressionName]; + if (!compression) { + throw new Error( + compressionName + + " is not a valid compression method !" + ); + } + var compressionOptions = + file.options.compressionOptions || + options.compressionOptions || + {}; + + var compressedObject = + generateCompressedObjectFrom.call( + this, + file, + compression, + compressionOptions + ); + + var zipPart = generateZipParts.call( + this, + name, + file, + compressedObject, + localDirLength, + options.platform, + options.encodeFileName + ); + localDirLength += + zipPart.fileRecord.length + + compressedObject.compressedSize; + centralDirLength += zipPart.dirRecord.length; + zipData.push(zipPart); + } + + var dirEnd = ""; + + // end of central dir signature + dirEnd = + signature.CENTRAL_DIRECTORY_END + + // number of this disk + "\x00\x00" + + // number of the disk with the start of the central directory + "\x00\x00" + + // total number of entries in the central directory on this disk + decToHex(zipData.length, 2) + + // total number of entries in the central directory + decToHex(zipData.length, 2) + + // size of the central directory 4 bytes + decToHex(centralDirLength, 4) + + // offset of start of central directory with respect to the starting disk number + decToHex(localDirLength, 4) + + // .ZIP file comment length + decToHex(encodedComment.length, 2) + + // .ZIP file comment + encodedComment; + + // we have all the parts (and the total length) + // time to create a writer ! + var typeName = options.type.toLowerCase(); + if ( + typeName === "uint8array" || + typeName === "arraybuffer" || + typeName === "blob" || + typeName === "nodebuffer" + ) { + writer = new Uint8ArrayWriter( + localDirLength + + centralDirLength + + dirEnd.length + ); + } else { + writer = new StringWriter( + localDirLength + + centralDirLength + + dirEnd.length + ); + } + + for (i = 0; i < zipData.length; i++) { + writer.append(zipData[i].fileRecord); + writer.append( + zipData[i].compressedObject + .compressedContent + ); + } + for (i = 0; i < zipData.length; i++) { + writer.append(zipData[i].dirRecord); + } + + writer.append(dirEnd); + + var zip = writer.finalize(); + + switch (options.type.toLowerCase()) { + // case "zip is an Uint8Array" + case "uint8array": + case "arraybuffer": + case "nodebuffer": + return utils.transformTo( + options.type.toLowerCase(), + zip + ); + case "blob": + return utils.arrayBuffer2Blob( + utils.transformTo("arraybuffer", zip), + options.mimeType + ); + // case "zip is a string" + case "base64": + return options.base64 + ? base64.encode(zip) + : zip; + default: // case "string" : + return zip; + } + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + crc32: function (input, crc) { + return crc32(input, crc); + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + utf8encode: function (string) { + return utils.transformTo( + "string", + utf8.utf8encode(string) + ); + }, + + /** + * @deprecated + * This method will be removed in a future version without replacement. + */ + utf8decode: function (input) { + return utf8.utf8decode(input); + }, + }; + module.exports = out; + }, + { + "./base64": 2, + "./compressedObject": 3, + "./compressions": 4, + "./crc32": 5, + "./defaults": 7, + "./nodeBuffer": 12, + "./signature": 15, + "./stringWriter": 17, + "./support": 18, + "./uint8ArrayWriter": 20, + "./utf8": 21, + "./utils": 22, + }, + ], + 15: [ + function (require, module, exports) { + "use strict"; + exports.LOCAL_FILE_HEADER = "PK\x03\x04"; + exports.CENTRAL_FILE_HEADER = "PK\x01\x02"; + exports.CENTRAL_DIRECTORY_END = "PK\x05\x06"; + exports.ZIP64_CENTRAL_DIRECTORY_LOCATOR = "PK\x06\x07"; + exports.ZIP64_CENTRAL_DIRECTORY_END = "PK\x06\x06"; + exports.DATA_DESCRIPTOR = "PK\x07\x08"; + }, + {}, + ], + 16: [ + function (require, module, exports) { + "use strict"; + var DataReader = require("./dataReader"); + var utils = require("./utils"); + + function StringReader(data, optimizedBinaryString) { + this.data = data; + if (!optimizedBinaryString) { + this.data = utils.string2binary(this.data); + } + this.length = this.data.length; + this.index = 0; + this.zero = 0; + } + StringReader.prototype = new DataReader(); + /** + * @see DataReader.byteAt + */ + StringReader.prototype.byteAt = function (i) { + return this.data.charCodeAt(this.zero + i); + }; + /** + * @see DataReader.lastIndexOfSignature + */ + StringReader.prototype.lastIndexOfSignature = function ( + sig + ) { + return this.data.lastIndexOf(sig) - this.zero; + }; + /** + * @see DataReader.readData + */ + StringReader.prototype.readData = function (size) { + this.checkOffset(size); + // this will work because the constructor applied the "& 0xff" mask. + var result = this.data.slice( + this.zero + this.index, + this.zero + this.index + size + ); + this.index += size; + return result; + }; + module.exports = StringReader; + }, + { "./dataReader": 6, "./utils": 22 }, + ], + 17: [ + function (require, module, exports) { + "use strict"; + + var utils = require("./utils"); + + /** + * An object to write any content to a string. + * @constructor + */ + var StringWriter = function () { + this.data = []; + }; + StringWriter.prototype = { + /** + * Append any content to the current string. + * @param {Object} input the content to add. + */ + append: function (input) { + input = utils.transformTo("string", input); + this.data.push(input); + }, + /** + * Finalize the construction an return the result. + * @return {string} the generated string. + */ + finalize: function () { + return this.data.join(""); + }, + }; + + module.exports = StringWriter; + }, + { "./utils": 22 }, + ], + 18: [ + function (require, module, exports) { + (function (Buffer) { + "use strict"; + exports.base64 = true; + exports.array = true; + exports.string = true; + exports.arraybuffer = + typeof ArrayBuffer !== "undefined" && + typeof Uint8Array !== "undefined"; + // contains true if JSZip can read/generate nodejs Buffer, false otherwise. + // Browserify will provide a Buffer implementation for browsers, which is + // an augmented Uint8Array (i.e., can be used as either Buffer or U8). + exports.nodebuffer = typeof Buffer !== "undefined"; + // contains true if JSZip can read/generate Uint8Array, false otherwise. + exports.uint8array = typeof Uint8Array !== "undefined"; + + if (typeof ArrayBuffer === "undefined") { + exports.blob = false; + } else { + var buffer = new ArrayBuffer(0); + try { + exports.blob = + new Blob([buffer], { + type: "application/zip", + }).size === 0; + } catch (e) { + try { + var Builder = + window.BlobBuilder || + window.WebKitBlobBuilder || + window.MozBlobBuilder || + window.MSBlobBuilder; + var builder = new Builder(); + builder.append(buffer); + exports.blob = + builder.getBlob("application/zip") + .size === 0; + } catch (e) { + exports.blob = false; + } + } + } + }).call( + this, + typeof Buffer !== "undefined" ? Buffer : undefined + ); + }, + {}, + ], + 19: [ + function (require, module, exports) { + "use strict"; + var ArrayReader = require("./arrayReader"); + + function Uint8ArrayReader(data) { + if (data) { + this.data = data; + this.length = this.data.length; + this.index = 0; + this.zero = 0; + } + } + Uint8ArrayReader.prototype = new ArrayReader(); + /** + * @see DataReader.readData + */ + Uint8ArrayReader.prototype.readData = function (size) { + this.checkOffset(size); + if (size === 0) { + // in IE10, when using subarray(idx, idx), we get the array [0x00] instead of []. + return new Uint8Array(0); + } + var result = this.data.subarray( + this.zero + this.index, + this.zero + this.index + size + ); + this.index += size; + return result; + }; + module.exports = Uint8ArrayReader; + }, + { "./arrayReader": 1 }, + ], + 20: [ + function (require, module, exports) { + "use strict"; + + var utils = require("./utils"); + + /** + * An object to write any content to an Uint8Array. + * @constructor + * @param {number} length The length of the array. + */ + var Uint8ArrayWriter = function (length) { + this.data = new Uint8Array(length); + this.index = 0; + }; + Uint8ArrayWriter.prototype = { + /** + * Append any content to the current array. + * @param {Object} input the content to add. + */ + append: function (input) { + if (input.length !== 0) { + // with an empty Uint8Array, Opera fails with a "Offset larger than array size" + input = utils.transformTo("uint8array", input); + this.data.set(input, this.index); + this.index += input.length; + } + }, + /** + * Finalize the construction an return the result. + * @return {Uint8Array} the generated array. + */ + finalize: function () { + return this.data; + }, + }; + + module.exports = Uint8ArrayWriter; + }, + { "./utils": 22 }, + ], + 21: [ + function (require, module, exports) { + "use strict"; + + var utils = require("./utils"); + var support = require("./support"); + var nodeBuffer = require("./nodeBuffer"); + + /** + * The following functions come from pako, from pako/lib/utils/strings + * released under the MIT license, see pako https://github.com/nodeca/pako/ + */ + + // Table with utf8 lengths (calculated by first byte of sequence) + // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, + // because max possible codepoint is 0x10ffff + var _utf8len = new Array(256); + for (var i = 0; i < 256; i++) { + _utf8len[i] = + i >= 252 + ? 6 + : i >= 248 + ? 5 + : i >= 240 + ? 4 + : i >= 224 + ? 3 + : i >= 192 + ? 2 + : 1; + } + _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start + + // convert string to array (typed, when possible) + var 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 + if (support.uint8array) { + buf = new Uint8Array(buf_len); + } else { + buf = new Array(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; + }; + + // 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); + var 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; + }; + + // convert array to string + var buf2string = function (buf) { + var str, i, out, c, c_len; + var len = 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); + } + } + + // shrinkBuf(utf16buf, out) + if (utf16buf.length !== out) { + if (utf16buf.subarray) { + utf16buf = utf16buf.subarray(0, out); + } else { + utf16buf.length = out; + } + } + + // return String.fromCharCode.apply(null, utf16buf); + return utils.applyFromCharCode(utf16buf); + }; + + // That's all for the pako functions. + + /** + * Transform a javascript string into an array (typed if possible) of bytes, + * UTF-8 encoded. + * @param {String} str the string to encode + * @return {Array|Uint8Array|Buffer} the UTF-8 encoded string. + */ + exports.utf8encode = function utf8encode(str) { + if (support.nodebuffer) { + return nodeBuffer(str, "utf-8"); + } + + return string2buf(str); + }; + + /** + * Transform a bytes array (or a representation) representing an UTF-8 encoded + * string into a javascript string. + * @param {Array|Uint8Array|Buffer} buf the data de decode + * @return {String} the decoded string. + */ + exports.utf8decode = function utf8decode(buf) { + if (support.nodebuffer) { + return utils + .transformTo("nodebuffer", buf) + .toString("utf-8"); + } + + buf = utils.transformTo( + support.uint8array ? "uint8array" : "array", + buf + ); + + // return buf2string(buf); + // Chrome prefers to work with "small" chunks of data + // for the method buf2string. + // Firefox and Chrome has their own shortcut, IE doesn't seem to really care. + var result = [], + k = 0, + len = buf.length, + chunk = 65536; + while (k < len) { + var nextBoundary = utf8border( + buf, + Math.min(k + chunk, len) + ); + if (support.uint8array) { + result.push( + buf2string(buf.subarray(k, nextBoundary)) + ); + } else { + result.push( + buf2string(buf.slice(k, nextBoundary)) + ); + } + k = nextBoundary; + } + return result.join(""); + }; + // vim: set shiftwidth=4 softtabstop=4: + }, + { "./nodeBuffer": 12, "./support": 18, "./utils": 22 }, + ], + 22: [ + function (require, module, exports) { + "use strict"; + var support = require("./support"); + var compressions = require("./compressions"); + var nodeBuffer = require("./nodeBuffer"); + /** + * Convert a string to a "binary string" : a string containing only char codes between 0 and 255. + * @param {string} str the string to transform. + * @return {String} the binary string. + */ + exports.string2binary = function (str) { + var result = ""; + for (var i = 0; i < str.length; i++) { + result += String.fromCharCode( + str.charCodeAt(i) & 0xff + ); + } + return result; + }; + exports.arrayBuffer2Blob = function (buffer, mimeType) { + exports.checkSupport("blob"); + mimeType = mimeType || "application/zip"; + + try { + // Blob constructor + return new Blob([buffer], { + type: mimeType, + }); + } catch (e) { + try { + // deprecated, browser only, old way + var Builder = + window.BlobBuilder || + window.WebKitBlobBuilder || + window.MozBlobBuilder || + window.MSBlobBuilder; + var builder = new Builder(); + builder.append(buffer); + return builder.getBlob(mimeType); + } catch (e) { + // well, fuck ?! + throw new Error( + "Bug : can't construct the Blob." + ); + } + } + }; + /** + * The identity function. + * @param {Object} input the input. + * @return {Object} the same input. + */ + function identity(input) { + return input; + } + + /** + * Fill in an array with a string. + * @param {String} str the string to use. + * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to fill in (will be mutated). + * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated array. + */ + function stringToArrayLike(str, array) { + for (var i = 0; i < str.length; ++i) { + array[i] = str.charCodeAt(i) & 0xff; + } + return array; + } + + /** + * Transform an array-like object to a string. + * @param {Array|ArrayBuffer|Uint8Array|Buffer} array the array to transform. + * @return {String} the result. + */ + function arrayLikeToString(array) { + // Performances notes : + // -------------------- + // String.fromCharCode.apply(null, array) is the fastest, see + // see http://jsperf.com/converting-a-uint8array-to-a-string/2 + // but the stack is limited (and we can get huge arrays !). + // + // result += String.fromCharCode(array[i]); generate too many strings ! + // + // This code is inspired by http://jsperf.com/arraybuffer-to-string-apply-performance/2 + var chunk = 65536; + var result = [], + len = array.length, + type = exports.getTypeOf(array), + k = 0, + canUseApply = true; + try { + switch (type) { + case "uint8array": + String.fromCharCode.apply( + null, + new Uint8Array(0) + ); + break; + case "nodebuffer": + String.fromCharCode.apply( + null, + nodeBuffer(0) + ); + break; + } + } catch (e) { + canUseApply = false; + } + + // no apply : slow and painful algorithm + // default browser on android 4.* + if (!canUseApply) { + var resultStr = ""; + for (var i = 0; i < array.length; i++) { + resultStr += String.fromCharCode(array[i]); + } + return resultStr; + } + while (k < len && chunk > 1) { + try { + if (type === "array" || type === "nodebuffer") { + result.push( + String.fromCharCode.apply( + null, + array.slice( + k, + Math.min(k + chunk, len) + ) + ) + ); + } else { + result.push( + String.fromCharCode.apply( + null, + array.subarray( + k, + Math.min(k + chunk, len) + ) + ) + ); + } + k += chunk; + } catch (e) { + chunk = Math.floor(chunk / 2); + } + } + return result.join(""); + } + + exports.applyFromCharCode = arrayLikeToString; + + /** + * Copy the data from an array-like to an other array-like. + * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayFrom the origin array. + * @param {Array|ArrayBuffer|Uint8Array|Buffer} arrayTo the destination array which will be mutated. + * @return {Array|ArrayBuffer|Uint8Array|Buffer} the updated destination array. + */ + function arrayLikeToArrayLike(arrayFrom, arrayTo) { + for (var i = 0; i < arrayFrom.length; i++) { + arrayTo[i] = arrayFrom[i]; + } + return arrayTo; + } + + // a matrix containing functions to transform everything into everything. + var transform = {}; + + // string to ? + transform["string"] = { + string: identity, + array: function (input) { + return stringToArrayLike( + input, + new Array(input.length) + ); + }, + arraybuffer: function (input) { + return transform["string"]["uint8array"](input) + .buffer; + }, + uint8array: function (input) { + return stringToArrayLike( + input, + new Uint8Array(input.length) + ); + }, + nodebuffer: function (input) { + return stringToArrayLike( + input, + nodeBuffer(input.length) + ); + }, + }; + + // array to ? + transform["array"] = { + string: arrayLikeToString, + array: identity, + arraybuffer: function (input) { + return new Uint8Array(input).buffer; + }, + uint8array: function (input) { + return new Uint8Array(input); + }, + nodebuffer: function (input) { + return nodeBuffer(input); + }, + }; + + // arraybuffer to ? + transform["arraybuffer"] = { + string: function (input) { + return arrayLikeToString(new Uint8Array(input)); + }, + array: function (input) { + return arrayLikeToArrayLike( + new Uint8Array(input), + new Array(input.byteLength) + ); + }, + arraybuffer: identity, + uint8array: function (input) { + return new Uint8Array(input); + }, + nodebuffer: function (input) { + return nodeBuffer(new Uint8Array(input)); + }, + }; + + // uint8array to ? + transform["uint8array"] = { + string: arrayLikeToString, + array: function (input) { + return arrayLikeToArrayLike( + input, + new Array(input.length) + ); + }, + arraybuffer: function (input) { + return input.buffer; + }, + uint8array: identity, + nodebuffer: function (input) { + return nodeBuffer(input); + }, + }; + + // nodebuffer to ? + transform["nodebuffer"] = { + string: arrayLikeToString, + array: function (input) { + return arrayLikeToArrayLike( + input, + new Array(input.length) + ); + }, + arraybuffer: function (input) { + return transform["nodebuffer"]["uint8array"](input) + .buffer; + }, + uint8array: function (input) { + return arrayLikeToArrayLike( + input, + new Uint8Array(input.length) + ); + }, + nodebuffer: identity, + }; + + /** + * Transform an input into any type. + * The supported output type are : string, array, uint8array, arraybuffer, nodebuffer. + * If no output type is specified, the unmodified input will be returned. + * @param {String} outputType the output type. + * @param {String|Array|ArrayBuffer|Uint8Array|Buffer} input the input to convert. + * @throws {Error} an Error if the browser doesn't support the requested output type. + */ + exports.transformTo = function (outputType, input) { + if (!input) { + // undefined, null, etc + // an empty string won't harm. + input = ""; + } + if (!outputType) { + return input; + } + exports.checkSupport(outputType); + var inputType = exports.getTypeOf(input); + var result = transform[inputType][outputType](input); + return result; + }; + + /** + * Return the type of the input. + * The type will be in a format valid for JSZip.utils.transformTo : string, array, uint8array, arraybuffer. + * @param {Object} input the input to identify. + * @return {String} the (lowercase) type of the input. + */ + exports.getTypeOf = function (input) { + if (typeof input === "string") { + return "string"; + } + if ( + Object.prototype.toString.call(input) === + "[object Array]" + ) { + return "array"; + } + if (support.nodebuffer && nodeBuffer.test(input)) { + return "nodebuffer"; + } + if (support.uint8array && input instanceof Uint8Array) { + return "uint8array"; + } + if ( + support.arraybuffer && + input instanceof ArrayBuffer + ) { + return "arraybuffer"; + } + }; + + /** + * Throw an exception if the type is not supported. + * @param {String} type the type to check. + * @throws {Error} an Error if the browser doesn't support the requested type. + */ + exports.checkSupport = function (type) { + var supported = support[type.toLowerCase()]; + if (!supported) { + throw new Error( + type + " is not supported by this browser" + ); + } + }; + exports.MAX_VALUE_16BITS = 65535; + exports.MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1 + + /** + * Prettify a string read as binary. + * @param {string} str the string to prettify. + * @return {string} a pretty string. + */ + exports.pretty = function (str) { + var res = "", + code, + i; + for (i = 0; i < (str || "").length; i++) { + code = str.charCodeAt(i); + res += + "\\x" + + (code < 16 ? "0" : "") + + code.toString(16).toUpperCase(); + } + return res; + }; + + /** + * Find a compression registered in JSZip. + * @param {string} compressionMethod the method magic to find. + * @return {Object|null} the JSZip compression object, null if none found. + */ + exports.findCompression = function (compressionMethod) { + for (var method in compressions) { + if (!compressions.hasOwnProperty(method)) { + continue; + } + if ( + compressions[method].magic === compressionMethod + ) { + return compressions[method]; + } + } + return null; + }; + /** + * Cross-window, cross-Node-context regular expression detection + * @param {Object} object Anything + * @return {Boolean} true if the object is a regular expression, + * false otherwise + */ + exports.isRegExp = function (object) { + return ( + Object.prototype.toString.call(object) === + "[object RegExp]" + ); + }; + + /** + * Merge the objects passed as parameters into a new one. + * @private + * @param {...Object} var_args All objects to merge. + * @return {Object} a new object with the data of the others. + */ + exports.extend = function () { + var result = {}, + i, + attr; + for (i = 0; i < arguments.length; i++) { + // arguments is not enumerable in some browsers + for (attr in arguments[i]) { + if ( + arguments[i].hasOwnProperty(attr) && + typeof result[attr] === "undefined" + ) { + result[attr] = arguments[i][attr]; + } + } + } + return result; + }; + }, + { "./compressions": 4, "./nodeBuffer": 12, "./support": 18 }, + ], + 23: [ + function (require, module, exports) { + "use strict"; + var StringReader = require("./stringReader"); + var NodeBufferReader = require("./nodeBufferReader"); + var Uint8ArrayReader = require("./uint8ArrayReader"); + var ArrayReader = require("./arrayReader"); + var utils = require("./utils"); + var sig = require("./signature"); + var ZipEntry = require("./zipEntry"); + var support = require("./support"); + var jszipProto = require("./object"); + // class ZipEntries {{{ + /** + * All the entries in the zip file. + * @constructor + * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load. + * @param {Object} loadOptions Options for loading the stream. + */ + function ZipEntries(data, loadOptions) { + this.files = []; + this.loadOptions = loadOptions; + if (data) { + this.load(data); + } + } + ZipEntries.prototype = { + /** + * Check that the reader is on the speficied signature. + * @param {string} expectedSignature the expected signature. + * @throws {Error} if it is an other signature. + */ + checkSignature: function (expectedSignature) { + var signature = this.reader.readString(4); + if (signature !== expectedSignature) { + throw new Error( + "Corrupted zip or bug : unexpected signature " + + "(" + + utils.pretty(signature) + + ", expected " + + utils.pretty(expectedSignature) + + ")" + ); + } + }, + /** + * Check if the given signature is at the given index. + * @param {number} askedIndex the index to check. + * @param {string} expectedSignature the signature to expect. + * @return {boolean} true if the signature is here, false otherwise. + */ + isSignature: function (askedIndex, expectedSignature) { + var currentIndex = this.reader.index; + this.reader.setIndex(askedIndex); + var signature = this.reader.readString(4); + var result = signature === expectedSignature; + this.reader.setIndex(currentIndex); + return result; + }, + /** + * Read the end of the central directory. + */ + readBlockEndOfCentral: function () { + this.diskNumber = this.reader.readInt(2); + this.diskWithCentralDirStart = + this.reader.readInt(2); + this.centralDirRecordsOnThisDisk = + this.reader.readInt(2); + this.centralDirRecords = this.reader.readInt(2); + this.centralDirSize = this.reader.readInt(4); + this.centralDirOffset = this.reader.readInt(4); + + this.zipCommentLength = this.reader.readInt(2); + // warning : the encoding depends of the system locale + // On a linux machine with LANG=en_US.utf8, this field is utf8 encoded. + // On a windows machine, this field is encoded with the localized windows code page. + var zipComment = this.reader.readData( + this.zipCommentLength + ); + var decodeParamType = support.uint8array + ? "uint8array" + : "array"; + // To get consistent behavior with the generation part, we will assume that + // this is utf8 encoded unless specified otherwise. + var decodeContent = utils.transformTo( + decodeParamType, + zipComment + ); + this.zipComment = + this.loadOptions.decodeFileName(decodeContent); + }, + /** + * Read the end of the Zip 64 central directory. + * Not merged with the method readEndOfCentral : + * The end of central can coexist with its Zip64 brother, + * I don't want to read the wrong number of bytes ! + */ + readBlockZip64EndOfCentral: function () { + this.zip64EndOfCentralSize = this.reader.readInt(8); + this.versionMadeBy = this.reader.readString(2); + this.versionNeeded = this.reader.readInt(2); + this.diskNumber = this.reader.readInt(4); + this.diskWithCentralDirStart = + this.reader.readInt(4); + this.centralDirRecordsOnThisDisk = + this.reader.readInt(8); + this.centralDirRecords = this.reader.readInt(8); + this.centralDirSize = this.reader.readInt(8); + this.centralDirOffset = this.reader.readInt(8); + + this.zip64ExtensibleData = {}; + var extraDataSize = this.zip64EndOfCentralSize - 44, + index = 0, + extraFieldId, + extraFieldLength, + extraFieldValue; + while (index < extraDataSize) { + extraFieldId = this.reader.readInt(2); + extraFieldLength = this.reader.readInt(4); + extraFieldValue = + this.reader.readString(extraFieldLength); + this.zip64ExtensibleData[extraFieldId] = { + id: extraFieldId, + length: extraFieldLength, + value: extraFieldValue, + }; + } + }, + /** + * Read the end of the Zip 64 central directory locator. + */ + readBlockZip64EndOfCentralLocator: function () { + this.diskWithZip64CentralDirStart = + this.reader.readInt(4); + this.relativeOffsetEndOfZip64CentralDir = + this.reader.readInt(8); + this.disksCount = this.reader.readInt(4); + if (this.disksCount > 1) { + throw new Error( + "Multi-volumes zip are not supported" + ); + } + }, + /** + * Read the local files, based on the offset read in the central part. + */ + readLocalFiles: function () { + var i, file; + for (i = 0; i < this.files.length; i++) { + file = this.files[i]; + this.reader.setIndex(file.localHeaderOffset); + this.checkSignature(sig.LOCAL_FILE_HEADER); + file.readLocalPart(this.reader); + file.handleUTF8(); + file.processAttributes(); + } + }, + /** + * Read the central directory. + */ + readCentralDir: function () { + var file; + + this.reader.setIndex(this.centralDirOffset); + while ( + this.reader.readString(4) === + sig.CENTRAL_FILE_HEADER + ) { + file = new ZipEntry( + { + zip64: this.zip64, + }, + this.loadOptions + ); + file.readCentralPart(this.reader); + this.files.push(file); + } + + if (this.centralDirRecords !== this.files.length) { + if ( + this.centralDirRecords !== 0 && + this.files.length === 0 + ) { + // We expected some records but couldn't find ANY. + // This is really suspicious, as if something went wrong. + throw new Error( + "Corrupted zip or bug: expected " + + this.centralDirRecords + + " records in central dir, got " + + this.files.length + ); + } else { + // We found some records but not all. + // Something is wrong but we got something for the user: no error here. + // console.warn("expected", this.centralDirRecords, "records in central dir, got", this.files.length); + } + } + }, + /** + * Read the end of central directory. + */ + readEndOfCentral: function () { + var offset = this.reader.lastIndexOfSignature( + sig.CENTRAL_DIRECTORY_END + ); + if (offset < 0) { + // Check if the content is a truncated zip or complete garbage. + // A "LOCAL_FILE_HEADER" is not required at the beginning (auto + // extractible zip for example) but it can give a good hint. + // If an ajax request was used without responseType, we will also + // get unreadable data. + var isGarbage = !this.isSignature( + 0, + sig.LOCAL_FILE_HEADER + ); + + if (isGarbage) { + throw new Error( + "Can't find end of central directory : is this a zip file ? " + + "If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html" + ); + } else { + throw new Error( + "Corrupted zip : can't find end of central directory" + ); + } + } + this.reader.setIndex(offset); + var endOfCentralDirOffset = offset; + this.checkSignature(sig.CENTRAL_DIRECTORY_END); + this.readBlockEndOfCentral(); + + /* extract from the zip spec : + 4) If one of the fields in the end of central directory + record is too small to hold required data, the field + should be set to -1 (0xFFFF or 0xFFFFFFFF) and the + ZIP64 format record should be created. + 5) The end of central directory record and the + Zip64 end of central directory locator record must + reside on the same disk when splitting or spanning + an archive. + */ + if ( + this.diskNumber === utils.MAX_VALUE_16BITS || + this.diskWithCentralDirStart === + utils.MAX_VALUE_16BITS || + this.centralDirRecordsOnThisDisk === + utils.MAX_VALUE_16BITS || + this.centralDirRecords === + utils.MAX_VALUE_16BITS || + this.centralDirSize === + utils.MAX_VALUE_32BITS || + this.centralDirOffset === utils.MAX_VALUE_32BITS + ) { + this.zip64 = true; + + /* + Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from + the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents + all numbers as 64-bit double precision IEEE 754 floating point numbers. + So, we have 53bits for integers and bitwise operations treat everything as 32bits. + see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators + and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5 + */ + + // should look for a zip64 EOCD locator + offset = this.reader.lastIndexOfSignature( + sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR + ); + if (offset < 0) { + throw new Error( + "Corrupted zip : can't find the ZIP64 end of central directory locator" + ); + } + this.reader.setIndex(offset); + this.checkSignature( + sig.ZIP64_CENTRAL_DIRECTORY_LOCATOR + ); + this.readBlockZip64EndOfCentralLocator(); + + // now the zip64 EOCD record + if ( + !this.isSignature( + this.relativeOffsetEndOfZip64CentralDir, + sig.ZIP64_CENTRAL_DIRECTORY_END + ) + ) { + // console.warn("ZIP64 end of central directory not where expected."); + this.relativeOffsetEndOfZip64CentralDir = + this.reader.lastIndexOfSignature( + sig.ZIP64_CENTRAL_DIRECTORY_END + ); + if ( + this + .relativeOffsetEndOfZip64CentralDir < + 0 + ) { + throw new Error( + "Corrupted zip : can't find the ZIP64 end of central directory" + ); + } + } + this.reader.setIndex( + this.relativeOffsetEndOfZip64CentralDir + ); + this.checkSignature( + sig.ZIP64_CENTRAL_DIRECTORY_END + ); + this.readBlockZip64EndOfCentral(); + } + + var expectedEndOfCentralDirOffset = + this.centralDirOffset + this.centralDirSize; + if (this.zip64) { + expectedEndOfCentralDirOffset += 20; // end of central dir 64 locator + expectedEndOfCentralDirOffset += + 12 /* should not include the leading 12 bytes */ + + this.zip64EndOfCentralSize; + } + + var extraBytes = + endOfCentralDirOffset - + expectedEndOfCentralDirOffset; + + if (extraBytes > 0) { + // console.warn(extraBytes, "extra bytes at beginning or within zipfile"); + if ( + this.isSignature( + endOfCentralDirOffset, + sig.CENTRAL_FILE_HEADER + ) + ) { + // The offsets seem wrong, but we have something at the specified offset. + // So… we keep it. + } else { + // the offset is wrong, update the "zero" of the reader + // this happens if data has been prepended (crx files for example) + this.reader.zero = extraBytes; + } + } else if (extraBytes < 0) { + throw new Error( + "Corrupted zip: missing " + + Math.abs(extraBytes) + + " bytes." + ); + } + }, + prepareReader: function (data) { + var type = utils.getTypeOf(data); + utils.checkSupport(type); + if (type === "string" && !support.uint8array) { + this.reader = new StringReader( + data, + this.loadOptions.optimizedBinaryString + ); + } else if (type === "nodebuffer") { + this.reader = new NodeBufferReader(data); + } else if (support.uint8array) { + this.reader = new Uint8ArrayReader( + utils.transformTo("uint8array", data) + ); + } else if (support.array) { + this.reader = new ArrayReader( + utils.transformTo("array", data) + ); + } else { + throw new Error( + "Unexpected error: unsupported type '" + + type + + "'" + ); + } + }, + /** + * Read a zip file and create ZipEntries. + * @param {String|ArrayBuffer|Uint8Array|Buffer} data the binary string representing a zip file. + */ + load: function (data) { + this.prepareReader(data); + this.readEndOfCentral(); + this.readCentralDir(); + this.readLocalFiles(); + }, + }; + // }}} end of ZipEntries + module.exports = ZipEntries; + }, + { + "./arrayReader": 1, + "./nodeBufferReader": 13, + "./object": 14, + "./signature": 15, + "./stringReader": 16, + "./support": 18, + "./uint8ArrayReader": 19, + "./utils": 22, + "./zipEntry": 24, + }, + ], + 24: [ + function (require, module, exports) { + "use strict"; + var StringReader = require("./stringReader"); + var utils = require("./utils"); + var CompressedObject = require("./compressedObject"); + var jszipProto = require("./object"); + var support = require("./support"); + + var MADE_BY_DOS = 0x00; + var MADE_BY_UNIX = 0x03; + + // class ZipEntry {{{ + /** + * An entry in the zip file. + * @constructor + * @param {Object} options Options of the current file. + * @param {Object} loadOptions Options for loading the stream. + */ + function ZipEntry(options, loadOptions) { + this.options = options; + this.loadOptions = loadOptions; + } + ZipEntry.prototype = { + /** + * say if the file is encrypted. + * @return {boolean} true if the file is encrypted, false otherwise. + */ + isEncrypted: function () { + // bit 1 is set + return (this.bitFlag & 0x0001) === 0x0001; + }, + /** + * say if the file has utf-8 filename/comment. + * @return {boolean} true if the filename/comment is in utf-8, false otherwise. + */ + useUTF8: function () { + // bit 11 is set + return (this.bitFlag & 0x0800) === 0x0800; + }, + /** + * Prepare the function used to generate the compressed content from this ZipFile. + * @param {DataReader} reader the reader to use. + * @param {number} from the offset from where we should read the data. + * @param {number} length the length of the data to read. + * @return {Function} the callback to get the compressed content (the type depends of the DataReader class). + */ + prepareCompressedContent: function ( + reader, + from, + length + ) { + return function () { + var previousIndex = reader.index; + reader.setIndex(from); + var compressedFileData = + reader.readData(length); + reader.setIndex(previousIndex); + + return compressedFileData; + }; + }, + /** + * Prepare the function used to generate the uncompressed content from this ZipFile. + * @param {DataReader} reader the reader to use. + * @param {number} from the offset from where we should read the data. + * @param {number} length the length of the data to read. + * @param {JSZip.compression} compression the compression used on this file. + * @param {number} uncompressedSize the uncompressed size to expect. + * @return {Function} the callback to get the uncompressed content (the type depends of the DataReader class). + */ + prepareContent: function ( + reader, + from, + length, + compression, + uncompressedSize + ) { + return function () { + var compressedFileData = utils.transformTo( + compression.uncompressInputType, + this.getCompressedContent() + ); + var uncompressedFileData = + compression.uncompress(compressedFileData); + + if ( + uncompressedFileData.length !== + uncompressedSize + ) { + throw new Error( + "Bug : uncompressed data size mismatch" + ); + } + + return uncompressedFileData; + }; + }, + /** + * Read the local part of a zip file and add the info in this object. + * @param {DataReader} reader the reader to use. + */ + readLocalPart: function (reader) { + var compression, localExtraFieldsLength; + + // we already know everything from the central dir ! + // If the central dir data are false, we are doomed. + // On the bright side, the local part is scary : zip64, data descriptors, both, etc. + // The less data we get here, the more reliable this should be. + // Let's skip the whole header and dash to the data ! + reader.skip(22); + // in some zip created on windows, the filename stored in the central dir contains \ instead of /. + // Strangely, the filename here is OK. + // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes + // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators... + // Search "unzip mismatching "local" filename continuing with "central" filename version" on + // the internet. + // + // I think I see the logic here : the central directory is used to display + // content and the local directory is used to extract the files. Mixing / and \ + // may be used to display \ to windows users and use / when extracting the files. + // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394 + this.fileNameLength = reader.readInt(2); + localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir + this.fileName = reader.readData( + this.fileNameLength + ); + reader.skip(localExtraFieldsLength); + + if ( + this.compressedSize == -1 || + this.uncompressedSize == -1 + ) { + throw new Error( + "Bug or corrupted zip : didn't get enough informations from the central directory " + + "(compressedSize == -1 || uncompressedSize == -1)" + ); + } + + compression = utils.findCompression( + this.compressionMethod + ); + if (compression === null) { + // no compression found + throw new Error( + "Corrupted zip : compression " + + utils.pretty(this.compressionMethod) + + " unknown (inner file : " + + utils.transformTo( + "string", + this.fileName + ) + + ")" + ); + } + this.decompressed = new CompressedObject(); + this.decompressed.compressedSize = + this.compressedSize; + this.decompressed.uncompressedSize = + this.uncompressedSize; + this.decompressed.crc32 = this.crc32; + this.decompressed.compressionMethod = + this.compressionMethod; + this.decompressed.getCompressedContent = + this.prepareCompressedContent( + reader, + reader.index, + this.compressedSize, + compression + ); + this.decompressed.getContent = this.prepareContent( + reader, + reader.index, + this.compressedSize, + compression, + this.uncompressedSize + ); + + // we need to compute the crc32... + if (this.loadOptions.checkCRC32) { + this.decompressed = utils.transformTo( + "string", + this.decompressed.getContent() + ); + if ( + jszipProto.crc32(this.decompressed) !== + this.crc32 + ) { + throw new Error( + "Corrupted zip : CRC32 mismatch" + ); + } + } + }, + + /** + * Read the central part of a zip file and add the info in this object. + * @param {DataReader} reader the reader to use. + */ + readCentralPart: function (reader) { + this.versionMadeBy = reader.readInt(2); + this.versionNeeded = reader.readInt(2); + this.bitFlag = reader.readInt(2); + this.compressionMethod = reader.readString(2); + this.date = reader.readDate(); + this.crc32 = reader.readInt(4); + this.compressedSize = reader.readInt(4); + this.uncompressedSize = reader.readInt(4); + this.fileNameLength = reader.readInt(2); + this.extraFieldsLength = reader.readInt(2); + this.fileCommentLength = reader.readInt(2); + this.diskNumberStart = reader.readInt(2); + this.internalFileAttributes = reader.readInt(2); + this.externalFileAttributes = reader.readInt(4); + this.localHeaderOffset = reader.readInt(4); + + if (this.isEncrypted()) { + throw new Error( + "Encrypted zip are not supported" + ); + } + + this.fileName = reader.readData( + this.fileNameLength + ); + this.readExtraFields(reader); + this.parseZIP64ExtraField(reader); + this.fileComment = reader.readData( + this.fileCommentLength + ); + }, + + /** + * Parse the external file attributes and get the unix/dos permissions. + */ + processAttributes: function () { + this.unixPermissions = null; + this.dosPermissions = null; + var madeBy = this.versionMadeBy >> 8; + + // Check if we have the DOS directory flag set. + // We look for it in the DOS and UNIX permissions + // but some unknown platform could set it as a compatibility flag. + this.dir = + this.externalFileAttributes & 0x0010 + ? true + : false; + + if (madeBy === MADE_BY_DOS) { + // first 6 bits (0 to 5) + this.dosPermissions = + this.externalFileAttributes & 0x3f; + } + + if (madeBy === MADE_BY_UNIX) { + this.unixPermissions = + (this.externalFileAttributes >> 16) & + 0xffff; + // the octal permissions are in (this.unixPermissions & 0x01FF).toString(8); + } + + // fail safe : if the name ends with a / it probably means a folder + if ( + !this.dir && + this.fileNameStr.slice(-1) === "/" + ) { + this.dir = true; + } + }, + + /** + * Parse the ZIP64 extra field and merge the info in the current ZipEntry. + * @param {DataReader} reader the reader to use. + */ + parseZIP64ExtraField: function (reader) { + if (!this.extraFields[0x0001]) { + return; + } + + // should be something, preparing the extra reader + var extraReader = new StringReader( + this.extraFields[0x0001].value + ); + + // I really hope that these 64bits integer can fit in 32 bits integer, because js + // won't let us have more. + if ( + this.uncompressedSize === utils.MAX_VALUE_32BITS + ) { + this.uncompressedSize = extraReader.readInt(8); + } + if ( + this.compressedSize === utils.MAX_VALUE_32BITS + ) { + this.compressedSize = extraReader.readInt(8); + } + if ( + this.localHeaderOffset === + utils.MAX_VALUE_32BITS + ) { + this.localHeaderOffset = extraReader.readInt(8); + } + if ( + this.diskNumberStart === utils.MAX_VALUE_32BITS + ) { + this.diskNumberStart = extraReader.readInt(4); + } + }, + /** + * Read the central part of a zip file and add the info in this object. + * @param {DataReader} reader the reader to use. + */ + readExtraFields: function (reader) { + var start = reader.index, + extraFieldId, + extraFieldLength, + extraFieldValue; + + this.extraFields = this.extraFields || {}; + + while ( + reader.index < + start + this.extraFieldsLength + ) { + extraFieldId = reader.readInt(2); + extraFieldLength = reader.readInt(2); + extraFieldValue = + reader.readString(extraFieldLength); + + this.extraFields[extraFieldId] = { + id: extraFieldId, + length: extraFieldLength, + value: extraFieldValue, + }; + } + }, + /** + * Apply an UTF8 transformation if needed. + */ + handleUTF8: function () { + var decodeParamType = support.uint8array + ? "uint8array" + : "array"; + if (this.useUTF8()) { + this.fileNameStr = jszipProto.utf8decode( + this.fileName + ); + this.fileCommentStr = jszipProto.utf8decode( + this.fileComment + ); + } else { + var upath = this.findExtraFieldUnicodePath(); + if (upath !== null) { + this.fileNameStr = upath; + } else { + var fileNameByteArray = utils.transformTo( + decodeParamType, + this.fileName + ); + this.fileNameStr = + this.loadOptions.decodeFileName( + fileNameByteArray + ); + } + + var ucomment = + this.findExtraFieldUnicodeComment(); + if (ucomment !== null) { + this.fileCommentStr = ucomment; + } else { + var commentByteArray = utils.transformTo( + decodeParamType, + this.fileComment + ); + this.fileCommentStr = + this.loadOptions.decodeFileName( + commentByteArray + ); + } + } + }, + + /** + * Find the unicode path declared in the extra field, if any. + * @return {String} the unicode path, null otherwise. + */ + findExtraFieldUnicodePath: function () { + var upathField = this.extraFields[0x7075]; + if (upathField) { + var extraReader = new StringReader( + upathField.value + ); + + // wrong version + if (extraReader.readInt(1) !== 1) { + return null; + } + + // the crc of the filename changed, this field is out of date. + if ( + jszipProto.crc32(this.fileName) !== + extraReader.readInt(4) + ) { + return null; + } + + return jszipProto.utf8decode( + extraReader.readString( + upathField.length - 5 + ) + ); + } + return null; + }, + + /** + * Find the unicode comment declared in the extra field, if any. + * @return {String} the unicode comment, null otherwise. + */ + findExtraFieldUnicodeComment: function () { + var ucommentField = this.extraFields[0x6375]; + if (ucommentField) { + var extraReader = new StringReader( + ucommentField.value + ); + + // wrong version + if (extraReader.readInt(1) !== 1) { + return null; + } + + // the crc of the comment changed, this field is out of date. + if ( + jszipProto.crc32(this.fileComment) !== + extraReader.readInt(4) + ) { + return null; + } + + return jszipProto.utf8decode( + extraReader.readString( + ucommentField.length - 5 + ) + ); + } + return null; + }, + }; + module.exports = ZipEntry; + }, + { + "./compressedObject": 3, + "./object": 14, + "./stringReader": 16, + "./support": 18, + "./utils": 22, + }, + ], + 25: [ + function (require, module, exports) { + // Top level file is just a mixin of submodules & constants + "use strict"; + + var assign = require("./lib/utils/common").assign; + + var deflate = require("./lib/deflate"); + var inflate = require("./lib/inflate"); + var constants = require("./lib/zlib/constants"); + + var pako = {}; + + assign(pako, deflate, inflate, constants); + + module.exports = pako; + }, + { + "./lib/deflate": 26, + "./lib/inflate": 27, + "./lib/utils/common": 28, + "./lib/zlib/constants": 31, + }, + ], + 26: [ + function (require, module, exports) { + "use strict"; + + var zlib_deflate = require("./zlib/deflate"); + var utils = require("./utils/common"); + var strings = require("./utils/strings"); + var msg = require("./zlib/messages"); + var ZStream = require("./zlib/zstream"); + + var toString = Object.prototype.toString; + + /* Public constants ==========================================================*/ + /* ===========================================================================*/ + + var Z_NO_FLUSH = 0; + var Z_FINISH = 4; + + var Z_OK = 0; + var Z_STREAM_END = 1; + var Z_SYNC_FLUSH = 2; + + var Z_DEFAULT_COMPRESSION = -1; + + var Z_DEFAULT_STRATEGY = 0; + + var Z_DEFLATED = 8; + + /* ===========================================================================*/ + + /** + * class Deflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[deflate]], + * [[deflateRaw]] and [[gzip]]. + **/ + + /* internal + * Deflate.chunks -> Array + * + * Chunks of output data, if [[Deflate#onData]] not overridden. + **/ + + /** + * Deflate.result -> Uint8Array|Array + * + * Compressed result, generated by default [[Deflate#onData]] + * and [[Deflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you + * push a chunk with explicit flush (call [[Deflate#push]] with + * `Z_SYNC_FLUSH` param). + **/ + + /** + * Deflate.err -> Number + * + * Error code after deflate finished. 0 (Z_OK) on success. + * You will not need it in real life, because deflate errors + * are possible only on wrong options or bad `onData` / `onEnd` + * custom handlers. + **/ + + /** + * Deflate.msg -> String + * + * Error message, if [[Deflate.err]] != 0 + **/ + + /** + * new Deflate(options) + * - options (Object): zlib deflate options. + * + * Creates new deflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `level` + * - `windowBits` + * - `memLevel` + * - `strategy` + * - `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 deflate + * - `gzip` (Boolean) - create gzip wrapper + * - `to` (String) - if equal to 'string', then result will be "binary string" + * (each char code [0..255]) + * - `header` (Object) - custom header for gzip + * - `text` (Boolean) - true if compressed data believed to be text + * - `time` (Number) - modification time, unix timestamp + * - `os` (Number) - operation system code + * - `extra` (Array) - array of bytes with extra data (max 65536) + * - `name` (String) - file name (binary string) + * - `comment` (String) - comment (binary string) + * - `hcrc` (Boolean) - true if header crc should be added + * + * ##### 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 deflate = new pako.Deflate({ level: 3}); + * + * deflate.push(chunk1, false); + * deflate.push(chunk2, true); // true -> last chunk + * + * if (deflate.err) { throw new Error(deflate.err); } + * + * console.log(deflate.result); + * ``` + **/ + function Deflate(options) { + if (!(this instanceof Deflate)) + return new Deflate(options); + + this.options = utils.assign( + { + level: Z_DEFAULT_COMPRESSION, + method: Z_DEFLATED, + chunkSize: 16384, + windowBits: 15, + memLevel: 8, + strategy: Z_DEFAULT_STRATEGY, + to: "", + }, + options || {} + ); + + var opt = this.options; + + if (opt.raw && opt.windowBits > 0) { + opt.windowBits = -opt.windowBits; + } else if ( + opt.gzip && + opt.windowBits > 0 && + opt.windowBits < 16 + ) { + opt.windowBits += 16; + } + + 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_deflate.deflateInit2( + this.strm, + opt.level, + opt.method, + opt.windowBits, + opt.memLevel, + opt.strategy + ); + + if (status !== Z_OK) { + throw new Error(msg[status]); + } + + if (opt.header) { + zlib_deflate.deflateSetHeader( + this.strm, + opt.header + ); + } + + if (opt.dictionary) { + var dict; + // Convert data if needed + if (typeof opt.dictionary === "string") { + // If we need to compress text, change encoding to utf8. + dict = strings.string2buf(opt.dictionary); + } else if ( + toString.call(opt.dictionary) === + "[object ArrayBuffer]" + ) { + dict = new Uint8Array(opt.dictionary); + } else { + dict = opt.dictionary; + } + + status = zlib_deflate.deflateSetDictionary( + this.strm, + dict + ); + + if (status !== Z_OK) { + throw new Error(msg[status]); + } + + this._dict_set = true; + } + } + + /** + * Deflate#push(data[, mode]) -> Boolean + * - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be + * converted to utf8 byte sequence. + * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. + * + * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with + * new compressed chunks. Returns `true` on success. The last data block must have + * mode Z_FINISH (or `true`). That will flush internal pending buffers and call + * [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you + * can use mode Z_SYNC_FLUSH, keeping the compression context. + * + * On fail call [[Deflate#onEnd]] with error code and return false. + * + * We strongly recommend to use `Uint8Array` on input for best speed (output + * array 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 + * ``` + **/ + Deflate.prototype.push = function (data, mode) { + var strm = this.strm; + var chunkSize = this.options.chunkSize; + var status, _mode; + + if (this.ended) { + return false; + } + + _mode = + mode === ~~mode + ? mode + : mode === true + ? Z_FINISH + : Z_NO_FLUSH; + + // Convert data if needed + if (typeof data === "string") { + // If we need to compress text, change encoding to utf8. + strm.input = strings.string2buf(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_deflate.deflate( + strm, + _mode + ); /* no bad return value */ + + if (status !== Z_STREAM_END && status !== Z_OK) { + this.onEnd(status); + this.ended = true; + return false; + } + if ( + strm.avail_out === 0 || + (strm.avail_in === 0 && + (_mode === Z_FINISH || + _mode === Z_SYNC_FLUSH)) + ) { + if (this.options.to === "string") { + this.onData( + strings.buf2binstring( + utils.shrinkBuf( + strm.output, + strm.next_out + ) + ) + ); + } else { + this.onData( + utils.shrinkBuf( + strm.output, + strm.next_out + ) + ); + } + } + } while ( + (strm.avail_in > 0 || strm.avail_out === 0) && + status !== Z_STREAM_END + ); + + // Finalize on the last chunk. + if (_mode === Z_FINISH) { + status = zlib_deflate.deflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === Z_OK; + } + + // callback interim results if Z_SYNC_FLUSH. + if (_mode === Z_SYNC_FLUSH) { + this.onEnd(Z_OK); + strm.avail_out = 0; + return true; + } + + return true; + }; + + /** + * Deflate#onData(chunk) -> Void + * - chunk (Uint8Array|Array|String): output 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. + **/ + Deflate.prototype.onData = function (chunk) { + this.chunks.push(chunk); + }; + + /** + * Deflate#onEnd(status) -> Void + * - status (Number): deflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell deflate 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. + **/ + Deflate.prototype.onEnd = function (status) { + // On success - join + if (status === Z_OK) { + if (this.options.to === "string") { + this.result = this.chunks.join(""); + } else { + this.result = utils.flattenChunks(this.chunks); + } + } + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; + }; + + /** + * deflate(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * Compress `data` with deflate algorithm and `options`. + * + * Supported options are: + * + * - level + * - windowBits + * - memLevel + * - strategy + * - dictionary + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * 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 "binary string" + * (each char code [0..255]) + * + * ##### Example: + * + * ```javascript + * var pako = require('pako') + * , data = Uint8Array([1,2,3,4,5,6,7,8,9]); + * + * console.log(pako.deflate(data)); + * ``` + **/ + function deflate(input, options) { + var deflator = new Deflate(options); + + deflator.push(input, true); + + // That will never happens, if you don't cheat with options :) + if (deflator.err) { + throw deflator.msg || msg[deflator.err]; + } + + return deflator.result; + } + + /** + * deflateRaw(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ + function deflateRaw(input, options) { + options = options || {}; + options.raw = true; + return deflate(input, options); + } + + /** + * gzip(data[, options]) -> Uint8Array|Array|String + * - data (Uint8Array|Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but create gzip wrapper instead of + * deflate one. + **/ + function gzip(input, options) { + options = options || {}; + options.gzip = true; + return deflate(input, options); + } + + exports.Deflate = Deflate; + exports.deflate = deflate; + exports.deflateRaw = deflateRaw; + exports.gzip = gzip; + }, + { + "./utils/common": 28, + "./utils/strings": 29, + "./zlib/deflate": 33, + "./zlib/messages": 38, + "./zlib/zstream": 40, + }, + ], + 27: [ + function (require, module, exports) { + "use strict"; + + 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 overridden. + **/ + + /** + * 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); + + // Setup dictionary + if (opt.dictionary) { + // Convert data if needed + if (typeof opt.dictionary === "string") { + opt.dictionary = strings.string2buf( + opt.dictionary + ); + } else if ( + toString.call(opt.dictionary) === + "[object ArrayBuffer]" + ) { + opt.dictionary = new Uint8Array(opt.dictionary); + } + if (opt.raw) { + //In raw mode we need to set the dictionary early + status = zlib_inflate.inflateSetDictionary( + this.strm, + opt.dictionary + ); + if (status !== c.Z_OK) { + throw new Error(msg[status]); + } + } + } + } + + /** + * 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` means 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; + + // 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) { + status = zlib_inflate.inflateSetDictionary( + this.strm, + dictionary + ); + } + + 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): output 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 aligned 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": 28, + "./utils/strings": 29, + "./zlib/constants": 31, + "./zlib/gzheader": 34, + "./zlib/inflate": 36, + "./zlib/messages": 38, + "./zlib/zstream": 40, + }, + ], + 28: [ + function (require, module, exports) { + "use strict"; + + var TYPED_OK = + typeof Uint8Array !== "undefined" && + typeof Uint16Array !== "undefined" && + typeof Int32Array !== "undefined"; + + function _has(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); + } + + exports.assign = function ( + obj /*from1, from2, from3, ...*/ + ) { + var sources = Array.prototype.slice.call(arguments, 1); + while (sources.length) { + var source = sources.shift(); + if (!source) { + continue; + } + + if (typeof source !== "object") { + throw new TypeError( + source + "must be non-object" + ); + } + + for (var p in source) { + if (_has(source, p)) { + obj[p] = source[p]; + } + } + } + + return obj; + }; + + // reduce buffer size, avoiding mem copy + exports.shrinkBuf = function (buf, size) { + if (buf.length === size) { + return buf; + } + if (buf.subarray) { + return buf.subarray(0, size); + } + buf.length = size; + return buf; + }; + + var fnTyped = { + arraySet: function ( + dest, + src, + src_offs, + len, + dest_offs + ) { + if (src.subarray && dest.subarray) { + dest.set( + src.subarray(src_offs, src_offs + len), + dest_offs + ); + return; + } + // Fallback to ordinary array + for (var i = 0; i < len; i++) { + dest[dest_offs + i] = src[src_offs + i]; + } + }, + // Join array of chunks to single array. + flattenChunks: function (chunks) { + var i, l, len, pos, chunk, result; + + // calculate data length + len = 0; + for (i = 0, l = chunks.length; i < l; i++) { + len += chunks[i].length; + } + + // join chunks + result = new Uint8Array(len); + pos = 0; + for (i = 0, l = chunks.length; i < l; i++) { + chunk = chunks[i]; + result.set(chunk, pos); + pos += chunk.length; + } + + return result; + }, + }; + + var fnUntyped = { + arraySet: function ( + dest, + src, + src_offs, + len, + dest_offs + ) { + for (var i = 0; i < len; i++) { + dest[dest_offs + i] = src[src_offs + i]; + } + }, + // Join array of chunks to single array. + flattenChunks: function (chunks) { + return [].concat.apply([], chunks); + }, + }; + + // Enable/Disable typed arrays use, for testing + // + exports.setTyped = function (on) { + if (on) { + exports.Buf8 = Uint8Array; + exports.Buf16 = Uint16Array; + exports.Buf32 = Int32Array; + exports.assign(exports, fnTyped); + } else { + exports.Buf8 = Array; + exports.Buf16 = Array; + exports.Buf32 = Array; + exports.assign(exports, fnUntyped); + } + }; + + exports.setTyped(TYPED_OK); + }, + {}, + ], + 29: [ + function (require, module, exports) { + // String encode/decode helpers + "use strict"; + + var utils = require("./common"); + + // Quick check if we can use fast array to bin string conversion + // + // - apply(Array) can fail on Android 2.2 + // - apply(Uint8Array) can fail on iOS 5.1 Safari + // + var STR_APPLY_OK = true; + var STR_APPLY_UIA_OK = true; + + try { + String.fromCharCode.apply(null, [0]); + } catch (__) { + STR_APPLY_OK = false; + } + try { + String.fromCharCode.apply(null, new Uint8Array(1)); + } catch (__) { + STR_APPLY_UIA_OK = false; + } + + // Table with utf8 lengths (calculated by first byte of sequence) + // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, + // because max possible codepoint is 0x10ffff + var _utf8len = new utils.Buf8(256); + for (var q = 0; q < 256; q++) { + _utf8len[q] = + q >= 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) { + // On Chrome, the arguments in a function call that are allowed is `65534`. + // If the length of the buffer is smaller than that, we can use this optimization, + // otherwise we will take a slower path. + if (len < 65534) { + 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--; + } + + // 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 buffer is too small, + // return max too. + if (pos === 0) { + return max; + } + + return pos + _utf8len[buf[pos]] > max ? pos : max; + }; + }, + { "./common": 28 }, + ], + 30: [ + function (require, module, exports) { + "use strict"; + + // Note: adler32 takes 12% for level 0 and 2% for level 6. + // It isn't worth it to make additional optimizations as in original. + // Small size is preferable. + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + 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; + }, + {}, + ], + 31: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + 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 + }; + }, + {}, + ], + 32: [ + function (require, module, exports) { + "use strict"; + + // Note: we can't get significant speed boost here. + // So write code to minimize size - no pregenerated tables + // and array tools dependencies. + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // 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; + }, + {}, + ], + 33: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + var utils = require("../utils/common"); + var trees = require("./trees"); + var adler32 = require("./adler32"); + var crc32 = require("./crc32"); + var msg = require("./messages"); + + /* 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; + + /* compression levels */ + //var Z_NO_COMPRESSION = 0; + //var Z_BEST_SPEED = 1; + //var Z_BEST_COMPRESSION = 9; + var Z_DEFAULT_COMPRESSION = -1; + + var Z_FILTERED = 1; + var Z_HUFFMAN_ONLY = 2; + var Z_RLE = 3; + var Z_FIXED = 4; + var Z_DEFAULT_STRATEGY = 0; + + /* Possible values of the data_type field (though see inflate()) */ + //var Z_BINARY = 0; + //var Z_TEXT = 1; + //var Z_ASCII = 1; // = Z_TEXT + var Z_UNKNOWN = 2; + + /* The deflate compression method */ + var Z_DEFLATED = 8; + + /*============================================================================*/ + + var MAX_MEM_LEVEL = 9; + /* Maximum value for memLevel in deflateInit2 */ + var MAX_WBITS = 15; + /* 32K LZ77 window */ + var DEF_MEM_LEVEL = 8; + + var LENGTH_CODES = 29; + /* number of length codes, not counting the special END_BLOCK code */ + var LITERALS = 256; + /* number of literal bytes 0..255 */ + var L_CODES = LITERALS + 1 + LENGTH_CODES; + /* number of Literal or Length codes, including the END_BLOCK code */ + var D_CODES = 30; + /* number of distance codes */ + var BL_CODES = 19; + /* number of codes used to transfer the bit lengths */ + var HEAP_SIZE = 2 * L_CODES + 1; + /* maximum heap size */ + var MAX_BITS = 15; + /* All codes must not exceed MAX_BITS bits */ + + var MIN_MATCH = 3; + var MAX_MATCH = 258; + var MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1; + + var PRESET_DICT = 0x20; + + var INIT_STATE = 42; + var EXTRA_STATE = 69; + var NAME_STATE = 73; + var COMMENT_STATE = 91; + var HCRC_STATE = 103; + var BUSY_STATE = 113; + var FINISH_STATE = 666; + + var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ + var BS_BLOCK_DONE = 2; /* block flush performed */ + var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ + var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + + var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + + function err(strm, errorCode) { + strm.msg = msg[errorCode]; + return errorCode; + } + + function rank(f) { + return (f << 1) - (f > 4 ? 9 : 0); + } + + function zero(buf) { + var len = buf.length; + while (--len >= 0) { + buf[len] = 0; + } + } + + /* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->output buffer and copying into it. + * (See also read_buf()). + */ + function flush_pending(strm) { + var s = strm.state; + + //_tr_flush_bits(s); + var len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { + return; + } + + utils.arraySet( + strm.output, + s.pending_buf, + s.pending_out, + len, + strm.next_out + ); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; + } + } + + function flush_block_only(s, last) { + trees._tr_flush_block( + s, + s.block_start >= 0 ? s.block_start : -1, + s.strstart - s.block_start, + last + ); + s.block_start = s.strstart; + flush_pending(s.strm); + } + + function put_byte(s, b) { + s.pending_buf[s.pending++] = b; + } + + /* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ + function putShortMSB(s, b) { + // put_byte(s, (Byte)(b >> 8)); + // put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; + } + + /* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ + function read_buf(strm, buf, start, size) { + var len = strm.avail_in; + + if (len > size) { + len = size; + } + if (len === 0) { + return 0; + } + + strm.avail_in -= len; + + // zmemcpy(buf, strm->next_in, len); + utils.arraySet( + buf, + strm.input, + strm.next_in, + len, + start + ); + if (strm.state.wrap === 1) { + strm.adler = adler32(strm.adler, buf, len, start); + } else if (strm.state.wrap === 2) { + strm.adler = crc32(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + + return len; + } + + /* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ + function longest_match(s, cur_match) { + var chain_length = + s.max_chain_length; /* max hash chain length */ + var scan = s.strstart; /* current string */ + var match; /* matched string */ + var len; /* length of current match */ + var best_len = + s.prev_length; /* best match length so far */ + var nice_match = + s.nice_match; /* stop if match long enough */ + var limit = + s.strstart > s.w_size - MIN_LOOKAHEAD + ? s.strstart - (s.w_size - MIN_LOOKAHEAD) + : 0; /*NIL*/ + + var _win = s.window; // shortcut + + var wmask = s.w_mask; + var prev = s.prev; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + var strend = s.strstart + MAX_MATCH; + var scan_end1 = _win[scan + best_len - 1]; + var scan_end = _win[scan + best_len]; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (nice_match > s.lookahead) { + nice_match = s.lookahead; + } + + // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if ( + _win[match + best_len] !== scan_end || + _win[match + best_len - 1] !== scan_end1 || + _win[match] !== _win[scan] || + _win[++match] !== _win[scan + 1] + ) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2; + match++; + // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + /*jshint noempty:false*/ + } while ( + _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && + scan < strend + ); + + // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + if (len >= nice_match) { + break; + } + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ( + (cur_match = prev[cur_match & wmask]) > limit && + --chain_length !== 0 + ); + + if (best_len <= s.lookahead) { + return best_len; + } + return s.lookahead; + } + + /* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ + function fill_window(s) { + var _w_size = s.w_size; + var p, n, m, more, str; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; + + // JS ints have 32 bit, block below not needed + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if ( + s.strstart >= + _w_size + (_w_size - MIN_LOOKAHEAD) + ) { + utils.arraySet( + s.window, + s.window, + _w_size, + _w_size, + 0 + ); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + s.block_start -= _w_size; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + + n = s.hash_size; + p = n; + do { + m = s.head[--p]; + s.head[p] = m >= _w_size ? m - _w_size : 0; + } while (--n); + + n = _w_size; + p = n; + do { + m = s.prev[--p]; + s.prev[p] = m >= _w_size ? m - _w_size : 0; + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += _w_size; + } + if (s.strm.avail_in === 0) { + break; + } + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf( + s.strm, + s.window, + s.strstart + s.lookahead, + more + ); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[str + 1]) & + s.hash_mask; + //#if MIN_MATCH != 3 + // Call update_hash() MIN_MATCH-3 more times + //#endif + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[str + MIN_MATCH - 1]) & + s.hash_mask; + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; + } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + } while ( + s.lookahead < MIN_LOOKAHEAD && + s.strm.avail_in !== 0 + ); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + // if (s.high_water < s.window_size) { + // var curr = s.strstart + s.lookahead; + // var init = 0; + // + // if (s.high_water < curr) { + // /* Previous high water mark below current data -- zero WIN_INIT + // * bytes or up to end of window, whichever is less. + // */ + // init = s.window_size - curr; + // if (init > WIN_INIT) + // init = WIN_INIT; + // zmemzero(s->window + curr, (unsigned)init); + // s->high_water = curr + init; + // } + // else if (s->high_water < (ulg)curr + WIN_INIT) { + // /* High water mark at or above current data, but below current data + // * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + // * to end of window, whichever is less. + // */ + // init = (ulg)curr + WIN_INIT - s->high_water; + // if (init > s->window_size - s->high_water) + // init = s->window_size - s->high_water; + // zmemzero(s->window + s->high_water, (unsigned)init); + // s->high_water += init; + // } + // } + // + // Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + // "not enough room for search"); + } + + /* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ + function deflate_stored(s, flush) { + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + var max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); + // if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || + // s.block_start >= s.w_size)) { + // throw new Error("slide too late"); + // } + + fill_window(s); + if (s.lookahead === 0 && flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + } + //Assert(s->block_start >= 0L, "block gone"); + // if (s.block_start < 0) throw new Error("block gone"); + + s.strstart += s.lookahead; + s.lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + var max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if ( + s.strstart - s.block_start >= + s.w_size - MIN_LOOKAHEAD + ) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + + s.insert = 0; + + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_NEED_MORE; + } + + /* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ + function deflate_fast(s, flush) { + var hash_head; /* head of the hash chain */ + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if ( + s.lookahead < MIN_LOOKAHEAD && + flush === Z_NO_FLUSH + ) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; /* flush the current block */ + } + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0 /*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[s.strstart + MIN_MATCH - 1]) & + s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = + s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if ( + hash_head !== 0 /*NIL*/ && + s.strstart - hash_head <= + s.w_size - MIN_LOOKAHEAD + ) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally( + s, + s.strstart - s.match_start, + s.match_length - MIN_MATCH + ); + + s.lookahead -= s.match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if ( + s.match_length <= + s.max_lazy_match /*max_insert_length*/ && + s.lookahead >= MIN_MATCH + ) { + s.match_length--; /* string at strstart already in table */ + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[ + s.strstart + MIN_MATCH - 1 + ]) & + s.hash_mask; + hash_head = s.prev[ + s.strstart & s.w_mask + ] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + s.strstart++; + } else { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[s.strstart + 1]) & + s.hash_mask; + + //#if MIN_MATCH != 3 + // Call UPDATE_HASH() MIN_MATCH-3 more times + //#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally( + s, + 0, + s.window[s.strstart] + ); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = + s.strstart < MIN_MATCH - 1 + ? s.strstart + : MIN_MATCH - 1; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; + } + + /* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ + function deflate_slow(s, flush) { + var hash_head; /* head of hash chain */ + var bflush; /* set if current block must be flushed */ + + var max_insert; + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if ( + s.lookahead < MIN_LOOKAHEAD && + flush === Z_NO_FLUSH + ) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; + } /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0 /*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[s.strstart + MIN_MATCH - 1]) & + s.hash_mask; + hash_head = s.prev[s.strstart & s.w_mask] = + s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + */ + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH - 1; + + if ( + hash_head !== 0 /*NIL*/ && + s.prev_length < s.max_lazy_match && + s.strstart - hash_head <= + s.w_size - MIN_LOOKAHEAD /*MAX_DIST(s)*/ + ) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if ( + s.match_length <= 5 && + (s.strategy === Z_FILTERED || + (s.match_length === MIN_MATCH && + s.strstart - s.match_start > + 4096) /*TOO_FAR*/) + ) { + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH - 1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if ( + s.prev_length >= MIN_MATCH && + s.match_length <= s.prev_length + ) { + max_insert = + s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + bflush = trees._tr_tally( + s, + s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH + ); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s.lookahead -= s.prev_length - 1; + s.prev_length -= 2; + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[ + s.strstart + MIN_MATCH - 1 + ]) & + s.hash_mask; + hash_head = s.prev[ + s.strstart & s.w_mask + ] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + s.match_available = 0; + s.match_length = MIN_MATCH - 1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally( + s, + 0, + s.window[s.strstart - 1] + ); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + s.strstart++; + s.lookahead--; + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; + } + } + //Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = trees._tr_tally( + s, + 0, + s.window[s.strstart - 1] + ); + + s.match_available = 0; + } + s.insert = + s.strstart < MIN_MATCH - 1 + ? s.strstart + : MIN_MATCH - 1; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + return BS_BLOCK_DONE; + } + + /* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ + function deflate_rle(s, flush) { + var bflush; /* set if current block must be flushed */ + var prev; /* byte at distance one to match */ + var scan, + strend; /* scan goes up to strend for length of run */ + + var _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + if ( + s.lookahead <= MAX_MATCH && + flush === Z_NO_FLUSH + ) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; + } /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s.match_length = 0; + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + if ( + prev === _win[++scan] && + prev === _win[++scan] && + prev === _win[++scan] + ) { + strend = s.strstart + MAX_MATCH; + do { + /*jshint noempty:false*/ + } while ( + prev === _win[++scan] && + prev === _win[++scan] && + prev === _win[++scan] && + prev === _win[++scan] && + prev === _win[++scan] && + prev === _win[++scan] && + prev === _win[++scan] && + prev === _win[++scan] && + scan < strend + ); + s.match_length = + MAX_MATCH - (strend - scan); + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } + //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = trees._tr_tally( + s, + 1, + s.match_length - MIN_MATCH + ); + + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally( + s, + 0, + s.window[s.strstart] + ); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; + } + + /* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ + function deflate_huff(s, flush) { + var bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH) { + return BS_NEED_MORE; + } + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s.match_length = 0; + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = trees._tr_tally( + s, + 0, + s.window[s.strstart] + ); + s.lookahead--; + s.strstart++; + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; + } + + /* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ + function Config( + good_length, + max_lazy, + nice_length, + max_chain, + func + ) { + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; + } + + var configuration_table; + + configuration_table = [ + /* good lazy nice chain */ + new Config( + 0, + 0, + 0, + 0, + deflate_stored + ) /* 0 store only */, + new Config( + 4, + 4, + 8, + 4, + deflate_fast + ) /* 1 max speed, no lazy matches */, + new Config(4, 5, 16, 8, deflate_fast) /* 2 */, + new Config(4, 6, 32, 32, deflate_fast) /* 3 */, + + new Config( + 4, + 4, + 16, + 16, + deflate_slow + ) /* 4 lazy matches */, + new Config(8, 16, 32, 32, deflate_slow) /* 5 */, + new Config(8, 16, 128, 128, deflate_slow) /* 6 */, + new Config(8, 32, 128, 256, deflate_slow) /* 7 */, + new Config(32, 128, 258, 1024, deflate_slow) /* 8 */, + new Config( + 32, + 258, + 258, + 4096, + deflate_slow + ) /* 9 max compression */, + ]; + + /* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ + function lm_init(s) { + s.window_size = 2 * s.w_size; + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: + */ + s.max_lazy_match = + configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = + configuration_table[s.level].max_chain; + + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; + } + + function DeflateState() { + this.strm = null; /* pointer back to this zlib stream */ + this.status = 0; /* as the name implies */ + this.pending_buf = null; /* output still pending */ + this.pending_buf_size = 0; /* size of pending_buf */ + this.pending_out = 0; /* next pending byte to output to the stream */ + this.pending = 0; /* nb of bytes in the pending buffer */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.gzhead = + null; /* gzip header information to write */ + this.gzindex = 0; /* where in extra, name, or comment */ + this.method = Z_DEFLATED; /* can only be DEFLATED */ + this.last_flush = + -1; /* value of flush param for previous deflate call */ + + this.w_size = 0; /* LZ77 window size (32K by default) */ + this.w_bits = 0; /* log2(w_size) (8..16) */ + this.w_mask = 0; /* w_size - 1 */ + + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + this.head = null; /* Heads of the hash chains or NIL. */ + + this.ins_h = 0; /* hash index of string to be inserted */ + this.hash_size = 0; /* number of elements in hash table */ + this.hash_bits = 0; /* log2(hash_size) */ + this.hash_mask = 0; /* hash_size-1 */ + + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + this.match_length = 0; /* length of best match */ + this.prev_match = 0; /* previous match */ + this.match_available = 0; /* set if previous match exists */ + this.strstart = 0; /* start of string to insert */ + this.match_start = 0; /* start of matching string */ + this.lookahead = 0; /* number of valid bytes ahead in window */ + + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + this.level = 0; /* compression level (1..9) */ + this.strategy = 0; /* favor or force Huffman coding*/ + + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); + this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2); + this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + + this.l_desc = null; /* desc. for literal tree */ + this.d_desc = null; /* desc. for distance tree */ + this.bl_desc = null; /* desc. for bit length tree */ + + //ush bl_count[MAX_BITS+1]; + this.bl_count = new utils.Buf16(MAX_BITS + 1); + /* number of codes at each bit length for an optimal tree */ + + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + this.heap = new utils.Buf16( + 2 * L_CODES + 1 + ); /* heap used to build the Huffman trees */ + zero(this.heap); + + this.heap_len = 0; /* number of elements in the heap */ + this.heap_max = 0; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + this.l_buf = 0; /* buffer index for literals or lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.last_lit = 0; /* running index in l_buf */ + + this.d_buf = 0; + /* Buffer index for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + this.opt_len = 0; /* bit length of current block with optimal trees */ + this.static_len = 0; /* bit length of current block with static trees */ + this.matches = 0; /* number of string matches in current block */ + this.insert = 0; /* bytes at end of window left to insert */ + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + } + + function deflateResetKeep(strm) { + var s; + + if (!strm || !strm.state) { + return err(strm, Z_STREAM_ERROR); + } + + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; + + s = strm.state; + s.pending = 0; + s.pending_out = 0; + + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ + } + s.status = s.wrap ? INIT_STATE : BUSY_STATE; + strm.adler = + s.wrap === 2 + ? 0 // crc32(0, Z_NULL, 0) + : 1; // adler32(0, Z_NULL, 0) + s.last_flush = Z_NO_FLUSH; + trees._tr_init(s); + return Z_OK; + } + + function deflateReset(strm) { + var ret = deflateResetKeep(strm); + if (ret === Z_OK) { + lm_init(strm.state); + } + return ret; + } + + function deflateSetHeader(strm, head) { + if (!strm || !strm.state) { + return Z_STREAM_ERROR; + } + if (strm.state.wrap !== 2) { + return Z_STREAM_ERROR; + } + strm.state.gzhead = head; + return Z_OK; + } + + function deflateInit2( + strm, + level, + method, + windowBits, + memLevel, + strategy + ) { + if (!strm) { + // === Z_NULL + return Z_STREAM_ERROR; + } + var wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION) { + level = 6; + } + + if (windowBits < 0) { + /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } + + if ( + memLevel < 1 || + memLevel > MAX_MEM_LEVEL || + method !== Z_DEFLATED || + windowBits < 8 || + windowBits > 15 || + level < 0 || + level > 9 || + strategy < 0 || + strategy > Z_FIXED + ) { + return err(strm, Z_STREAM_ERROR); + } + + if (windowBits === 8) { + windowBits = 9; + } + /* until 256-byte window bug fixed */ + + var s = new DeflateState(); + + strm.state = s; + s.strm = strm; + + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~( + (s.hash_bits + MIN_MATCH - 1) / + MIN_MATCH + ); + + s.window = new utils.Buf8(s.w_size * 2); + s.head = new utils.Buf16(s.hash_size); + s.prev = new utils.Buf16(s.w_size); + + // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = + 1 << (memLevel + 6); /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; + + //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + //s->pending_buf = (uchf *) overlay; + s.pending_buf = new utils.Buf8(s.pending_buf_size); + + // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) + //s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s.d_buf = 1 * s.lit_bufsize; + + //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + s.l_buf = (1 + 2) * s.lit_bufsize; + + s.level = level; + s.strategy = strategy; + s.method = method; + + return deflateReset(strm); + } + + function deflateInit(strm, level) { + return deflateInit2( + strm, + level, + Z_DEFLATED, + MAX_WBITS, + DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY + ); + } + + function deflate(strm, flush) { + var old_flush, s; + var beg, val; // for gzip header write only + + if ( + !strm || + !strm.state || + flush > Z_BLOCK || + flush < 0 + ) { + return strm + ? err(strm, Z_STREAM_ERROR) + : Z_STREAM_ERROR; + } + + s = strm.state; + + if ( + !strm.output || + (!strm.input && strm.avail_in !== 0) || + (s.status === FINISH_STATE && flush !== Z_FINISH) + ) { + return err( + strm, + strm.avail_out === 0 + ? Z_BUF_ERROR + : Z_STREAM_ERROR + ); + } + + s.strm = strm; /* just in case */ + old_flush = s.last_flush; + s.last_flush = flush; + + /* Write the header */ + if (s.status === INIT_STATE) { + if (s.wrap === 2) { + // GZIP header + strm.adler = 0; //crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (!s.gzhead) { + // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte( + s, + s.level === 9 + ? 2 + : s.strategy >= Z_HUFFMAN_ONLY || + s.level < 2 + ? 4 + : 0 + ); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + } else { + put_byte( + s, + (s.gzhead.text ? 1 : 0) + + (s.gzhead.hcrc ? 2 : 0) + + (!s.gzhead.extra ? 0 : 4) + + (!s.gzhead.name ? 0 : 8) + + (!s.gzhead.comment ? 0 : 16) + ); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, (s.gzhead.time >> 8) & 0xff); + put_byte(s, (s.gzhead.time >> 16) & 0xff); + put_byte(s, (s.gzhead.time >> 24) & 0xff); + put_byte( + s, + s.level === 9 + ? 2 + : s.strategy >= Z_HUFFMAN_ONLY || + s.level < 2 + ? 4 + : 0 + ); + put_byte(s, s.gzhead.os & 0xff); + if ( + s.gzhead.extra && + s.gzhead.extra.length + ) { + put_byte( + s, + s.gzhead.extra.length & 0xff + ); + put_byte( + s, + (s.gzhead.extra.length >> 8) & 0xff + ); + } + if (s.gzhead.hcrc) { + strm.adler = crc32( + strm.adler, + s.pending_buf, + s.pending, + 0 + ); + } + s.gzindex = 0; + s.status = EXTRA_STATE; + } + } // DEFLATE header + else { + var header = + (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; + var level_flags = -1; + + if ( + s.strategy >= Z_HUFFMAN_ONLY || + s.level < 2 + ) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= level_flags << 6; + if (s.strstart !== 0) { + header |= PRESET_DICT; + } + header += 31 - (header % 31); + + s.status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1; // adler32(0L, Z_NULL, 0); + } + } + + //#ifdef GZIP + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra /* != Z_NULL*/) { + beg = + s.pending; /* start of bytes to update crc */ + + while ( + s.gzindex < + (s.gzhead.extra.length & 0xffff) + ) { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32( + strm.adler, + s.pending_buf, + s.pending - beg, + beg + ); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + break; + } + } + put_byte( + s, + s.gzhead.extra[s.gzindex] & 0xff + ); + s.gzindex++; + } + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32( + strm.adler, + s.pending_buf, + s.pending - beg, + beg + ); + } + if (s.gzindex === s.gzhead.extra.length) { + s.gzindex = 0; + s.status = NAME_STATE; + } + } else { + s.status = NAME_STATE; + } + } + if (s.status === NAME_STATE) { + if (s.gzhead.name /* != Z_NULL*/) { + beg = + s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32( + strm.adler, + s.pending_buf, + s.pending - beg, + beg + ); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.name.length) { + val = + s.gzhead.name.charCodeAt( + s.gzindex++ + ) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32( + strm.adler, + s.pending_buf, + s.pending - beg, + beg + ); + } + if (val === 0) { + s.gzindex = 0; + s.status = COMMENT_STATE; + } + } else { + s.status = COMMENT_STATE; + } + } + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment /* != Z_NULL*/) { + beg = + s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32( + strm.adler, + s.pending_buf, + s.pending - beg, + beg + ); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.comment.length) { + val = + s.gzhead.comment.charCodeAt( + s.gzindex++ + ) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32( + strm.adler, + s.pending_buf, + s.pending - beg, + beg + ); + } + if (val === 0) { + s.status = HCRC_STATE; + } + } else { + s.status = HCRC_STATE; + } + } + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + } + if (s.pending + 2 <= s.pending_buf_size) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + s.status = BUSY_STATE; + } + } else { + s.status = BUSY_STATE; + } + } + //#endif + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if ( + strm.avail_in === 0 && + rank(flush) <= rank(old_flush) && + flush !== Z_FINISH + ) { + return err(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if ( + strm.avail_in !== 0 || + s.lookahead !== 0 || + (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE) + ) { + var bstate = + s.strategy === Z_HUFFMAN_ONLY + ? deflate_huff(s, flush) + : s.strategy === Z_RLE + ? deflate_rle(s, flush) + : configuration_table[s.level].func( + s, + flush + ); + + if ( + bstate === BS_FINISH_STARTED || + bstate === BS_FINISH_DONE + ) { + s.status = FINISH_STATE; + } + if ( + bstate === BS_NEED_MORE || + bstate === BS_FINISH_STARTED + ) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + trees._tr_align(s); + } else if (flush !== Z_BLOCK) { + /* FULL_FLUSH or SYNC_FLUSH */ + + trees._tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === Z_FULL_FLUSH) { + /*** CLEAR_HASH(s); ***/ /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = + -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + if (flush !== Z_FINISH) { + return Z_OK; + } + if (s.wrap <= 0) { + return Z_STREAM_END; + } + + /* Write the trailer */ + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + put_byte(s, (strm.adler >> 16) & 0xff); + put_byte(s, (strm.adler >> 24) & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, (strm.total_in >> 8) & 0xff); + put_byte(s, (strm.total_in >> 16) & 0xff); + put_byte(s, (strm.total_in >> 24) & 0xff); + } else { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { + s.wrap = -s.wrap; + } + /* write the trailer only once! */ + return s.pending !== 0 ? Z_OK : Z_STREAM_END; + } + + function deflateEnd(strm) { + var status; + + if (!strm /*== Z_NULL*/ || !strm.state /*== Z_NULL*/) { + return Z_STREAM_ERROR; + } + + status = strm.state.status; + if ( + status !== INIT_STATE && + status !== EXTRA_STATE && + status !== NAME_STATE && + status !== COMMENT_STATE && + status !== HCRC_STATE && + status !== BUSY_STATE && + status !== FINISH_STATE + ) { + return err(strm, Z_STREAM_ERROR); + } + + strm.state = null; + + return status === BUSY_STATE + ? err(strm, Z_DATA_ERROR) + : Z_OK; + } + + /* ========================================================================= + * Initializes the compression dictionary from the given byte + * sequence without producing any compressed output. + */ + function deflateSetDictionary(strm, dictionary) { + var dictLength = dictionary.length; + + var s; + var str, n; + var wrap; + var avail; + var next; + var input; + var tmpDict; + + if (!strm /*== Z_NULL*/ || !strm.state /*== Z_NULL*/) { + return Z_STREAM_ERROR; + } + + s = strm.state; + wrap = s.wrap; + + if ( + wrap === 2 || + (wrap === 1 && s.status !== INIT_STATE) || + s.lookahead + ) { + return Z_STREAM_ERROR; + } + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap === 1) { + /* adler32(strm->adler, dictionary, dictLength); */ + strm.adler = adler32( + strm.adler, + dictionary, + dictLength, + 0 + ); + } + + s.wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s.w_size) { + if (wrap === 0) { + /* already empty otherwise */ + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + /* use the tail */ + // dictionary = dictionary.slice(dictLength - s.w_size); + tmpDict = new utils.Buf8(s.w_size); + utils.arraySet( + tmpDict, + dictionary, + dictLength - s.w_size, + s.w_size, + 0 + ); + dictionary = tmpDict; + dictLength = s.w_size; + } + /* insert dictionary into window and hash */ + avail = strm.avail_in; + next = strm.next_in; + input = strm.input; + strm.avail_in = dictLength; + strm.next_in = 0; + strm.input = dictionary; + fill_window(s); + while (s.lookahead >= MIN_MATCH) { + str = s.strstart; + n = s.lookahead - (MIN_MATCH - 1); + do { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = + ((s.ins_h << s.hash_shift) ^ + s.window[str + MIN_MATCH - 1]) & + s.hash_mask; + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + + s.head[s.ins_h] = str; + str++; + } while (--n); + s.strstart = str; + s.lookahead = MIN_MATCH - 1; + fill_window(s); + } + s.strstart += s.lookahead; + s.block_start = s.strstart; + s.insert = s.lookahead; + s.lookahead = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + strm.next_in = next; + strm.input = input; + strm.avail_in = avail; + s.wrap = wrap; + return Z_OK; + } + + exports.deflateInit = deflateInit; + exports.deflateInit2 = deflateInit2; + exports.deflateReset = deflateReset; + exports.deflateResetKeep = deflateResetKeep; + exports.deflateSetHeader = deflateSetHeader; + exports.deflate = deflate; + exports.deflateEnd = deflateEnd; + exports.deflateSetDictionary = deflateSetDictionary; + exports.deflateInfo = "pako deflate (from Nodeca project)"; + + /* Not implemented + exports.deflateBound = deflateBound; + exports.deflateCopy = deflateCopy; + exports.deflateParams = deflateParams; + exports.deflatePending = deflatePending; + exports.deflatePrime = deflatePrime; + exports.deflateTune = deflateTune; + */ + }, + { + "../utils/common": 28, + "./adler32": 30, + "./crc32": 32, + "./messages": 38, + "./trees": 39, + }, + ], + 34: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + 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; + }, + {}, + ], + 35: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // 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 defaults, + // 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; + }; + }, + {}, + ], + 36: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + 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; + + // goto emulation + inf_leave: 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 convenient 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 defaults, + // 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 '|' instead 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 + ) + ) { + state.mode = MEM; + return Z_MEM_ERROR; + } + } + _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": 28, + "./adler32": 30, + "./crc32": 32, + "./inffast": 35, + "./inftrees": 37, + }, + ], + 37: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + 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": 28 }, + ], + 38: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + 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) */, + }; + }, + {}, + ], + 39: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + /* eslint-disable space-unary-ops */ + + var utils = require("../utils/common"); + + /* Public constants ==========================================================*/ + /* ===========================================================================*/ + + //var Z_FILTERED = 1; + //var Z_HUFFMAN_ONLY = 2; + //var Z_RLE = 3; + var Z_FIXED = 4; + //var Z_DEFAULT_STRATEGY = 0; + + /* Possible values of the data_type field (though see inflate()) */ + var Z_BINARY = 0; + var Z_TEXT = 1; + //var Z_ASCII = 1; // = Z_TEXT + var Z_UNKNOWN = 2; + + /*============================================================================*/ + + function zero(buf) { + var len = buf.length; + while (--len >= 0) { + buf[len] = 0; + } + } + + // From zutil.h + + var STORED_BLOCK = 0; + var STATIC_TREES = 1; + var DYN_TREES = 2; + /* The three kinds of block type */ + + var MIN_MATCH = 3; + var MAX_MATCH = 258; + /* The minimum and maximum match lengths */ + + // From deflate.h + /* =========================================================================== + * Internal compression state. + */ + + var LENGTH_CODES = 29; + /* number of length codes, not counting the special END_BLOCK code */ + + var LITERALS = 256; + /* number of literal bytes 0..255 */ + + var L_CODES = LITERALS + 1 + LENGTH_CODES; + /* number of Literal or Length codes, including the END_BLOCK code */ + + var D_CODES = 30; + /* number of distance codes */ + + var BL_CODES = 19; + /* number of codes used to transfer the bit lengths */ + + var HEAP_SIZE = 2 * L_CODES + 1; + /* maximum heap size */ + + var MAX_BITS = 15; + /* All codes must not exceed MAX_BITS bits */ + + var Buf_size = 16; + /* size of bit buffer in bi_buf */ + + /* =========================================================================== + * Constants + */ + + var MAX_BL_BITS = 7; + /* Bit length codes must not exceed MAX_BL_BITS bits */ + + var END_BLOCK = 256; + /* end of block literal code */ + + var REP_3_6 = 16; + /* repeat previous bit length 3-6 times (2 bits of repeat count) */ + + var REPZ_3_10 = 17; + /* repeat a zero length 3-10 times (3 bits of repeat count) */ + + var REPZ_11_138 = 18; + /* repeat a zero length 11-138 times (7 bits of repeat count) */ + + /* eslint-disable comma-spacing,array-bracket-spacing */ + var extra_lbits = + /* extra bits for each length code */ + [ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, + 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, + ]; + + var extra_dbits = + /* extra bits for each distance code */ + [ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, + 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, + ]; + + var extra_blbits = + /* extra bits for each bit length code */ + [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 3, 7, + ]; + + var bl_order = [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, + 14, 1, 15, + ]; + /* eslint-enable comma-spacing,array-bracket-spacing */ + + /* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + + /* =========================================================================== + * Local data. These are initialized only once. + */ + + // We pre-fill arrays with 0 to avoid uninitialized gaps + + var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ + + // !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 + var static_ltree = new Array((L_CODES + 2) * 2); + zero(static_ltree); + /* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + + var static_dtree = new Array(D_CODES * 2); + zero(static_dtree); + /* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + + var _dist_code = new Array(DIST_CODE_LEN); + zero(_dist_code); + /* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + + var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1); + zero(_length_code); + /* length code for each normalized match length (0 == MIN_MATCH) */ + + var base_length = new Array(LENGTH_CODES); + zero(base_length); + /* First normalized length for each code (0 = MIN_MATCH) */ + + var base_dist = new Array(D_CODES); + zero(base_dist); + /* First normalized distance for each code (0 = distance of 1) */ + + function StaticTreeDesc( + static_tree, + extra_bits, + extra_base, + elems, + max_length + ) { + this.static_tree = + static_tree; /* static tree or NULL */ + this.extra_bits = + extra_bits; /* extra bits for each code or NULL */ + this.extra_base = + extra_base; /* base index for extra_bits */ + this.elems = + elems; /* max number of elements in the tree */ + this.max_length = + max_length; /* max bit length for the codes */ + + // show if `static_tree` has data or dummy - needed for monomorphic objects + this.has_stree = static_tree && static_tree.length; + } + + var static_l_desc; + var static_d_desc; + var static_bl_desc; + + function TreeDesc(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; /* the dynamic tree */ + this.max_code = 0; /* largest code with non zero frequency */ + this.stat_desc = + stat_desc; /* the corresponding static tree */ + } + + function d_code(dist) { + return dist < 256 + ? _dist_code[dist] + : _dist_code[256 + (dist >>> 7)]; + } + + /* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ + function put_short(s, w) { + // put_byte(s, (uch)((w) & 0xff)); + // put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = w & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; + } + + /* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ + function send_bits(s, value, length) { + if (s.bi_valid > Buf_size - length) { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> (Buf_size - s.bi_valid); + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + s.bi_valid += length; + } + } + + function send_code(s, c, tree) { + send_bits( + s, + tree[c * 2] /*.Code*/, + tree[c * 2 + 1] /*.Len*/ + ); + } + + /* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ + function bi_reverse(code, len) { + var res = 0; + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + return res >>> 1; + } + + /* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ + function bi_flush(s) { + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } + } + + /* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ + function gen_bitlen(s, desc) { + // deflate_state *s; + // tree_desc *desc; /* the tree descriptor */ + var tree = desc.dyn_tree; + var max_code = desc.max_code; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var extra = desc.stat_desc.extra_bits; + var base = desc.stat_desc.extra_base; + var max_length = desc.stat_desc.max_length; + var h; /* heap index */ + var n, m; /* iterate over the tree elements */ + var bits; /* bit length */ + var xbits; /* extra bits */ + var f; /* frequency */ + var overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) { + s.bl_count[bits] = 0; + } + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[ + s.heap[s.heap_max] * 2 + 1 + ] /*.Len*/ = 0; /* root of the heap */ + + for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { + n = s.heap[h]; + bits = + tree[ + tree[n * 2 + 1] /*.Dad*/ * 2 + 1 + ] /*.Len*/ + 1; + if (bits > max_length) { + bits = max_length; + overflow++; + } + tree[n * 2 + 1] /*.Len*/ = bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) { + continue; + } /* not a leaf node */ + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) { + xbits = extra[n - base]; + } + f = tree[n * 2] /*.Freq*/; + s.opt_len += f * (bits + xbits); + if (has_stree) { + s.static_len += + f * (stree[n * 2 + 1] /*.Len*/ + xbits); + } + } + if (overflow === 0) { + return; + } + + // Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s.bl_count[bits] === 0) { + bits--; + } + s.bl_count[ + bits + ]--; /* move one leaf down the tree */ + s.bl_count[ + bits + 1 + ] += 2; /* move one overflow item as its brother */ + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + while (n !== 0) { + m = s.heap[--h]; + if (m > max_code) { + continue; + } + if (tree[m * 2 + 1] /*.Len*/ !== bits) { + // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += + (bits - tree[m * 2 + 1]) /*.Len*/ * + tree[m * 2] /*.Freq*/; + tree[m * 2 + 1] /*.Len*/ = bits; + } + n--; + } + } + } + + /* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ + function gen_codes(tree, max_code, bl_count) { + // ct_data *tree; /* the tree to decorate */ + // int max_code; /* largest code with non zero frequency */ + // ushf *bl_count; /* number of codes at each bit length */ + var next_code = new Array( + MAX_BITS + 1 + ); /* next code value for each bit length */ + var code = 0; /* running code value */ + var bits; /* bit index */ + var n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = + (code + bl_count[bits - 1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES - 1; code++) { + base_length[code] = length; + for (n = 0; n < 1 << extra_lbits[code]; n++) { + _length_code[length++] = code; + } + } + //Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length - 1] = code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < 1 << extra_dbits[code]; n++) { + _dist_code[dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for (; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < 1 << (extra_dbits[code] - 7); n++) { + _dist_code[256 + dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) { + bl_count[bits] = 0; + } + + n = 0; + while (n <= 143) { + static_ltree[n * 2 + 1] /*.Len*/ = 8; + n++; + bl_count[8]++; + } + while (n <= 255) { + static_ltree[n * 2 + 1] /*.Len*/ = 9; + n++; + bl_count[9]++; + } + while (n <= 279) { + static_ltree[n * 2 + 1] /*.Len*/ = 7; + n++; + bl_count[7]++; + } + while (n <= 287) { + static_ltree[n * 2 + 1] /*.Len*/ = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(static_ltree, L_CODES + 1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n * 2 + 1] /*.Len*/ = 5; + static_dtree[n * 2] /*.Code*/ = bi_reverse(n, 5); + } + + // Now data ready and we can init static trees + static_l_desc = new StaticTreeDesc( + static_ltree, + extra_lbits, + LITERALS + 1, + L_CODES, + MAX_BITS + ); + static_d_desc = new StaticTreeDesc( + static_dtree, + extra_dbits, + 0, + D_CODES, + MAX_BITS + ); + static_bl_desc = new StaticTreeDesc( + new Array(0), + extra_blbits, + 0, + BL_CODES, + MAX_BL_BITS + ); + + //static_init_done = true; + } + + /* =========================================================================== + * Initialize a new block. + */ + function init_block(s) { + var n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) { + s.dyn_ltree[n * 2] /*.Freq*/ = 0; + } + for (n = 0; n < D_CODES; n++) { + s.dyn_dtree[n * 2] /*.Freq*/ = 0; + } + for (n = 0; n < BL_CODES; n++) { + s.bl_tree[n * 2] /*.Freq*/ = 0; + } + + s.dyn_ltree[END_BLOCK * 2] /*.Freq*/ = 1; + s.opt_len = s.static_len = 0; + s.last_lit = s.matches = 0; + } + + /* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ + function bi_windup(s) { + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; + } + + /* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ + function copy_block(s, buf, len, header) { + //DeflateState *s; + //charf *buf; /* the input data */ + //unsigned len; /* its length */ + //int header; /* true if block header must be written */ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, len); + put_short(s, ~len); + } + // while (len--) { + // put_byte(s, *buf++); + // } + utils.arraySet( + s.pending_buf, + s.window, + buf, + len, + s.pending + ); + s.pending += len; + } + + /* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ + function smaller(tree, n, m, depth) { + var _n2 = n * 2; + var _m2 = m * 2; + return ( + tree[_n2] /*.Freq*/ < tree[_m2] /*.Freq*/ || + (tree[_n2] /*.Freq*/ === tree[_m2] /*.Freq*/ && + depth[n] <= depth[m]) + ); + } + + /* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ + function pqdownheap(s, tree, k) { + // deflate_state *s; + // ct_data *tree; /* the tree to restore */ + // int k; /* node to move down */ + var v = s.heap[k]; + var j = k << 1; /* left son of k */ + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if ( + j < s.heap_len && + smaller(tree, s.heap[j + 1], s.heap[j], s.depth) + ) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s.heap[j], s.depth)) { + break; + } + + /* Exchange v with the smallest son */ + s.heap[k] = s.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s.heap[k] = v; + } + + // inlined manually + // var SMALLEST = 1; + + /* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ + function compress_block(s, ltree, dtree) { + // deflate_state *s; + // const ct_data *ltree; /* literal tree */ + // const ct_data *dtree; /* distance tree */ + var dist; /* distance of matched string */ + var lc; /* match length or unmatched char (if dist == 0) */ + var lx = 0; /* running index in l_buf */ + var code; /* the code to send */ + var extra; /* number of extra bits to send */ + + if (s.last_lit !== 0) { + do { + dist = + (s.pending_buf[s.d_buf + lx * 2] << 8) | + s.pending_buf[s.d_buf + lx * 2 + 1]; + lc = s.pending_buf[s.l_buf + lx]; + lx++; + + if (dist === 0) { + send_code( + s, + lc, + ltree + ); /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code( + s, + code + LITERALS + 1, + ltree + ); /* send the length code */ + extra = extra_lbits[code]; + if (extra !== 0) { + lc -= base_length[code]; + send_bits( + s, + lc, + extra + ); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + //Assert (code < D_CODES, "bad d_code"); + + send_code( + s, + code, + dtree + ); /* send the distance code */ + extra = extra_dbits[code]; + if (extra !== 0) { + dist -= base_dist[code]; + send_bits( + s, + dist, + extra + ); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + // "pendingBuf overflow"); + } while (lx < s.last_lit); + } + + send_code(s, END_BLOCK, ltree); + } + + /* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ + function build_tree(s, desc) { + // deflate_state *s; + // tree_desc *desc; /* the tree descriptor */ + var tree = desc.dyn_tree; + var stree = desc.stat_desc.static_tree; + var has_stree = desc.stat_desc.has_stree; + var elems = desc.stat_desc.elems; + var n, m; /* iterate over heap elements */ + var max_code = + -1; /* largest code with non zero frequency */ + var node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s.heap_len = 0; + s.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n * 2] /*.Freq*/ !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; + } else { + tree[n * 2 + 1] /*.Len*/ = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = + max_code < 2 ? ++max_code : 0; + tree[node * 2] /*.Freq*/ = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node * 2 + 1] /*.Len*/; + } + /* node is 0 or 1 so it does not have extra bits */ + } + desc.max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s.heap_len >> 1 /*int /2*/; n >= 1; n--) { + pqdownheap(s, tree, n); + } + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + /*** pqremove ***/ + n = s.heap[1 /*SMALLEST*/]; + s.heap[1 /*SMALLEST*/] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1 /*SMALLEST*/); + /***/ + + m = + s + .heap[1 /*SMALLEST*/]; /* m = node of next least frequency */ + + s.heap[--s.heap_max] = + n; /* keep the nodes sorted by frequency */ + s.heap[--s.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node * 2] /*.Freq*/ = + tree[n * 2] /*.Freq*/ + tree[m * 2] /*.Freq*/; + s.depth[node] = + (s.depth[n] >= s.depth[m] + ? s.depth[n] + : s.depth[m]) + 1; + tree[n * 2 + 1] /*.Dad*/ = tree[ + m * 2 + 1 + ] /*.Dad*/ = node; + + /* and insert the new node in the heap */ + s.heap[1 /*SMALLEST*/] = node++; + pqdownheap(s, tree, 1 /*SMALLEST*/); + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1 /*SMALLEST*/]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, s.bl_count); + } + + /* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ + function scan_tree(s, tree, max_code) { + // deflate_state *s; + // ct_data *tree; /* the tree to be scanned */ + // int max_code; /* and its largest code of non zero frequency */ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = + tree[0 * 2 + 1]; /*.Len*/ /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + tree[ + (max_code + 1) * 2 + 1 + ] /*.Len*/ = 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1] /*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + } else if (count < min_count) { + s.bl_tree[curlen * 2] /*.Freq*/ += count; + } else if (curlen !== 0) { + if (curlen !== prevlen) { + s.bl_tree[curlen * 2] /*.Freq*/++; + } + s.bl_tree[REP_3_6 * 2] /*.Freq*/++; + } else if (count <= 10) { + s.bl_tree[REPZ_3_10 * 2] /*.Freq*/++; + } else { + s.bl_tree[REPZ_11_138 * 2] /*.Freq*/++; + } + + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } + } + + /* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ + function send_tree(s, tree, max_code) { + // deflate_state *s; + // ct_data *tree; /* the tree to be scanned */ + // int max_code; /* and its largest code of non zero frequency */ + var n; /* iterates over all tree elements */ + var prevlen = -1; /* last emitted length */ + var curlen; /* length of current code */ + + var nextlen = + tree[0 * 2 + 1]; /*.Len*/ /* length of next code */ + + var count = 0; /* repeat count of the current code */ + var max_count = 7; /* max repeat count */ + var min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1] /*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + } else if (count < min_count) { + do { + send_code(s, curlen, s.bl_tree); + } while (--count !== 0); + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; + } + //Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count - 3, 2); + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count - 3, 3); + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count - 11, 7); + } + + count = 0; + prevlen = curlen; + if (nextlen === 0) { + max_count = 138; + min_count = 3; + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } + } + + /* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ + function build_bl_tree(s) { + var max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for ( + max_blindex = BL_CODES - 1; + max_blindex >= 3; + max_blindex-- + ) { + if ( + s.bl_tree[ + bl_order[max_blindex] * 2 + 1 + ] /*.Len*/ !== 0 + ) { + break; + } + } + /* Update opt_len to include the bit length tree and counts */ + s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); + + return max_blindex; + } + + /* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ + function send_all_trees(s, lcodes, dcodes, blcodes) { + // deflate_state *s; + // int lcodes, dcodes, blcodes; /* number of codes for each tree */ + var rank; /* index in bl_order */ + + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + send_bits( + s, + lcodes - 257, + 5 + ); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits( + s, + blcodes - 4, + 4 + ); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits( + s, + s.bl_tree[bl_order[rank] * 2 + 1] /*.Len*/, + 3 + ); + } + //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree( + s, + s.dyn_ltree, + lcodes - 1 + ); /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree( + s, + s.dyn_dtree, + dcodes - 1 + ); /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); + } + + /* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ + function detect_data_type(s) { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + var black_mask = 0xf3ffc07f; + var n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>>= 1) { + if ( + black_mask & 1 && + s.dyn_ltree[n * 2] /*.Freq*/ !== 0 + ) { + return Z_BINARY; + } + } + + /* Check for textual ("white-listed") bytes. */ + if ( + s.dyn_ltree[9 * 2] /*.Freq*/ !== 0 || + s.dyn_ltree[10 * 2] /*.Freq*/ !== 0 || + s.dyn_ltree[13 * 2] /*.Freq*/ !== 0 + ) { + return Z_TEXT; + } + for (n = 32; n < LITERALS; n++) { + if (s.dyn_ltree[n * 2] /*.Freq*/ !== 0) { + return Z_TEXT; + } + } + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; + } + + var static_init_done = false; + + /* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ + function _tr_init(s) { + if (!static_init_done) { + tr_static_init(); + static_init_done = true; + } + + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + + s.bi_buf = 0; + s.bi_valid = 0; + + /* Initialize the first block of the first file: */ + init_block(s); + } + + /* =========================================================================== + * Send a stored block + */ + function _tr_stored_block(s, buf, stored_len, last) { + //DeflateState *s; + //charf *buf; /* input block */ + //ulg stored_len; /* length of input block */ + //int last; /* one if this is the last block for a file */ + send_bits( + s, + (STORED_BLOCK << 1) + (last ? 1 : 0), + 3 + ); /* send block type */ + copy_block(s, buf, stored_len, true); /* with header */ + } + + /* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ + function _tr_align(s) { + send_bits(s, STATIC_TREES << 1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); + } + + /* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ + function _tr_flush_block(s, buf, stored_len, last) { + //DeflateState *s; + //charf *buf; /* input block, or NULL if too old */ + //ulg stored_len; /* length of input block */ + //int last; /* one if this is the last block for a file */ + var opt_lenb, + static_lenb; /* opt_len and static_len in bytes */ + var max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN) { + s.strm.data_type = detect_data_type(s); + } + + /* Construct the literal and distance trees */ + build_tree(s, s.l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + + build_tree(s, s.d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len + 3 + 7) >>> 3; + static_lenb = (s.static_len + 3 + 7) >>> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->last_lit)); + + if (static_lenb <= opt_lenb) { + opt_lenb = static_lenb; + } + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = + stored_len + 5; /* force a stored block */ + } + + if (stored_len + 4 <= opt_lenb && buf !== -1) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + } else if ( + s.strategy === Z_FIXED || + static_lenb === opt_lenb + ) { + send_bits( + s, + (STATIC_TREES << 1) + (last ? 1 : 0), + 3 + ); + compress_block(s, static_ltree, static_dtree); + } else { + send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); + send_all_trees( + s, + s.l_desc.max_code + 1, + s.d_desc.max_code + 1, + max_blindex + 1 + ); + compress_block(s, s.dyn_ltree, s.dyn_dtree); + } + // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); + } + // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); + } + + /* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ + function _tr_tally(s, dist, lc) { + // deflate_state *s; + // unsigned dist; /* distance of matched string */ + // unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ + //var out_length, in_length, dcode; + + s.pending_buf[s.d_buf + s.last_lit * 2] = + (dist >>> 8) & 0xff; + s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = + dist & 0xff; + + s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; + s.last_lit++; + + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc * 2] /*.Freq*/++; + } else { + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[ + (_length_code[lc] + LITERALS + 1) * 2 + ] /*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2] /*.Freq*/++; + } + + // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + + //#ifdef TRUNCATE_BLOCK + // /* Try to guess if it is profitable to stop the current block here */ + // if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { + // /* Compute an upper bound for the compressed length */ + // out_length = s.last_lit*8; + // in_length = s.strstart - s.block_start; + // + // for (dcode = 0; dcode < D_CODES; dcode++) { + // out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); + // } + // out_length >>>= 3; + // //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + // // s->last_lit, in_length, out_length, + // // 100L - out_length*100L/in_length)); + // if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { + // return true; + // } + // } + //#endif + + return s.last_lit === s.lit_bufsize - 1; + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + } + + exports._tr_init = _tr_init; + exports._tr_stored_block = _tr_stored_block; + exports._tr_flush_block = _tr_flush_block; + exports._tr_tally = _tr_tally; + exports._tr_align = _tr_align; + }, + { "../utils/common": 28 }, + ], + 40: [ + function (require, module, exports) { + "use strict"; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + 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; + }, + {}, + ], + }, + {}, + [10] + )(10); +}); diff --git a/game/keyWords.js b/game/keyWords.js index a1b8fe1c1..4b287bca7 100644 --- a/game/keyWords.js +++ b/game/keyWords.js @@ -1,3 +1,3 @@ window.bannedKeyWords=JSON.parse( decodeURIComponent( - atob("JTVCJTIyZ2hzJTIyJTJDJTIyJUU3JTlCJUI0JUU4JTgyJUEwJTIyJTJDJTIyJUU2JTgwJUE3JUU0JUJBJUE0JTIyJTJDJTIyJUU1JTgxJTlBJUU3JTg4JUIxJTIyJTJDJTIyaHR0cCUyMiUyQyUyMiVFNSU5MCU4MyVFNSVBNSVCNiUyMiUyQyUyMiVFOSVBQSU5QSVFOSU4MCVCQyUyMiUyQyUyMiVFNSU5MyU4OCVFNSVCNyVCNCVFNyU4QiU5NyUyMiUyQyUyMiVFNyVCRSU4RSVFNyU5QyU4OSUyMiUyQyUyMiVFNyU5OSU4QyUyMiUyQyUyMiVFNSVCMSU4MSVFNyU5QyVCQyUyMiUyQyUyMiVFOCU4OSVCOSUyMiUyQyUyMiVFNSU4MiVCQiVFOSU4MCVCQyUyMiUyQyUyMiVFNiU5MyU4RCVFNCVCRCVBMCUyMiUyQyUyMiVFNSU4MSU5QSVFOSVCOCVBMSUyMiUyQyUyMiVFNSVBNSVCOCUyMiUyQyUyMiVFNSVBNyVBNiUyMiUyQyUyMiVFNSU4RCU4RSVFNCVCOCVCQSUyMiUyQyUyMiVFNSVCMSU4NCUyMiUyQyUyMiVFNyU4QiU5NyVFNSVBRCU5MCUyMiUyQyUyMiVFNSVCMSU4RSUyMiUyQyUyMiVFNSU5MCU4QyVFNiU4MCVBNyVFNiU4MSU4QiUyMiUyQyUyMiVFOCU4MiU5NiVFNiU4OCU5OCUyMiUyQyUyMiVFOSVCOCVBMSVFNSVCNyVCNCUyMiUyQyUyMiVFNyVCMiVCRSVFNiVCNiVCMiUyMiUyQyUyMiVFNyVCMiVBQSVFNiVCMCVCNCUyMiUyQyUyMiVFNiU4QyU4MiVFNiU5QyU4OCVFNCVCQSVBRSVFNCVCOCVBRCUyMiUyQyUyMiVFOCVCNCVCMSVFOSVBQSVBOCVFNSVBNCVCNCUyMiUyQyUyMiVFNSU5MCU4MyVFNSVCMSU4MSUyMiUyQyUyMiVFNSU4MiVCQiUyMiUyQyUyMiVFNSVBNSVBNSVFNSU4OCVBOSVFNyVCQiU5OSUyMiUyQyUyMiVFNCVCOCU4MSVFNyU5QyU5RiUyMiUyQyUyMiVFOCU5QiU4NiUyMiUyQyUyMiVFOSVCQyVBMCVFOSVCQyVBMCUyMiUyQyUyMiVFOSVCQyVBMCVFNCVCQSVCQSUyMiUyQyUyMiVFNyVBNSU5RSVFNSU4RiU4QiUyMiUyQyUyMiUzQyUyRmElM0UlMjIlNUQ="))); \ No newline at end of file + atob("JTVCJTIyZ2hzJTIyJTJDJTIyJUU3JTlCJUI0JUU4JTgyJUEwJTIyJTJDJTIyJUU2JTgwJUE3JUU0JUJBJUE0JTIyJTJDJTIyJUU1JTgxJTlBJUU3JTg4JUIxJTIyJTJDJTIyaHR0cCUyMiUyQyUyMiVFNSU5MCU4MyVFNSVBNSVCNiUyMiUyQyUyMiVFOSVBQSU5QSVFOSU4MCVCQyUyMiUyQyUyMiVFNSU5MyU4OCVFNSVCNyVCNCVFNyU4QiU5NyUyMiUyQyUyMiVFNyVCRSU4RSVFNyU5QyU4OSUyMiUyQyUyMiVFNyU5OSU4QyUyMiUyQyUyMiVFNSVCMSU4MSVFNyU5QyVCQyUyMiUyQyUyMiVFOCU4OSVCOSUyMiUyQyUyMiVFNSU4MiVCQiVFOSU4MCVCQyUyMiUyQyUyMiVFNiU5MyU4RCVFNCVCRCVBMCUyMiUyQyUyMiVFNSU4MSU5QSVFOSVCOCVBMSUyMiUyQyUyMiVFNSVBNSVCOCUyMiUyQyUyMiVFNSVBNyVBNiUyMiUyQyUyMiVFNSU4RCU4RSVFNCVCOCVCQSUyMiUyQyUyMiVFNSVCMSU4NCUyMiUyQyUyMiVFNyU4QiU5NyVFNSVBRCU5MCUyMiUyQyUyMiVFNSVCMSU4RSUyMiUyQyUyMiVFNSU5MCU4QyVFNiU4MCVBNyVFNiU4MSU4QiUyMiUyQyUyMiVFOCU4MiU5NiVFNiU4OCU5OCUyMiUyQyUyMiVFOSVCOCVBMSVFNSVCNyVCNCUyMiUyQyUyMiVFNyVCMiVCRSVFNiVCNiVCMiUyMiUyQyUyMiVFNyVCMiVBQSVFNiVCMCVCNCUyMiUyQyUyMiVFNiU4QyU4MiVFNiU5QyU4OCVFNCVCQSVBRSVFNCVCOCVBRCUyMiUyQyUyMiVFOCVCNCVCMSVFOSVBQSVBOCVFNSVBNCVCNCUyMiUyQyUyMiVFNSU5MCU4MyVFNSVCMSU4MSUyMiUyQyUyMiVFNSU4MiVCQiUyMiUyQyUyMiVFNSVBNSVBNSVFNSU4OCVBOSVFNyVCQiU5OSUyMiUyQyUyMiVFNCVCOCU4MSVFNyU5QyU5RiUyMiUyQyUyMiVFOCU5QiU4NiUyMiUyQyUyMiVFOSVCQyVBMCVFOSVCQyVBMCUyMiUyQyUyMiVFOSVCQyVBMCVFNCVCQSVCQSUyMiUyQyUyMiVFNyVBNSU5RSVFNSU4RiU4QiUyMiUyQyUyMiUzQyUyRmElM0UlMjIlNUQ="))); diff --git a/game/package.js b/game/package.js index 2179706eb..d59c37dac 100644 --- a/game/package.js +++ b/game/package.js @@ -1,144 +1,144 @@ -window.noname_package={ - character:{ - standard:'标准', - refresh:'界限突破', - shenhua:'神话再临', - yijiang:'一将成名', - sp:'璀璨星河', - onlyOL:'OL专属', - yingbian:'文德武备', - clan:'门阀士族', - xinghuoliaoyuan:'星火燎原', - huicui:'群英荟萃', - xianding:'限定专属', - sp2:'系列专属', - extra:'神将', - mobile:'移动版', - shiji:'始计篇', - sb:'谋攻篇', - tw:'外服武将', - collab:'联动卡', - offline:'线下武将', - jsrg:'江山如故', - old:'怀旧', - diy:'DIY', - ddd:'3D精选', - yxs:'英雄杀', - hearth:'炉石传说', - gwent:'昆特牌', - mtg:'万智牌', - ow:'守望先锋', - swd:'轩辕剑', - gujian:'古剑奇谭', - xianjian:'仙剑奇侠传', +window.noname_package = { + character: { + standard: "标准", + refresh: "界限突破", + shenhua: "神话再临", + yijiang: "一将成名", + sp: "璀璨星河", + onlyOL: "OL专属", + yingbian: "文德武备", + clan: "门阀士族", + xinghuoliaoyuan: "星火燎原", + huicui: "群英荟萃", + xianding: "限定专属", + sp2: "系列专属", + extra: "神将", + mobile: "移动版", + shiji: "始计篇", + sb: "谋攻篇", + tw: "外服武将", + collab: "联动卡", + offline: "线下武将", + jsrg: "江山如故", + old: "怀旧", + diy: "DIY", + ddd: "3D精选", + yxs: "英雄杀", + hearth: "炉石传说", + gwent: "昆特牌", + mtg: "万智牌", + ow: "守望先锋", + swd: "轩辕剑", + gujian: "古剑奇谭", + xianjian: "仙剑奇侠传", }, - card:{ - standard:'标准', - extra:'军争', - guozhan:'国战', - yingbian:'应变篇', - yongjian:'用间篇', - sp:'忠胆英杰', - zhulu:'逐鹿天下', - yunchou:'运筹帷幄', - zhenfa:'阵法', - swd:'轩辕剑', - gujian:'古剑奇谭', - hearth:'炉石传说', - gwent:'昆特牌', - mtg:'万智牌', - huanlekapai:'欢乐卡牌', + card: { + standard: "标准", + extra: "军争", + guozhan: "国战", + yingbian: "应变篇", + yongjian: "用间篇", + sp: "忠胆英杰", + zhulu: "逐鹿天下", + yunchou: "运筹帷幄", + zhenfa: "阵法", + swd: "轩辕剑", + gujian: "古剑奇谭", + hearth: "炉石传说", + gwent: "昆特牌", + mtg: "万智牌", + huanlekapai: "欢乐卡牌", }, - play:{ - boss:'诸神降临', - cardpile:'牌堆补充', - wuxing:'五行生克', - coin:'富甲天下', + play: { + boss: "诸神降临", + cardpile: "牌堆补充", + wuxing: "五行生克", + coin: "富甲天下", }, - mode:{ - identity:'身份', - guozhan:'国战', - versus:'对决', - connect:'联机', - boss:'挑战', - doudizhu:'斗地主', - single:'单挑', - chess:'战棋', - tafang:'塔防', - stone:'炉石', - brawl:'乱斗', + mode: { + identity: "身份", + guozhan: "国战", + versus: "对决", + connect: "联机", + boss: "挑战", + doudizhu: "斗地主", + single: "单挑", + chess: "战棋", + tafang: "塔防", + stone: "炉石", + brawl: "乱斗", }, - submode:{ - identity:{ - normal:'身份模式', - zhong:'忠胆英杰', - purple:'3v3v2', + submode: { + identity: { + normal: "身份模式", + zhong: "忠胆英杰", + purple: "3v3v2", }, - guozhan:{ - normal:'国战模式', - mingjiang:'明将国战' + guozhan: { + normal: "国战模式", + mingjiang: "明将国战", }, - versus:{ - four:'四人对抗', - three:'统率三军', - two:'欢乐成双', - jiange:'守卫剑阁', - siguo:'四国争霸', - standard:'自由对决' + versus: { + four: "四人对抗", + three: "统率三军", + two: "欢乐成双", + jiange: "守卫剑阁", + siguo: "四国争霸", + standard: "自由对决", }, - chess:{ - combat:'战棋模式', - three:'战棋统率', - leader:'战棋君主' + chess: { + combat: "战棋模式", + three: "战棋统率", + leader: "战棋君主", }, - single:{ - normal:'新1v1', + single: { + normal: "新1v1", }, }, - background:{ - ol_bg:'龙纹', - planetarian_bg:'星梦', - heaven_bg:'红烧', - kyoani_bg:'京都', - key_bg:'键社', - xiaowu_bg:'小无', - noname_bg:'璀璨', - wuming_bg:'无名', - zhulin_bg:'竹林', - shengshi_bg:'盛世', - taoyuan_bg:'桃园', - zhanhuo_bg:'战火', - huangtian_bg:'黄天', - september_bg:'九月', - yinxiang_bg:'印象', - zhanyun_bg:'战云', - beipan_bg:'背叛', - lanting_bg:'兰亭', - lingju_bg:'灵雎', - sanying_bg:'三英', - wangshi_bg:'往事', - xiongxin_bg:'雄心', - xinsha_bg:'新杀', + background: { + ol_bg: "龙纹", + planetarian_bg: "星梦", + heaven_bg: "红烧", + kyoani_bg: "京都", + key_bg: "键社", + xiaowu_bg: "小无", + noname_bg: "璀璨", + wuming_bg: "无名", + zhulin_bg: "竹林", + shengshi_bg: "盛世", + taoyuan_bg: "桃园", + zhanhuo_bg: "战火", + huangtian_bg: "黄天", + september_bg: "九月", + yinxiang_bg: "印象", + zhanyun_bg: "战云", + beipan_bg: "背叛", + lanting_bg: "兰亭", + lingju_bg: "灵雎", + sanying_bg: "三英", + wangshi_bg: "往事", + xiongxin_bg: "雄心", + xinsha_bg: "新杀", }, - music:{ - music_phliosophy:'Philosophy of ours', - music_diaochan:'貂蝉', - music_shezhan:'舌战群儒', - music_danji:'千里走单骑', - music_jifeng:'祭风', - music_jilve:'极略', + music: { + music_phliosophy: "Philosophy of ours", + music_diaochan: "貂蝉", + music_shezhan: "舌战群儒", + music_danji: "千里走单骑", + music_jifeng: "祭风", + music_jilve: "极略", }, - font:{ - xiaozhuan:'方正小篆体', - xinwei:'华文新魏_GBK', - huangcao:'方正黄草_GBK', - yuanli:'方正北魏楷书_GBK', - xingkai:'方正行楷_GBK', - shousha:'方正隶变_GBK', + font: { + xiaozhuan: "方正小篆体", + xinwei: "华文新魏_GBK", + huangcao: "方正黄草_GBK", + yuanli: "方正北魏楷书_GBK", + xingkai: "方正行楷_GBK", + shousha: "方正隶变_GBK", + }, + theme: { + woodden: "木纹", + music: "音乐", + simple: "简约", }, - theme:{ - woodden:'木纹', - music:'音乐', - simple:'简约' - } }; diff --git a/game/phantom.js b/game/phantom.js index 8d72bafdd..17e8a5cc5 100644 --- a/game/phantom.js +++ b/game/phantom.js @@ -1,29 +1,29 @@ -var fs = require('fs'); -var webpage = require('webpage') -var load = function(id){ - var page = webpage.create(); - page.settings.userAgent = 'NonameServer'; - page.open('file://'+fs.workingDirectory+'/index.html?server='+id, function(status) { - if(status !== 'success') { - console.log(fs.workingDirectory); - console.log('Unable to access network'); - } - setInterval(function(){ - if(page.evaluate(function(){ - if(!lib.node||!lib.node.clients||!lib.node.clients.length){ - return true; - } - else{ - return false; - } - })){ - page.close(); - load(id); - } - },600000); - }); -} - -load(1); -load(2); -load(3); +var fs = require('fs'); +var webpage = require('webpage') +var load = function(id){ + var page = webpage.create(); + page.settings.userAgent = 'NonameServer'; + page.open('file://'+fs.workingDirectory+'/index.html?server='+id, function(status) { + if(status !== 'success') { + console.log(fs.workingDirectory); + console.log('Unable to access network'); + } + setInterval(function(){ + if(page.evaluate(function(){ + if(!lib.node||!lib.node.clients||!lib.node.clients.length){ + return true; + } + else{ + return false; + } + })){ + page.close(); + load(id); + } + },600000); + }); +} + +load(1); +load(2); +load(3); diff --git a/game/pinyinjs.js b/game/pinyinjs.js index 20aa02846..9f338c748 100644 --- a/game/pinyinjs.js +++ b/game/pinyinjs.js @@ -41646,4 +41646,4 @@ var pinyin_dict_withtone = "yī,dīng zhēng,kǎo qiǎo yú,qī,shàng,xià,hǎn pinyinUtilx.dict = dict; window.pinyinUtilx = pinyinUtilx; -}); \ No newline at end of file +}); diff --git a/game/pressure.js b/game/pressure.js index 9e66e7e70..dbf205895 100644 --- a/game/pressure.js +++ b/game/pressure.js @@ -1,576 +1,576 @@ -// Pressure v2.1.1 | Created By Stuart Yamartino | MIT License | 2015 - 2017 -;(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.Pressure = factory(); - } -}(this, function() { -'use strict'; - -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; - -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); - -function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -//--------------------- Public API Section ---------------------// -// this is the Pressure Object, this is the only object that is accessible to the end user -// only the methods in this object can be called, making it the "public api" - -var Pressure = { - - // targets any device with Force or 3D Touch - set: function set(selector, closure, options) { - loopPressureElements(selector, closure, options); - }, - - - // set configuration options for global config - config: function config(options) { - Config.set(options); - }, - - - // the map method allows for interpolating a value from one range of values to another - // example from the Arduino documentation: https://www.arduino.cc/en/Reference/Map - map: function map(x, in_min, in_max, out_min, out_max) { - return _map.apply(null, arguments); - } -}; - -var Element = function () { - function Element(el, block, options) { - _classCallCheck(this, Element); - - this.routeEvents(el, block, options); - this.preventSelect(el, options); - } - - _createClass(Element, [{ - key: 'routeEvents', - value: function routeEvents(el, block, options) { - var type = Config.get('only', options); - // for devices that support pointer events - if (supportsPointer && (type === 'pointer' || type === null)) { - this.adapter = new AdapterPointer(el, block, options).bindEvents(); - } - // for devices that support 3D Touch - else if (supportsTouch && (type === 'touch' || type === null)) { - this.adapter = new Adapter3DTouch(el, block, options).bindEvents(); - } - // for devices that support Force Touch - else if (supportsMouse && (type === 'mouse' || type === null)) { - this.adapter = new AdapterForceTouch(el, block, options).bindEvents(); - } - // unsupported if it is requesting a type and your browser is of other type - else { - this.adapter = new Adapter(el, block).bindUnsupportedEvent(); - } - } - - // prevent the default action of text selection, "peak & pop", and force touch special feature - - }, { - key: 'preventSelect', - value: function preventSelect(el, options) { - if (Config.get('preventSelect', options)) { - el.style.webkitTouchCallout = "none"; - el.style.webkitUserSelect = "none"; - el.style.khtmlUserSelect = "none"; - el.style.MozUserSelect = "none"; - el.style.msUserSelect = "none"; - el.style.userSelect = "none"; - } - } - }]); - - return Element; -}(); - -/* -This is the base adapter from which all the other adapters extend. -*/ - -var Adapter = function () { - function Adapter(el, block, options) { - _classCallCheck(this, Adapter); - - this.el = el; - this.block = block; - this.options = options; - this.pressed = false; - this.deepPressed = false; - this.nativeSupport = false; - this.runningPolyfill = false; - this.runKey = Math.random(); - } - - _createClass(Adapter, [{ - key: 'setPressed', - value: function setPressed(boolean) { - this.pressed = boolean; - } - }, { - key: 'setDeepPressed', - value: function setDeepPressed(boolean) { - this.deepPressed = boolean; - } - }, { - key: 'isPressed', - value: function isPressed() { - return this.pressed; - } - }, { - key: 'isDeepPressed', - value: function isDeepPressed() { - return this.deepPressed; - } - }, { - key: 'add', - value: function add(event, set) { - this.el.addEventListener(event, set, false); - } - }, { - key: 'runClosure', - value: function runClosure(method) { - if (method in this.block) { - // call the closure method and apply nth arguments if they exist - this.block[method].apply(this.el, Array.prototype.slice.call(arguments, 1)); - } - } - }, { - key: 'fail', - value: function fail(event, runKey) { - if (Config.get('polyfill', this.options)) { - if (this.runKey === runKey) { - this.runPolyfill(event); - } - } else { - this.runClosure('unsupported', event); - } - } - }, { - key: 'bindUnsupportedEvent', - value: function bindUnsupportedEvent() { - var _this = this; - - this.add(supportsTouch ? 'touchstart' : 'mousedown', function (event) { - return _this.runClosure('unsupported', event); - }); - } - }, { - key: '_startPress', - value: function _startPress(event) { - if (this.isPressed() === false) { - this.runningPolyfill = false; - this.setPressed(true); - this.runClosure('start', event); - } - } - }, { - key: '_startDeepPress', - value: function _startDeepPress(event) { - if (this.isPressed() && this.isDeepPressed() === false) { - this.setDeepPressed(true); - this.runClosure('startDeepPress', event); - } - } - }, { - key: '_changePress', - value: function _changePress(force, event) { - this.nativeSupport = true; - this.runClosure('change', force, event); - } - }, { - key: '_endDeepPress', - value: function _endDeepPress() { - if (this.isPressed() && this.isDeepPressed()) { - this.setDeepPressed(false); - this.runClosure('endDeepPress'); - } - } - }, { - key: '_endPress', - value: function _endPress() { - if (this.runningPolyfill === false) { - if (this.isPressed()) { - this._endDeepPress(); - this.setPressed(false); - this.runClosure('end'); - } - this.runKey = Math.random(); - this.nativeSupport = false; - } else { - this.setPressed(false); - } - } - }, { - key: 'deepPress', - value: function deepPress(force, event) { - force >= 0.5 ? this._startDeepPress(event) : this._endDeepPress(); - } - }, { - key: 'runPolyfill', - value: function runPolyfill(event) { - this.increment = Config.get('polyfillSpeedUp', this.options) === 0 ? 1 : 10 / Config.get('polyfillSpeedUp', this.options); - this.decrement = Config.get('polyfillSpeedDown', this.options) === 0 ? 1 : 10 / Config.get('polyfillSpeedDown', this.options); - this.setPressed(true); - this.runClosure('start', event); - if (this.runningPolyfill === false) { - this.loopPolyfillForce(0, event); - } - } - }, { - key: 'loopPolyfillForce', - value: function loopPolyfillForce(force, event) { - if (this.nativeSupport === false) { - if (this.isPressed()) { - this.runningPolyfill = true; - force = force + this.increment > 1 ? 1 : force + this.increment; - this.runClosure('change', force, event); - this.deepPress(force, event); - setTimeout(this.loopPolyfillForce.bind(this, force, event), 10); - } else { - force = force - this.decrement < 0 ? 0 : force - this.decrement; - if (force < 0.5 && this.isDeepPressed()) { - this.setDeepPressed(false); - this.runClosure('endDeepPress'); - } - if (force === 0) { - this.runningPolyfill = false; - this.setPressed(true); - this._endPress(); - } else { - this.runClosure('change', force, event); - this.deepPress(force, event); - setTimeout(this.loopPolyfillForce.bind(this, force, event), 10); - } - } - } - } - }]); - - return Adapter; -}(); - -/* -This adapter is for Macs with Force Touch trackpads. -*/ - -var AdapterForceTouch = function (_Adapter) { - _inherits(AdapterForceTouch, _Adapter); - - function AdapterForceTouch(el, block, options) { - _classCallCheck(this, AdapterForceTouch); - - return _possibleConstructorReturn(this, (AdapterForceTouch.__proto__ || Object.getPrototypeOf(AdapterForceTouch)).call(this, el, block, options)); - } - - _createClass(AdapterForceTouch, [{ - key: 'bindEvents', - value: function bindEvents() { - this.add('webkitmouseforcewillbegin', this._startPress.bind(this)); - this.add('mousedown', this.support.bind(this)); - this.add('webkitmouseforcechanged', this.change.bind(this)); - this.add('webkitmouseforcedown', this._startDeepPress.bind(this)); - this.add('webkitmouseforceup', this._endDeepPress.bind(this)); - this.add('mouseleave', this._endPress.bind(this)); - this.add('mouseup', this._endPress.bind(this)); - } - }, { - key: 'support', - value: function support(event) { - if (this.isPressed() === false) { - this.fail(event, this.runKey); - } - } - }, { - key: 'change', - value: function change(event) { - if (this.isPressed() && event.webkitForce > 0) { - this._changePress(this.normalizeForce(event.webkitForce), event); - } - } - - // make the force the standard 0 to 1 scale and not the 1 to 3 scale - - }, { - key: 'normalizeForce', - value: function normalizeForce(force) { - return this.reachOne(_map(force, 1, 3, 0, 1)); - } - - // if the force value is above 0.995 set the force to 1 - - }, { - key: 'reachOne', - value: function reachOne(force) { - return force > 0.995 ? 1 : force; - } - }]); - - return AdapterForceTouch; -}(Adapter); - -/* -This adapter is more mobile devices that support 3D Touch. -*/ - -var Adapter3DTouch = function (_Adapter2) { - _inherits(Adapter3DTouch, _Adapter2); - - function Adapter3DTouch(el, block, options) { - _classCallCheck(this, Adapter3DTouch); - - return _possibleConstructorReturn(this, (Adapter3DTouch.__proto__ || Object.getPrototypeOf(Adapter3DTouch)).call(this, el, block, options)); - } - - _createClass(Adapter3DTouch, [{ - key: 'bindEvents', - value: function bindEvents() { - if (supportsTouchForceChange) { - this.add('touchforcechange', this.start.bind(this)); - this.add('touchstart', this.support.bind(this, 0)); - this.add('touchend', this._endPress.bind(this)); - } else { - this.add('touchstart', this.startLegacy.bind(this)); - this.add('touchend', this._endPress.bind(this)); - } - } - }, { - key: 'start', - value: function start(event) { - if (event.touches.length > 0) { - this._startPress(event); - this.touch = this.selectTouch(event); - if (this.touch) { - this._changePress(this.touch.force, event); - } - } - } - }, { - key: 'support', - value: function support(iter, event) { - var runKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.runKey; - - if (this.isPressed() === false) { - if (iter <= 6) { - iter++; - setTimeout(this.support.bind(this, iter, event, runKey), 10); - } else { - this.fail(event, runKey); - } - } - } - }, { - key: 'startLegacy', - value: function startLegacy(event) { - this.initialForce = event.touches[0].force; - this.supportLegacy(0, event, this.runKey, this.initialForce); - } - - // this checks up to 6 times on a touch to see if the touch can read a force value - // if the force value has changed it means the device supports pressure - // more info from this issue https://github.com/yamartino/pressure/issues/15 - - }, { - key: 'supportLegacy', - value: function supportLegacy(iter, event, runKey, force) { - if (force !== this.initialForce) { - this._startPress(event); - this.loopForce(event); - } else if (iter <= 6) { - iter++; - setTimeout(this.supportLegacy.bind(this, iter, event, runKey, force), 10); - } else { - this.fail(event, runKey); - } - } - }, { - key: 'loopForce', - value: function loopForce(event) { - if (this.isPressed()) { - this.touch = this.selectTouch(event); - setTimeout(this.loopForce.bind(this, event), 10); - this._changePress(this.touch.force, event); - } - } - - // link up the touch point to the correct element, this is to support multitouch - - }, { - key: 'selectTouch', - value: function selectTouch(event) { - if (event.touches.length === 1) { - return this.returnTouch(event.touches[0], event); - } else { - for (var i = 0; i < event.touches.length; i++) { - // if the target press is on this element - if (event.touches[i].target === this.el || this.el.contains(event.touches[i].target)) { - return this.returnTouch(event.touches[i], event); - } - } - } - } - - // return the touch and run a start or end for deep press - - }, { - key: 'returnTouch', - value: function returnTouch(touch, event) { - this.deepPress(touch.force, event); - return touch; - } - }]); - - return Adapter3DTouch; -}(Adapter); - -/* -This adapter is for devices that support pointer events. -*/ - -var AdapterPointer = function (_Adapter3) { - _inherits(AdapterPointer, _Adapter3); - - function AdapterPointer(el, block, options) { - _classCallCheck(this, AdapterPointer); - - return _possibleConstructorReturn(this, (AdapterPointer.__proto__ || Object.getPrototypeOf(AdapterPointer)).call(this, el, block, options)); - } - - _createClass(AdapterPointer, [{ - key: 'bindEvents', - value: function bindEvents() { - this.add('pointerdown', this.support.bind(this)); - this.add('pointermove', this.change.bind(this)); - this.add('pointerup', this._endPress.bind(this)); - this.add('pointerleave', this._endPress.bind(this)); - } - }, { - key: 'support', - value: function support(event) { - if (this.isPressed() === false) { - if (event.pressure === 0 || event.pressure === 0.5) { - this.fail(event, this.runKey); - } else { - this._startPress(event); - this._changePress(event.pressure, event); - } - } - } - }, { - key: 'change', - value: function change(event) { - if (this.isPressed() && event.pressure > 0 && event.pressure !== 0.5) { - this._changePress(event.pressure, event); - this.deepPress(event.pressure, event); - } - } - }]); - - return AdapterPointer; -}(Adapter); - -// This class holds the states of the the Pressure config - - -var Config = { - - // 'false' will make polyfill not run when pressure is not supported and the 'unsupported' method will be called - polyfill: true, - - // milliseconds it takes to go from 0 to 1 for the polyfill - polyfillSpeedUp: 1000, - - // milliseconds it takes to go from 1 to 0 for the polyfill - polyfillSpeedDown: 0, - - // 'true' prevents the selecting of text and images via css properties - preventSelect: true, - - // 'touch', 'mouse', or 'pointer' will make it run only on that type of device - only: null, - - // this will get the correct config / option settings for the current pressure check - get: function get(option, options) { - return options.hasOwnProperty(option) ? options[option] : this[option]; - }, - - - // this will set the global configs - set: function set(options) { - for (var k in options) { - if (options.hasOwnProperty(k) && this.hasOwnProperty(k) && k != 'get' && k != 'set') { - this[k] = options[k]; - } - } - } -}; - -//------------------- Helpers -------------------// - -// accepts jQuery object, node list, string selector, then called a setup for each element -var loopPressureElements = function loopPressureElements(selector, closure) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - - // if a string is passed in as an element - if (typeof selector === 'string' || selector instanceof String) { - var elements = document.querySelectorAll(selector); - for (var i = 0; i < elements.length; i++) { - new Element(elements[i], closure, options); - } - // if a single element object is passed in - } else if (isElement(selector)) { - new Element(selector, closure, options); - // if a node list is passed in ex. jQuery $() object - } else { - for (var i = 0; i < selector.length; i++) { - new Element(selector[i], closure, options); - } - } -}; - -//Returns true if it is a DOM element -var isElement = function isElement(o) { - return (typeof HTMLElement === 'undefined' ? 'undefined' : _typeof(HTMLElement)) === "object" ? o instanceof HTMLElement : //DOM2 - o && (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string"; -}; - -// the map method allows for interpolating a value from one range of values to another -// example from the Arduino documentation: https://www.arduino.cc/en/Reference/Map -var _map = function _map(x, in_min, in_max, out_min, out_max) { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; -}; - -var supportsMouse = false; -var supportsTouch = false; -var supportsPointer = false; -var supportsTouchForce = false; -var supportsTouchForceChange = false; - -if (typeof window !== 'undefined') { - // only attempt to assign these in a browser environment. - // on the server, this is a no-op, like the rest of the library - if (typeof Touch !== 'undefined') { - // In Android, new Touch requires arguments. - try { - if (Touch.prototype.hasOwnProperty('force') || 'force' in new Touch()) { - supportsTouchForce = true; - } - } catch (e) {} - } - supportsTouch = 'ontouchstart' in window.document && supportsTouchForce; - supportsMouse = 'onmousemove' in window.document && !supportsTouch; - supportsPointer = 'onpointermove' in window.document; - supportsTouchForceChange = 'ontouchforcechange' in window.document; -} -return Pressure; -})); +// Pressure v2.1.1 | Created By Stuart Yamartino | MIT License | 2015 - 2017 +;(function(root, factory) { + if (typeof define === 'function' && define.amd) { + define([], factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.Pressure = factory(); + } +}(this, function() { +'use strict'; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +//--------------------- Public API Section ---------------------// +// this is the Pressure Object, this is the only object that is accessible to the end user +// only the methods in this object can be called, making it the "public api" + +var Pressure = { + + // targets any device with Force or 3D Touch + set: function set(selector, closure, options) { + loopPressureElements(selector, closure, options); + }, + + + // set configuration options for global config + config: function config(options) { + Config.set(options); + }, + + + // the map method allows for interpolating a value from one range of values to another + // example from the Arduino documentation: https://www.arduino.cc/en/Reference/Map + map: function map(x, in_min, in_max, out_min, out_max) { + return _map.apply(null, arguments); + } +}; + +var Element = function () { + function Element(el, block, options) { + _classCallCheck(this, Element); + + this.routeEvents(el, block, options); + this.preventSelect(el, options); + } + + _createClass(Element, [{ + key: 'routeEvents', + value: function routeEvents(el, block, options) { + var type = Config.get('only', options); + // for devices that support pointer events + if (supportsPointer && (type === 'pointer' || type === null)) { + this.adapter = new AdapterPointer(el, block, options).bindEvents(); + } + // for devices that support 3D Touch + else if (supportsTouch && (type === 'touch' || type === null)) { + this.adapter = new Adapter3DTouch(el, block, options).bindEvents(); + } + // for devices that support Force Touch + else if (supportsMouse && (type === 'mouse' || type === null)) { + this.adapter = new AdapterForceTouch(el, block, options).bindEvents(); + } + // unsupported if it is requesting a type and your browser is of other type + else { + this.adapter = new Adapter(el, block).bindUnsupportedEvent(); + } + } + + // prevent the default action of text selection, "peak & pop", and force touch special feature + + }, { + key: 'preventSelect', + value: function preventSelect(el, options) { + if (Config.get('preventSelect', options)) { + el.style.webkitTouchCallout = "none"; + el.style.webkitUserSelect = "none"; + el.style.khtmlUserSelect = "none"; + el.style.MozUserSelect = "none"; + el.style.msUserSelect = "none"; + el.style.userSelect = "none"; + } + } + }]); + + return Element; +}(); + +/* +This is the base adapter from which all the other adapters extend. +*/ + +var Adapter = function () { + function Adapter(el, block, options) { + _classCallCheck(this, Adapter); + + this.el = el; + this.block = block; + this.options = options; + this.pressed = false; + this.deepPressed = false; + this.nativeSupport = false; + this.runningPolyfill = false; + this.runKey = Math.random(); + } + + _createClass(Adapter, [{ + key: 'setPressed', + value: function setPressed(boolean) { + this.pressed = boolean; + } + }, { + key: 'setDeepPressed', + value: function setDeepPressed(boolean) { + this.deepPressed = boolean; + } + }, { + key: 'isPressed', + value: function isPressed() { + return this.pressed; + } + }, { + key: 'isDeepPressed', + value: function isDeepPressed() { + return this.deepPressed; + } + }, { + key: 'add', + value: function add(event, set) { + this.el.addEventListener(event, set, false); + } + }, { + key: 'runClosure', + value: function runClosure(method) { + if (method in this.block) { + // call the closure method and apply nth arguments if they exist + this.block[method].apply(this.el, Array.prototype.slice.call(arguments, 1)); + } + } + }, { + key: 'fail', + value: function fail(event, runKey) { + if (Config.get('polyfill', this.options)) { + if (this.runKey === runKey) { + this.runPolyfill(event); + } + } else { + this.runClosure('unsupported', event); + } + } + }, { + key: 'bindUnsupportedEvent', + value: function bindUnsupportedEvent() { + var _this = this; + + this.add(supportsTouch ? 'touchstart' : 'mousedown', function (event) { + return _this.runClosure('unsupported', event); + }); + } + }, { + key: '_startPress', + value: function _startPress(event) { + if (this.isPressed() === false) { + this.runningPolyfill = false; + this.setPressed(true); + this.runClosure('start', event); + } + } + }, { + key: '_startDeepPress', + value: function _startDeepPress(event) { + if (this.isPressed() && this.isDeepPressed() === false) { + this.setDeepPressed(true); + this.runClosure('startDeepPress', event); + } + } + }, { + key: '_changePress', + value: function _changePress(force, event) { + this.nativeSupport = true; + this.runClosure('change', force, event); + } + }, { + key: '_endDeepPress', + value: function _endDeepPress() { + if (this.isPressed() && this.isDeepPressed()) { + this.setDeepPressed(false); + this.runClosure('endDeepPress'); + } + } + }, { + key: '_endPress', + value: function _endPress() { + if (this.runningPolyfill === false) { + if (this.isPressed()) { + this._endDeepPress(); + this.setPressed(false); + this.runClosure('end'); + } + this.runKey = Math.random(); + this.nativeSupport = false; + } else { + this.setPressed(false); + } + } + }, { + key: 'deepPress', + value: function deepPress(force, event) { + force >= 0.5 ? this._startDeepPress(event) : this._endDeepPress(); + } + }, { + key: 'runPolyfill', + value: function runPolyfill(event) { + this.increment = Config.get('polyfillSpeedUp', this.options) === 0 ? 1 : 10 / Config.get('polyfillSpeedUp', this.options); + this.decrement = Config.get('polyfillSpeedDown', this.options) === 0 ? 1 : 10 / Config.get('polyfillSpeedDown', this.options); + this.setPressed(true); + this.runClosure('start', event); + if (this.runningPolyfill === false) { + this.loopPolyfillForce(0, event); + } + } + }, { + key: 'loopPolyfillForce', + value: function loopPolyfillForce(force, event) { + if (this.nativeSupport === false) { + if (this.isPressed()) { + this.runningPolyfill = true; + force = force + this.increment > 1 ? 1 : force + this.increment; + this.runClosure('change', force, event); + this.deepPress(force, event); + setTimeout(this.loopPolyfillForce.bind(this, force, event), 10); + } else { + force = force - this.decrement < 0 ? 0 : force - this.decrement; + if (force < 0.5 && this.isDeepPressed()) { + this.setDeepPressed(false); + this.runClosure('endDeepPress'); + } + if (force === 0) { + this.runningPolyfill = false; + this.setPressed(true); + this._endPress(); + } else { + this.runClosure('change', force, event); + this.deepPress(force, event); + setTimeout(this.loopPolyfillForce.bind(this, force, event), 10); + } + } + } + } + }]); + + return Adapter; +}(); + +/* +This adapter is for Macs with Force Touch trackpads. +*/ + +var AdapterForceTouch = function (_Adapter) { + _inherits(AdapterForceTouch, _Adapter); + + function AdapterForceTouch(el, block, options) { + _classCallCheck(this, AdapterForceTouch); + + return _possibleConstructorReturn(this, (AdapterForceTouch.__proto__ || Object.getPrototypeOf(AdapterForceTouch)).call(this, el, block, options)); + } + + _createClass(AdapterForceTouch, [{ + key: 'bindEvents', + value: function bindEvents() { + this.add('webkitmouseforcewillbegin', this._startPress.bind(this)); + this.add('mousedown', this.support.bind(this)); + this.add('webkitmouseforcechanged', this.change.bind(this)); + this.add('webkitmouseforcedown', this._startDeepPress.bind(this)); + this.add('webkitmouseforceup', this._endDeepPress.bind(this)); + this.add('mouseleave', this._endPress.bind(this)); + this.add('mouseup', this._endPress.bind(this)); + } + }, { + key: 'support', + value: function support(event) { + if (this.isPressed() === false) { + this.fail(event, this.runKey); + } + } + }, { + key: 'change', + value: function change(event) { + if (this.isPressed() && event.webkitForce > 0) { + this._changePress(this.normalizeForce(event.webkitForce), event); + } + } + + // make the force the standard 0 to 1 scale and not the 1 to 3 scale + + }, { + key: 'normalizeForce', + value: function normalizeForce(force) { + return this.reachOne(_map(force, 1, 3, 0, 1)); + } + + // if the force value is above 0.995 set the force to 1 + + }, { + key: 'reachOne', + value: function reachOne(force) { + return force > 0.995 ? 1 : force; + } + }]); + + return AdapterForceTouch; +}(Adapter); + +/* +This adapter is more mobile devices that support 3D Touch. +*/ + +var Adapter3DTouch = function (_Adapter2) { + _inherits(Adapter3DTouch, _Adapter2); + + function Adapter3DTouch(el, block, options) { + _classCallCheck(this, Adapter3DTouch); + + return _possibleConstructorReturn(this, (Adapter3DTouch.__proto__ || Object.getPrototypeOf(Adapter3DTouch)).call(this, el, block, options)); + } + + _createClass(Adapter3DTouch, [{ + key: 'bindEvents', + value: function bindEvents() { + if (supportsTouchForceChange) { + this.add('touchforcechange', this.start.bind(this)); + this.add('touchstart', this.support.bind(this, 0)); + this.add('touchend', this._endPress.bind(this)); + } else { + this.add('touchstart', this.startLegacy.bind(this)); + this.add('touchend', this._endPress.bind(this)); + } + } + }, { + key: 'start', + value: function start(event) { + if (event.touches.length > 0) { + this._startPress(event); + this.touch = this.selectTouch(event); + if (this.touch) { + this._changePress(this.touch.force, event); + } + } + } + }, { + key: 'support', + value: function support(iter, event) { + var runKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.runKey; + + if (this.isPressed() === false) { + if (iter <= 6) { + iter++; + setTimeout(this.support.bind(this, iter, event, runKey), 10); + } else { + this.fail(event, runKey); + } + } + } + }, { + key: 'startLegacy', + value: function startLegacy(event) { + this.initialForce = event.touches[0].force; + this.supportLegacy(0, event, this.runKey, this.initialForce); + } + + // this checks up to 6 times on a touch to see if the touch can read a force value + // if the force value has changed it means the device supports pressure + // more info from this issue https://github.com/yamartino/pressure/issues/15 + + }, { + key: 'supportLegacy', + value: function supportLegacy(iter, event, runKey, force) { + if (force !== this.initialForce) { + this._startPress(event); + this.loopForce(event); + } else if (iter <= 6) { + iter++; + setTimeout(this.supportLegacy.bind(this, iter, event, runKey, force), 10); + } else { + this.fail(event, runKey); + } + } + }, { + key: 'loopForce', + value: function loopForce(event) { + if (this.isPressed()) { + this.touch = this.selectTouch(event); + setTimeout(this.loopForce.bind(this, event), 10); + this._changePress(this.touch.force, event); + } + } + + // link up the touch point to the correct element, this is to support multitouch + + }, { + key: 'selectTouch', + value: function selectTouch(event) { + if (event.touches.length === 1) { + return this.returnTouch(event.touches[0], event); + } else { + for (var i = 0; i < event.touches.length; i++) { + // if the target press is on this element + if (event.touches[i].target === this.el || this.el.contains(event.touches[i].target)) { + return this.returnTouch(event.touches[i], event); + } + } + } + } + + // return the touch and run a start or end for deep press + + }, { + key: 'returnTouch', + value: function returnTouch(touch, event) { + this.deepPress(touch.force, event); + return touch; + } + }]); + + return Adapter3DTouch; +}(Adapter); + +/* +This adapter is for devices that support pointer events. +*/ + +var AdapterPointer = function (_Adapter3) { + _inherits(AdapterPointer, _Adapter3); + + function AdapterPointer(el, block, options) { + _classCallCheck(this, AdapterPointer); + + return _possibleConstructorReturn(this, (AdapterPointer.__proto__ || Object.getPrototypeOf(AdapterPointer)).call(this, el, block, options)); + } + + _createClass(AdapterPointer, [{ + key: 'bindEvents', + value: function bindEvents() { + this.add('pointerdown', this.support.bind(this)); + this.add('pointermove', this.change.bind(this)); + this.add('pointerup', this._endPress.bind(this)); + this.add('pointerleave', this._endPress.bind(this)); + } + }, { + key: 'support', + value: function support(event) { + if (this.isPressed() === false) { + if (event.pressure === 0 || event.pressure === 0.5) { + this.fail(event, this.runKey); + } else { + this._startPress(event); + this._changePress(event.pressure, event); + } + } + } + }, { + key: 'change', + value: function change(event) { + if (this.isPressed() && event.pressure > 0 && event.pressure !== 0.5) { + this._changePress(event.pressure, event); + this.deepPress(event.pressure, event); + } + } + }]); + + return AdapterPointer; +}(Adapter); + +// This class holds the states of the the Pressure config + + +var Config = { + + // 'false' will make polyfill not run when pressure is not supported and the 'unsupported' method will be called + polyfill: true, + + // milliseconds it takes to go from 0 to 1 for the polyfill + polyfillSpeedUp: 1000, + + // milliseconds it takes to go from 1 to 0 for the polyfill + polyfillSpeedDown: 0, + + // 'true' prevents the selecting of text and images via css properties + preventSelect: true, + + // 'touch', 'mouse', or 'pointer' will make it run only on that type of device + only: null, + + // this will get the correct config / option settings for the current pressure check + get: function get(option, options) { + return options.hasOwnProperty(option) ? options[option] : this[option]; + }, + + + // this will set the global configs + set: function set(options) { + for (var k in options) { + if (options.hasOwnProperty(k) && this.hasOwnProperty(k) && k != 'get' && k != 'set') { + this[k] = options[k]; + } + } + } +}; + +//------------------- Helpers -------------------// + +// accepts jQuery object, node list, string selector, then called a setup for each element +var loopPressureElements = function loopPressureElements(selector, closure) { + var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + // if a string is passed in as an element + if (typeof selector === 'string' || selector instanceof String) { + var elements = document.querySelectorAll(selector); + for (var i = 0; i < elements.length; i++) { + new Element(elements[i], closure, options); + } + // if a single element object is passed in + } else if (isElement(selector)) { + new Element(selector, closure, options); + // if a node list is passed in ex. jQuery $() object + } else { + for (var i = 0; i < selector.length; i++) { + new Element(selector[i], closure, options); + } + } +}; + +//Returns true if it is a DOM element +var isElement = function isElement(o) { + return (typeof HTMLElement === 'undefined' ? 'undefined' : _typeof(HTMLElement)) === "object" ? o instanceof HTMLElement : //DOM2 + o && (typeof o === 'undefined' ? 'undefined' : _typeof(o)) === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string"; +}; + +// the map method allows for interpolating a value from one range of values to another +// example from the Arduino documentation: https://www.arduino.cc/en/Reference/Map +var _map = function _map(x, in_min, in_max, out_min, out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +}; + +var supportsMouse = false; +var supportsTouch = false; +var supportsPointer = false; +var supportsTouchForce = false; +var supportsTouchForceChange = false; + +if (typeof window !== 'undefined') { + // only attempt to assign these in a browser environment. + // on the server, this is a no-op, like the rest of the library + if (typeof Touch !== 'undefined') { + // In Android, new Touch requires arguments. + try { + if (Touch.prototype.hasOwnProperty('force') || 'force' in new Touch()) { + supportsTouchForce = true; + } + } catch (e) {} + } + supportsTouch = 'ontouchstart' in window.document && supportsTouchForce; + supportsMouse = 'onmousemove' in window.document && !supportsTouch; + supportsPointer = 'onpointermove' in window.document; + supportsTouchForceChange = 'ontouchforcechange' in window.document; +} +return Pressure; +})); diff --git a/game/server.js b/game/server.js index 0ddc4d1d6..49a0ad87f 100644 --- a/game/server.js +++ b/game/server.js @@ -1,386 +1,402 @@ -(function(){ - var WebSocketServer=require('ws').Server; - var wss=new WebSocketServer({port:8080}); - var bannedKeys=[]; - var bannedIps=[]; +(function () { + var WebSocketServer = require("ws").Server; + var wss = new WebSocketServer({ port: 8080 }); + var bannedKeys = []; + var bannedIps = []; - var rooms=[]; - var events=[]; - var clients={}; - var bannedKeyWords=[]; - var messages={ - create:function(key,nickname,avatar,config,mode){ - if(this.onlineKey!=key) return; - this.nickname=util.getNickname(nickname); - this.avatar=avatar; - var room={}; + var rooms = []; + var events = []; + var clients = {}; + var bannedKeyWords = []; + var messages = { + create: function (key, nickname, avatar, config, mode) { + if (this.onlineKey != key) return; + this.nickname = util.getNickname(nickname); + this.avatar = avatar; + var room = {}; rooms.push(room); - this.room=room; + this.room = room; delete this.status; - room.owner=this; - room.key=key; - this.sendl('createroom',key); + room.owner = this; + room.key = key; + this.sendl("createroom", key); }, - enter:function(key,nickname,avatar){ - this.nickname=util.getNickname(nickname); - this.avatar=avatar; - var room=false; - for(var i of rooms){ - if(i.key==key){ - room=i; + enter: function (key, nickname, avatar) { + this.nickname = util.getNickname(nickname); + this.avatar = avatar; + var room = false; + for (var i of rooms) { + if (i.key == key) { + room = i; break; } } - if(!room){ - this.sendl('enterroomfailed'); + if (!room) { + this.sendl("enterroomfailed"); return; } - this.room=room; + this.room = room; delete this.status; - if(room.owner){ - if(room.servermode&&!room.owner._onconfig&&config&&mode){ - room.owner.sendl('createroom',index,config,mode); - room.owner._onconfig=this; - room.owner.nickname=util.getNickname(nickname); - room.owner.avatar=avatar; - } - else if(!room.config||(room.config.gameStarted&&(!room.config.observe||!room.config.observeReady))){ - this.sendl('enterroomfailed'); - } - else{ - this.owner=room.owner; - this.owner.sendl('onconnection',this.wsid); + if (room.owner) { + if ( + room.servermode && + !room.owner._onconfig && + config && + mode + ) { + room.owner.sendl("createroom", index, config, mode); + room.owner._onconfig = this; + room.owner.nickname = util.getNickname(nickname); + room.owner.avatar = avatar; + } else if ( + !room.config || + (room.config.gameStarted && + (!room.config.observe || !room.config.observeReady)) + ) { + this.sendl("enterroomfailed"); + } else { + this.owner = room.owner; + this.owner.sendl("onconnection", this.wsid); } util.updaterooms(); } }, - changeAvatar:function(nickname,avatar){ - this.nickname=util.getNickname(nickname); - this.avatar=avatar; + changeAvatar: function (nickname, avatar) { + this.nickname = util.getNickname(nickname); + this.avatar = avatar; util.updateclients(); }, - server:function(cfg){ - if(cfg){ - this.servermode=true; - var room=rooms[cfg[0]]; - if(!room||room.owner){ - this.sendl('reloadroom',true); + server: function (cfg) { + if (cfg) { + this.servermode = true; + var room = rooms[cfg[0]]; + if (!room || room.owner) { + this.sendl("reloadroom", true); + } else { + room.owner = this; + this.room = room; + this.nickname = util.getNickname(cfg[1]); + this.avatar = cfg[2]; + this.sendl("createroom", cfg[0], {}, "auto"); } - else{ - room.owner=this; - this.room=room; - this.nickname=util.getNickname(cfg[1]); - this.avatar=cfg[2]; - this.sendl('createroom',cfg[0],{},'auto') - } - } - else{ - for(var i=0;i=20){ - this.sendl('eventsdenied','total'); - } - else if(cfg.utc<=time){ - this.sendl('eventsdenied','time'); - } - else if(util.isBanned(cfg.content)){ - this.sendl('eventsdenied','ban'); - } - else{ - cfg.nickname=util.getNickname(cfg.nickname); - cfg.avatar=cfg.nickname||'caocao'; - cfg.creator=id; - cfg.id=util.getid(); - cfg.members=[id]; + } else if ( + cfg.hasOwnProperty("utc") && + cfg.hasOwnProperty("day") && + cfg.hasOwnProperty("hour") && + cfg.hasOwnProperty("content") + ) { + if (events.length >= 20) { + this.sendl("eventsdenied", "total"); + } else if (cfg.utc <= time) { + this.sendl("eventsdenied", "time"); + } else if (util.isBanned(cfg.content)) { + this.sendl("eventsdenied", "ban"); + } else { + cfg.nickname = util.getNickname(cfg.nickname); + cfg.avatar = cfg.nickname || "caocao"; + cfg.creator = id; + cfg.id = util.getid(); + cfg.members = [id]; events.unshift(cfg); - changed=true; + changed = true; } } } - if(changed){ + if (changed) { util.updateevents(); } }, - config:function(config){ - var room=this.room; - if(room&&room.owner==this){ - if(room.servermode){ - room.servermode=false; - if(this._onconfig){ - if(clients[this._onconfig.wsid]){ - this._onconfig.owner=this; - this.sendl('onconnection',this._onconfig.wsid); + config: function (config) { + var room = this.room; + if (room && room.owner == this) { + if (room.servermode) { + room.servermode = false; + if (this._onconfig) { + if (clients[this._onconfig.wsid]) { + this._onconfig.owner = this; + this.sendl("onconnection", this._onconfig.wsid); } delete this._onconfig; } } - room.config=config; + room.config = config; } util.updaterooms(); }, - status:function(str){ - if(typeof str=='string'){ - this.status=str; - } - else{ + status: function (str) { + if (typeof str == "string") { + this.status = str; + } else { delete this.status; } util.updateclients(); }, - send:function(id,message){ - if(clients[id]&&clients[id].owner==this){ - try{ + send: function (id, message) { + if (clients[id] && clients[id].owner == this) { + try { clients[id].send(message); - } - catch(e){ + } catch (e) { clients[id].close(); } } }, - close:function(id){ - if(clients[id]&&clients[id].owner==this){ + close: function (id) { + if (clients[id] && clients[id].owner == this) { clients[id].close(); } }, }; - var util={ - getNickname:function(str){ - return typeof str=='string'?(str.slice(0,12)):'无名玩家'; + var util = { + getNickname: function (str) { + return typeof str == "string" ? str.slice(0, 12) : "无名玩家"; }, - isBanned:function(str){ - for(var i of bannedKeyWords){ - if(str.indexOf(i)!=-1) return true; + isBanned: function (str) { + for (var i of bannedKeyWords) { + if (str.indexOf(i) != -1) return true; } return false; }, - sendl:function(){ - var args=[]; - for(var i=0;i