diff --git a/o2web/source/o2_core/o2/lp/zh-cn.js b/o2web/source/o2_core/o2/lp/zh-cn.js index 6e6def930823b755d0e2861a51e70cda791f5223..54212caa903b5d30c9c1246ecdac29368d5a4cb2 100644 --- a/o2web/source/o2_core/o2/lp/zh-cn.js +++ b/o2web/source/o2_core/o2/lp/zh-cn.js @@ -305,6 +305,7 @@ o2.LP.widget = { "uploadTitle": "上传文件", "uploadInfor": "请选择要上传的文件", "delete": "删除", + "previewAtt" : "预览", "replace": "替换", "select": "选择", diff --git a/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt.png b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt.png new file mode 100644 index 0000000000000000000000000000000000000000..3eed2902e1789d04fb0a1092296ad1a1d2048c5d Binary files /dev/null and b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt.png differ diff --git a/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt_gray.png b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8e633789e2eb8abd41bb2a9d46edf20bcc467d Binary files /dev/null and b/o2web/source/o2_core/o2/widget/$AttachmentController/default/icon/previewAtt_gray.png differ diff --git a/o2web/source/o2_core/o2/widget/AttachmentController.js b/o2web/source/o2_core/o2/widget/AttachmentController.js index 95d64e9d9f14e65644b5e169417a5d5687b9d4fd..a2bbc4f885e0af1baff4cc4fa22ba1d2387515f1 100644 --- a/o2web/source/o2_core/o2/widget/AttachmentController.js +++ b/o2web/source/o2_core/o2/widget/AttachmentController.js @@ -13,6 +13,7 @@ o2.widget.AttachmentController = o2.widget.ATTER = new Class({ "isDelete": true, "isReplace": true, "isDownload": true, + "isPreviewAtt": true, "isSizeChange": true, "readonly": false, "availableListStyles" : ["list","seq","icon","preview"], @@ -1116,9 +1117,11 @@ o2.widget.AttachmentController = o2.widget.ATTER = new Class({ this.doFormDataUploadAttachment(obj, action, invokeUrl, parameter, callback, multiple, accept, accept, size); } }, - - - + previewAttachment: function(e, node){ + if (this.selectedAttachments.length){ + if (this.module) this.module.previewAttachment(this.selectedAttachments); + } + }, downloadAttachment: function(e, node){ if (this.selectedAttachments.length){ if (this.module) this.module.downloadAttachment(e, node, this.selectedAttachments); diff --git a/o2web/source/o2_lib/viewer/viewer.css b/o2web/source/o2_lib/viewer/viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ec0653bd18e5dd0d6644bb72bef51b54ecfdea37 --- /dev/null +++ b/o2web/source/o2_lib/viewer/viewer.css @@ -0,0 +1,456 @@ +/*! + * Viewer.js v1.3.5 + * https://fengyuanchen.github.io/viewerjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2019-07-04T11:00:13.705Z + */ + +.viewer-zoom-in::before, +.viewer-zoom-out::before, +.viewer-one-to-one::before, +.viewer-reset::before, +.viewer-prev::before, +.viewer-play::before, +.viewer-next::before, +.viewer-rotate-left::before, +.viewer-rotate-right::before, +.viewer-flip-horizontal::before, +.viewer-flip-vertical::before, +.viewer-fullscreen::before, +.viewer-fullscreen-exit::before, +.viewer-close::before { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC'); + background-repeat: no-repeat; + background-size: 280px; + color: transparent; + display: block; + font-size: 0; + height: 20px; + line-height: 0; + width: 20px; +} + +.viewer-zoom-in::before { + background-position: 0 0; + content: 'Zoom In'; +} + +.viewer-zoom-out::before { + background-position: -20px 0; + content: 'Zoom Out'; +} + +.viewer-one-to-one::before { + background-position: -40px 0; + content: 'One to One'; +} + +.viewer-reset::before { + background-position: -60px 0; + content: 'Reset'; +} + +.viewer-prev::before { + background-position: -80px 0; + content: 'Previous'; +} + +.viewer-play::before { + background-position: -100px 0; + content: 'Play'; +} + +.viewer-next::before { + background-position: -120px 0; + content: 'Next'; +} + +.viewer-rotate-left::before { + background-position: -140px 0; + content: 'Rotate Left'; +} + +.viewer-rotate-right::before { + background-position: -160px 0; + content: 'Rotate Right'; +} + +.viewer-flip-horizontal::before { + background-position: -180px 0; + content: 'Flip Horizontal'; +} + +.viewer-flip-vertical::before { + background-position: -200px 0; + content: 'Flip Vertical'; +} + +.viewer-fullscreen::before { + background-position: -220px 0; + content: 'Enter Full Screen'; +} + +.viewer-fullscreen-exit::before { + background-position: -240px 0; + content: 'Exit Full Screen'; +} + +.viewer-close::before { + background-position: -260px 0; + content: 'Close'; +} + +.viewer-container { + bottom: 0; + direction: ltr; + font-size: 0; + left: 0; + line-height: 0; + overflow: hidden; + position: absolute; + right: 0; + -webkit-tap-highlight-color: transparent; + top: 0; + -ms-touch-action: none; + touch-action: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.viewer-container::-moz-selection, +.viewer-container *::-moz-selection { + background-color: transparent; +} + +.viewer-container::selection, +.viewer-container *::selection { + background-color: transparent; +} + +.viewer-container img { + display: block; + height: auto; + max-height: none !important; + max-width: none !important; + min-height: 0 !important; + min-width: 0 !important; + width: 100%; +} + +.viewer-canvas { + bottom: 0; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; +} + +.viewer-canvas > img { + height: auto; + margin: 15px auto; + max-width: 90% !important; + width: auto; +} + +.viewer-footer { + bottom: 0; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + text-align: center; +} + +.viewer-navbar { + background-color: rgba(0, 0, 0, 0.5); + overflow: hidden; +} + +.viewer-list { + -webkit-box-sizing: content-box; + box-sizing: content-box; + height: 50px; + margin: 0; + overflow: hidden; + padding: 1px 0; +} + +.viewer-list > li { + color: transparent; + cursor: pointer; + float: left; + font-size: 0; + height: 50px; + line-height: 0; + opacity: 0.5; + overflow: hidden; + -webkit-transition: opacity 0.15s; + transition: opacity 0.15s; + width: 30px; +} + +.viewer-list > li:hover { + opacity: 0.75; +} + +.viewer-list > li + li { + margin-left: 1px; +} + +.viewer-list > .viewer-loading { + position: relative; +} + +.viewer-list > .viewer-loading::after { + border-width: 2px; + height: 20px; + margin-left: -10px; + margin-top: -10px; + width: 20px; +} + +.viewer-list > .viewer-active, +.viewer-list > .viewer-active:hover { + opacity: 1; +} + +.viewer-player { + background-color: #000; + bottom: 0; + cursor: none; + display: none; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.viewer-player > img { + left: 0; + position: absolute; + top: 0; +} + +.viewer-toolbar > ul { + display: inline-block; + margin: 0 auto 5px; + overflow: hidden; + padding: 3px 0; +} + +.viewer-toolbar > ul > li { + background-color: rgba(0, 0, 0, 0.5); + border-radius: 50%; + cursor: pointer; + float: left; + height: 24px; + overflow: hidden; + -webkit-transition: background-color 0.15s; + transition: background-color 0.15s; + width: 24px; +} + +.viewer-toolbar > ul > li:hover { + background-color: rgba(0, 0, 0, 0.8); +} + +.viewer-toolbar > ul > li::before { + margin: 2px; +} + +.viewer-toolbar > ul > li + li { + margin-left: 1px; +} + +.viewer-toolbar > ul > .viewer-small { + height: 18px; + margin-bottom: 3px; + margin-top: 3px; + width: 18px; +} + +.viewer-toolbar > ul > .viewer-small::before { + margin: -1px; +} + +.viewer-toolbar > ul > .viewer-large { + height: 30px; + margin-bottom: -3px; + margin-top: -3px; + width: 30px; +} + +.viewer-toolbar > ul > .viewer-large::before { + margin: 5px; +} + +.viewer-tooltip { + background-color: rgba(0, 0, 0, 0.8); + border-radius: 10px; + color: #fff; + display: none; + font-size: 12px; + height: 20px; + left: 50%; + line-height: 20px; + margin-left: -25px; + margin-top: -10px; + position: absolute; + text-align: center; + top: 50%; + width: 50px; +} + +.viewer-title { + color: #ccc; + display: inline-block; + font-size: 12px; + line-height: 1; + margin: 0 5% 5px; + max-width: 90%; + opacity: 0.8; + overflow: hidden; + text-overflow: ellipsis; + -webkit-transition: opacity 0.15s; + transition: opacity 0.15s; + white-space: nowrap; +} + +.viewer-title:hover { + opacity: 1; +} + +.viewer-button { + background-color: rgba(0, 0, 0, 0.5); + border-radius: 50%; + cursor: pointer; + height: 80px; + overflow: hidden; + position: absolute; + right: -40px; + top: -40px; + -webkit-transition: background-color 0.15s; + transition: background-color 0.15s; + width: 80px; +} + +.viewer-button:focus, +.viewer-button:hover { + background-color: rgba(0, 0, 0, 0.8); +} + +.viewer-button::before { + bottom: 15px; + left: 15px; + position: absolute; +} + +.viewer-fixed { + position: fixed; +} + +.viewer-open { + overflow: hidden; +} + +.viewer-show { + display: block; +} + +.viewer-hide { + display: none; +} + +.viewer-backdrop { + background-color: rgba(0, 0, 0, 0.5); +} + +.viewer-invisible { + visibility: hidden; +} + +.viewer-move { + cursor: move; + cursor: -webkit-grab; + cursor: grab; +} + +.viewer-fade { + opacity: 0; +} + +.viewer-in { + opacity: 1; +} + +.viewer-transition { + -webkit-transition: all 0.3s; + transition: all 0.3s; +} + +@-webkit-keyframes viewer-spinner { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes viewer-spinner { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +.viewer-loading::after { + -webkit-animation: viewer-spinner 1s linear infinite; + animation: viewer-spinner 1s linear infinite; + border: 4px solid rgba(255, 255, 255, 0.1); + border-left-color: rgba(255, 255, 255, 0.5); + border-radius: 50%; + content: ''; + display: inline-block; + height: 40px; + left: 50%; + margin-left: -20px; + margin-top: -20px; + position: absolute; + top: 50%; + width: 40px; + z-index: 1; +} + +@media (max-width: 767px) { + .viewer-hide-xs-down { + display: none; + } +} + +@media (max-width: 991px) { + .viewer-hide-sm-down { + display: none; + } +} + +@media (max-width: 1199px) { + .viewer-hide-md-down { + display: none; + } +} \ No newline at end of file diff --git a/o2web/source/o2_lib/viewer/viewer.js b/o2web/source/o2_lib/viewer/viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..a410d3ab90a29c88765d51865fc6cc13ac413d27 --- /dev/null +++ b/o2web/source/o2_lib/viewer/viewer.js @@ -0,0 +1,3043 @@ +/*! + * Viewer.js v1.3.5 + * https://fengyuanchen.github.io/viewerjs + * + * Copyright 2015-present Chen Fengyuan + * Released under the MIT license + * + * Date: 2019-07-04T11:00:16.790Z + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = global || self, global.Viewer = factory()); +}(this, function () { 'use strict'; + + function _typeof(obj) { + if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { + _typeof = function (obj) { + return typeof obj; + }; + } else { + _typeof = function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + } + + return _typeof(obj); + } + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; + } + + var DEFAULTS = { + /** + * Enable a modal backdrop, specify `static` for a backdrop + * which doesn't close the modal on click. + * @type {boolean} + */ + backdrop: true, + + /** + * Show the button on the top-right of the viewer. + * @type {boolean} + */ + button: true, + + /** + * Show the navbar. + * @type {boolean | number} + */ + navbar: true, + + /** + * Specify the visibility and the content of the title. + * @type {boolean | number | Function | Array} + */ + title: true, + + /** + * Show the toolbar. + * @type {boolean | number | Object} + */ + toolbar: true, + + /** + * Custom class name(s) to add to the viewer's root element. + * @type {string} + */ + className: '', + + /** + * Define where to put the viewer in modal mode. + * @type {string | Element} + */ + container: 'body', + + /** + * Filter the images for viewing. Return true if the image is viewable. + * @type {Function} + */ + filter: null, + + /** + * Enable to request fullscreen when play. + * @type {boolean} + */ + fullscreen: true, + + /** + * Define the initial index of image for viewing. + * @type {number} + */ + initialViewIndex: 0, + + /** + * Enable inline mode. + * @type {boolean} + */ + inline: false, + + /** + * The amount of time to delay between automatically cycling an image when playing. + * @type {number} + */ + interval: 5000, + + /** + * Enable keyboard support. + * @type {boolean} + */ + keyboard: true, + + /** + * Indicate if show a loading spinner when load image or not. + * @type {boolean} + */ + loading: true, + + /** + * Indicate if enable loop viewing or not. + * @type {boolean} + */ + loop: true, + + /** + * Min width of the viewer in inline mode. + * @type {number} + */ + minWidth: 200, + + /** + * Min height of the viewer in inline mode. + * @type {number} + */ + minHeight: 100, + + /** + * Enable to move the image. + * @type {boolean} + */ + movable: true, + + /** + * Enable to zoom the image. + * @type {boolean} + */ + zoomable: true, + + /** + * Enable to rotate the image. + * @type {boolean} + */ + rotatable: true, + + /** + * Enable to scale the image. + * @type {boolean} + */ + scalable: true, + + /** + * Indicate if toggle the image size between its natural size + * and initial size when double click on the image or not. + * @type {boolean} + */ + toggleOnDblclick: true, + + /** + * Show the tooltip with image ratio (percentage) when zoom in or zoom out. + * @type {boolean} + */ + tooltip: true, + + /** + * Enable CSS3 Transition for some special elements. + * @type {boolean} + */ + transition: true, + + /** + * Define the CSS `z-index` value of viewer in modal mode. + * @type {number} + */ + zIndex: 2015, + + /** + * Define the CSS `z-index` value of viewer in inline mode. + * @type {number} + */ + zIndexInline: 0, + + /** + * Define the ratio when zoom the image by wheeling mouse. + * @type {number} + */ + zoomRatio: 0.1, + + /** + * Define the min ratio of the image when zoom out. + * @type {number} + */ + minZoomRatio: 0.01, + + /** + * Define the max ratio of the image when zoom in. + * @type {number} + */ + maxZoomRatio: 100, + + /** + * Define where to get the original image URL for viewing. + * @type {string | Function} + */ + url: 'src', + + /** + * Event shortcuts. + * @type {Function} + */ + ready: null, + show: null, + shown: null, + hide: null, + hidden: null, + view: null, + viewed: null, + zoom: null, + zoomed: null + }; + + var TEMPLATE = '
' + '
' + '' + '
' + '
' + '
' + '
'; + + var IS_BROWSER = typeof window !== 'undefined'; + var WINDOW = IS_BROWSER ? window : {}; + var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false; + var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false; + var NAMESPACE = 'viewer'; // Actions + + var ACTION_MOVE = 'move'; + var ACTION_SWITCH = 'switch'; + var ACTION_ZOOM = 'zoom'; // Classes + + var CLASS_ACTIVE = "".concat(NAMESPACE, "-active"); + var CLASS_CLOSE = "".concat(NAMESPACE, "-close"); + var CLASS_FADE = "".concat(NAMESPACE, "-fade"); + var CLASS_FIXED = "".concat(NAMESPACE, "-fixed"); + var CLASS_FULLSCREEN = "".concat(NAMESPACE, "-fullscreen"); + var CLASS_FULLSCREEN_EXIT = "".concat(NAMESPACE, "-fullscreen-exit"); + var CLASS_HIDE = "".concat(NAMESPACE, "-hide"); + var CLASS_HIDE_MD_DOWN = "".concat(NAMESPACE, "-hide-md-down"); + var CLASS_HIDE_SM_DOWN = "".concat(NAMESPACE, "-hide-sm-down"); + var CLASS_HIDE_XS_DOWN = "".concat(NAMESPACE, "-hide-xs-down"); + var CLASS_IN = "".concat(NAMESPACE, "-in"); + var CLASS_INVISIBLE = "".concat(NAMESPACE, "-invisible"); + var CLASS_LOADING = "".concat(NAMESPACE, "-loading"); + var CLASS_MOVE = "".concat(NAMESPACE, "-move"); + var CLASS_OPEN = "".concat(NAMESPACE, "-open"); + var CLASS_SHOW = "".concat(NAMESPACE, "-show"); + var CLASS_TRANSITION = "".concat(NAMESPACE, "-transition"); // Events + + var EVENT_CLICK = 'click'; + var EVENT_DBLCLICK = 'dblclick'; + var EVENT_DRAG_START = 'dragstart'; + var EVENT_HIDDEN = 'hidden'; + var EVENT_HIDE = 'hide'; + var EVENT_KEY_DOWN = 'keydown'; + var EVENT_LOAD = 'load'; + var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown'; + var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove'; + var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup'; + var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START; + var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE; + var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END; + var EVENT_READY = 'ready'; + var EVENT_RESIZE = 'resize'; + var EVENT_SHOW = 'show'; + var EVENT_SHOWN = 'shown'; + var EVENT_TRANSITION_END = 'transitionend'; + var EVENT_VIEW = 'view'; + var EVENT_VIEWED = 'viewed'; + var EVENT_WHEEL = 'wheel'; + var EVENT_ZOOM = 'zoom'; + var EVENT_ZOOMED = 'zoomed'; // Data keys + + var DATA_ACTION = "".concat(NAMESPACE, "Action"); // RegExps + + var REGEXP_SPACES = /\s\s*/; // Misc + + var BUTTONS = ['zoom-in', 'zoom-out', 'one-to-one', 'reset', 'prev', 'play', 'next', 'rotate-left', 'rotate-right', 'flip-horizontal', 'flip-vertical']; + + /** + * Check if the given value is a string. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a string, else `false`. + */ + + function isString(value) { + return typeof value === 'string'; + } + /** + * Check if the given value is not a number. + */ + + var isNaN = Number.isNaN || WINDOW.isNaN; + /** + * Check if the given value is a number. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a number, else `false`. + */ + + function isNumber(value) { + return typeof value === 'number' && !isNaN(value); + } + /** + * Check if the given value is undefined. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is undefined, else `false`. + */ + + function isUndefined(value) { + return typeof value === 'undefined'; + } + /** + * Check if the given value is an object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is an object, else `false`. + */ + + function isObject(value) { + return _typeof(value) === 'object' && value !== null; + } + var hasOwnProperty = Object.prototype.hasOwnProperty; + /** + * Check if the given value is a plain object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a plain object, else `false`. + */ + + function isPlainObject(value) { + if (!isObject(value)) { + return false; + } + + try { + var _constructor = value.constructor; + var prototype = _constructor.prototype; + return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (error) { + return false; + } + } + /** + * Check if the given value is a function. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a function, else `false`. + */ + + function isFunction(value) { + return typeof value === 'function'; + } + /** + * Iterate the given data. + * @param {*} data - The data to iterate. + * @param {Function} callback - The process function for each element. + * @returns {*} The original data. + */ + + function forEach(data, callback) { + if (data && isFunction(callback)) { + if (Array.isArray(data) || isNumber(data.length) + /* array-like */ + ) { + var length = data.length; + var i; + + for (i = 0; i < length; i += 1) { + if (callback.call(data, data[i], i, data) === false) { + break; + } + } + } else if (isObject(data)) { + Object.keys(data).forEach(function (key) { + callback.call(data, data[key], key, data); + }); + } + } + + return data; + } + /** + * Extend the given object. + * @param {*} obj - The object to be extended. + * @param {*} args - The rest objects which will be merged to the first object. + * @returns {Object} The extended object. + */ + + var assign = Object.assign || function assign(obj) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (isObject(obj) && args.length > 0) { + args.forEach(function (arg) { + if (isObject(arg)) { + Object.keys(arg).forEach(function (key) { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; + }; + var REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/; + /** + * Apply styles to the given element. + * @param {Element} element - The target element. + * @param {Object} styles - The styles for applying. + */ + + function setStyle(element, styles) { + var style = element.style; + forEach(styles, function (value, property) { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); + } + /** + * Escape a string for using in HTML. + * @param {String} value - The string to escape. + * @returns {String} Returns the escaped string. + */ + + function escapeHTMLEntities(value) { + return isString(value) ? value.replace(/&(?!amp;|quot;|#39;|lt;|gt;)/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(//g, '>') : value; + } + /** + * Check if the given element has a special class. + * @param {Element} element - The element to check. + * @param {string} value - The class to search. + * @returns {boolean} Returns `true` if the special class was found. + */ + + function hasClass(element, value) { + return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1; + } + /** + * Add classes to the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be added. + */ + + function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + forEach(element, function (elem) { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + var className = element.className.trim(); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = "".concat(className, " ").concat(value); + } + } + /** + * Remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be removed. + */ + + function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + forEach(element, function (elem) { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } + } + /** + * Add or remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be toggled. + * @param {boolean} added - Add only. + */ + + function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + forEach(element, function (elem) { + toggleClass(elem, value, added); + }); + return; + } // IE10-11 doesn't support the second parameter of `classList.toggle` + + + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } + } + var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; + /** + * Transform the given string from camelCase to kebab-case + * @param {string} value - The value to transform. + * @returns {string} The transformed value. + */ + + function hyphenate(value) { + return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); + } + /** + * Get data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to get. + * @returns {string} The data value. + */ + + function getData(element, name) { + if (isObject(element[name])) { + return element[name]; + } + + if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute("data-".concat(hyphenate(name))); + } + /** + * Set data to the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to set. + * @param {string} data - The data value. + */ + + function setData(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute("data-".concat(hyphenate(name)), data); + } + } + + var onceSupported = function () { + var supported = false; + + if (IS_BROWSER) { + var once = false; + + var listener = function listener() {}; + + var options = Object.defineProperty({}, 'once', { + get: function get() { + supported = true; + return once; + }, + + /** + * This setter can fix a `TypeError` in strict mode + * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only} + * @param {boolean} value - The value to set + */ + set: function set(value) { + once = value; + } + }); + WINDOW.addEventListener('test', listener, options); + WINDOW.removeEventListener('test', listener, options); + } + + return supported; + }(); + /** + * Remove event listener from the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ + + + function removeListener(element, type, listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var handler = listener; + type.trim().split(REGEXP_SPACES).forEach(function (event) { + if (!onceSupported) { + var listeners = element.listeners; + + if (listeners && listeners[event] && listeners[event][listener]) { + handler = listeners[event][listener]; + delete listeners[event][listener]; + + if (Object.keys(listeners[event]).length === 0) { + delete listeners[event]; + } + + if (Object.keys(listeners).length === 0) { + delete element.listeners; + } + } + } + + element.removeEventListener(event, handler, options); + }); + } + /** + * Add event listener to the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ + + function addListener(element, type, listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + var _handler = listener; + type.trim().split(REGEXP_SPACES).forEach(function (event) { + if (options.once && !onceSupported) { + var _element$listeners = element.listeners, + listeners = _element$listeners === void 0 ? {} : _element$listeners; + + _handler = function handler() { + delete listeners[event][listener]; + element.removeEventListener(event, _handler, options); + + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + listener.apply(element, args); + }; + + if (!listeners[event]) { + listeners[event] = {}; + } + + if (listeners[event][listener]) { + element.removeEventListener(event, listeners[event][listener], options); + } + + listeners[event][listener] = _handler; + element.listeners = listeners; + } + + element.addEventListener(event, _handler, options); + }); + } + /** + * Dispatch event on the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Object} data - The additional event data. + * @returns {boolean} Indicate if the event is default prevented or not. + */ + + function dispatchEvent(element, type, data) { + var event; // Event and CustomEvent on IE9-11 are global objects, not constructors + + if (isFunction(Event) && isFunction(CustomEvent)) { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + return element.dispatchEvent(event); + } + /** + * Get the offset base on the document. + * @param {Element} element - The target element. + * @returns {Object} The offset data. + */ + + function getOffset(element) { + var box = element.getBoundingClientRect(); + return { + left: box.left + (window.pageXOffset - document.documentElement.clientLeft), + top: box.top + (window.pageYOffset - document.documentElement.clientTop) + }; + } + /** + * Get transforms base on the given object. + * @param {Object} obj - The target object. + * @returns {string} A string contains transform values. + */ + + function getTransforms(_ref) { + var rotate = _ref.rotate, + scaleX = _ref.scaleX, + scaleY = _ref.scaleY, + translateX = _ref.translateX, + translateY = _ref.translateY; + var values = []; + + if (isNumber(translateX) && translateX !== 0) { + values.push("translateX(".concat(translateX, "px)")); + } + + if (isNumber(translateY) && translateY !== 0) { + values.push("translateY(".concat(translateY, "px)")); + } // Rotate should come first before scale to match orientation transform + + + if (isNumber(rotate) && rotate !== 0) { + values.push("rotate(".concat(rotate, "deg)")); + } + + if (isNumber(scaleX) && scaleX !== 1) { + values.push("scaleX(".concat(scaleX, ")")); + } + + if (isNumber(scaleY) && scaleY !== 1) { + values.push("scaleY(".concat(scaleY, ")")); + } + + var transform = values.length ? values.join(' ') : 'none'; + return { + WebkitTransform: transform, + msTransform: transform, + transform: transform + }; + } + /** + * Get an image name from an image url. + * @param {string} url - The target url. + * @example + * // picture.jpg + * getImageNameFromURL('http://domain.com/path/to/picture.jpg?size=1280×960') + * @returns {string} A string contains the image name. + */ + + function getImageNameFromURL(url) { + return isString(url) ? decodeURIComponent(url.replace(/^.*\//, '').replace(/[?&#].*$/, '')) : ''; + } + var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent); + /** + * Get an image's natural sizes. + * @param {string} image - The target image. + * @param {Function} callback - The callback function. + * @returns {HTMLImageElement} The new image. + */ + + function getImageNaturalSizes(image, callback) { + var newImage = document.createElement('img'); // Modern browsers (except Safari) + + if (image.naturalWidth && !IS_SAFARI) { + callback(image.naturalWidth, image.naturalHeight); + return newImage; + } + + var body = document.body || document.documentElement; + + newImage.onload = function () { + callback(newImage.width, newImage.height); + + if (!IS_SAFARI) { + body.removeChild(newImage); + } + }; + + newImage.src = image.src; // iOS Safari will convert the image automatically + // with its orientation once append it into DOM + + if (!IS_SAFARI) { + newImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;'; + body.appendChild(newImage); + } + + return newImage; + } + /** + * Get the related class name of a responsive type number. + * @param {string} type - The responsive type. + * @returns {string} The related class name. + */ + + function getResponsiveClass(type) { + switch (type) { + case 2: + return CLASS_HIDE_XS_DOWN; + + case 3: + return CLASS_HIDE_SM_DOWN; + + case 4: + return CLASS_HIDE_MD_DOWN; + + default: + return ''; + } + } + /** + * Get the max ratio of a group of pointers. + * @param {string} pointers - The target pointers. + * @returns {number} The result ratio. + */ + + function getMaxZoomRatio(pointers) { + var pointers2 = assign({}, pointers); + var ratios = []; + forEach(pointers, function (pointer, pointerId) { + delete pointers2[pointerId]; + forEach(pointers2, function (pointer2) { + var x1 = Math.abs(pointer.startX - pointer2.startX); + var y1 = Math.abs(pointer.startY - pointer2.startY); + var x2 = Math.abs(pointer.endX - pointer2.endX); + var y2 = Math.abs(pointer.endY - pointer2.endY); + var z1 = Math.sqrt(x1 * x1 + y1 * y1); + var z2 = Math.sqrt(x2 * x2 + y2 * y2); + var ratio = (z2 - z1) / z1; + ratios.push(ratio); + }); + }); + ratios.sort(function (a, b) { + return Math.abs(a) < Math.abs(b); + }); + return ratios[0]; + } + /** + * Get a pointer from an event object. + * @param {Object} event - The target event object. + * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not. + * @returns {Object} The result pointer contains start and/or end point coordinates. + */ + + function getPointer(_ref2, endOnly) { + var pageX = _ref2.pageX, + pageY = _ref2.pageY; + var end = { + endX: pageX, + endY: pageY + }; + return endOnly ? end : assign({ + timeStamp: Date.now(), + startX: pageX, + startY: pageY + }, end); + } + /** + * Get the center point coordinate of a group of pointers. + * @param {Object} pointers - The target pointers. + * @returns {Object} The center point coordinate. + */ + + function getPointersCenter(pointers) { + var pageX = 0; + var pageY = 0; + var count = 0; + forEach(pointers, function (_ref3) { + var startX = _ref3.startX, + startY = _ref3.startY; + pageX += startX; + pageY += startY; + count += 1; + }); + pageX /= count; + pageY /= count; + return { + pageX: pageX, + pageY: pageY + }; + } + + var render = { + render: function render() { + this.initContainer(); + this.initViewer(); + this.initList(); + this.renderViewer(); + }, + initContainer: function initContainer() { + this.containerData = { + width: window.innerWidth, + height: window.innerHeight + }; + }, + initViewer: function initViewer() { + var options = this.options, + parent = this.parent; + var viewerData; + + if (options.inline) { + viewerData = { + width: Math.max(parent.offsetWidth, options.minWidth), + height: Math.max(parent.offsetHeight, options.minHeight) + }; + this.parentData = viewerData; + } + + if (this.fulled || !viewerData) { + viewerData = this.containerData; + } + + this.viewerData = assign({}, viewerData); + }, + renderViewer: function renderViewer() { + if (this.options.inline && !this.fulled) { + setStyle(this.viewer, this.viewerData); + } + }, + initList: function initList() { + var _this = this; + + var element = this.element, + options = this.options, + list = this.list; + var items = []; + forEach(this.images, function (image, index) { + var src = image.src; + var alt = escapeHTMLEntities(image.alt || getImageNameFromURL(src)); + var url = options.url; + + if (isString(url)) { + url = image.getAttribute(url); + } else if (isFunction(url)) { + url = url.call(_this, image); + } + + if (src || url) { + var item = document.createElement('li'); + var img = document.createElement('img'); + img.src = src || url; + img.alt = alt; + img.setAttribute('data-index', index); + img.setAttribute('data-original-url', url || src); + img.setAttribute('data-viewer-action', 'view'); + img.setAttribute('role', 'button'); + item.appendChild(img); + list.appendChild(item); + items.push(item); + } + }); + this.items = items; + forEach(items, function (item) { + var image = item.firstElementChild; + setData(image, 'filled', true); + + if (options.loading) { + addClass(item, CLASS_LOADING); + } + + addListener(image, EVENT_LOAD, function (event) { + if (options.loading) { + removeClass(item, CLASS_LOADING); + } + + _this.loadImage(event); + }, { + once: true + }); + }); + + if (options.transition) { + addListener(element, EVENT_VIEWED, function () { + addClass(list, CLASS_TRANSITION); + }, { + once: true + }); + } + }, + renderList: function renderList(index) { + var i = index || this.index; + var width = this.items[i].offsetWidth || 30; + var outerWidth = width + 1; // 1 pixel of `margin-left` width + // Place the active item in the center of the screen + + setStyle(this.list, assign({ + width: outerWidth * this.length + }, getTransforms({ + translateX: (this.viewerData.width - width) / 2 - outerWidth * i + }))); + }, + resetList: function resetList() { + var list = this.list; + list.innerHTML = ''; + removeClass(list, CLASS_TRANSITION); + setStyle(list, getTransforms({ + translateX: 0 + })); + }, + initImage: function initImage(done) { + var _this2 = this; + + var options = this.options, + image = this.image, + viewerData = this.viewerData; + var footerHeight = this.footer.offsetHeight; + var viewerWidth = viewerData.width; + var viewerHeight = Math.max(viewerData.height - footerHeight, footerHeight); + var oldImageData = this.imageData || {}; + var sizingImage; + this.imageInitializing = { + abort: function abort() { + sizingImage.onload = null; + } + }; + sizingImage = getImageNaturalSizes(image, function (naturalWidth, naturalHeight) { + var aspectRatio = naturalWidth / naturalHeight; + var width = viewerWidth; + var height = viewerHeight; + _this2.imageInitializing = false; + + if (viewerHeight * aspectRatio > viewerWidth) { + height = viewerWidth / aspectRatio; + } else { + width = viewerHeight * aspectRatio; + } + + width = Math.min(width * 0.9, naturalWidth); + height = Math.min(height * 0.9, naturalHeight); + var imageData = { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: aspectRatio, + ratio: width / naturalWidth, + width: width, + height: height, + left: (viewerWidth - width) / 2, + top: (viewerHeight - height) / 2 + }; + var initialImageData = assign({}, imageData); + + if (options.rotatable) { + imageData.rotate = oldImageData.rotate || 0; + initialImageData.rotate = 0; + } + + if (options.scalable) { + imageData.scaleX = oldImageData.scaleX || 1; + imageData.scaleY = oldImageData.scaleY || 1; + initialImageData.scaleX = 1; + initialImageData.scaleY = 1; + } + + _this2.imageData = imageData; + _this2.initialImageData = initialImageData; + + if (done) { + done(); + } + }); + }, + renderImage: function renderImage(done) { + var _this3 = this; + + var image = this.image, + imageData = this.imageData; + setStyle(image, assign({ + width: imageData.width, + height: imageData.height, + // XXX: Not to use translateX/Y to avoid image shaking when zooming + marginLeft: imageData.left, + marginTop: imageData.top + }, getTransforms(imageData))); + + if (done) { + if ((this.viewing || this.zooming) && this.options.transition) { + var onTransitionEnd = function onTransitionEnd() { + _this3.imageRendering = false; + done(); + }; + + this.imageRendering = { + abort: function abort() { + removeListener(image, EVENT_TRANSITION_END, onTransitionEnd); + } + }; + addListener(image, EVENT_TRANSITION_END, onTransitionEnd, { + once: true + }); + } else { + done(); + } + } + }, + resetImage: function resetImage() { + // this.image only defined after viewed + if (this.viewing || this.viewed) { + var image = this.image; + + if (this.viewing) { + this.viewing.abort(); + } + + image.parentNode.removeChild(image); + this.image = null; + } + } + }; + + var events = { + bind: function bind() { + var options = this.options, + viewer = this.viewer, + canvas = this.canvas; + var document = this.element.ownerDocument; + addListener(viewer, EVENT_CLICK, this.onClick = this.click.bind(this)); + addListener(viewer, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), { + passive: false, + capture: true + }); + addListener(viewer, EVENT_DRAG_START, this.onDragStart = this.dragstart.bind(this)); + addListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this)); + addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this)); + addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this)); + addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this)); + addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this)); + + if (options.toggleOnDblclick) { + addListener(canvas, EVENT_DBLCLICK, this.onDblclick = this.dblclick.bind(this)); + } + }, + unbind: function unbind() { + var options = this.options, + viewer = this.viewer, + canvas = this.canvas; + var document = this.element.ownerDocument; + removeListener(viewer, EVENT_CLICK, this.onClick); + removeListener(viewer, EVENT_WHEEL, this.onWheel, { + passive: false, + capture: true + }); + removeListener(viewer, EVENT_DRAG_START, this.onDragStart); + removeListener(canvas, EVENT_POINTER_DOWN, this.onPointerDown); + removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove); + removeListener(document, EVENT_POINTER_UP, this.onPointerUp); + removeListener(document, EVENT_KEY_DOWN, this.onKeyDown); + removeListener(window, EVENT_RESIZE, this.onResize); + + if (options.toggleOnDblclick) { + removeListener(canvas, EVENT_DBLCLICK, this.onDblclick); + } + } + }; + + var handlers = { + click: function click(event) { + var target = event.target; + var options = this.options, + imageData = this.imageData; + var action = getData(target, DATA_ACTION); // Cancel the emulated click when the native click event was triggered. + + if (IS_TOUCH_DEVICE && event.isTrusted && target === this.canvas) { + clearTimeout(this.clickCanvasTimeout); + } + + switch (action) { + case 'mix': + if (this.played) { + this.stop(); + } else if (options.inline) { + if (this.fulled) { + this.exit(); + } else { + this.full(); + } + } else { + this.hide(); + } + + break; + + case 'hide': + this.hide(); + break; + + case 'view': + this.view(getData(target, 'index')); + break; + + case 'zoom-in': + this.zoom(0.1, true); + break; + + case 'zoom-out': + this.zoom(-0.1, true); + break; + + case 'one-to-one': + this.toggle(); + break; + + case 'reset': + this.reset(); + break; + + case 'prev': + this.prev(options.loop); + break; + + case 'play': + this.play(options.fullscreen); + break; + + case 'next': + this.next(options.loop); + break; + + case 'rotate-left': + this.rotate(-90); + break; + + case 'rotate-right': + this.rotate(90); + break; + + case 'flip-horizontal': + this.scaleX(-imageData.scaleX || -1); + break; + + case 'flip-vertical': + this.scaleY(-imageData.scaleY || -1); + break; + + default: + if (this.played) { + this.stop(); + } + + } + }, + dblclick: function dblclick(event) { + event.preventDefault(); + + if (this.viewed && event.target === this.image) { + // Cancel the emulated double click when the native dblclick event was triggered. + if (IS_TOUCH_DEVICE && event.isTrusted) { + clearTimeout(this.doubleClickImageTimeout); + } + + this.toggle(); + } + }, + load: function load() { + var _this = this; + + if (this.timeout) { + clearTimeout(this.timeout); + this.timeout = false; + } + + var element = this.element, + options = this.options, + image = this.image, + index = this.index, + viewerData = this.viewerData; + removeClass(image, CLASS_INVISIBLE); + + if (options.loading) { + removeClass(this.canvas, CLASS_LOADING); + } + + image.style.cssText = 'height:0;' + "margin-left:".concat(viewerData.width / 2, "px;") + "margin-top:".concat(viewerData.height / 2, "px;") + 'max-width:none!important;' + 'position:absolute;' + 'width:0;'; + this.initImage(function () { + toggleClass(image, CLASS_MOVE, options.movable); + toggleClass(image, CLASS_TRANSITION, options.transition); + + _this.renderImage(function () { + _this.viewed = true; + _this.viewing = false; + + if (isFunction(options.viewed)) { + addListener(element, EVENT_VIEWED, options.viewed, { + once: true + }); + } + + dispatchEvent(element, EVENT_VIEWED, { + originalImage: _this.images[index], + index: index, + image: image + }); + }); + }); + }, + loadImage: function loadImage(event) { + var image = event.target; + var parent = image.parentNode; + var parentWidth = parent.offsetWidth || 30; + var parentHeight = parent.offsetHeight || 50; + var filled = !!getData(image, 'filled'); + getImageNaturalSizes(image, function (naturalWidth, naturalHeight) { + var aspectRatio = naturalWidth / naturalHeight; + var width = parentWidth; + var height = parentHeight; + + if (parentHeight * aspectRatio > parentWidth) { + if (filled) { + width = parentHeight * aspectRatio; + } else { + height = parentWidth / aspectRatio; + } + } else if (filled) { + height = parentWidth / aspectRatio; + } else { + width = parentHeight * aspectRatio; + } + + setStyle(image, assign({ + width: width, + height: height + }, getTransforms({ + translateX: (parentWidth - width) / 2, + translateY: (parentHeight - height) / 2 + }))); + }); + }, + keydown: function keydown(event) { + var options = this.options; + + if (!this.fulled || !options.keyboard) { + return; + } + + switch (event.keyCode || event.which || event.charCode) { + // Escape + case 27: + if (this.played) { + this.stop(); + } else if (options.inline) { + if (this.fulled) { + this.exit(); + } + } else { + this.hide(); + } + + break; + // Space + + case 32: + if (this.played) { + this.stop(); + } + + break; + // ArrowLeft + + case 37: + this.prev(options.loop); + break; + // ArrowUp + + case 38: + // Prevent scroll on Firefox + event.preventDefault(); // Zoom in + + this.zoom(options.zoomRatio, true); + break; + // ArrowRight + + case 39: + this.next(options.loop); + break; + // ArrowDown + + case 40: + // Prevent scroll on Firefox + event.preventDefault(); // Zoom out + + this.zoom(-options.zoomRatio, true); + break; + // Ctrl + 0 + + case 48: // Fall through + // Ctrl + 1 + // eslint-disable-next-line no-fallthrough + + case 49: + if (event.ctrlKey) { + event.preventDefault(); + this.toggle(); + } + + break; + + default: + } + }, + dragstart: function dragstart(event) { + if (event.target.tagName.toLowerCase() === 'img') { + event.preventDefault(); + } + }, + pointerdown: function pointerdown(event) { + var options = this.options, + pointers = this.pointers; + var buttons = event.buttons, + button = event.button; + + if (!this.viewed || this.showing || this.viewing || this.hiding // No primary button (Usually the left button) + // Note that touch events have no `buttons` or `button` property + || isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu + || event.ctrlKey) { + return; + } // Prevent default behaviours as page zooming in touch devices. + + + event.preventDefault(); + + if (event.changedTouches) { + forEach(event.changedTouches, function (touch) { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + pointers[event.pointerId || 0] = getPointer(event); + } + + var action = options.movable ? ACTION_MOVE : false; + + if (Object.keys(pointers).length > 1) { + action = ACTION_ZOOM; + } else if ((event.pointerType === 'touch' || event.type === 'touchstart') && this.isSwitchable()) { + action = ACTION_SWITCH; + } + + if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) { + removeClass(this.image, CLASS_TRANSITION); + } + + this.action = action; + }, + pointermove: function pointermove(event) { + var pointers = this.pointers, + action = this.action; + + if (!this.viewed || !action) { + return; + } + + event.preventDefault(); + + if (event.changedTouches) { + forEach(event.changedTouches, function (touch) { + assign(pointers[touch.identifier] || {}, getPointer(touch, true)); + }); + } else { + assign(pointers[event.pointerId || 0] || {}, getPointer(event, true)); + } + + this.change(event); + }, + pointerup: function pointerup(event) { + var _this2 = this; + + var options = this.options, + action = this.action, + pointers = this.pointers; + var pointer; + + if (event.changedTouches) { + forEach(event.changedTouches, function (touch) { + pointer = pointers[touch.identifier]; + delete pointers[touch.identifier]; + }); + } else { + pointer = pointers[event.pointerId || 0]; + delete pointers[event.pointerId || 0]; + } + + if (!action) { + return; + } + + event.preventDefault(); + + if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) { + addClass(this.image, CLASS_TRANSITION); + } + + this.action = false; // Emulate click and double click in touch devices to support backdrop and image zooming (#210). + + if (IS_TOUCH_DEVICE && action !== ACTION_ZOOM && pointer && Date.now() - pointer.timeStamp < 500) { + clearTimeout(this.clickCanvasTimeout); + clearTimeout(this.doubleClickImageTimeout); + + if (options.toggleOnDblclick && this.viewed && event.target === this.image) { + if (this.imageClicked) { + this.imageClicked = false; // This timeout will be cleared later when a native dblclick event is triggering + + this.doubleClickImageTimeout = setTimeout(function () { + dispatchEvent(_this2.image, EVENT_DBLCLICK); + }, 50); + } else { + this.imageClicked = true; // The default timing of a double click in Windows is 500 ms + + this.doubleClickImageTimeout = setTimeout(function () { + _this2.imageClicked = false; + }, 500); + } + } else { + this.imageClicked = false; + + if (options.backdrop && options.backdrop !== 'static' && event.target === this.canvas) { + // This timeout will be cleared later when a native click event is triggering + this.clickCanvasTimeout = setTimeout(function () { + dispatchEvent(_this2.canvas, EVENT_CLICK); + }, 50); + } + } + } + }, + resize: function resize() { + var _this3 = this; + + if (!this.isShown || this.hiding) { + return; + } + + this.initContainer(); + this.initViewer(); + this.renderViewer(); + this.renderList(); + + if (this.viewed) { + this.initImage(function () { + _this3.renderImage(); + }); + } + + if (this.played) { + if (this.options.fullscreen && this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) { + this.stop(); + return; + } + + forEach(this.player.getElementsByTagName('img'), function (image) { + addListener(image, EVENT_LOAD, _this3.loadImage.bind(_this3), { + once: true + }); + dispatchEvent(image, EVENT_LOAD); + }); + } + }, + wheel: function wheel(event) { + var _this4 = this; + + if (!this.viewed) { + return; + } + + event.preventDefault(); // Limit wheel speed to prevent zoom too fast + + if (this.wheeling) { + return; + } + + this.wheeling = true; + setTimeout(function () { + _this4.wheeling = false; + }, 50); + var ratio = Number(this.options.zoomRatio) || 0.1; + var delta = 1; + + if (event.deltaY) { + delta = event.deltaY > 0 ? 1 : -1; + } else if (event.wheelDelta) { + delta = -event.wheelDelta / 120; + } else if (event.detail) { + delta = event.detail > 0 ? 1 : -1; + } + + this.zoom(-delta * ratio, true, event); + } + }; + + var methods = { + /** Show the viewer (only available in modal mode) + * @param {boolean} [immediate=false] - Indicates if show the viewer immediately or not. + * @returns {Viewer} this + */ + show: function show() { + var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var element = this.element, + options = this.options; + + if (options.inline || this.showing || this.isShown || this.showing) { + return this; + } + + if (!this.ready) { + this.build(); + + if (this.ready) { + this.show(immediate); + } + + return this; + } + + if (isFunction(options.show)) { + addListener(element, EVENT_SHOW, options.show, { + once: true + }); + } + + if (dispatchEvent(element, EVENT_SHOW) === false || !this.ready) { + return this; + } + + if (this.hiding) { + this.transitioning.abort(); + } + + this.showing = true; + this.open(); + var viewer = this.viewer; + removeClass(viewer, CLASS_HIDE); + + if (options.transition && !immediate) { + var shown = this.shown.bind(this); + this.transitioning = { + abort: function abort() { + removeListener(viewer, EVENT_TRANSITION_END, shown); + removeClass(viewer, CLASS_IN); + } + }; + addClass(viewer, CLASS_TRANSITION); // Force reflow to enable CSS3 transition + // eslint-disable-next-line + + viewer.offsetWidth; + addListener(viewer, EVENT_TRANSITION_END, shown, { + once: true + }); + addClass(viewer, CLASS_IN); + } else { + addClass(viewer, CLASS_IN); + this.shown(); + } + + return this; + }, + + /** + * Hide the viewer (only available in modal mode) + * @param {boolean} [immediate=false] - Indicates if hide the viewer immediately or not. + * @returns {Viewer} this + */ + hide: function hide() { + var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var element = this.element, + options = this.options; + + if (options.inline || this.hiding || !(this.isShown || this.showing)) { + return this; + } + + if (isFunction(options.hide)) { + addListener(element, EVENT_HIDE, options.hide, { + once: true + }); + } + + if (dispatchEvent(element, EVENT_HIDE) === false) { + return this; + } + + if (this.showing) { + this.transitioning.abort(); + } + + this.hiding = true; + + if (this.played) { + this.stop(); + } else if (this.viewing) { + this.viewing.abort(); + } + + var viewer = this.viewer; + + if (options.transition && !immediate) { + var hidden = this.hidden.bind(this); + + var hide = function hide() { + // XXX: It seems the `event.stopPropagation()` method does not work here + setTimeout(function () { + addListener(viewer, EVENT_TRANSITION_END, hidden, { + once: true + }); + removeClass(viewer, CLASS_IN); + }, 0); + }; + + this.transitioning = { + abort: function abort() { + if (this.viewed) { + removeListener(this.image, EVENT_TRANSITION_END, hide); + } else { + removeListener(viewer, EVENT_TRANSITION_END, hidden); + } + } + }; // Note that the `CLASS_TRANSITION` class will be removed on pointer down (#255) + + if (this.viewed && hasClass(this.image, CLASS_TRANSITION)) { + addListener(this.image, EVENT_TRANSITION_END, hide, { + once: true + }); + this.zoomTo(0, false, false, true); + } else { + hide(); + } + } else { + removeClass(viewer, CLASS_IN); + this.hidden(); + } + + return this; + }, + + /** + * View one of the images with image's index + * @param {number} index - The index of the image to view. + * @returns {Viewer} this + */ + view: function view() { + var _this = this; + + var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.initialViewIndex; + index = Number(index) || 0; + + if (!this.isShown) { + this.index = index; + return this.show(); + } + + if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) { + return this; + } + + if (this.viewing) { + this.viewing.abort(); + } + + var element = this.element, + options = this.options, + title = this.title, + canvas = this.canvas; + var item = this.items[index]; + var img = item.querySelector('img'); + var url = getData(img, 'originalUrl'); + var alt = escapeHTMLEntities(img.getAttribute('alt')); + var image = document.createElement('img'); + image.src = url; + image.alt = alt; + + if (isFunction(options.view)) { + addListener(element, EVENT_VIEW, options.view, { + once: true + }); + } + + if (dispatchEvent(element, EVENT_VIEW, { + originalImage: this.images[index], + index: index, + image: image + }) === false || !this.isShown || this.hiding || this.played) { + return this; + } + + this.image = image; + removeClass(this.items[this.index], CLASS_ACTIVE); + addClass(item, CLASS_ACTIVE); + this.viewed = false; + this.index = index; + this.imageData = {}; + addClass(image, CLASS_INVISIBLE); + + if (options.loading) { + addClass(canvas, CLASS_LOADING); + } + + canvas.innerHTML = ''; + canvas.appendChild(image); // Center current item + + this.renderList(); // Clear title + + title.innerHTML = ''; // Generate title after viewed + + var onViewed = function onViewed() { + var imageData = _this.imageData; + var render = Array.isArray(options.title) ? options.title[1] : options.title; + title.innerHTML = escapeHTMLEntities(isFunction(render) ? render.call(_this, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " \xD7 ").concat(imageData.naturalHeight, ")")); + }; + + var onLoad; + addListener(element, EVENT_VIEWED, onViewed, { + once: true + }); + this.viewing = { + abort: function abort() { + removeListener(element, EVENT_VIEWED, onViewed); + + if (image.complete) { + if (this.imageRendering) { + this.imageRendering.abort(); + } else if (this.imageInitializing) { + this.imageInitializing.abort(); + } + } else { + // Cancel download to save bandwidth. + image.src = ''; + removeListener(image, EVENT_LOAD, onLoad); + + if (this.timeout) { + clearTimeout(this.timeout); + } + } + } + }; + + if (image.complete) { + this.load(); + } else { + addListener(image, EVENT_LOAD, onLoad = this.load.bind(this), { + once: true + }); + + if (this.timeout) { + clearTimeout(this.timeout); + } // Make the image visible if it fails to load within 1s + + + this.timeout = setTimeout(function () { + removeClass(image, CLASS_INVISIBLE); + _this.timeout = false; + }, 1000); + } + + return this; + }, + + /** + * View the previous image + * @param {boolean} [loop=false] - Indicate if view the last one + * when it is the first one at present. + * @returns {Viewer} this + */ + prev: function prev() { + var loop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var index = this.index - 1; + + if (index < 0) { + index = loop ? this.length - 1 : 0; + } + + this.view(index); + return this; + }, + + /** + * View the next image + * @param {boolean} [loop=false] - Indicate if view the first one + * when it is the last one at present. + * @returns {Viewer} this + */ + next: function next() { + var loop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var maxIndex = this.length - 1; + var index = this.index + 1; + + if (index > maxIndex) { + index = loop ? 0 : maxIndex; + } + + this.view(index); + return this; + }, + + /** + * Move the image with relative offsets. + * @param {number} offsetX - The relative offset distance on the x-axis. + * @param {number} offsetY - The relative offset distance on the y-axis. + * @returns {Viewer} this + */ + move: function move(offsetX, offsetY) { + var imageData = this.imageData; + this.moveTo(isUndefined(offsetX) ? offsetX : imageData.left + Number(offsetX), isUndefined(offsetY) ? offsetY : imageData.top + Number(offsetY)); + return this; + }, + + /** + * Move the image to an absolute point. + * @param {number} x - The x-axis coordinate. + * @param {number} [y=x] - The y-axis coordinate. + * @returns {Viewer} this + */ + moveTo: function moveTo(x) { + var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x; + var imageData = this.imageData; + x = Number(x); + y = Number(y); + + if (this.viewed && !this.played && this.options.movable) { + var changed = false; + + if (isNumber(x)) { + imageData.left = x; + changed = true; + } + + if (isNumber(y)) { + imageData.top = y; + changed = true; + } + + if (changed) { + this.renderImage(); + } + } + + return this; + }, + + /** + * Zoom the image with a relative ratio. + * @param {number} ratio - The target ratio. + * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not. + * @param {Event} [_originalEvent=null] - The original event if any. + * @returns {Viewer} this + */ + zoom: function zoom(ratio) { + var hasTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + var imageData = this.imageData; + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + this.zoomTo(imageData.width * ratio / imageData.naturalWidth, hasTooltip, _originalEvent); + return this; + }, + + /** + * Zoom the image to an absolute ratio. + * @param {number} ratio - The target ratio. + * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not. + * @param {Event} [_originalEvent=null] - The original event if any. + * @param {Event} [_zoomable=false] - Indicates if the current zoom is available or not. + * @returns {Viewer} this + */ + zoomTo: function zoomTo(ratio) { + var _this2 = this; + + var hasTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + var _zoomable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + + var element = this.element, + options = this.options, + pointers = this.pointers, + imageData = this.imageData; + var width = imageData.width, + height = imageData.height, + left = imageData.left, + top = imageData.top, + naturalWidth = imageData.naturalWidth, + naturalHeight = imageData.naturalHeight; + ratio = Math.max(0, ratio); + + if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) { + if (!_zoomable) { + var minZoomRatio = Math.max(0.01, options.minZoomRatio); + var maxZoomRatio = Math.min(100, options.maxZoomRatio); + ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio); + } + + if (_originalEvent && ratio > 0.95 && ratio < 1.05) { + ratio = 1; + } + + var newWidth = naturalWidth * ratio; + var newHeight = naturalHeight * ratio; + var offsetWidth = newWidth - width; + var offsetHeight = newHeight - height; + var oldRatio = width / naturalWidth; + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom, { + once: true + }); + } + + if (dispatchEvent(element, EVENT_ZOOM, { + ratio: ratio, + oldRatio: oldRatio, + originalEvent: _originalEvent + }) === false) { + return this; + } + + this.zooming = true; + + if (_originalEvent) { + var offset = getOffset(this.viewer); + var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY + }; // Zoom from the triggering point of the event + + imageData.left -= offsetWidth * ((center.pageX - offset.left - left) / width); + imageData.top -= offsetHeight * ((center.pageY - offset.top - top) / height); + } else { + // Zoom from the center of the image + imageData.left -= offsetWidth / 2; + imageData.top -= offsetHeight / 2; + } + + imageData.width = newWidth; + imageData.height = newHeight; + imageData.ratio = ratio; + this.renderImage(function () { + _this2.zooming = false; + + if (isFunction(options.zoomed)) { + addListener(element, EVENT_ZOOMED, options.zoomed, { + once: true + }); + } + + dispatchEvent(element, EVENT_ZOOMED, { + ratio: ratio, + oldRatio: oldRatio, + originalEvent: _originalEvent + }); + }); + + if (hasTooltip) { + this.tooltip(); + } + } + + return this; + }, + + /** + * Rotate the image with a relative degree. + * @param {number} degree - The rotate degree. + * @returns {Viewer} this + */ + rotate: function rotate(degree) { + this.rotateTo((this.imageData.rotate || 0) + Number(degree)); + return this; + }, + + /** + * Rotate the image to an absolute degree. + * @param {number} degree - The rotate degree. + * @returns {Viewer} this + */ + rotateTo: function rotateTo(degree) { + var imageData = this.imageData; + degree = Number(degree); + + if (isNumber(degree) && this.viewed && !this.played && this.options.rotatable) { + imageData.rotate = degree; + this.renderImage(); + } + + return this; + }, + + /** + * Scale the image on the x-axis. + * @param {number} scaleX - The scale ratio on the x-axis. + * @returns {Viewer} this + */ + scaleX: function scaleX(_scaleX) { + this.scale(_scaleX, this.imageData.scaleY); + return this; + }, + + /** + * Scale the image on the y-axis. + * @param {number} scaleY - The scale ratio on the y-axis. + * @returns {Viewer} this + */ + scaleY: function scaleY(_scaleY) { + this.scale(this.imageData.scaleX, _scaleY); + return this; + }, + + /** + * Scale the image. + * @param {number} scaleX - The scale ratio on the x-axis. + * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. + * @returns {Viewer} this + */ + scale: function scale(scaleX) { + var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX; + var imageData = this.imageData; + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (this.viewed && !this.played && this.options.scalable) { + var changed = false; + + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + changed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + changed = true; + } + + if (changed) { + this.renderImage(); + } + } + + return this; + }, + + /** + * Play the images + * @param {boolean} [fullscreen=false] - Indicate if request fullscreen or not. + * @returns {Viewer} this + */ + play: function play() { + var _this3 = this; + + var fullscreen = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + + if (!this.isShown || this.played) { + return this; + } + + var options = this.options, + player = this.player; + var onLoad = this.loadImage.bind(this); + var list = []; + var total = 0; + var index = 0; + this.played = true; + this.onLoadWhenPlay = onLoad; + + if (fullscreen) { + this.requestFullscreen(); + } + + addClass(player, CLASS_SHOW); + forEach(this.items, function (item, i) { + var img = item.querySelector('img'); + var image = document.createElement('img'); + image.src = getData(img, 'originalUrl'); + image.alt = escapeHTMLEntities(img.getAttribute('alt')); + total += 1; + addClass(image, CLASS_FADE); + toggleClass(image, CLASS_TRANSITION, options.transition); + + if (hasClass(item, CLASS_ACTIVE)) { + addClass(image, CLASS_IN); + index = i; + } + + list.push(image); + addListener(image, EVENT_LOAD, onLoad, { + once: true + }); + player.appendChild(image); + }); + + if (isNumber(options.interval) && options.interval > 0) { + var play = function play() { + _this3.playing = setTimeout(function () { + removeClass(list[index], CLASS_IN); + index += 1; + index = index < total ? index : 0; + addClass(list[index], CLASS_IN); + play(); + }, options.interval); + }; + + if (total > 1) { + play(); + } + } + + return this; + }, + // Stop play + stop: function stop() { + var _this4 = this; + + if (!this.played) { + return this; + } + + var player = this.player; + this.played = false; + clearTimeout(this.playing); + forEach(player.getElementsByTagName('img'), function (image) { + removeListener(image, EVENT_LOAD, _this4.onLoadWhenPlay); + }); + removeClass(player, CLASS_SHOW); + player.innerHTML = ''; + this.exitFullscreen(); + return this; + }, + // Enter modal mode (only available in inline mode) + full: function full() { + var _this5 = this; + + var options = this.options, + viewer = this.viewer, + image = this.image, + list = this.list; + + if (!this.isShown || this.played || this.fulled || !options.inline) { + return this; + } + + this.fulled = true; + this.open(); + addClass(this.button, CLASS_FULLSCREEN_EXIT); + + if (options.transition) { + removeClass(list, CLASS_TRANSITION); + + if (this.viewed) { + removeClass(image, CLASS_TRANSITION); + } + } + + addClass(viewer, CLASS_FIXED); + viewer.setAttribute('style', ''); + setStyle(viewer, { + zIndex: options.zIndex + }); + this.initContainer(); + this.viewerData = assign({}, this.containerData); + this.renderList(); + + if (this.viewed) { + this.initImage(function () { + _this5.renderImage(function () { + if (options.transition) { + setTimeout(function () { + addClass(image, CLASS_TRANSITION); + addClass(list, CLASS_TRANSITION); + }, 0); + } + }); + }); + } + + return this; + }, + // Exit modal mode (only available in inline mode) + exit: function exit() { + var _this6 = this; + + var options = this.options, + viewer = this.viewer, + image = this.image, + list = this.list; + + if (!this.isShown || this.played || !this.fulled || !options.inline) { + return this; + } + + this.fulled = false; + this.close(); + removeClass(this.button, CLASS_FULLSCREEN_EXIT); + + if (options.transition) { + removeClass(list, CLASS_TRANSITION); + + if (this.viewed) { + removeClass(image, CLASS_TRANSITION); + } + } + + removeClass(viewer, CLASS_FIXED); + setStyle(viewer, { + zIndex: options.zIndexInline + }); + this.viewerData = assign({}, this.parentData); + this.renderViewer(); + this.renderList(); + + if (this.viewed) { + this.initImage(function () { + _this6.renderImage(function () { + if (options.transition) { + setTimeout(function () { + addClass(image, CLASS_TRANSITION); + addClass(list, CLASS_TRANSITION); + }, 0); + } + }); + }); + } + + return this; + }, + // Show the current ratio of the image with percentage + tooltip: function tooltip() { + var _this7 = this; + + var options = this.options, + tooltipBox = this.tooltipBox, + imageData = this.imageData; + + if (!this.viewed || this.played || !options.tooltip) { + return this; + } + + tooltipBox.textContent = "".concat(Math.round(imageData.ratio * 100), "%"); + + if (!this.tooltipping) { + if (options.transition) { + if (this.fading) { + dispatchEvent(tooltipBox, EVENT_TRANSITION_END); + } + + addClass(tooltipBox, CLASS_SHOW); + addClass(tooltipBox, CLASS_FADE); + addClass(tooltipBox, CLASS_TRANSITION); // Force reflow to enable CSS3 transition + // eslint-disable-next-line + + tooltipBox.offsetWidth; + addClass(tooltipBox, CLASS_IN); + } else { + addClass(tooltipBox, CLASS_SHOW); + } + } else { + clearTimeout(this.tooltipping); + } + + this.tooltipping = setTimeout(function () { + if (options.transition) { + addListener(tooltipBox, EVENT_TRANSITION_END, function () { + removeClass(tooltipBox, CLASS_SHOW); + removeClass(tooltipBox, CLASS_FADE); + removeClass(tooltipBox, CLASS_TRANSITION); + _this7.fading = false; + }, { + once: true + }); + removeClass(tooltipBox, CLASS_IN); + _this7.fading = true; + } else { + removeClass(tooltipBox, CLASS_SHOW); + } + + _this7.tooltipping = false; + }, 1000); + return this; + }, + // Toggle the image size between its natural size and initial size + toggle: function toggle() { + if (this.imageData.ratio === 1) { + this.zoomTo(this.initialImageData.ratio, true); + } else { + this.zoomTo(1, true); + } + + return this; + }, + // Reset the image to its initial state + reset: function reset() { + if (this.viewed && !this.played) { + this.imageData = assign({}, this.initialImageData); + this.renderImage(); + } + + return this; + }, + // Update viewer when images changed + update: function update() { + var element = this.element, + options = this.options, + isImg = this.isImg; // Destroy viewer if the target image was deleted + + if (isImg && !element.parentNode) { + return this.destroy(); + } + + var images = []; + forEach(isImg ? [element] : element.querySelectorAll('img'), function (image) { + if (options.filter) { + if (options.filter(image)) { + images.push(image); + } + } else { + images.push(image); + } + }); + + if (!images.length) { + return this; + } + + this.images = images; + this.length = images.length; + + if (this.ready) { + var indexes = []; + forEach(this.items, function (item, i) { + var img = item.querySelector('img'); + var image = images[i]; + + if (image) { + if (image.src !== img.src) { + indexes.push(i); + } + } else { + indexes.push(i); + } + }); + setStyle(this.list, { + width: 'auto' + }); + this.initList(); + + if (this.isShown) { + if (this.length) { + if (this.viewed) { + var index = indexes.indexOf(this.index); + + if (index >= 0) { + this.viewed = false; + this.view(Math.max(this.index - (index + 1), 0)); + } else { + addClass(this.items[this.index], CLASS_ACTIVE); + } + } + } else { + this.image = null; + this.viewed = false; + this.index = 0; + this.imageData = {}; + this.canvas.innerHTML = ''; + this.title.innerHTML = ''; + } + } + } else { + this.build(); + } + + return this; + }, + // Destroy the viewer + destroy: function destroy() { + var element = this.element, + options = this.options; + + if (!element[NAMESPACE]) { + return this; + } + + this.destroyed = true; + + if (this.ready) { + if (this.played) { + this.stop(); + } + + if (options.inline) { + if (this.fulled) { + this.exit(); + } + + this.unbind(); + } else if (this.isShown) { + if (this.viewing) { + if (this.imageRendering) { + this.imageRendering.abort(); + } else if (this.imageInitializing) { + this.imageInitializing.abort(); + } + } + + if (this.hiding) { + this.transitioning.abort(); + } + + this.hidden(); + } else if (this.showing) { + this.transitioning.abort(); + this.hidden(); + } + + this.ready = false; + this.viewer.parentNode.removeChild(this.viewer); + } else if (options.inline) { + if (this.delaying) { + this.delaying.abort(); + } else if (this.initializing) { + this.initializing.abort(); + } + } + + if (!options.inline) { + removeListener(element, EVENT_CLICK, this.onStart); + } + + element[NAMESPACE] = undefined; + return this; + } + }; + + var others = { + open: function open() { + var body = this.body; + addClass(body, CLASS_OPEN); + body.style.paddingRight = "".concat(this.scrollbarWidth + (parseFloat(this.initialBodyPaddingRight) || 0), "px"); + }, + close: function close() { + var body = this.body; + removeClass(body, CLASS_OPEN); + body.style.paddingRight = this.initialBodyPaddingRight; + }, + shown: function shown() { + var element = this.element, + options = this.options; + this.fulled = true; + this.isShown = true; + this.render(); + this.bind(); + this.showing = false; + + if (isFunction(options.shown)) { + addListener(element, EVENT_SHOWN, options.shown, { + once: true + }); + } + + if (dispatchEvent(element, EVENT_SHOWN) === false) { + return; + } + + if (this.ready && this.isShown && !this.hiding) { + this.view(this.index); + } + }, + hidden: function hidden() { + var element = this.element, + options = this.options; + this.fulled = false; + this.viewed = false; + this.isShown = false; + this.close(); + this.unbind(); + addClass(this.viewer, CLASS_HIDE); + this.resetList(); + this.resetImage(); + this.hiding = false; + + if (!this.destroyed) { + if (isFunction(options.hidden)) { + addListener(element, EVENT_HIDDEN, options.hidden, { + once: true + }); + } + + dispatchEvent(element, EVENT_HIDDEN); + } + }, + requestFullscreen: function requestFullscreen() { + var document = this.element.ownerDocument; + + if (this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) { + var documentElement = document.documentElement; // Element.requestFullscreen() + + if (documentElement.requestFullscreen) { + documentElement.requestFullscreen(); + } else if (documentElement.webkitRequestFullscreen) { + documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); + } else if (documentElement.mozRequestFullScreen) { + documentElement.mozRequestFullScreen(); + } else if (documentElement.msRequestFullscreen) { + documentElement.msRequestFullscreen(); + } + } + }, + exitFullscreen: function exitFullscreen() { + var document = this.element.ownerDocument; + + if (this.fulled && (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) { + // Document.exitFullscreen() + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.msExitFullscreen) { + document.msExitFullscreen(); + } + } + }, + change: function change(event) { + var options = this.options, + pointers = this.pointers; + var pointer = pointers[Object.keys(pointers)[0]]; + var offsetX = pointer.endX - pointer.startX; + var offsetY = pointer.endY - pointer.startY; + + switch (this.action) { + // Move the current image + case ACTION_MOVE: + this.move(offsetX, offsetY); + break; + // Zoom the current image + + case ACTION_ZOOM: + this.zoom(getMaxZoomRatio(pointers), false, event); + break; + + case ACTION_SWITCH: + { + this.action = 'switched'; + var absoluteOffsetX = Math.abs(offsetX); + + if (absoluteOffsetX > 1 && absoluteOffsetX > Math.abs(offsetY)) { + // Empty `pointers` as `touchend` event will not be fired after swiped in iOS browsers. + this.pointers = {}; + + if (offsetX > 1) { + this.prev(options.loop); + } else if (offsetX < -1) { + this.next(options.loop); + } + } + + break; + } + + default: + } // Override + + + forEach(pointers, function (p) { + p.startX = p.endX; + p.startY = p.endY; + }); + }, + isSwitchable: function isSwitchable() { + var imageData = this.imageData, + viewerData = this.viewerData; + return this.length > 1 && imageData.left >= 0 && imageData.top >= 0 && imageData.width <= viewerData.width && imageData.height <= viewerData.height; + } + }; + + var AnotherViewer = WINDOW.Viewer; + + var Viewer = + /*#__PURE__*/ + function () { + /** + * Create a new Viewer. + * @param {Element} element - The target element for viewing. + * @param {Object} [options={}] - The configuration options. + */ + function Viewer(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Viewer); + + if (!element || element.nodeType !== 1) { + throw new Error('The first argument is required and must be an element.'); + } + + this.element = element; + this.options = assign({}, DEFAULTS, isPlainObject(options) && options); + this.action = false; + this.fading = false; + this.fulled = false; + this.hiding = false; + this.imageClicked = false; + this.imageData = {}; + this.index = this.options.initialViewIndex; + this.isImg = false; + this.isShown = false; + this.length = 0; + this.played = false; + this.playing = false; + this.pointers = {}; + this.ready = false; + this.showing = false; + this.timeout = false; + this.tooltipping = false; + this.viewed = false; + this.viewing = false; + this.wheeling = false; + this.zooming = false; + this.init(); + } + + _createClass(Viewer, [{ + key: "init", + value: function init() { + var _this = this; + + var element = this.element, + options = this.options; + + if (element[NAMESPACE]) { + //return; + } + + element[NAMESPACE] = this; + var isImg = element.tagName.toLowerCase() === 'img'; + var images = []; + forEach(isImg ? [element] : element.querySelectorAll('img'), function (image) { + if (isFunction(options.filter)) { + if (options.filter.call(_this, image)) { + images.push(image); + } + } else { + images.push(image); + } + }); + this.isImg = isImg; + this.length = images.length; + this.images = images; + var ownerDocument = element.ownerDocument; + var body = ownerDocument.body || ownerDocument.documentElement; + this.body = body; + this.scrollbarWidth = window.innerWidth - ownerDocument.documentElement.clientWidth; + this.initialBodyPaddingRight = window.getComputedStyle(body).paddingRight; // Override `transition` option if it is not supported + + if (isUndefined(document.createElement(NAMESPACE).style.transition)) { + options.transition = false; + } + + if (options.inline) { + var count = 0; + + var progress = function progress() { + count += 1; + + if (count === _this.length) { + var timeout; + _this.initializing = false; + _this.delaying = { + abort: function abort() { + clearTimeout(timeout); + } + }; // build asynchronously to keep `this.viewer` is accessible in `ready` event handler. + + timeout = setTimeout(function () { + _this.delaying = false; + + _this.build(); + }, 0); + } + }; + + this.initializing = { + abort: function abort() { + forEach(images, function (image) { + if (!image.complete) { + removeListener(image, EVENT_LOAD, progress); + } + }); + } + }; + forEach(images, function (image) { + if (image.complete) { + progress(); + } else { + addListener(image, EVENT_LOAD, progress, { + once: true + }); + } + }); + } else { + addListener(element, EVENT_CLICK, this.onStart = function (_ref) { + var target = _ref.target; + + if (target.tagName.toLowerCase() === 'img' && (!isFunction(options.filter) || options.filter.call(_this, target))) { + _this.view(_this.images.indexOf(target)); + } + }); + } + } + }, { + key: "build", + value: function build() { + if (this.ready) { + return; + } + + var element = this.element, + options = this.options; + var parent = element.parentNode; + var template = document.createElement('div'); + template.innerHTML = TEMPLATE; + var viewer = template.querySelector(".".concat(NAMESPACE, "-container")); + var title = viewer.querySelector(".".concat(NAMESPACE, "-title")); + var toolbar = viewer.querySelector(".".concat(NAMESPACE, "-toolbar")); + var navbar = viewer.querySelector(".".concat(NAMESPACE, "-navbar")); + var button = viewer.querySelector(".".concat(NAMESPACE, "-button")); + var canvas = viewer.querySelector(".".concat(NAMESPACE, "-canvas")); + this.parent = parent; + this.viewer = viewer; + this.title = title; + this.toolbar = toolbar; + this.navbar = navbar; + this.button = button; + this.canvas = canvas; + this.footer = viewer.querySelector(".".concat(NAMESPACE, "-footer")); + this.tooltipBox = viewer.querySelector(".".concat(NAMESPACE, "-tooltip")); + this.player = viewer.querySelector(".".concat(NAMESPACE, "-player")); + this.list = viewer.querySelector(".".concat(NAMESPACE, "-list")); + addClass(title, !options.title ? CLASS_HIDE : getResponsiveClass(Array.isArray(options.title) ? options.title[0] : options.title)); + addClass(navbar, !options.navbar ? CLASS_HIDE : getResponsiveClass(options.navbar)); + toggleClass(button, CLASS_HIDE, !options.button); + + if (options.backdrop) { + addClass(viewer, "".concat(NAMESPACE, "-backdrop")); + + if (!options.inline && options.backdrop !== 'static') { + setData(canvas, DATA_ACTION, 'hide'); + } + } + + if (isString(options.className) && options.className) { + // In case there are multiple class names + options.className.split(REGEXP_SPACES).forEach(function (className) { + addClass(viewer, className); + }); + } + + if (options.toolbar) { + var list = document.createElement('ul'); + var custom = isPlainObject(options.toolbar); + var zoomButtons = BUTTONS.slice(0, 3); + var rotateButtons = BUTTONS.slice(7, 9); + var scaleButtons = BUTTONS.slice(9); + + if (!custom) { + addClass(toolbar, getResponsiveClass(options.toolbar)); + } + + forEach(custom ? options.toolbar : BUTTONS, function (value, index) { + var deep = custom && isPlainObject(value); + var name = custom ? hyphenate(index) : value; + var show = deep && !isUndefined(value.show) ? value.show : value; + + if (!show || !options.zoomable && zoomButtons.indexOf(name) !== -1 || !options.rotatable && rotateButtons.indexOf(name) !== -1 || !options.scalable && scaleButtons.indexOf(name) !== -1) { + return; + } + + var size = deep && !isUndefined(value.size) ? value.size : value; + var click = deep && !isUndefined(value.click) ? value.click : value; + var item = document.createElement('li'); + item.setAttribute('role', 'button'); + addClass(item, "".concat(NAMESPACE, "-").concat(name)); + + if (!isFunction(click)) { + setData(item, DATA_ACTION, name); + } + + if (isNumber(show)) { + addClass(item, getResponsiveClass(show)); + } + + if (['small', 'large'].indexOf(size) !== -1) { + addClass(item, "".concat(NAMESPACE, "-").concat(size)); + } else if (name === 'play') { + addClass(item, "".concat(NAMESPACE, "-large")); + } + + if (isFunction(click)) { + addListener(item, EVENT_CLICK, click); + } + + list.appendChild(item); + }); + toolbar.appendChild(list); + } else { + addClass(toolbar, CLASS_HIDE); + } + + if (!options.rotatable) { + var rotates = toolbar.querySelectorAll('li[class*="rotate"]'); + addClass(rotates, CLASS_INVISIBLE); + forEach(rotates, function (rotate) { + toolbar.appendChild(rotate); + }); + } + + if (options.inline) { + addClass(button, CLASS_FULLSCREEN); + setStyle(viewer, { + zIndex: options.zIndexInline + }); + + if (window.getComputedStyle(parent).position === 'static') { + setStyle(parent, { + position: 'relative' + }); + } + + parent.insertBefore(viewer, element.nextSibling); + } else { + addClass(button, CLASS_CLOSE); + addClass(viewer, CLASS_FIXED); + addClass(viewer, CLASS_FADE); + addClass(viewer, CLASS_HIDE); + setStyle(viewer, { + zIndex: options.zIndex + }); + var container = options.container; + + if (isString(container)) { + container = element.ownerDocument.querySelector(container); + } + + if (!container) { + container = this.body; + } + + container.appendChild(viewer); + } + + if (options.inline) { + this.render(); + this.bind(); + this.isShown = true; + } + + this.ready = true; + + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, { + once: true + }); + } + + if (dispatchEvent(element, EVENT_READY) === false) { + this.ready = false; + return; + } + + if (this.ready && options.inline) { + this.view(this.index); + } + } + /** + * Get the no conflict viewer class. + * @returns {Viewer} The viewer class. + */ + + }], [{ + key: "noConflict", + value: function noConflict() { + window.Viewer = AnotherViewer; + return Viewer; + } + /** + * Change the default options. + * @param {Object} options - The new default options. + */ + + }, { + key: "setDefaults", + value: function setDefaults(options) { + assign(DEFAULTS, isPlainObject(options) && options); + } + }]); + + return Viewer; + }(); + + assign(Viewer.prototype, render, events, handlers, methods, others); + + return Viewer; + +})); \ No newline at end of file diff --git a/o2web/source/o2_lib/zTree/img/diy/1_close.png b/o2web/source/o2_lib/zTree/img/diy/1_close.png new file mode 100644 index 0000000000000000000000000000000000000000..68ccb3c3b90170df7cddab1fe6e8e455c3854573 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/1_close.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/1_open.png b/o2web/source/o2_lib/zTree/img/diy/1_open.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ff36d3a99012028c6cf3d4009719108e31bc79 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/1_open.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/2.png b/o2web/source/o2_lib/zTree/img/diy/2.png new file mode 100644 index 0000000000000000000000000000000000000000..9eff506ba391fa1ddf0dc44d02ae84403700321b Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/2.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/3.png b/o2web/source/o2_lib/zTree/img/diy/3.png new file mode 100644 index 0000000000000000000000000000000000000000..d7ba6d0c675c35197e2dae8a379155e67c0ac6cb Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/3.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/4.png b/o2web/source/o2_lib/zTree/img/diy/4.png new file mode 100644 index 0000000000000000000000000000000000000000..753e2bfd5725b1f32cda4e41c36a448a4b12c280 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/4.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/5.png b/o2web/source/o2_lib/zTree/img/diy/5.png new file mode 100644 index 0000000000000000000000000000000000000000..0c5eccd562c303cf5197629ef5f2666b6180bd48 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/5.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/6.png b/o2web/source/o2_lib/zTree/img/diy/6.png new file mode 100644 index 0000000000000000000000000000000000000000..070b8352d7770e6be4b6f3cbc61f7ee21ae3e4da Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/6.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/7.png b/o2web/source/o2_lib/zTree/img/diy/7.png new file mode 100644 index 0000000000000000000000000000000000000000..532b037f2045cfa26c62d23cb928ff7405f6fc18 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/7.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/8.png b/o2web/source/o2_lib/zTree/img/diy/8.png new file mode 100644 index 0000000000000000000000000000000000000000..a8f3a86e7091de4acdd38745f74b30f0f3d40f9e Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/8.png differ diff --git a/o2web/source/o2_lib/zTree/img/diy/9.png b/o2web/source/o2_lib/zTree/img/diy/9.png new file mode 100644 index 0000000000000000000000000000000000000000..4db73cd41c95bc74496175625ce9ed3737e599f5 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/diy/9.png differ diff --git a/o2web/source/o2_lib/zTree/img/line_conn.gif b/o2web/source/o2_lib/zTree/img/line_conn.gif new file mode 100644 index 0000000000000000000000000000000000000000..d561d36a915776730eb3069cee4c949f027667ed Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/line_conn.gif differ diff --git a/o2web/source/o2_lib/zTree/img/loading.gif b/o2web/source/o2_lib/zTree/img/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..e8c289293b11c889703d83dce6631fce90da4630 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/loading.gif differ diff --git a/o2web/source/o2_lib/zTree/img/zTreeStandard.gif b/o2web/source/o2_lib/zTree/img/zTreeStandard.gif new file mode 100644 index 0000000000000000000000000000000000000000..50c94fd41ef9f1f7c07442d669923fd7a3226f55 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/zTreeStandard.gif differ diff --git a/o2web/source/o2_lib/zTree/img/zTreeStandard.png b/o2web/source/o2_lib/zTree/img/zTreeStandard.png new file mode 100644 index 0000000000000000000000000000000000000000..ffda01ef1cccc398ee4e2327f4093ba1130a4961 Binary files /dev/null and b/o2web/source/o2_lib/zTree/img/zTreeStandard.png differ diff --git a/o2web/source/o2_lib/zipjs/zip-fs.js b/o2web/source/o2_lib/zipjs/zip-fs.js new file mode 100644 index 0000000000000000000000000000000000000000..2437749fcd99b9dc65c24512dde4ce456d60a5b9 --- /dev/null +++ b/o2web/source/o2_lib/zipjs/zip-fs.js @@ -0,0 +1,3903 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.zip = {})); +}(this, (function (exports) { 'use strict'; + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const DEFAULT_CONFIGURATION = { + chunkSize: 512 * 1024, + maxWorkers: (typeof navigator != "undefined" && navigator.hardwareConcurrency) || 2, + useWebWorkers: true, + workerScripts: undefined + }; + + const config = Object.assign({}, DEFAULT_CONFIGURATION); + + function getConfiguration() { + return config; + } + + function configure(configuration) { + if (configuration.chunkSize !== undefined) { + config.chunkSize = configuration.chunkSize; + } + if (configuration.maxWorkers !== undefined) { + config.maxWorkers = configuration.maxWorkers; + } + if (configuration.useWebWorkers !== undefined) { + config.useWebWorkers = configuration.useWebWorkers; + } + if (configuration.Deflate !== undefined) { + config.Deflate = configuration.Deflate; + } + if (configuration.Inflate !== undefined) { + config.Inflate = configuration.Inflate; + } + if (configuration.workerScripts !== undefined) { + if (configuration.workerScripts.deflate) { + if (!Array.isArray(configuration.workerScripts.deflate)) { + throw new Error("workerScripts.deflate must be an array"); + } + if (!config.workerScripts) { + config.workerScripts = {}; + } + config.workerScripts.deflate = configuration.workerScripts.deflate; + } + if (configuration.workerScripts.inflate) { + if (!Array.isArray(configuration.workerScripts.inflate)) { + throw new Error("workerScripts.inflate must be an array"); + } + if (!config.workerScripts) { + config.workerScripts = {}; + } + config.workerScripts.inflate = configuration.workerScripts.inflate; + } + } + } + + var configureWebWorker = ()=>{if("function"==typeof URL.createObjectURL){const e=(()=>{const t=[];for(let e=0;e<256;e++){let n=e;for(let t=0;t<8;t++)1&n?n=n>>>1^3988292384:n>>>=1;t[e]=n;}class e{constructor(t){this.crc=t||-1;}append(e){let n=0|this.crc;for(let i=0,a=0|e.length;i>>8^t[255&(n^e[i])];this.crc=n;}get(){return ~this.crc}}const n={concat(t,e){if(0===t.length||0===e.length)return t.concat(e);const i=t[t.length-1],a=n.getPartial(i);return 32===a?t.concat(e):n._shiftRight(e,a,0|i,t.slice(0,t.length-1))},bitLength(t){const e=t.length;if(0===e)return 0;const i=t[e-1];return 32*(e-1)+n.getPartial(i)},clamp(t,e){if(32*t.length0&&e&&(t[i-1]=n.partial(e,t[i-1]&2147483648>>e-1,1)),t},partial:(t,e,n)=>32===t?e:(n?0|e:e<<32-t)+1099511627776*t,getPartial:t=>Math.round(t/1099511627776)||32,_shiftRight(t,e,i,a){for(void 0===a&&(a=[]);e>=32;e-=32)a.push(i),i=0;if(0===e)return a.concat(t);for(let n=0;n>>e),i=t[n]<<32-e;const r=t.length?t[t.length-1]:0,s=n.getPartial(r);return a.push(n.partial(e+s&31,e+s>32?i:a.pop(),1)),a}},i={bytes:{fromBits(t){const e=n.bitLength(t)/8,i=new Uint8Array(e);let a;for(let n=0;n>>24,a<<=8;return i},toBits(t){const e=[];let i,a=0;for(i=0;i9007199254740991)throw new Error("Cannot hash more than 2^53 - 1 bits");const o=new Uint32Array(a);let l=0;for(let t=e.blockSize+r-(e.blockSize+r&e.blockSize-1);t<=s;t+=e.blockSize)e._block(o.subarray(16*l,16*(l+1))),l+=1;return a.splice(0,16*l),e},finalize:function(){const t=this;let e=t._buffer;const i=t._h;e=n.concat(e,[n.partial(1,1)]);for(let t=e.length+2;15&t;t++)e.push(0);for(e.push(Math.floor(t._length/4294967296)),e.push(0|t._length);e.length;)t._block(e.splice(0,16));return t.reset(),i},_init:[1732584193,4023233417,2562383102,271733878,3285377520],_key:[1518500249,1859775393,2400959708,3395469782],_f:function(t,e,n,i){return t<=19?e&n|~e&i:t<=39?e^n^i:t<=59?e&n|e&i|n&i:t<=79?e^n^i:void 0},_S:function(t,e){return e<>>32-t},_block:function(t){const e=this,n=e._h,i=Array(80);for(let e=0;e<16;e++)i[e]=t[e];let a=n[0],r=n[1],s=n[2],o=n[3],l=n[4];for(let t=0;t<=79;t++){t>=16&&(i[t]=e._S(1,i[t-3]^i[t-8]^i[t-14]^i[t-16]));const n=e._S(5,a)+e._f(t,r,s,o)+l+i[t]+e._key[Math.floor(t/20)]|0;l=o,o=s,s=e._S(30,r),r=a,a=n;}n[0]=n[0]+a|0,n[1]=n[1]+r|0,n[2]=n[2]+s|0,n[3]=n[3]+o|0,n[4]=n[4]+l|0;}};const r=class{constructor(t){const e=this;e._tables=[[[],[],[],[],[]],[[],[],[],[],[]]],e._tables[0][0][0]||e._precompute();const n=e._tables[0][4],i=e._tables[1],a=t.length;let r,s,o,l=1;if(4!==a&&6!==a&&8!==a)throw new Error("invalid aes key size");for(e._key=[s=t.slice(0),o=[]],r=a;r<4*a+28;r++){let t=s[r-1];(r%a==0||8===a&&r%a==4)&&(t=n[t>>>24]<<24^n[t>>16&255]<<16^n[t>>8&255]<<8^n[255&t],r%a==0&&(t=t<<8^t>>>24^l<<24,l=l<<1^283*(l>>7))),s[r]=s[r-a]^t;}for(let t=0;r;t++,r--){const e=s[3&t?r:r-4];o[t]=r<=4||t<4?e:i[0][n[e>>>24]]^i[1][n[e>>16&255]]^i[2][n[e>>8&255]]^i[3][n[255&e]];}}encrypt(t){return this._crypt(t,0)}decrypt(t){return this._crypt(t,1)}_precompute(){const t=this._tables[0],e=this._tables[1],n=t[4],i=e[4],a=[],r=[];let s,o,l,_;for(let t=0;t<256;t++)r[(a[t]=t<<1^283*(t>>7))^t]=t;for(let d=s=0;!n[d];d^=o||1,s=r[s]||1){let r=s^s<<1^s<<2^s<<3^s<<4;r=r>>8^255&r^99,n[d]=r,i[r]=d,_=a[l=a[o=a[d]]];let c=16843009*_^65537*l^257*o^16843008*d,f=257*a[r]^16843008*r;for(let n=0;n<4;n++)t[n][d]=f=f<<24^f>>>8,e[n][r]=c=c<<24^c>>>8;}for(let n=0;n<5;n++)t[n]=t[n].slice(0),e[n]=e[n].slice(0);}_crypt(t,e){if(4!==t.length)throw new Error("invalid aes block size");const n=this._key[e],i=n.length/4-2,a=[0,0,0,0],r=this._tables[e],s=r[0],o=r[1],l=r[2],_=r[3],d=r[4];let c,f,u,h=t[0]^n[0],b=t[e?3:1]^n[1],w=t[2]^n[2],p=t[e?1:3]^n[3],x=4;for(let t=0;t>>24]^o[b>>16&255]^l[w>>8&255]^_[255&p]^n[x],f=s[b>>>24]^o[w>>16&255]^l[p>>8&255]^_[255&h]^n[x+1],u=s[w>>>24]^o[p>>16&255]^l[h>>8&255]^_[255&b]^n[x+2],p=s[p>>>24]^o[h>>16&255]^l[b>>8&255]^_[255&w]^n[x+3],x+=4,h=c,b=f,w=u;for(let t=0;t<4;t++)a[e?3&-t:t]=d[h>>>24]<<24^d[b>>16&255]<<16^d[w>>8&255]<<8^d[255&p]^n[x++],c=h,h=b,b=w,w=p,p=c;return a}},s=class{constructor(t,e){this._prf=t,this._initIv=e,this._iv=e;}reset(){this._iv=this._initIv;}update(t){return this.calculate(this._prf,t,this._iv)}incWord(t){if(255==(t>>24&255)){let e=t>>16&255,n=t>>8&255,i=255&t;255===e?(e=0,255===n?(n=0,255===i?i=0:++i):++n):++e,t=0,t+=e<<16,t+=n<<8,t+=i;}else t+=1<<24;return t}incCounter(t){0===(t[0]=this.incWord(t[0]))&&(t[1]=this.incWord(t[1]));}calculate(t,e,i){let a;if(!(a=e.length))return [];const r=n.bitLength(e);for(let n=0;nr&&(t=n.hash(t));for(let e=0;et.length){const n=t;(t=new Uint8Array(e)).set(n,0);}return t}(n,s-s%16)),o=0;o<=s-16;o+=16){const a=w.toBits(U(e,o,o+16));r&&t.hmac.update(a);const s=t.aesCtrGladman.update(a);r||t.hmac.update(s),n.set(w.fromBits(s),o+i);}return t.pendingInput=U(e,o),n}async function v(t,e,n){const i=(new TextEncoder).encode(e),a=await b.importKey("raw",i,_,!1,c),r=await b.deriveBits(Object.assign({salt:n},d),a,8*(2*u[t.strength]+2)),s=new Uint8Array(r);t.keys={key:w.toBits(U(s,0,u[t.strength])),authentication:w.toBits(U(s,u[t.strength],2*u[t.strength])),passwordVerification:U(s,2*u[t.strength])};}function A(t,e){let n=t;return t.length+e.length&&(n=new Uint8Array(t.length+e.length),n.set(t,0),n.set(e,t.length)),n}function U(t,e,n){return t.subarray(e,n)}class S{constructor(t,e){Object.assign(this,{password:t,passwordVerification:e}),C(this,t);}async append(t){const e=this;if(e.password){const n=I(e,t.subarray(0,12));if(e.password=null,n[11]!=e.passwordVerification)throw new Error("Invalid pasword");t=t.subarray(12);}return I(e,t)}async flush(){return {valid:!0,data:new Uint8Array(0)}}}class z{constructor(t,e){Object.assign(this,{password:t,passwordVerification:e}),C(this,t);}async append(t){const e=this;let n,i;if(e.password){e.password=null;const a=crypto.getRandomValues(new Uint8Array(12));a[11]=e.passwordVerification,n=new Uint8Array(t.length+a.length),n.set(E(e,a),0),i=12;}else n=new Uint8Array(t.length),i=0;return n.set(E(e,t),i),n}async flush(){return {data:new Uint8Array(0)}}}function I(t,e){const n=new Uint8Array(e.length);for(let i=0;i>>24]),t.keys[2]=~t.crcKey2.get();}function B(t){const e=2|t.keys[2];return j(Math.imul(e,1^e)>>>8)}function j(t){return 255&t}function H(t){return 4294967295&t}class V{constructor(t,{signature:n,password:i,signed:a,compressed:r,zipCrypto:s,passwordVerification:o,encryptionStrength:l},{chunkSize:_}){const d=Boolean(i);Object.assign(this,{signature:n,encrypted:d,signed:a,compressed:r,inflate:r&&new t({chunkSize:_}),crc32:a&&new e,zipCrypto:s,decrypt:d&&s?new S(i,o):new y(i,a,l)});}async append(t){const e=this;return e.encrypted&&t.length&&(t=await e.decrypt.append(t)),e.compressed&&t.length&&(t=await e.inflate.append(t)),(!e.encrypted||e.zipCrypto)&&e.signed&&t.length&&e.crc32.append(t),t}async flush(){const t=this;let e,n=new Uint8Array(0);if(t.encrypted){const e=await t.decrypt.flush();if(!e.valid)throw new Error("Invalid signature");n=e.data;}if((!t.encrypted||t.zipCrypto)&&t.signed){const n=new DataView(new Uint8Array(4).buffer);if(e=t.crc32.get(),n.setUint32(0,e),t.cipher!=n.getUint32(0,!1))throw new Error("Invalid signature")}return t.compressed&&(n=await t.inflate.append(n)||new Uint8Array(0),await t.inflate.flush()),{data:n,signature:e}}}class O{constructor(t,{encrypted:n,signed:i,compressed:a,level:r,zipCrypto:s,password:o,passwordVerification:l,encryptionStrength:_},{chunkSize:d}){Object.assign(this,{encrypted:n,signed:i,compressed:a,deflate:a&&new t({level:r||5,chunkSize:d}),crc32:i&&new e,zipCrypto:s,encrypt:n&&s?new z(o,l):new m(o,_)});}async append(t){const e=this;let n=t;return e.compressed&&t.length&&(n=await e.deflate.append(t)),e.encrypted&&n.length&&(n=await e.encrypt.append(n)),(!e.encrypted||e.zipCrypto)&&e.signed&&t.length&&e.crc32.append(t),n}async flush(){const t=this;let e,n=new Uint8Array(0);if(t.compressed&&(n=await t.deflate.flush()||new Uint8Array(0)),t.encrypted){n=await t.encrypt.append(n);const i=await t.encrypt.flush();e=i.signature;const a=new Uint8Array(n.length+i.data.length);a.set(n,0),a.set(i.data,n.length),n=a;}return t.encrypted&&!t.zipCrypto||!t.signed||(e=t.crc32.get()),{data:n,signature:e}}}const D={init(t){t.scripts&&t.scripts.length&&importScripts.apply(void 0,t.scripts);const e=t.options;let n;self.initCodec&&self.initCodec(),e.codecType.startsWith("deflate")?n=self.Deflate:e.codecType.startsWith("inflate")&&(n=self.Inflate),L=function(t,e,n){return e.codecType.startsWith("deflate")?new O(t,e,n):e.codecType.startsWith("inflate")?new V(t,e,n):void 0}(n,e,t.config);},append:async t=>({data:await L.append(t.data)}),flush:()=>L.flush()};let L;function P(t){return t.map((([t,e])=>new Array(t).fill(e,0,t))).flat()}addEventListener("message",(async t=>{const e=t.data,n=e.type,i=D[n];if(i)try{e.data&&(e.data=new Uint8Array(e.data));const t=await i(e)||{};if(t.type=n,t.data)try{t.data=t.data.buffer,postMessage(t,[t.data]);}catch(e){postMessage(t);}else postMessage(t);}catch(t){postMessage({type:n,error:{message:t.message,stack:t.stack}});}}));const K=[0,1,2,3].concat(...P([[2,4],[2,5],[4,6],[4,7],[8,8],[8,9],[16,10],[16,11],[32,12],[32,13],[64,14],[64,15],[2,0],[1,16],[1,17],[2,18],[2,19],[4,20],[4,21],[8,22],[8,23],[16,24],[16,25],[32,26],[32,27],[64,28],[64,29]]));function R(){const t=this;function e(t,e){let n=0;do{n|=1&t,t>>>=1,n<<=1;}while(--e>0);return n>>>1}t.build_tree=function(n){const i=t.dyn_tree,a=t.stat_desc.static_tree,r=t.stat_desc.elems;let s,o,l,_=-1;for(n.heap_len=0,n.heap_max=573,s=0;s=1;s--)n.pqdownheap(i,s);l=r;do{s=n.heap[1],n.heap[1]=n.heap[n.heap_len--],n.pqdownheap(i,1),o=n.heap[1],n.heap[--n.heap_max]=s,n.heap[--n.heap_max]=o,i[2*l]=i[2*s]+i[2*o],n.depth[l]=Math.max(n.depth[s],n.depth[o])+1,i[2*s+1]=i[2*o+1]=l,n.heap[1]=l++,n.pqdownheap(i,1);}while(n.heap_len>=2);n.heap[--n.heap_max]=n.heap[1],function(e){const n=t.dyn_tree,i=t.stat_desc.static_tree,a=t.stat_desc.extra_bits,r=t.stat_desc.extra_base,s=t.stat_desc.max_length;let o,l,_,d,c,f,u=0;for(d=0;d<=15;d++)e.bl_count[d]=0;for(n[2*e.heap[e.heap_max]+1]=0,o=e.heap_max+1;o<573;o++)l=e.heap[o],d=n[2*n[2*l+1]+1]+1,d>s&&(d=s,u++),n[2*l+1]=d,l>t.max_code||(e.bl_count[d]++,c=0,l>=r&&(c=a[l-r]),f=n[2*l],e.opt_len+=f*(d+c),i&&(e.static_len+=f*(i[2*l+1]+c)));if(0!==u){do{for(d=s-1;0===e.bl_count[d];)d--;e.bl_count[d]--,e.bl_count[d+1]+=2,e.bl_count[s]--,u-=2;}while(u>0);for(d=s;0!==d;d--)for(l=e.bl_count[d];0!==l;)_=e.heap[--o],_>t.max_code||(n[2*_+1]!=d&&(e.opt_len+=(d-n[2*_+1])*n[2*_],n[2*_+1]=d),l--);}}(n),function(t,n,i){const a=[];let r,s,o,l=0;for(r=1;r<=15;r++)a[r]=l=l+i[r-1]<<1;for(s=0;s<=n;s++)o=t[2*s+1],0!==o&&(t[2*s]=e(a[o]++,o));}(i,t.max_code,n.bl_count);};}function W(t,e,n,i,a){const r=this;r.static_tree=t,r.extra_bits=e,r.extra_base=n,r.elems=i,r.max_length=a;}function G(t,e,n,i,a){const r=this;r.good_length=t,r.max_lazy=e,r.nice_length=n,r.max_chain=i,r.func=a;}R._length_code=[0,1,2,3,4,5,6,7].concat(...P([[2,8],[2,9],[2,10],[2,11],[4,12],[4,13],[4,14],[4,15],[8,16],[8,17],[8,18],[8,19],[16,20],[16,21],[16,22],[16,23],[32,24],[32,25],[32,26],[31,27],[1,28]])),R.base_length=[0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224,0],R.base_dist=[0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576],R.d_code=function(t){return t<256?K[t]:K[256+(t>>>7)]},R.extra_lbits=[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],R.extra_dbits=[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],R.extra_blbits=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],R.bl_order=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],W.static_ltree=[12,8,140,8,76,8,204,8,44,8,172,8,108,8,236,8,28,8,156,8,92,8,220,8,60,8,188,8,124,8,252,8,2,8,130,8,66,8,194,8,34,8,162,8,98,8,226,8,18,8,146,8,82,8,210,8,50,8,178,8,114,8,242,8,10,8,138,8,74,8,202,8,42,8,170,8,106,8,234,8,26,8,154,8,90,8,218,8,58,8,186,8,122,8,250,8,6,8,134,8,70,8,198,8,38,8,166,8,102,8,230,8,22,8,150,8,86,8,214,8,54,8,182,8,118,8,246,8,14,8,142,8,78,8,206,8,46,8,174,8,110,8,238,8,30,8,158,8,94,8,222,8,62,8,190,8,126,8,254,8,1,8,129,8,65,8,193,8,33,8,161,8,97,8,225,8,17,8,145,8,81,8,209,8,49,8,177,8,113,8,241,8,9,8,137,8,73,8,201,8,41,8,169,8,105,8,233,8,25,8,153,8,89,8,217,8,57,8,185,8,121,8,249,8,5,8,133,8,69,8,197,8,37,8,165,8,101,8,229,8,21,8,149,8,85,8,213,8,53,8,181,8,117,8,245,8,13,8,141,8,77,8,205,8,45,8,173,8,109,8,237,8,29,8,157,8,93,8,221,8,61,8,189,8,125,8,253,8,19,9,275,9,147,9,403,9,83,9,339,9,211,9,467,9,51,9,307,9,179,9,435,9,115,9,371,9,243,9,499,9,11,9,267,9,139,9,395,9,75,9,331,9,203,9,459,9,43,9,299,9,171,9,427,9,107,9,363,9,235,9,491,9,27,9,283,9,155,9,411,9,91,9,347,9,219,9,475,9,59,9,315,9,187,9,443,9,123,9,379,9,251,9,507,9,7,9,263,9,135,9,391,9,71,9,327,9,199,9,455,9,39,9,295,9,167,9,423,9,103,9,359,9,231,9,487,9,23,9,279,9,151,9,407,9,87,9,343,9,215,9,471,9,55,9,311,9,183,9,439,9,119,9,375,9,247,9,503,9,15,9,271,9,143,9,399,9,79,9,335,9,207,9,463,9,47,9,303,9,175,9,431,9,111,9,367,9,239,9,495,9,31,9,287,9,159,9,415,9,95,9,351,9,223,9,479,9,63,9,319,9,191,9,447,9,127,9,383,9,255,9,511,9,0,7,64,7,32,7,96,7,16,7,80,7,48,7,112,7,8,7,72,7,40,7,104,7,24,7,88,7,56,7,120,7,4,7,68,7,36,7,100,7,20,7,84,7,52,7,116,7,3,8,131,8,67,8,195,8,35,8,163,8,99,8,227,8],W.static_dtree=[0,5,16,5,8,5,24,5,4,5,20,5,12,5,28,5,2,5,18,5,10,5,26,5,6,5,22,5,14,5,30,5,1,5,17,5,9,5,25,5,5,5,21,5,13,5,29,5,3,5,19,5,11,5,27,5,7,5,23,5],W.static_l_desc=new W(W.static_ltree,R.extra_lbits,257,286,15),W.static_d_desc=new W(W.static_dtree,R.extra_dbits,0,30,15),W.static_bl_desc=new W(null,R.extra_blbits,0,19,7);const T=[new G(0,0,0,0,0),new G(4,4,8,4,1),new G(4,5,16,8,1),new G(4,6,32,32,1),new G(4,4,16,16,2),new G(8,16,32,32,2),new G(8,16,128,128,2),new G(8,32,128,256,2),new G(32,128,258,1024,2),new G(32,258,258,4096,2)],q=["need dictionary","stream end","","","stream error","data error","","buffer error","",""];function F(t,e,n,i){const a=t[2*e],r=t[2*n];return a>>8&255);}function tt(t,e){let n;const i=e;Q>16-i?(n=t,N|=n<>>16-Q,Q+=i-16):(N|=t<=8&&(Z(255&N),N>>>=8,Q-=8);}function at(e,n){let i,a,r;if(t.pending_buf[K+2*P]=e>>>8&255,t.pending_buf[K+2*P+1]=255&e,t.pending_buf[D+P]=255&n,P++,0===e?M[2*n]++:(G++,e--,M[2*(R._length_code[n]+256+1)]++,B[2*R.d_code(e)]++),0==(8191&P)&&z>2){for(i=8*P,a=m-p,r=0;r<30;r++)i+=B[2*r]*(5+R.extra_dbits[r]);if(i>>>=3,G8?$(N):Q>0&&Z(255&N),N=0,Q=0;}function ot(e,n,i){tt(0+(i?1:0),3),function(e,n,i){st(),J=8,$(n),$(~n),t.pending_buf.set(l.subarray(e,e+n),t.pending),t.pending+=n;}(e,n);}function lt(e,n,i){let a,r,s=0;z>0?(H.build_tree(t),V.build_tree(t),s=function(){let e;for(Y(M,H.max_code),Y(B,V.max_code),O.build_tree(t),e=18;e>=3&&0===j[2*R.bl_order[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}(),a=t.opt_len+3+7>>>3,r=t.static_len+3+7>>>3,r<=a&&(a=r)):a=r=n+5,n+4<=a&&-1!=e?ot(e,n,i):r==a?(tt(2+(i?1:0),3),rt(W.static_ltree,W.static_dtree)):(tt(4+(i?1:0),3),function(t,e,n){let i;for(tt(t-257,5),tt(e-1,5),tt(n-4,4),i=0;i=0?p:-1,m-p,t),p=m,e.flush_pending();}function dt(){let t,n,i,a;do{if(a=_-v-m,0===a&&0===m&&0===v)a=r;else if(-1==a)a--;else if(m>=r+r-262){l.set(l.subarray(r,r+r),0),k-=r,m-=r,p-=r,t=u,i=t;do{n=65535&c[--i],c[i]=n>=r?n-r:0;}while(0!=--t);t=r,i=t;do{n=65535&d[--i],d[i]=n>=r?n-r:0;}while(0!=--t);a+=r;}if(0===e.avail_in)return;t=e.read_buf(l,m+v,a),v+=t,v>=3&&(f=255&l[m],f=(f<r-262?m-(r-262):0;let c=C;const f=o,u=m+258;let h=l[a+s-1],b=l[a+s];A>=E&&(i>>=2),c>v&&(c=v);do{if(e=t,l[e+s]==b&&l[e+s-1]==h&&l[e]==l[a]&&l[++e]==l[a+1]){a+=2,e++;do{}while(l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&l[++a]==l[++e]&&as){if(k=t,s=n,n>=c)break;h=l[a+s-1],b=l[a+s];}}}while((t=65535&d[t&f])>_&&0!=--i);return s<=v?s:v}function ft(e){return e.total_in=e.total_out=0,e.msg=null,t.pending=0,t.pending_out=0,n=113,a=0,H.dyn_tree=M,H.stat_desc=W.static_l_desc,V.dyn_tree=B,V.stat_desc=W.static_d_desc,O.dyn_tree=j,O.stat_desc=W.static_bl_desc,N=0,Q=0,J=8,X(),function(){_=2*r,c[u-1]=0;for(let t=0;t9||8!=_||a<9||a>15||n<0||n>9||p<0||p>2?-2:(e.dstate=t,s=a,r=1<9||n<0||n>2?-2:(T[z].func!=T[e].func&&0!==t.total_in&&(i=t.deflate(1)),z!=e&&(z=e,S=T[z].max_lazy,E=T[z].good_length,C=T[z].nice_length,U=T[z].max_chain),I=n,i)},t.deflateSetDictionary=function(t,e,i){let a,s=i,_=0;if(!e||42!=n)return -2;if(s<3)return 0;for(s>r-262&&(s=r-262,_=i-s),l.set(e.subarray(_,_+s),0),m=s,p=s,f=255&l[0],f=(f<4||h<0)return -2;if(!_.next_out||!_.next_in&&0!==_.avail_in||666==n&&4!=h)return _.msg=q[4],-2;if(0===_.avail_out)return _.msg=q[7],-5;var j;if(e=_,M=a,a=h,42==n&&(E=8+(s-8<<4)<<8,C=(z-1&255)>>1,C>3&&(C=3),E|=C<<6,0!==m&&(E|=32),E+=31-E%31,n=113,Z((j=E)>>8&255),Z(255&j)),0!==t.pending){if(e.flush_pending(),0===e.avail_out)return a=-1,0}else if(0===e.avail_in&&h<=M&&4!=h)return e.msg=q[7],-5;if(666==n&&0!==e.avail_in)return _.msg=q[7],-5;if(0!==e.avail_in||0!==v||0!=h&&666!=n){switch(B=-1,T[z].func){case 0:B=function(t){let n,a=65535;for(a>i-5&&(a=i-5);;){if(v<=1){if(dt(),0===v&&0==t)return 0;if(0===v)break}if(m+=v,v=0,n=p+a,(0===m||m>=n)&&(v=m-n,m=n,_t(!1),0===e.avail_out))return 0;if(m-p>=r-262&&(_t(!1),0===e.avail_out))return 0}return _t(4==t),0===e.avail_out?4==t?2:0:4==t?3:1}(h);break;case 1:B=function(t){let n,i=0;for(;;){if(v<262){if(dt(),v<262&&0==t)return 0;if(0===v)break}if(v>=3&&(f=(f<=3)if(n=at(m-k,x-3),v-=x,x<=S&&v>=3){x--;do{m++,f=(f<=3&&(f=(f<4096)&&(x=2)),A>=3&&x<=A){i=m+v-3,n=at(m-1-g,A-3),v-=A-1,A-=2;do{++m<=i&&(f=(f<0&&e.next_in_index!=o&&(a(e.next_in_index),o=e.next_in_index);}while(e.avail_in>0||0===e.avail_out);return d.length>1?(s=new Uint8Array(_),d.forEach((function(t){s.set(t,l),l+=t.length;}))):s=d[0]||new Uint8Array(0),s}},this.flush=function(){let t,a,r=0,s=0;const o=[];do{if(e.next_out_index=0,e.avail_out=n,t=e.deflate(4),1!=t&&0!=t)throw new Error("deflating: "+e.msg);n-e.avail_out>0&&o.push(i.slice(0,e.next_out_index)),s+=e.next_out_index;}while(e.avail_in>0||0===e.avail_out);return e.deflateEnd(),a=new Uint8Array(s),o.forEach((function(t){a.set(t,r),r+=t.length;})),a};}N.prototype={deflateInit:function(t,e){const n=this;return n.dstate=new J,e||(e=15),n.dstate.deflateInit(n,t,e)},deflate:function(t){const e=this;return e.dstate?e.dstate.deflate(e,t):-2},deflateEnd:function(){const t=this;if(!t.dstate)return -2;const e=t.dstate.deflateEnd();return t.dstate=null,e},deflateParams:function(t,e){const n=this;return n.dstate?n.dstate.deflateParams(n,t,e):-2},deflateSetDictionary:function(t,e){const n=this;return n.dstate?n.dstate.deflateSetDictionary(n,t,e):-2},read_buf:function(t,e,n){const i=this;let a=i.avail_in;return a>n&&(a=n),0===a?0:(i.avail_in-=a,t.set(i.next_in.subarray(i.next_in_index,i.next_in_index+a),e),i.next_in_index+=a,i.total_in+=a,a)},flush_pending:function(){const t=this;let e=t.dstate.pending;e>t.avail_out&&(e=t.avail_out),0!==e&&(t.next_out.set(t.dstate.pending_buf.subarray(t.dstate.pending_out,t.dstate.pending_out+e),t.next_out_index),t.next_out_index+=e,t.dstate.pending_out+=e,t.total_out+=e,t.avail_out-=e,t.dstate.pending-=e,0===t.dstate.pending&&(t.dstate.pending_out=0));}};const X=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535],Y=[96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,192,80,7,10,0,8,96,0,8,32,0,9,160,0,8,0,0,8,128,0,8,64,0,9,224,80,7,6,0,8,88,0,8,24,0,9,144,83,7,59,0,8,120,0,8,56,0,9,208,81,7,17,0,8,104,0,8,40,0,9,176,0,8,8,0,8,136,0,8,72,0,9,240,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,200,81,7,13,0,8,100,0,8,36,0,9,168,0,8,4,0,8,132,0,8,68,0,9,232,80,7,8,0,8,92,0,8,28,0,9,152,84,7,83,0,8,124,0,8,60,0,9,216,82,7,23,0,8,108,0,8,44,0,9,184,0,8,12,0,8,140,0,8,76,0,9,248,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,196,81,7,11,0,8,98,0,8,34,0,9,164,0,8,2,0,8,130,0,8,66,0,9,228,80,7,7,0,8,90,0,8,26,0,9,148,84,7,67,0,8,122,0,8,58,0,9,212,82,7,19,0,8,106,0,8,42,0,9,180,0,8,10,0,8,138,0,8,74,0,9,244,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,204,81,7,15,0,8,102,0,8,38,0,9,172,0,8,6,0,8,134,0,8,70,0,9,236,80,7,9,0,8,94,0,8,30,0,9,156,84,7,99,0,8,126,0,8,62,0,9,220,82,7,27,0,8,110,0,8,46,0,9,188,0,8,14,0,8,142,0,8,78,0,9,252,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,194,80,7,10,0,8,97,0,8,33,0,9,162,0,8,1,0,8,129,0,8,65,0,9,226,80,7,6,0,8,89,0,8,25,0,9,146,83,7,59,0,8,121,0,8,57,0,9,210,81,7,17,0,8,105,0,8,41,0,9,178,0,8,9,0,8,137,0,8,73,0,9,242,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,202,81,7,13,0,8,101,0,8,37,0,9,170,0,8,5,0,8,133,0,8,69,0,9,234,80,7,8,0,8,93,0,8,29,0,9,154,84,7,83,0,8,125,0,8,61,0,9,218,82,7,23,0,8,109,0,8,45,0,9,186,0,8,13,0,8,141,0,8,77,0,9,250,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,198,81,7,11,0,8,99,0,8,35,0,9,166,0,8,3,0,8,131,0,8,67,0,9,230,80,7,7,0,8,91,0,8,27,0,9,150,84,7,67,0,8,123,0,8,59,0,9,214,82,7,19,0,8,107,0,8,43,0,9,182,0,8,11,0,8,139,0,8,75,0,9,246,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,206,81,7,15,0,8,103,0,8,39,0,9,174,0,8,7,0,8,135,0,8,71,0,9,238,80,7,9,0,8,95,0,8,31,0,9,158,84,7,99,0,8,127,0,8,63,0,9,222,82,7,27,0,8,111,0,8,47,0,9,190,0,8,15,0,8,143,0,8,79,0,9,254,96,7,256,0,8,80,0,8,16,84,8,115,82,7,31,0,8,112,0,8,48,0,9,193,80,7,10,0,8,96,0,8,32,0,9,161,0,8,0,0,8,128,0,8,64,0,9,225,80,7,6,0,8,88,0,8,24,0,9,145,83,7,59,0,8,120,0,8,56,0,9,209,81,7,17,0,8,104,0,8,40,0,9,177,0,8,8,0,8,136,0,8,72,0,9,241,80,7,4,0,8,84,0,8,20,85,8,227,83,7,43,0,8,116,0,8,52,0,9,201,81,7,13,0,8,100,0,8,36,0,9,169,0,8,4,0,8,132,0,8,68,0,9,233,80,7,8,0,8,92,0,8,28,0,9,153,84,7,83,0,8,124,0,8,60,0,9,217,82,7,23,0,8,108,0,8,44,0,9,185,0,8,12,0,8,140,0,8,76,0,9,249,80,7,3,0,8,82,0,8,18,85,8,163,83,7,35,0,8,114,0,8,50,0,9,197,81,7,11,0,8,98,0,8,34,0,9,165,0,8,2,0,8,130,0,8,66,0,9,229,80,7,7,0,8,90,0,8,26,0,9,149,84,7,67,0,8,122,0,8,58,0,9,213,82,7,19,0,8,106,0,8,42,0,9,181,0,8,10,0,8,138,0,8,74,0,9,245,80,7,5,0,8,86,0,8,22,192,8,0,83,7,51,0,8,118,0,8,54,0,9,205,81,7,15,0,8,102,0,8,38,0,9,173,0,8,6,0,8,134,0,8,70,0,9,237,80,7,9,0,8,94,0,8,30,0,9,157,84,7,99,0,8,126,0,8,62,0,9,221,82,7,27,0,8,110,0,8,46,0,9,189,0,8,14,0,8,142,0,8,78,0,9,253,96,7,256,0,8,81,0,8,17,85,8,131,82,7,31,0,8,113,0,8,49,0,9,195,80,7,10,0,8,97,0,8,33,0,9,163,0,8,1,0,8,129,0,8,65,0,9,227,80,7,6,0,8,89,0,8,25,0,9,147,83,7,59,0,8,121,0,8,57,0,9,211,81,7,17,0,8,105,0,8,41,0,9,179,0,8,9,0,8,137,0,8,73,0,9,243,80,7,4,0,8,85,0,8,21,80,8,258,83,7,43,0,8,117,0,8,53,0,9,203,81,7,13,0,8,101,0,8,37,0,9,171,0,8,5,0,8,133,0,8,69,0,9,235,80,7,8,0,8,93,0,8,29,0,9,155,84,7,83,0,8,125,0,8,61,0,9,219,82,7,23,0,8,109,0,8,45,0,9,187,0,8,13,0,8,141,0,8,77,0,9,251,80,7,3,0,8,83,0,8,19,85,8,195,83,7,35,0,8,115,0,8,51,0,9,199,81,7,11,0,8,99,0,8,35,0,9,167,0,8,3,0,8,131,0,8,67,0,9,231,80,7,7,0,8,91,0,8,27,0,9,151,84,7,67,0,8,123,0,8,59,0,9,215,82,7,19,0,8,107,0,8,43,0,9,183,0,8,11,0,8,139,0,8,75,0,9,247,80,7,5,0,8,87,0,8,23,192,8,0,83,7,51,0,8,119,0,8,55,0,9,207,81,7,15,0,8,103,0,8,39,0,9,175,0,8,7,0,8,135,0,8,71,0,9,239,80,7,9,0,8,95,0,8,31,0,9,159,84,7,99,0,8,127,0,8,63,0,9,223,82,7,27,0,8,111,0,8,47,0,9,191,0,8,15,0,8,143,0,8,79,0,9,255],Z=[80,5,1,87,5,257,83,5,17,91,5,4097,81,5,5,89,5,1025,85,5,65,93,5,16385,80,5,3,88,5,513,84,5,33,92,5,8193,82,5,9,90,5,2049,86,5,129,192,5,24577,80,5,2,87,5,385,83,5,25,91,5,6145,81,5,7,89,5,1537,85,5,97,93,5,24577,80,5,4,88,5,769,84,5,49,92,5,12289,82,5,13,90,5,3073,86,5,193,192,5,24577],$=[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],tt=[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,112,112],et=[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],nt=[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];function it(){let t,e,n,i,a,r;function s(t,e,s,o,l,_,d,c,f,u,h){let b,w,p,x,g,y,m,k,v,A,U,S,z,I,E;A=0,g=s;do{n[t[e+A]]++,A++,g--;}while(0!==g);if(n[0]==s)return d[0]=-1,c[0]=0,0;for(k=c[0],y=1;y<=15&&0===n[y];y++);for(m=y,kg&&(k=g),c[0]=k,I=1<S+k;){if(x++,S+=k,E=p-S,E=E>k?k:E,(w=1<<(y=m-S))>b+1&&(w-=b+1,z=m,y1440)return -3;a[x]=U=u[0],u[0]+=E,0!==x?(r[x]=g,i[0]=y,i[1]=k,y=g>>>S-k,i[2]=U-a[x-1]-y,f.set(i,3*(a[x-1]+y))):d[0]=U;}for(i[1]=m-S,A>=s?i[0]=192:h[A]>>S;y>>=1)g^=y;for(g^=y,v=(1<257?(-3==u?f.msg="oversubscribed distance tree":-5==u?(f.msg="incomplete distance tree",u=-3):-4!=u&&(f.msg="empty distance tree with lengths",u=-3),u):0)};}function at(){const t=this;let e,n,i,a,r=0,s=0,o=0,l=0,_=0,d=0,c=0,f=0,u=0,h=0;function b(t,e,n,i,a,r,s,o){let l,_,d,c,f,u,h,b,w,p,x,g,y,m,k,v;h=o.next_in_index,b=o.avail_in,f=s.bitb,u=s.bitk,w=s.write,p=w>=_[v+1],u-=_[v+1],0!=(16&c)){for(c&=15,y=_[v+2]+(f&X[c]),f>>=c,u-=c;u<15;)b--,f|=(255&o.read_byte(h++))<>=_[v+1],u-=_[v+1],0!=(16&c)){for(c&=15;u>=c,u-=c,p-=y,w>=m)k=w-m,w-k>0&&2>w-k?(s.window[w++]=s.window[k++],s.window[w++]=s.window[k++],y-=2):(s.window.set(s.window.subarray(k,k+2),w),w+=2,k+=2,y-=2);else {k=w-m;do{k+=s.end;}while(k<0);if(c=s.end-k,y>c){if(y-=c,w-k>0&&c>w-k)do{s.window[w++]=s.window[k++];}while(0!=--c);else s.window.set(s.window.subarray(k,k+c),w),w+=c,k+=c,c=0;k=0;}}if(w-k>0&&y>w-k)do{s.window[w++]=s.window[k++];}while(0!=--y);else s.window.set(s.window.subarray(k,k+y),w),w+=y,k+=y,y=0;break}if(0!=(64&c))return o.msg="invalid distance code",y=o.avail_in-b,y=u>>3>3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,-3;l+=_[v+2],l+=f&X[c],v=3*(d+l),c=_[v];}break}if(0!=(64&c))return 0!=(32&c)?(y=o.avail_in-b,y=u>>3>3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,1):(o.msg="invalid literal/length code",y=o.avail_in-b,y=u>>3>3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,-3);if(l+=_[v+2],l+=f&X[c],v=3*(d+l),0===(c=_[v])){f>>=_[v+1],u-=_[v+1],s.window[w++]=_[v+2],p--;break}}else f>>=_[v+1],u-=_[v+1],s.window[w++]=_[v+2],p--;}while(p>=258&&b>=10);return y=o.avail_in-b,y=u>>3>3:y,b+=y,h-=y,u-=y<<3,s.bitb=f,s.bitk=u,o.avail_in=b,o.total_in+=h-o.next_in_index,o.next_in_index=h,s.write=w,0}t.init=function(t,r,s,o,l,_){e=0,c=t,f=r,i=s,u=o,a=l,h=_,n=null;},t.proc=function(t,w,p){let x,g,y,m,k,v,A,U=0,S=0,z=0;for(z=w.next_in_index,m=w.avail_in,U=t.bitb,S=t.bitk,k=t.write,v=k=258&&m>=10&&(t.bitb=U,t.bitk=S,w.avail_in=m,w.total_in+=z-w.next_in_index,w.next_in_index=z,t.write=k,p=b(c,f,i,u,a,h,t,w),z=w.next_in_index,m=w.avail_in,U=t.bitb,S=t.bitk,k=t.write,v=k>>=n[g+1],S-=n[g+1],y=n[g],0===y){l=n[g+2],e=6;break}if(0!=(16&y)){_=15&y,r=n[g+2],e=2;break}if(0==(64&y)){o=y,s=g/3+n[g+2];break}if(0!=(32&y)){e=7;break}return e=9,w.msg="invalid literal/length code",p=-3,t.bitb=U,t.bitk=S,w.avail_in=m,w.total_in+=z-w.next_in_index,w.next_in_index=z,t.write=k,t.inflate_flush(w,p);case 2:for(x=_;S>=x,S-=x,o=f,n=a,s=h,e=3;case 3:for(x=o;S>=n[g+1],S-=n[g+1],y=n[g],0!=(16&y)){_=15&y,d=n[g+2],e=4;break}if(0==(64&y)){o=y,s=g/3+n[g+2];break}return e=9,w.msg="invalid distance code",p=-3,t.bitb=U,t.bitk=S,w.avail_in=m,w.total_in+=z-w.next_in_index,w.next_in_index=z,t.write=k,t.inflate_flush(w,p);case 4:for(x=_;S>=x,S-=x,e=5;case 5:for(A=k-d;A<0;)A+=t.end;for(;0!==r;){if(0===v&&(k==t.end&&0!==t.read&&(k=0,v=k7&&(S-=8,m++,z--),t.write=k,p=t.inflate_flush(w,p),k=t.write,v=kt.avail_out&&(i=t.avail_out),0!==i&&-5==e&&(e=0),t.avail_out-=i,t.total_out+=i,t.next_out.set(n.window.subarray(r,r+i),a),a+=i,r+=i,r==n.end&&(r=0,n.write==n.end&&(n.write=0),i=n.write-r,i>t.avail_out&&(i=t.avail_out),0!==i&&-5==e&&(e=0),t.avail_out-=i,t.total_out+=i,t.next_out.set(n.window.subarray(r,r+i),a),a+=i,r+=i),t.next_out_index=a,n.read=r,e},n.proc=function(t,e){let h,b,w,p,x,g,y,m;for(p=t.next_in_index,x=t.avail_in,b=n.bitb,w=n.bitk,g=n.write,y=g>>1){case 0:b>>>=3,w-=3,h=7&w,b>>>=h,w-=h,a=1;break;case 1:k=[],v=[],A=[[]],U=[[]],it.inflate_trees_fixed(k,v,A,U),d.init(k[0],v[0],A[0],0,U[0],0),b>>>=3,w-=3,a=6;break;case 2:b>>>=3,w-=3,a=3;break;case 3:return b>>>=3,w-=3,a=9,t.msg="invalid block type",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e)}break;case 1:for(;w<32;){if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);e=0,x--,b|=(255&t.read_byte(p++))<>>16&65535)!=(65535&b))return a=9,t.msg="invalid stored block lengths",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);r=65535&b,b=w=0,a=0!==r?2:0!==c?7:0;break;case 2:if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);if(0===y&&(g==n.end&&0!==n.read&&(g=0,y=gx&&(h=x),h>y&&(h=y),n.window.set(t.read_buf(p,h),g),p+=h,x-=h,g+=h,y-=h,0!=(r-=h))break;a=0!==c?7:0;break;case 3:for(;w<14;){if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);e=0,x--,b|=(255&t.read_byte(p++))<29||(h>>5&31)>29)return a=9,t.msg="too many length or distance symbols",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);if(h=258+(31&h)+(h>>5&31),!i||i.length>>=14,w-=14,o=0,a=4;case 4:for(;o<4+(s>>>10);){for(;w<3;){if(0===x)return n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);e=0,x--,b|=(255&t.read_byte(p++))<>>=3,w-=3;}for(;o<19;)i[rt[o++]]=0;if(l[0]=7,h=u.inflate_trees_bits(i,l,_,f,t),0!=h)return -3==(e=h)&&(i=null,a=9),n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);o=0,a=5;case 5:for(;h=s,!(o>=258+(31&h)+(h>>5&31));){let r,d;for(h=l[0];w>>=h,w-=h,i[o++]=d;else {for(m=18==d?7:d-14,r=18==d?11:3;w>>=h,w-=h,r+=b&X[m],b>>>=m,w-=m,m=o,h=s,m+r>258+(31&h)+(h>>5&31)||16==d&&m<1)return i=null,a=9,t.msg="invalid bit length repeat",e=-3,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);d=16==d?i[m-1]:0;do{i[m++]=d;}while(0!=--r);o=m;}}if(_[0]=-1,S=[],z=[],I=[],E=[],S[0]=9,z[0]=6,h=s,h=u.inflate_trees_dynamic(257+(31&h),1+(h>>5&31),i,S,z,I,E,f,t),0!=h)return -3==h&&(i=null,a=9),e=h,n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,n.inflate_flush(t,e);d.init(S[0],z[0],f,I[0],f,E[0]),a=6;case 6:if(n.bitb=b,n.bitk=w,t.avail_in=x,t.total_in+=p-t.next_in_index,t.next_in_index=p,n.write=g,1!=(e=d.proc(n,t,e)))return n.inflate_flush(t,e);if(e=0,d.free(t),p=t.next_in_index,x=t.avail_in,b=n.bitb,w=n.bitk,g=n.write,y=g15?(t.inflateEnd(n),-2):(t.wbits=i,n.istate.blocks=new st(n,1<>4)>a.wbits){a.mode=13,t.msg="invalid window size",a.marker=5;break}a.mode=1;case 1:if(0===t.avail_in)return n;if(n=e,t.avail_in--,t.total_in++,i=255&t.read_byte(t.next_in_index++),((a.method<<8)+i)%31!=0){a.mode=13,t.msg="incorrect header check",a.marker=5;break}if(0==(32&i)){a.mode=7;break}a.mode=2;case 2:if(0===t.avail_in)return n;n=e,t.avail_in--,t.total_in++,a.need=(255&t.read_byte(t.next_in_index++))<<24&4278190080,a.mode=3;case 3:if(0===t.avail_in)return n;n=e,t.avail_in--,t.total_in++,a.need+=(255&t.read_byte(t.next_in_index++))<<16&16711680,a.mode=4;case 4:if(0===t.avail_in)return n;n=e,t.avail_in--,t.total_in++,a.need+=(255&t.read_byte(t.next_in_index++))<<8&65280,a.mode=5;case 5:return 0===t.avail_in?n:(n=e,t.avail_in--,t.total_in++,a.need+=255&t.read_byte(t.next_in_index++),a.mode=6,2);case 6:return a.mode=13,t.msg="need dictionary",a.marker=0,-2;case 7:if(n=a.blocks.proc(t,n),-3==n){a.mode=13,a.marker=0;break}if(0==n&&(n=e),1!=n)return n;n=e,a.blocks.reset(t,a.was),a.mode=12;case 12:return 1;case 13:return -3;default:return -2}},t.inflateSetDictionary=function(t,e,n){let i=0,a=n;if(!t||!t.istate||6!=t.istate.mode)return -2;const r=t.istate;return a>=1<0&&e.next_in_index!=_&&(r(e.next_in_index),_=e.next_in_index);}while(e.avail_in>0||0===e.avail_out);return s.length>1?(l=new Uint8Array(c),s.forEach((function(t){l.set(t,d),d+=t.length;}))):l=s[0]||new Uint8Array(0),l}},this.flush=function(){e.inflateEnd();};}_t.prototype={inflateInit:function(t){const e=this;return e.istate=new lt,t||(t=15),e.istate.inflateInit(e,t)},inflate:function(t){const e=this;return e.istate?e.istate.inflate(e,t):-2},inflateEnd:function(){const t=this;if(!t.istate)return -2;const e=t.istate.inflateEnd(t);return t.istate=null,e},inflateSync:function(){const t=this;return t.istate?t.istate.inflateSync(t):-2},inflateSetDictionary:function(t,e){const n=this;return n.istate?n.istate.inflateSetDictionary(n,t,e):-2},read_byte:function(t){return this.next_in[t]},read_buf:function(t,e){return this.next_in.subarray(t,t+e)}},self.initCodec=()=>{self.Deflate=Q,self.Inflate=dt;};}).toString(),n=URL.createObjectURL(new Blob(["("+e+")()"],{type:"text/javascript"}));configure({workerScripts:{inflate:[n],deflate:[n]}});}}; + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + function getMimeType() { + return "application/octet-stream"; + } + + var streamCodecShim = (library, options = {}, registerDataHandler) => { + return { + Deflate: createCodecClass(library.Deflate, options.deflate, registerDataHandler), + Inflate: createCodecClass(library.Inflate, options.inflate, registerDataHandler) + }; + }; + + function createCodecClass(constructor, constructorOptions, registerDataHandler) { + return class { + + constructor(options) { + const codecAdapter = this; + const onData = data => { + if (codecAdapter.pendingData) { + const pendingData = codecAdapter.pendingData; + codecAdapter.pendingData = new Uint8Array(pendingData.length + data.length); + codecAdapter.pendingData.set(pendingData, 0); + codecAdapter.pendingData.set(data, pendingData.length); + } else { + codecAdapter.pendingData = new Uint8Array(data); + } + }; + codecAdapter.codec = new constructor(Object.assign({}, constructorOptions, options)); + registerDataHandler(codecAdapter.codec, onData); + } + async append(data) { + this.codec.push(data); + return getResponse(this); + } + async flush() { + this.codec.push(new Uint8Array(0), true); + return getResponse(this); + } + }; + + function getResponse(codec) { + if (codec.pendingData) { + const output = codec.pendingData; + codec.pendingData = null; + return output; + } else { + return new Uint8Array(0); + } + } + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const ERR_HTTP_STATUS = "HTTP error "; + const ERR_HTTP_RANGE = "HTTP Range not supported"; + + const CONTENT_TYPE_TEXT_PLAIN = "text/plain"; + const HTTP_HEADER_CONTENT_LENGTH = "Content-Length"; + const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges"; + const HTTP_HEADER_RANGE = "Range"; + const HTTP_METHOD_HEAD = "HEAD"; + const HTTP_METHOD_GET = "GET"; + const HTTP_RANGE_UNIT = "bytes"; + + class Stream { + + constructor() { + this.size = 0; + } + + init() { + this.initialized = true; + } + } + + class Reader extends Stream { + } + + class Writer extends Stream { + + writeUint8Array(array) { + this.size += array.length; + } + } + + class TextReader extends Reader { + + constructor(text) { + super(); + this.blobReader = new BlobReader(new Blob([text], { type: CONTENT_TYPE_TEXT_PLAIN })); + } + + async init() { + super.init(); + this.blobReader.init(); + this.size = this.blobReader.size; + } + + async readUint8Array(offset, length) { + return this.blobReader.readUint8Array(offset, length); + } + } + + class TextWriter extends Writer { + + constructor(encoding) { + super(); + this.encoding = encoding; + this.blob = new Blob([], { type: CONTENT_TYPE_TEXT_PLAIN }); + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + this.blob = new Blob([this.blob, array.buffer], { type: CONTENT_TYPE_TEXT_PLAIN }); + } + + getData() { + const reader = new FileReader(); + return new Promise((resolve, reject) => { + reader.onload = event => resolve(event.target.result); + reader.onerror = reject; + reader.readAsText(this.blob, this.encoding); + }); + } + } + + class Data64URIReader extends Reader { + + constructor(dataURI) { + super(); + this.dataURI = dataURI; + let dataEnd = dataURI.length; + while (dataURI.charAt(dataEnd - 1) == "=") { + dataEnd--; + } + this.dataStart = dataURI.indexOf(",") + 1; + this.size = Math.floor((dataEnd - this.dataStart) * 0.75); + } + + async readUint8Array(offset, length) { + const dataArray = new Uint8Array(length); + const start = Math.floor(offset / 3) * 4; + const bytes = atob(this.dataURI.substring(start + this.dataStart, Math.ceil((offset + length) / 3) * 4 + this.dataStart)); + const delta = offset - Math.floor(start / 4) * 3; + for (let indexByte = delta; indexByte < delta + length; indexByte++) { + dataArray[indexByte - delta] = bytes.charCodeAt(indexByte); + } + return dataArray; + } + } + + class Data64URIWriter extends Writer { + + constructor(contentType) { + super(); + this.data = "data:" + (contentType || "") + ";base64,"; + this.pending = []; + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + let indexArray = 0; + let dataString = this.pending; + const delta = this.pending.length; + this.pending = ""; + for (indexArray = 0; indexArray < (Math.floor((delta + array.length) / 3) * 3) - delta; indexArray++) { + dataString += String.fromCharCode(array[indexArray]); + } + for (; indexArray < array.length; indexArray++) { + this.pending += String.fromCharCode(array[indexArray]); + } + if (dataString.length > 2) { + this.data += btoa(dataString); + } else { + this.pending = dataString; + } + } + + getData() { + return this.data + btoa(this.pending); + } + } + + class BlobReader extends Reader { + + constructor(blob) { + super(); + this.blob = blob; + this.size = blob.size; + } + + async readUint8Array(offset, length) { + const reader = new FileReader(); + return new Promise((resolve, reject) => { + reader.onload = event => resolve(new Uint8Array(event.target.result)); + reader.onerror = reject; + reader.readAsArrayBuffer(this.blob.slice(offset, offset + length)); + }); + } + } + + class BlobWriter extends Writer { + + constructor(contentType) { + super(); + this.offset = 0; + this.contentType = contentType; + this.blob = new Blob([], { type: contentType }); + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + this.blob = new Blob([this.blob, array.buffer], { type: this.contentType }); + this.offset = this.blob.size; + } + + getData() { + return this.blob; + } + } + + class FetchReader extends Reader { + + constructor(url, options) { + super(); + this.url = url; + this.preventHeadRequest = options.preventHeadRequest; + this.useRangeHeader = options.useRangeHeader; + this.forceRangeRequests = options.forceRangeRequests; + this.options = Object.assign({}, options); + delete this.options.preventHeadRequest; + delete this.options.useRangeHeader; + delete this.options.forceRangeRequests; + delete this.options.useXHR; + } + + async init() { + super.init(); + if (isHttpFamily(this.url) && !this.preventHeadRequest) { + const response = await sendFetchRequest(HTTP_METHOD_HEAD, this.url, this.options); + this.size = Number(response.headers.get(HTTP_HEADER_CONTENT_LENGTH)); + if (!this.forceRangeRequests && this.useRangeHeader && response.headers.get(HTTP_HEADER_ACCEPT_RANGES) != HTTP_RANGE_UNIT) { + throw new Error(ERR_HTTP_RANGE); + } else if (this.size === undefined) { + await getFetchData(this, this.options); + } + } else { + await getFetchData(this, this.options); + } + } + + async readUint8Array(index, length) { + if (this.useRangeHeader) { + const response = await sendFetchRequest(HTTP_METHOD_GET, this.url, this.options, Object.assign({}, this.options.headers, + { HEADER_RANGE: HTTP_RANGE_UNIT + "=" + index + "-" + (index + length - 1) })); + if (response.status != 206) { + throw new Error(ERR_HTTP_RANGE); + } + return new Uint8Array(await response.arrayBuffer()); + } else { + if (!this.data) { + await getFetchData(this, this.options); + } + return new Uint8Array(this.data.subarray(index, index + length)); + } + } + } + + async function getFetchData(httpReader, options) { + const response = await sendFetchRequest(HTTP_METHOD_GET, httpReader.url, options); + httpReader.data = new Uint8Array(await response.arrayBuffer()); + if (!httpReader.size) { + httpReader.size = httpReader.data.length; + } + } + + async function sendFetchRequest(method, url, options, headers) { + headers = Object.assign({}, options.headers, headers); + const response = await fetch(url, Object.assign({}, options, { method, headers })); + if (response.status < 400) { + return response; + } else { + throw new Error(ERR_HTTP_STATUS + (response.statusText || response.status)); + } + } + + class XHRReader extends Reader { + + constructor(url, options) { + super(); + this.url = url; + this.preventHeadRequest = options.preventHeadRequest; + this.useRangeHeader = options.useRangeHeader; + this.forceRangeRequests = options.forceRangeRequests; + } + + async init() { + super.init(); + if (isHttpFamily(this.url) && !this.preventHeadRequest) { + return new Promise((resolve, reject) => sendXHR(HTTP_METHOD_HEAD, this.url, request => { + this.size = Number(request.getResponseHeader(HTTP_HEADER_CONTENT_LENGTH)); + if (this.useRangeHeader) { + if (this.forceRangeRequests || request.getResponseHeader(HTTP_HEADER_ACCEPT_RANGES) == HTTP_RANGE_UNIT) { + resolve(); + } else { + reject(new Error(ERR_HTTP_RANGE)); + } + } else if (this.size === undefined) { + getXHRData(this, this.url).then(() => resolve()).catch(reject); + } else { + resolve(); + } + }, reject)); + } else { + await getXHRData(this, this.url); + } + } + + async readUint8Array(index, length) { + if (this.useRangeHeader) { + const request = await new Promise((resolve, reject) => sendXHR(HTTP_METHOD_GET, this.url, request => resolve(new Uint8Array(request.response)), reject, + [[HTTP_HEADER_RANGE, HTTP_RANGE_UNIT + "=" + index + "-" + (index + length - 1)]])); + if (request.status != 206) { + throw new Error(ERR_HTTP_RANGE); + } + } else { + if (!this.data) { + await getXHRData(this, this.url); + } + return new Uint8Array(this.data.subarray(index, index + length)); + } + } + } + + function getXHRData(httpReader, url) { + return new Promise((resolve, reject) => sendXHR(HTTP_METHOD_GET, url, request => { + httpReader.data = new Uint8Array(request.response); + if (!httpReader.size) { + httpReader.size = httpReader.data.length; + } + resolve(); + }, reject)); + } + + function sendXHR(method, url, onload, onerror, headers = []) { + const request = new XMLHttpRequest(); + request.addEventListener("load", () => { + if (request.status < 400) { + onload(request); + } else { + onerror(ERR_HTTP_STATUS + (request.statusText || request.status)); + } + }, false); + request.addEventListener("error", onerror, false); + request.open(method, url); + headers.forEach(header => request.setRequestHeader(header[0], header[1])); + request.responseType = "arraybuffer"; + request.send(); + return request; + } + + class HttpReader extends Reader { + + constructor(url, options = {}) { + super(); + this.url = url; + if (options.useXHR) { + this.reader = new XHRReader(url, options); + } else { + this.reader = new FetchReader(url, options); + } + } + + set size(value) { + // ignored + } + + get size() { + return this.reader.size; + } + + async init() { + super.init(); + await this.reader.init(); + } + + async readUint8Array(index, length) { + return this.reader.readUint8Array(index, length); + } + } + + class HttpRangeReader extends HttpReader { + + constructor(url, options = {}) { + options.useRangeHeader = true; + super(url, options); + } + } + + + class Uint8ArrayReader extends Reader { + + constructor(array) { + super(); + this.array = array; + this.size = array.length; + } + + async readUint8Array(index, length) { + return this.array.slice(index, index + length); + } + } + + class Uint8ArrayWriter extends Writer { + + constructor() { + super(); + this.array = new Uint8Array(0); + } + + async writeUint8Array(array) { + super.writeUint8Array(array); + const previousArray = this.array; + this.array = new Uint8Array(previousArray.length + array.length); + this.array.set(previousArray); + this.array.set(array, previousArray.length); + } + + getData() { + return this.array; + } + } + + function isHttpFamily(url) { + if (typeof document != "undefined") { + const anchor = document.createElement("a"); + anchor.href = url; + return anchor.protocol == "http:" || anchor.protocol == "https:"; + } else { + return /^https?:\/\//i.test(url); + } + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const MAX_32_BITS = 0xffffffff; + const MAX_16_BITS = 0xffff; + const COMPRESSION_METHOD_DEFLATE = 0x08; + const COMPRESSION_METHOD_STORE = 0x00; + const COMPRESSION_METHOD_AES = 0x63; + + const LOCAL_FILE_HEADER_SIGNATURE = 0x04034b50; + const DATA_DESCRIPTOR_RECORD_SIGNATURE = 0x08074b50; + const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50; + const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50; + const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50; + const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50; + const END_OF_CENTRAL_DIR_LENGTH = 22; + const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20; + const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56; + const ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH = END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LENGTH; + + const ZIP64_TOTAL_NUMBER_OF_DISKS = 1; + + const EXTRAFIELD_TYPE_ZIP64 = 0x0001; + const EXTRAFIELD_TYPE_AES = 0x9901; + const EXTRAFIELD_TYPE_UNICODE_PATH = 0x7075; + const EXTRAFIELD_TYPE_UNICODE_COMMENT = 0x6375; + + const BITFLAG_ENCRYPTED = 0x01; + const BITFLAG_LEVEL = 0x06; + const BITFLAG_DATA_DESCRIPTOR = 0x0008; + const BITFLAG_LANG_ENCODING_FLAG = 0x0800; + const FILE_ATTR_MSDOS_DIR_MASK = 0x10; + + const VERSION_DEFLATE = 0x14; + const VERSION_ZIP64 = 0x2D; + const VERSION_AES = 0x33; + + const DIRECTORY_SIGNATURE = "/"; + + const MAX_DATE = new Date(2107, 11, 31); + const MIN_DATE = new Date(1980, 0, 1); + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split(""); + + var decodeCP437 = stringValue => { + let result = ""; + for (let indexCharacter = 0; indexCharacter < stringValue.length; indexCharacter++) { + result += CP437[stringValue[indexCharacter]]; + } + return result; + }; + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const table = []; + for (let i = 0; i < 256; i++) { + let t = i; + for (let j = 0; j < 8; j++) { + if (t & 1) { + t = (t >>> 1) ^ 0xEDB88320; + } else { + t = t >>> 1; + } + } + table[i] = t; + } + + class Crc32 { + + constructor(crc) { + this.crc = crc || -1; + } + + append(data) { + let crc = this.crc | 0; + for (let offset = 0, length = data.length | 0; offset < length; offset++) { + crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF]; + } + this.crc = crc; + } + + get() { + return ~this.crc; + } + } + + // Derived from https://github.com/xqdoo00o/jszip/blob/master/lib/sjcl.js + /*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */ + + /** @fileOverview Arrays of bits, encoded as arrays of Numbers. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** + * Arrays of bits, encoded as arrays of Numbers. + * @namespace + * @description + *

+ * These objects are the currency accepted by SJCL's crypto functions. + *

+ * + *

+ * Most of our crypto primitives operate on arrays of 4-byte words internally, + * but many of them can take arguments that are not a multiple of 4 bytes. + * This library encodes arrays of bits (whose size need not be a multiple of 8 + * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an + * array of words, 32 bits at a time. Since the words are double-precision + * floating point numbers, they fit some extra data. We use this (in a private, + * possibly-changing manner) to encode the number of bits actually present + * in the last word of the array. + *

+ * + *

+ * Because bitwise ops clear this out-of-band data, these arrays can be passed + * to ciphers like AES which want arrays of words. + *

+ */ + const bitArray = { + /** + * Concatenate two bit arrays. + * @param {bitArray} a1 The first array. + * @param {bitArray} a2 The second array. + * @return {bitArray} The concatenation of a1 and a2. + */ + concat(a1, a2) { + if (a1.length === 0 || a2.length === 0) { + return a1.concat(a2); + } + + const last = a1[a1.length - 1], shift = bitArray.getPartial(last); + if (shift === 32) { + return a1.concat(a2); + } else { + return bitArray._shiftRight(a2, shift, last | 0, a1.slice(0, a1.length - 1)); + } + }, + + /** + * Find the length of an array of bits. + * @param {bitArray} a The array. + * @return {Number} The length of a, in bits. + */ + bitLength(a) { + const l = a.length; + if (l === 0) { + return 0; + } + const x = a[l - 1]; + return (l - 1) * 32 + bitArray.getPartial(x); + }, + + /** + * Truncate an array. + * @param {bitArray} a The array. + * @param {Number} len The length to truncate to, in bits. + * @return {bitArray} A new array, truncated to len bits. + */ + clamp(a, len) { + if (a.length * 32 < len) { + return a; + } + a = a.slice(0, Math.ceil(len / 32)); + const l = a.length; + len = len & 31; + if (l > 0 && len) { + a[l - 1] = bitArray.partial(len, a[l - 1] & 0x80000000 >> (len - 1), 1); + } + return a; + }, + + /** + * Make a partial word for a bit array. + * @param {Number} len The number of bits in the word. + * @param {Number} x The bits. + * @param {Number} [_end=0] Pass 1 if x has already been shifted to the high side. + * @return {Number} The partial word. + */ + partial(len, x, _end) { + if (len === 32) { + return x; + } + return (_end ? x | 0 : x << (32 - len)) + len * 0x10000000000; + }, + + /** + * Get the number of bits used by a partial word. + * @param {Number} x The partial word. + * @return {Number} The number of bits used by the partial word. + */ + getPartial(x) { + return Math.round(x / 0x10000000000) || 32; + }, + + /** Shift an array right. + * @param {bitArray} a The array to shift. + * @param {Number} shift The number of bits to shift. + * @param {Number} [carry=0] A byte to carry in + * @param {bitArray} [out=[]] An array to prepend to the output. + * @private + */ + _shiftRight(a, shift, carry, out) { + if (out === undefined) { + out = []; + } + + for (; shift >= 32; shift -= 32) { + out.push(carry); + carry = 0; + } + if (shift === 0) { + return out.concat(a); + } + + for (let i = 0; i < a.length; i++) { + out.push(carry | a[i] >>> shift); + carry = a[i] << (32 - shift); + } + const last2 = a.length ? a[a.length - 1] : 0; + const shift2 = bitArray.getPartial(last2); + out.push(bitArray.partial(shift + shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(), 1)); + return out; + } + }; + + /** @fileOverview Bit array codec implementations. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** + * Arrays of bytes + * @namespace + */ + const codec = { + bytes: { + /** Convert from a bitArray to an array of bytes. */ + fromBits(arr) { + const bl = bitArray.bitLength(arr); + const byteLength = bl / 8; + const out = new Uint8Array(byteLength); + let tmp; + for (let i = 0; i < byteLength; i++) { + if ((i & 3) === 0) { + tmp = arr[i / 4]; + } + out[i] = tmp >>> 24; + tmp <<= 8; + } + return out; + }, + /** Convert from an array of bytes to a bitArray. */ + toBits(bytes) { + const out = []; + let i; + let tmp = 0; + for (i = 0; i < bytes.length; i++) { + tmp = tmp << 8 | bytes[i]; + if ((i & 3) === 3) { + out.push(tmp); + tmp = 0; + } + } + if (i & 3) { + out.push(bitArray.partial(8 * (i & 3), tmp)); + } + return out; + } + } + }; + + const hash = {}; + + /** + * Context for a SHA-1 operation in progress. + * @constructor + */ + hash.sha1 = function (hash) { + if (hash) { + this._h = hash._h.slice(0); + this._buffer = hash._buffer.slice(0); + this._length = hash._length; + } else { + this.reset(); + } + }; + + hash.sha1.prototype = { + /** + * The hash's block size, in bits. + * @constant + */ + blockSize: 512, + + /** + * Reset the hash state. + * @return this + */ + reset: function () { + const sha1 = this; + sha1._h = this._init.slice(0); + sha1._buffer = []; + sha1._length = 0; + return sha1; + }, + + /** + * Input several words to the hash. + * @param {bitArray|String} data the data to hash. + * @return this + */ + update: function (data) { + const sha1 = this; + if (typeof data === "string") { + data = codec.utf8String.toBits(data); + } + const b = sha1._buffer = bitArray.concat(sha1._buffer, data); + const ol = sha1._length; + const nl = sha1._length = ol + bitArray.bitLength(data); + if (nl > 9007199254740991) { + throw new Error("Cannot hash more than 2^53 - 1 bits"); + } + const c = new Uint32Array(b); + let j = 0; + for (let i = sha1.blockSize + ol - ((sha1.blockSize + ol) & (sha1.blockSize - 1)); i <= nl; + i += sha1.blockSize) { + sha1._block(c.subarray(16 * j, 16 * (j + 1))); + j += 1; + } + b.splice(0, 16 * j); + return sha1; + }, + + /** + * Complete hashing and output the hash value. + * @return {bitArray} The hash value, an array of 5 big-endian words. TODO + */ + finalize: function () { + const sha1 = this; + let b = sha1._buffer; + const h = sha1._h; + + // Round out and push the buffer + b = bitArray.concat(b, [bitArray.partial(1, 1)]); + // Round out the buffer to a multiple of 16 words, less the 2 length words. + for (let i = b.length + 2; i & 15; i++) { + b.push(0); + } + + // append the length + b.push(Math.floor(sha1._length / 0x100000000)); + b.push(sha1._length | 0); + + while (b.length) { + sha1._block(b.splice(0, 16)); + } + + sha1.reset(); + return h; + }, + + /** + * The SHA-1 initialization vector. + * @private + */ + _init: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0], + + /** + * The SHA-1 hash key. + * @private + */ + _key: [0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6], + + /** + * The SHA-1 logical functions f(0), f(1), ..., f(79). + * @private + */ + _f: function (t, b, c, d) { + if (t <= 19) { + return (b & c) | (~b & d); + } else if (t <= 39) { + return b ^ c ^ d; + } else if (t <= 59) { + return (b & c) | (b & d) | (c & d); + } else if (t <= 79) { + return b ^ c ^ d; + } + }, + + /** + * Circular left-shift operator. + * @private + */ + _S: function (n, x) { + return (x << n) | (x >>> 32 - n); + }, + + /** + * Perform one cycle of SHA-1. + * @param {Uint32Array|bitArray} words one block of words. + * @private + */ + _block: function (words) { + const sha1 = this; + const h = sha1._h; + // When words is passed to _block, it has 16 elements. SHA1 _block + // function extends words with new elements (at the end there are 80 elements). + // The problem is that if we use Uint32Array instead of Array, + // the length of Uint32Array cannot be changed. Thus, we replace words with a + // normal Array here. + const w = Array(80); // do not use Uint32Array here as the instantiation is slower + for (let j = 0; j < 16; j++) { + w[j] = words[j]; + } + + let a = h[0]; + let b = h[1]; + let c = h[2]; + let d = h[3]; + let e = h[4]; + + for (let t = 0; t <= 79; t++) { + if (t >= 16) { + w[t] = sha1._S(1, w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]); + } + const tmp = (sha1._S(5, a) + sha1._f(t, b, c, d) + e + w[t] + + sha1._key[Math.floor(t / 20)]) | 0; + e = d; + d = c; + c = sha1._S(30, b); + b = a; + a = tmp; + } + + h[0] = (h[0] + a) | 0; + h[1] = (h[1] + b) | 0; + h[2] = (h[2] + c) | 0; + h[3] = (h[3] + d) | 0; + h[4] = (h[4] + e) | 0; + } + }; + + /** @fileOverview Low-level AES implementation. + * + * This file contains a low-level implementation of AES, optimized for + * size and for efficiency on several browsers. It is based on + * OpenSSL's aes_core.c, a public-domain implementation by Vincent + * Rijmen, Antoon Bosselaers and Paulo Barreto. + * + * An older version of this implementation is available in the public + * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh, + * Stanford University 2008-2010 and BSD-licensed for liability + * reasons. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + const cipher = {}; + + /** + * Schedule out an AES key for both encryption and decryption. This + * is a low-level class. Use a cipher mode to do bulk encryption. + * + * @constructor + * @param {Array} key The key as an array of 4, 6 or 8 words. + */ + cipher.aes = class { + constructor(key) { + /** + * The expanded S-box and inverse S-box tables. These will be computed + * on the client so that we don't have to send them down the wire. + * + * There are two tables, _tables[0] is for encryption and + * _tables[1] is for decryption. + * + * The first 4 sub-tables are the expanded S-box with MixColumns. The + * last (_tables[01][4]) is the S-box itself. + * + * @private + */ + const aes = this; + aes._tables = [[[], [], [], [], []], [[], [], [], [], []]]; + + if (!aes._tables[0][0][0]) { + aes._precompute(); + } + + const sbox = aes._tables[0][4]; + const decTable = aes._tables[1]; + const keyLen = key.length; + + let i, encKey, decKey, rcon = 1; + + if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) { + throw new Error("invalid aes key size"); + } + + aes._key = [encKey = key.slice(0), decKey = []]; + + // schedule encryption keys + for (i = keyLen; i < 4 * keyLen + 28; i++) { + let tmp = encKey[i - 1]; + + // apply sbox + if (i % keyLen === 0 || (keyLen === 8 && i % keyLen === 4)) { + tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255]; + + // shift rows and add rcon + if (i % keyLen === 0) { + tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24; + rcon = rcon << 1 ^ (rcon >> 7) * 283; + } + } + + encKey[i] = encKey[i - keyLen] ^ tmp; + } + + // schedule decryption keys + for (let j = 0; i; j++, i--) { + const tmp = encKey[j & 3 ? i : i - 4]; + if (i <= 4 || j < 4) { + decKey[j] = tmp; + } else { + decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ + decTable[1][sbox[tmp >> 16 & 255]] ^ + decTable[2][sbox[tmp >> 8 & 255]] ^ + decTable[3][sbox[tmp & 255]]; + } + } + } + // public + /* Something like this might appear here eventually + name: "AES", + blockSize: 4, + keySizes: [4,6,8], + */ + + /** + * Encrypt an array of 4 big-endian words. + * @param {Array} data The plaintext. + * @return {Array} The ciphertext. + */ + encrypt(data) { + return this._crypt(data, 0); + } + + /** + * Decrypt an array of 4 big-endian words. + * @param {Array} data The ciphertext. + * @return {Array} The plaintext. + */ + decrypt(data) { + return this._crypt(data, 1); + } + + /** + * Expand the S-box tables. + * + * @private + */ + _precompute() { + const encTable = this._tables[0]; + const decTable = this._tables[1]; + const sbox = encTable[4]; + const sboxInv = decTable[4]; + const d = []; + const th = []; + let xInv, x2, x4, x8; + + // Compute double and third tables + for (let i = 0; i < 256; i++) { + th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i; + } + + for (let x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) { + // Compute sbox + let s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4; + s = s >> 8 ^ s & 255 ^ 99; + sbox[x] = s; + sboxInv[s] = x; + + // Compute MixColumns + x8 = d[x4 = d[x2 = d[x]]]; + let tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100; + let tEnc = d[s] * 0x101 ^ s * 0x1010100; + + for (let i = 0; i < 4; i++) { + encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8; + decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8; + } + } + + // Compactify. Considerable speedup on Firefox. + for (let i = 0; i < 5; i++) { + encTable[i] = encTable[i].slice(0); + decTable[i] = decTable[i].slice(0); + } + } + + /** + * Encryption and decryption core. + * @param {Array} input Four words to be encrypted or decrypted. + * @param dir The direction, 0 for encrypt and 1 for decrypt. + * @return {Array} The four encrypted or decrypted words. + * @private + */ + _crypt(input, dir) { + if (input.length !== 4) { + throw new Error("invalid aes block size"); + } + + const key = this._key[dir]; + + const nInnerRounds = key.length / 4 - 2; + const out = [0, 0, 0, 0]; + const table = this._tables[dir]; + + // load up the tables + const t0 = table[0]; + const t1 = table[1]; + const t2 = table[2]; + const t3 = table[3]; + const sbox = table[4]; + + // state variables a,b,c,d are loaded with pre-whitened data + let a = input[0] ^ key[0]; + let b = input[dir ? 3 : 1] ^ key[1]; + let c = input[2] ^ key[2]; + let d = input[dir ? 1 : 3] ^ key[3]; + let kIndex = 4; + let a2, b2, c2; + + // Inner rounds. Cribbed from OpenSSL. + for (let i = 0; i < nInnerRounds; i++) { + a2 = t0[a >>> 24] ^ t1[b >> 16 & 255] ^ t2[c >> 8 & 255] ^ t3[d & 255] ^ key[kIndex]; + b2 = t0[b >>> 24] ^ t1[c >> 16 & 255] ^ t2[d >> 8 & 255] ^ t3[a & 255] ^ key[kIndex + 1]; + c2 = t0[c >>> 24] ^ t1[d >> 16 & 255] ^ t2[a >> 8 & 255] ^ t3[b & 255] ^ key[kIndex + 2]; + d = t0[d >>> 24] ^ t1[a >> 16 & 255] ^ t2[b >> 8 & 255] ^ t3[c & 255] ^ key[kIndex + 3]; + kIndex += 4; + a = a2; b = b2; c = c2; + } + + // Last round. + for (let i = 0; i < 4; i++) { + out[dir ? 3 & -i : i] = + sbox[a >>> 24] << 24 ^ + sbox[b >> 16 & 255] << 16 ^ + sbox[c >> 8 & 255] << 8 ^ + sbox[d & 255] ^ + key[kIndex++]; + a2 = a; a = b; b = c; c = d; d = a2; + } + + return out; + } + }; + + /** @fileOverview CTR mode implementation. + * + * Special thanks to Roy Nicholson for pointing out a bug in our + * implementation. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** Brian Gladman's CTR Mode. + * @constructor + * @param {Object} _prf The aes instance to generate key. + * @param {bitArray} _iv The iv for ctr mode, it must be 128 bits. + */ + + const mode = {}; + + /** + * Brian Gladman's CTR Mode. + * @namespace + */ + mode.ctrGladman = class { + constructor(prf, iv) { + this._prf = prf; + this._initIv = iv; + this._iv = iv; + } + + reset() { + this._iv = this._initIv; + } + + /** Input some data to calculate. + * @param {bitArray} data the data to process, it must be intergral multiple of 128 bits unless it's the last. + */ + update(data) { + return this.calculate(this._prf, data, this._iv); + } + + incWord(word) { + if (((word >> 24) & 0xff) === 0xff) { //overflow + let b1 = (word >> 16) & 0xff; + let b2 = (word >> 8) & 0xff; + let b3 = word & 0xff; + + if (b1 === 0xff) { // overflow b1 + b1 = 0; + if (b2 === 0xff) { + b2 = 0; + if (b3 === 0xff) { + b3 = 0; + } else { + ++b3; + } + } else { + ++b2; + } + } else { + ++b1; + } + + word = 0; + word += (b1 << 16); + word += (b2 << 8); + word += b3; + } else { + word += (0x01 << 24); + } + return word; + } + + incCounter(counter) { + if ((counter[0] = this.incWord(counter[0])) === 0) { + // encr_data in fileenc.c from Dr Brian Gladman's counts only with DWORD j < 8 + counter[1] = this.incWord(counter[1]); + } + } + + calculate(prf, data, iv) { + let l; + if (!(l = data.length)) { + return []; + } + const bl = bitArray.bitLength(data); + for (let i = 0; i < l; i += 4) { + this.incCounter(iv); + const e = prf.encrypt(iv); + data[i] ^= e[0]; + data[i + 1] ^= e[1]; + data[i + 2] ^= e[2]; + data[i + 3] ^= e[3]; + } + return bitArray.clamp(data, bl); + } + }; + + + const misc = {}; + + /** @fileOverview HMAC implementation. + * + * @author Emily Stark + * @author Mike Hamburg + * @author Dan Boneh + */ + + /** HMAC with the specified hash function. + * @constructor + * @param {bitArray} key the key for HMAC. + * @param {Object} [Hash=hash.sha1] The hash function to use. + */ + misc.hmacSha1 = class { + + constructor(key) { + const hmac = this; + const Hash = hmac._hash = hash.sha1; + const exKey = [[], []]; + const bs = Hash.prototype.blockSize / 32; + hmac._baseHash = [new Hash(), new Hash()]; + + if (key.length > bs) { + key = Hash.hash(key); + } + + for (let i = 0; i < bs; i++) { + exKey[0][i] = key[i] ^ 0x36363636; + exKey[1][i] = key[i] ^ 0x5C5C5C5C; + } + + hmac._baseHash[0].update(exKey[0]); + hmac._baseHash[1].update(exKey[1]); + hmac._resultHash = new Hash(hmac._baseHash[0]); + } + reset() { + const hmac = this; + hmac._resultHash = new hmac._hash(hmac._baseHash[0]); + hmac._updated = false; + } + + update(data) { + const hmac = this; + hmac._updated = true; + hmac._resultHash.update(data); + } + + digest() { + const hmac = this; + const w = hmac._resultHash.finalize(); + const result = new (hmac._hash)(hmac._baseHash[1]).update(w).finalize(); + + hmac.reset(); + + return result; + } + }; + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const ERR_INVALID_PASSWORD = "Invalid pasword"; + const BLOCK_LENGTH = 16; + const RAW_FORMAT = "raw"; + const PBKDF2_ALGORITHM = { name: "PBKDF2" }; + const HASH_ALGORITHM = { name: "HMAC" }; + const HASH_FUNCTION = "SHA-1"; + const BASE_KEY_ALGORITHM = Object.assign({ hash: HASH_ALGORITHM }, PBKDF2_ALGORITHM); + const DERIVED_BITS_ALGORITHM = Object.assign({ iterations: 1000, hash: { name: HASH_FUNCTION } }, PBKDF2_ALGORITHM); + const DERIVED_BITS_USAGE = ["deriveBits"]; + const SALT_LENGTH = [8, 12, 16]; + const KEY_LENGTH = [16, 24, 32]; + const SIGNATURE_LENGTH = 10; + const COUNTER_DEFAULT_VALUE = [0, 0, 0, 0]; + const subtle = crypto.subtle; + const codecBytes = codec.bytes; + const Aes = cipher.aes; + const CtrGladman = mode.ctrGladman; + const HmacSha1 = misc.hmacSha1; + class AESDecrypt { + + constructor(password, signed, strength) { + Object.assign(this, { + password, + signed, + strength: strength - 1, + pendingInput: new Uint8Array(0) + }); + } + + async append(input) { + const aesCrypto = this; + if (aesCrypto.password) { + const preamble = subarray(input, 0, SALT_LENGTH[aesCrypto.strength] + 2); + await createDecryptionKeys(aesCrypto, preamble, aesCrypto.password); + aesCrypto.password = null; + aesCrypto.aesCtrGladman = new CtrGladman(new Aes(aesCrypto.keys.key), Array.from(COUNTER_DEFAULT_VALUE)); + aesCrypto.hmac = new HmacSha1(aesCrypto.keys.authentication); + input = subarray(input, SALT_LENGTH[aesCrypto.strength] + 2); + } + const output = new Uint8Array(input.length - SIGNATURE_LENGTH - ((input.length - SIGNATURE_LENGTH) % BLOCK_LENGTH)); + return append(aesCrypto, input, output, 0, SIGNATURE_LENGTH, true); + } + + async flush() { + const aesCrypto = this; + const pendingInput = aesCrypto.pendingInput; + const chunkToDecrypt = subarray(pendingInput, 0, pendingInput.length - SIGNATURE_LENGTH); + const originalSignature = subarray(pendingInput, pendingInput.length - SIGNATURE_LENGTH); + let decryptedChunkArray = new Uint8Array(0); + if (chunkToDecrypt.length) { + const encryptedChunk = codecBytes.toBits(chunkToDecrypt); + aesCrypto.hmac.update(encryptedChunk); + const decryptedChunk = aesCrypto.aesCtrGladman.update(encryptedChunk); + decryptedChunkArray = codecBytes.fromBits(decryptedChunk); + } + let valid = true; + if (aesCrypto.signed) { + const signature = subarray(codecBytes.fromBits(aesCrypto.hmac.digest()), 0, SIGNATURE_LENGTH); + for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) { + if (signature[indexSignature] != originalSignature[indexSignature]) { + valid = false; + } + } + } + return { + valid, + data: decryptedChunkArray + }; + } + } + + class AESEncrypt { + + constructor(password, strength) { + Object.assign(this, { + password, + strength: strength - 1, + pendingInput: new Uint8Array(0) + }); + } + + async append(input) { + const aesCrypto = this; + let preamble = new Uint8Array(0); + if (aesCrypto.password) { + preamble = await createEncryptionKeys(aesCrypto, aesCrypto.password); + aesCrypto.password = null; + aesCrypto.aesCtrGladman = new CtrGladman(new Aes(aesCrypto.keys.key), Array.from(COUNTER_DEFAULT_VALUE)); + aesCrypto.hmac = new HmacSha1(aesCrypto.keys.authentication); + } + const output = new Uint8Array(preamble.length + input.length - (input.length % BLOCK_LENGTH)); + output.set(preamble, 0); + return append(aesCrypto, input, output, preamble.length, 0); + } + + async flush() { + const aesCrypto = this; + let encryptedChunkArray = new Uint8Array(0); + if (aesCrypto.pendingInput.length) { + const encryptedChunk = aesCrypto.aesCtrGladman.update(codecBytes.toBits(aesCrypto.pendingInput)); + aesCrypto.hmac.update(encryptedChunk); + encryptedChunkArray = codecBytes.fromBits(encryptedChunk); + } + const signature = subarray(codecBytes.fromBits(aesCrypto.hmac.digest()), 0, SIGNATURE_LENGTH); + return { + data: concat(encryptedChunkArray, signature), + signature + }; + } + } + + function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) { + const inputLength = input.length - paddingEnd; + if (aesCrypto.pendingInput.length) { + input = concat(aesCrypto.pendingInput, input); + output = expand(output, inputLength - (inputLength % BLOCK_LENGTH)); + } + let offset; + for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) { + const inputChunk = codecBytes.toBits(subarray(input, offset, offset + BLOCK_LENGTH)); + if (verifySignature) { + aesCrypto.hmac.update(inputChunk); + } + const outputChunk = aesCrypto.aesCtrGladman.update(inputChunk); + if (!verifySignature) { + aesCrypto.hmac.update(outputChunk); + } + output.set(codecBytes.fromBits(outputChunk), offset + paddingStart); + } + aesCrypto.pendingInput = subarray(input, offset); + return output; + } + + async function createDecryptionKeys(decrypt, preambleArray, password) { + await createKeys$1(decrypt, password, subarray(preambleArray, 0, SALT_LENGTH[decrypt.strength])); + const passwordVerification = subarray(preambleArray, SALT_LENGTH[decrypt.strength]); + const passwordVerificationKey = decrypt.keys.passwordVerification; + if (passwordVerificationKey[0] != passwordVerification[0] || passwordVerificationKey[1] != passwordVerification[1]) { + throw new Error(ERR_INVALID_PASSWORD); + } + } + + async function createEncryptionKeys(encrypt, password) { + const salt = crypto.getRandomValues(new Uint8Array(SALT_LENGTH[encrypt.strength])); + await createKeys$1(encrypt, password, salt); + return concat(salt, encrypt.keys.passwordVerification); + } + + async function createKeys$1(target, password, salt) { + const encodedPassword = (new TextEncoder()).encode(password); + const basekey = await subtle.importKey(RAW_FORMAT, encodedPassword, BASE_KEY_ALGORITHM, false, DERIVED_BITS_USAGE); + const derivedBits = await subtle.deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM), basekey, 8 * ((KEY_LENGTH[target.strength] * 2) + 2)); + const compositeKey = new Uint8Array(derivedBits); + target.keys = { + key: codecBytes.toBits(subarray(compositeKey, 0, KEY_LENGTH[target.strength])), + authentication: codecBytes.toBits(subarray(compositeKey, KEY_LENGTH[target.strength], KEY_LENGTH[target.strength] * 2)), + passwordVerification: subarray(compositeKey, KEY_LENGTH[target.strength] * 2) + }; + } + + function concat(leftArray, rightArray) { + let array = leftArray; + if (leftArray.length + rightArray.length) { + array = new Uint8Array(leftArray.length + rightArray.length); + array.set(leftArray, 0); + array.set(rightArray, leftArray.length); + } + return array; + } + + function expand(inputArray, length) { + if (length && length > inputArray.length) { + const array = inputArray; + inputArray = new Uint8Array(length); + inputArray.set(array, 0); + } + return inputArray; + } + + function subarray(array, begin, end) { + return array.subarray(begin, end); + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const HEADER_LENGTH = 12; + + class ZipCryptoDecrypt { + + constructor(password, passwordVerification) { + const zipCrypto = this; + Object.assign(zipCrypto, { + password, + passwordVerification + }); + createKeys(zipCrypto, password); + } + + async append(input) { + const zipCrypto = this; + if (zipCrypto.password) { + const decryptedHeader = decrypt(zipCrypto, input.subarray(0, HEADER_LENGTH)); + zipCrypto.password = null; + if (decryptedHeader[HEADER_LENGTH - 1] != zipCrypto.passwordVerification) { + throw new Error(ERR_INVALID_PASSWORD); + } + input = input.subarray(HEADER_LENGTH); + } + return decrypt(zipCrypto, input); + } + + async flush() { + return { + valid: true, + data: new Uint8Array(0) + }; + } + } + + class ZipCryptoEncrypt { + + constructor(password, passwordVerification) { + const zipCrypto = this; + Object.assign(zipCrypto, { + password, + passwordVerification + }); + createKeys(zipCrypto, password); + } + + async append(input) { + const zipCrypto = this; + let output; + let offset; + if (zipCrypto.password) { + zipCrypto.password = null; + const header = crypto.getRandomValues(new Uint8Array(HEADER_LENGTH)); + header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification; + output = new Uint8Array(input.length + header.length); + output.set(encrypt(zipCrypto, header), 0); + offset = HEADER_LENGTH; + } else { + output = new Uint8Array(input.length); + offset = 0; + } + output.set(encrypt(zipCrypto, input), offset); + return output; + } + + async flush() { + return { + data: new Uint8Array(0) + }; + } + } + + function decrypt(target, input) { + const output = new Uint8Array(input.length); + for (let index = 0; index < input.length; index++) { + output[index] = getByte(target) ^ input[index]; + updateKeys(target, output[index]); + } + return output; + } + + function encrypt(target, input) { + const output = new Uint8Array(input.length); + for (let index = 0; index < input.length; index++) { + output[index] = getByte(target) ^ input[index]; + updateKeys(target, input[index]); + } + return output; + } + + function createKeys(target, password) { + target.keys = [0x12345678, 0x23456789, 0x34567890]; + target.crcKey0 = new Crc32(target.keys[0]); + target.crcKey2 = new Crc32(target.keys[2]); + for (let index = 0; index < password.length; index++) { + updateKeys(target, password.charCodeAt(index)); + } + } + + function updateKeys(target, byte) { + target.crcKey0.append([byte]); + target.keys[0] = ~target.crcKey0.get(); + target.keys[1] = getInt32(target.keys[1] + getInt8(target.keys[0])); + target.keys[1] = getInt32(Math.imul(target.keys[1], 134775813) + 1); + target.crcKey2.append([target.keys[1] >>> 24]); + target.keys[2] = ~target.crcKey2.get(); + } + + function getByte(target) { + const temp = target.keys[2] | 2; + return getInt8(Math.imul(temp, (temp ^ 1)) >>> 8); + } + + function getInt8(number) { + return number & 0xFF; + } + + function getInt32(number) { + return number & 0xFFFFFFFF; + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const CODEC_DEFLATE = "deflate"; + const CODEC_INFLATE = "inflate"; + const ERR_INVALID_SIGNATURE = "Invalid signature"; + + class Inflate { + + constructor(codecConstructor, { + signature, + password, + signed, + compressed, + zipCrypto, + passwordVerification, + encryptionStrength + }, { chunkSize }) { + const encrypted = Boolean(password); + Object.assign(this, { + signature, + encrypted, + signed, + compressed, + inflate: compressed && new codecConstructor({ chunkSize }), + crc32: signed && new Crc32(), + zipCrypto, + decrypt: encrypted && zipCrypto ? + new ZipCryptoDecrypt(password, passwordVerification) : + new AESDecrypt(password, signed, encryptionStrength) + }); + } + + async append(data) { + const codec = this; + if (codec.encrypted && data.length) { + data = await codec.decrypt.append(data); + } + if (codec.compressed && data.length) { + data = await codec.inflate.append(data); + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed && data.length) { + codec.crc32.append(data); + } + return data; + } + + async flush() { + const codec = this; + let signature; + let data = new Uint8Array(0); + if (codec.encrypted) { + const result = await codec.decrypt.flush(); + if (!result.valid) { + throw new Error(ERR_INVALID_SIGNATURE); + } + data = result.data; + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed) { + const dataViewSignature = new DataView(new Uint8Array(4).buffer); + signature = codec.crc32.get(); + dataViewSignature.setUint32(0, signature); + if (codec.cipher != dataViewSignature.getUint32(0, false)) { + throw new Error(ERR_INVALID_SIGNATURE); + } + } + if (codec.compressed) { + data = (await codec.inflate.append(data)) || new Uint8Array(0); + await codec.inflate.flush(); + } + return { data, signature }; + } + } + + class Deflate { + + constructor(codecConstructor, { + encrypted, + signed, + compressed, + level, + zipCrypto, + password, + passwordVerification, + encryptionStrength + }, { chunkSize }) { + Object.assign(this, { + encrypted, + signed, + compressed, + deflate: compressed && new codecConstructor({ level: level || 5, chunkSize }), + crc32: signed && new Crc32(), + zipCrypto, + encrypt: encrypted && zipCrypto ? + new ZipCryptoEncrypt(password, passwordVerification) : + new AESEncrypt(password, encryptionStrength) + }); + } + + async append(inputData) { + const codec = this; + let data = inputData; + if (codec.compressed && inputData.length) { + data = await codec.deflate.append(inputData); + } + if (codec.encrypted && data.length) { + data = await codec.encrypt.append(data); + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed && inputData.length) { + codec.crc32.append(inputData); + } + return data; + } + + async flush() { + const codec = this; + let signature; + let data = new Uint8Array(0); + if (codec.compressed) { + data = (await codec.deflate.flush()) || new Uint8Array(0); + } + if (codec.encrypted) { + data = await codec.encrypt.append(data); + const result = await codec.encrypt.flush(); + signature = result.signature; + const newData = new Uint8Array(data.length + result.data.length); + newData.set(data, 0); + newData.set(result.data, data.length); + data = newData; + } + if ((!codec.encrypted || codec.zipCrypto) && codec.signed) { + signature = codec.crc32.get(); + } + return { data, signature }; + } + } + + function createCodec$1(codecConstructor, options, config) { + if (options.codecType.startsWith(CODEC_DEFLATE)) { + return new Deflate(codecConstructor, options, config); + } else if (options.codecType.startsWith(CODEC_INFLATE)) { + return new Inflate(codecConstructor, options, config); + } + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const MESSAGE_INIT = "init"; + const MESSAGE_APPEND = "append"; + const MESSAGE_FLUSH = "flush"; + const MESSAGE_EVENT_TYPE = "message"; + + var getWorker = (workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts) => { + Object.assign(workerData, { + busy: true, + codecConstructor, + options: Object.assign({}, options), + scripts, + webWorker, + onTaskFinished() { + workerData.busy = false; + const terminateWorker = onTaskFinished(workerData); + if (terminateWorker && workerData.worker) { + workerData.worker.terminate(); + } + } + }); + return webWorker ? createWebWorkerInterface(workerData, config) : createWorkerInterface(workerData, config); + }; + + function createWorkerInterface(workerData, config) { + const interfaceCodec = createCodec$1(workerData.codecConstructor, workerData.options, config); + return { + async append(data) { + try { + return await interfaceCodec.append(data); + } catch (error) { + workerData.onTaskFinished(); + throw error; + } + }, + async flush() { + try { + return await interfaceCodec.flush(); + } finally { + workerData.onTaskFinished(); + } + } + }; + } + + function createWebWorkerInterface(workerData, config) { + let messageTask; + if (!workerData.interface) { + workerData.worker = new Worker(new URL(workerData.scripts[0], (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('zip-fs.js', document.baseURI).href)))); + workerData.worker.addEventListener(MESSAGE_EVENT_TYPE, onMessage, false); + workerData.interface = { + append(data) { + return initAndSendMessage({ type: MESSAGE_APPEND, data }); + }, + flush() { + return initAndSendMessage({ type: MESSAGE_FLUSH }); + } + }; + } + return workerData.interface; + + async function initAndSendMessage(message) { + if (!messageTask) { + const options = workerData.options; + const scripts = workerData.scripts.slice(1); + await sendMessage({ scripts, type: MESSAGE_INIT, options, config: { chunkSize: config.chunkSize } }); + } + return sendMessage(message); + } + + function sendMessage(message) { + const worker = workerData.worker; + const result = new Promise((resolve, reject) => messageTask = { resolve, reject }); + try { + if (message.data) { + try { + message.data = message.data.buffer; + worker.postMessage(message, [message.data]); + } catch (error) { + worker.postMessage(message); + } + } else { + worker.postMessage(message); + } + } catch (error) { + messageTask.reject(error); + messageTask = null; + workerData.onTaskFinished(); + } + return result; + } + + function onMessage(event) { + const message = event.data; + if (messageTask) { + const reponseError = message.error; + const type = message.type; + if (reponseError) { + const error = new Error(reponseError.message); + error.stack = reponseError.stack; + messageTask.reject(error); + messageTask = null; + workerData.onTaskFinished(); + } else if (type == MESSAGE_INIT || type == MESSAGE_FLUSH || type == MESSAGE_APPEND) { + const data = message.data; + if (type == MESSAGE_FLUSH) { + messageTask.resolve({ data: new Uint8Array(data), signature: message.signature }); + messageTask = null; + workerData.onTaskFinished(); + } else { + messageTask.resolve(data && new Uint8Array(data)); + } + } + } + } + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + let pool = []; + let pendingRequests = []; + + function createCodec(codecConstructor, options, config) { + const streamCopy = !options.compressed && !options.signed && !options.encrypted; + const webWorker = !streamCopy && (options.useWebWorkers || (options.useWebWorkers === undefined && config.useWebWorkers)); + const scripts = webWorker && config.workerScripts ? config.workerScripts[options.codecType] : []; + if (pool.length < config.maxWorkers) { + const workerData = {}; + pool.push(workerData); + return getWorker(workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts); + } else { + const workerData = pool.find(workerData => !workerData.busy); + if (workerData) { + return getWorker(workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts); + } else { + return new Promise(resolve => pendingRequests.push({ resolve, codecConstructor, options, webWorker, scripts })); + } + } + + function onTaskFinished(workerData) { + const finished = !pendingRequests.length; + if (finished) { + pool = pool.filter(data => data != workerData); + } else { + const [{ resolve, codecConstructor, options, webWorker, scripts }] = pendingRequests.splice(0, 1); + resolve(getWorker(workerData, codecConstructor, options, config, onTaskFinished, webWorker, scripts)); + } + return finished; + } + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const MINIMUM_CHUNK_SIZE = 64; + const ERR_ABORT = "Abort error"; + + async function processData(codec, reader, writer, offset, inputLength, config, options) { + const chunkSize = Math.max(config.chunkSize, MINIMUM_CHUNK_SIZE); + return processChunk(); + + async function processChunk(chunkOffset = 0, outputLength = 0) { + const signal = options.signal; + if (chunkOffset < inputLength) { + testAborted(signal); + const inputData = await reader.readUint8Array(chunkOffset + offset, Math.min(chunkSize, inputLength - chunkOffset)); + const chunkLength = inputData.length; + testAborted(signal); + const data = await codec.append(inputData); + testAborted(signal); + outputLength += await writeData(writer, data); + if (options.onprogress) { + try { + options.onprogress(chunkOffset + chunkLength, inputLength); + } catch (error) { + // ignored + } + } + return processChunk(chunkOffset + chunkSize, outputLength); + } else { + const result = await codec.flush(); + outputLength += await writeData(writer, result.data); + return { signature: result.signature, length: outputLength }; + } + } + } + + function testAborted(signal) { + if (signal && signal.aborted) { + throw new Error(ERR_ABORT); + } + } + + async function writeData(writer, data) { + if (data.length) { + await writer.writeUint8Array(data); + } + return data.length; + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const PROPERTY_NAMES = [ + "filename", "rawFilename", "directory", "encrypted", "compressedSize", "uncompressedSize", + "lastModDate", "rawLastModDate", "comment", "rawComment", "signature", "extraField", + "rawExtraField", "bitFlag", "extraFieldZip64", "extraFieldUnicodePath", "extraFieldUnicodeComment", + "extraFieldAES", "filenameUTF8", "commentUTF8", "offset", "zip64"]; + + class Entry { + + constructor(data) { + PROPERTY_NAMES.forEach(name => this[name] = data[name]); + } + + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const ERR_BAD_FORMAT = "File format is not recognized"; + const ERR_EOCDR_NOT_FOUND = "End of central directory not found"; + const ERR_EOCDR_ZIP64_NOT_FOUND = "End of Zip64 central directory not found"; + const ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = "End of Zip64 central directory locator not found"; + const ERR_CENTRAL_DIRECTORY_NOT_FOUND = "Central directory header not found"; + const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found"; + const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found"; + const ERR_ENCRYPTED = "File contains encrypted entry"; + const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported"; + const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported"; + const CHARSET_UTF8 = "utf-8"; + const ZIP64_PROPERTIES = ["uncompressedSize", "compressedSize", "offset"]; + + class ZipReader { + + constructor(reader, options = {}) { + Object.assign(this, { + reader, + options, + config: getConfiguration() + }); + } + + async getEntries(options = {}) { + const zipReader = this; + const reader = zipReader.reader; + if (!reader.initialized) { + await reader.init(); + } + if (reader.size < END_OF_CENTRAL_DIR_LENGTH) { + throw new Error(ERR_BAD_FORMAT); + } + const endOfDirectoryInfo = await seekSignature(reader, END_OF_CENTRAL_DIR_SIGNATURE, reader.size, END_OF_CENTRAL_DIR_LENGTH, MAX_16_BITS * 16); + if (!endOfDirectoryInfo) { + throw new Error(ERR_EOCDR_NOT_FOUND); + } + const endOfDirectoryView = getDataView$1(endOfDirectoryInfo); + let directoryDataLength = getUint32(endOfDirectoryView, 12); + let directoryDataOffset = getUint32(endOfDirectoryView, 16); + let filesLength = getUint16(endOfDirectoryView, 8); + let prependedDataLength = 0; + if (directoryDataOffset == MAX_32_BITS || filesLength == MAX_16_BITS) { + const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH); + const endOfDirectoryLocatorView = getDataView$1(endOfDirectoryLocatorArray); + if (getUint32(endOfDirectoryLocatorView, 0) != ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) { + throw new Error(ERR_EOCDR_ZIP64_NOT_FOUND); + } + directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8); + let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH); + let endOfDirectoryView = getDataView$1(endOfDirectoryArray); + const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH; + if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) { + const originalDirectoryDataOffset = directoryDataOffset; + directoryDataOffset = expectedDirectoryDataOffset; + prependedDataLength = directoryDataOffset - originalDirectoryDataOffset; + endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH); + endOfDirectoryView = getDataView$1(endOfDirectoryArray); + } + if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) { + throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND); + } + filesLength = getBigUint64(endOfDirectoryView, 24); + directoryDataLength = getUint32(endOfDirectoryLocatorView, 4); + directoryDataOffset -= getBigUint64(endOfDirectoryView, 40); + } + if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) { + throw new Error(ERR_BAD_FORMAT); + } + let offset = 0; + let directoryArray = await readUint8Array(reader, directoryDataOffset, reader.size - directoryDataOffset); + let directoryView = getDataView$1(directoryArray); + const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength; + if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) { + const originalDirectoryDataOffset = directoryDataOffset; + directoryDataOffset = expectedDirectoryDataOffset; + prependedDataLength = directoryDataOffset - originalDirectoryDataOffset; + directoryArray = await readUint8Array(reader, directoryDataOffset, reader.size - directoryDataOffset); + directoryView = getDataView$1(directoryArray); + } + if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) { + throw new Error(ERR_BAD_FORMAT); + } + const entries = []; + for (let indexFile = 0; indexFile < filesLength; indexFile++) { + const fileEntry = new ZipEntry$1(reader, zipReader.config, zipReader.options); + if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) { + throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND); + } + readCommonHeader(fileEntry, directoryView, offset + 6); + const languageEncodingFlag = Boolean(fileEntry.bitFlag.languageEncodingFlag); + const filenameOffset = offset + 46; + const extraFieldOffset = filenameOffset + fileEntry.filenameLength; + const commentOffset = extraFieldOffset + fileEntry.extraFieldLength; + Object.assign(fileEntry, { + compressedSize: 0, + uncompressedSize: 0, + commentLength: getUint16(directoryView, offset + 32), + directory: (getUint8(directoryView, offset + 38) & FILE_ATTR_MSDOS_DIR_MASK) == FILE_ATTR_MSDOS_DIR_MASK, + offset: getUint32(directoryView, offset + 42) + prependedDataLength, + rawFilename: directoryArray.subarray(filenameOffset, extraFieldOffset), + filenameUTF8: languageEncodingFlag, + commentUTF8: languageEncodingFlag, + rawExtraField: directoryArray.subarray(extraFieldOffset, commentOffset) + }); + const endOffset = commentOffset + fileEntry.commentLength; + fileEntry.rawComment = directoryArray.subarray(commentOffset, endOffset); + fileEntry.filename = decodeString(fileEntry.rawFilename, fileEntry.filenameUTF8 ? CHARSET_UTF8 : getOptionValue$1(zipReader, options, "filenameEncoding")); + fileEntry.comment = decodeString(fileEntry.rawComment, fileEntry.commentUTF8 ? CHARSET_UTF8 : getOptionValue$1(zipReader, options, "commentEncoding")); + if (!fileEntry.directory && fileEntry.filename.endsWith(DIRECTORY_SIGNATURE)) { + fileEntry.directory = true; + } + readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6); + const entry = new Entry(fileEntry); + entry.getData = (writer, options) => fileEntry.getData(writer, options); + entries.push(entry); + offset = endOffset; + } + return entries; + } + + async close() { + } + } + + class ZipEntry$1 { + + constructor(reader, config, options) { + Object.assign(this, { + reader, + config, + options + }); + } + + async getData(writer, options = {}) { + const zipEntry = this; + const { + reader, + offset, + extraFieldAES, + compressionMethod, + config, + bitFlag, + signature, + rawLastModDate, + compressedSize + } = zipEntry; + const localDirectory = zipEntry.localDirectory = {}; + if (!reader.initialized) { + await reader.init(); + } + const dataArray = await readUint8Array(reader, offset, 30); + const dataView = getDataView$1(dataArray); + let password = getOptionValue$1(zipEntry, options, "password"); + password = password && password.length && password; + if (extraFieldAES) { + if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) { + throw new Error(ERR_UNSUPPORTED_COMPRESSION); + } + } + if (compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE) { + throw new Error(ERR_UNSUPPORTED_COMPRESSION); + } + if (getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) { + throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND); + } + readCommonHeader(localDirectory, dataView, 4); + const extraFieldOffset = offset + 30 + localDirectory.filenameLength; + const dataOffset = extraFieldOffset + localDirectory.extraFieldLength; + localDirectory.rawExtraField = dataArray.subarray(extraFieldOffset, dataOffset); + readCommonFooter(zipEntry, localDirectory, dataView, 4); + const encrypted = zipEntry.encrypted && localDirectory.encrypted; + const zipCrypto = encrypted && !extraFieldAES; + if (encrypted) { + if (!zipCrypto && extraFieldAES.strength === undefined) { + throw new Error(ERR_UNSUPPORTED_ENCRYPTION); + } else if (!password) { + throw new Error(ERR_ENCRYPTED); + } + } + const codec = await createCodec(config.Inflate, { + codecType: CODEC_INFLATE, + password, + zipCrypto, + encryptionStrength: extraFieldAES && extraFieldAES.strength, + signed: getOptionValue$1(zipEntry, options, "checkSignature"), + passwordVerification: zipCrypto && (bitFlag.dataDescriptor ? ((rawLastModDate >>> 8) & 0xFF) : ((signature >>> 24) & 0xFF)), + signature, + compressed: compressionMethod != 0, + encrypted, + useWebWorkers: getOptionValue$1(zipEntry, options, "useWebWorkers") + }, config); + if (!writer.initialized) { + await writer.init(); + } + const signal = getOptionValue$1(zipEntry, options, "signal"); + await processData(codec, reader, writer, dataOffset, compressedSize, config, { onprogress: options.onprogress, signal }); + return writer.getData(); + } + } + + function readCommonHeader(directory, dataView, offset) { + const rawBitFlag = directory.rawBitFlag = getUint16(dataView, offset + 2); + const encrypted = (rawBitFlag & BITFLAG_ENCRYPTED) == BITFLAG_ENCRYPTED; + Object.assign(directory, { + encrypted, + version: getUint16(dataView, offset), + bitFlag: { + level: (rawBitFlag & BITFLAG_LEVEL) >> 1, + dataDescriptor: (rawBitFlag & BITFLAG_DATA_DESCRIPTOR) == BITFLAG_DATA_DESCRIPTOR, + languageEncodingFlag: (rawBitFlag & BITFLAG_LANG_ENCODING_FLAG) == BITFLAG_LANG_ENCODING_FLAG + }, + rawLastModDate: getUint32(dataView, offset + 6), + lastModDate: getDate(directory.rawLastModDate), + filenameLength: getUint16(dataView, offset + 22), + extraFieldLength: getUint16(dataView, offset + 24) + }); + } + + function readCommonFooter(fileEntry, directory, dataView, offset) { + const rawExtraField = directory.rawExtraField; + const extraField = directory.extraField = new Map(); + const rawExtraFieldView = getDataView$1(new Uint8Array(rawExtraField)); + let offsetExtraField = 0; + try { + while (offsetExtraField < rawExtraField.length) { + const type = getUint16(rawExtraFieldView, offsetExtraField); + const size = getUint16(rawExtraFieldView, offsetExtraField + 2); + extraField.set(type, { + type, + data: rawExtraField.slice(offsetExtraField + 4, offsetExtraField + 4 + size) + }); + offsetExtraField += 4 + size; + } + } catch (error) { + // ignored + } + const compressionMethod = getUint16(dataView, offset + 4); + directory.signature = getUint32(dataView, offset + 10); + directory.uncompressedSize = getUint32(dataView, offset + 18); + directory.compressedSize = getUint32(dataView, offset + 14); + const extraFieldZip64 = directory.extraFieldZip64 = extraField.get(EXTRAFIELD_TYPE_ZIP64); + if (extraFieldZip64) { + readExtraFieldZip64(extraFieldZip64, directory); + } + const extraFieldUnicodePath = directory.extraFieldUnicodePath = extraField.get(EXTRAFIELD_TYPE_UNICODE_PATH); + if (extraFieldUnicodePath) { + readExtraFieldUnicode(extraFieldUnicodePath, "filename", "rawFilename", directory, fileEntry); + } + const extraFieldUnicodeComment = directory.extraFieldUnicodeComment = extraField.get(EXTRAFIELD_TYPE_UNICODE_COMMENT); + if (extraFieldUnicodeComment) { + readExtraFieldUnicode(extraFieldUnicodeComment, "comment", "rawComment", directory, fileEntry); + } + const extraFieldAES = directory.extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES); + if (extraFieldAES) { + readExtraFieldAES(extraFieldAES, directory, compressionMethod); + } else { + directory.compressionMethod = compressionMethod; + } + } + + function readExtraFieldZip64(extraFieldZip64, directory) { + directory.zip64 = true; + const extraFieldView = getDataView$1(extraFieldZip64.data); + extraFieldZip64.values = []; + for (let indexValue = 0; indexValue < Math.floor(extraFieldZip64.data.length / 8); indexValue++) { + extraFieldZip64.values.push(getBigUint64(extraFieldView, 0 + indexValue * 8)); + } + const missingProperties = ZIP64_PROPERTIES.filter(propertyName => directory[propertyName] == MAX_32_BITS); + for (let indexMissingProperty = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) { + extraFieldZip64[missingProperties[indexMissingProperty]] = extraFieldZip64.values[indexMissingProperty]; + } + ZIP64_PROPERTIES.forEach(propertyName => { + if (directory[propertyName] == MAX_32_BITS) { + if (extraFieldZip64 && extraFieldZip64[propertyName] !== undefined) { + directory[propertyName] = extraFieldZip64[propertyName]; + } else { + throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND); + } + } + }); + } + + function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) { + const extraFieldView = getDataView$1(extraFieldUnicode.data); + extraFieldUnicode.version = getUint8(extraFieldView, 0); + extraFieldUnicode.signature = getUint32(extraFieldView, 1); + const crc32 = new Crc32(); + crc32.append(fileEntry[rawPropertyName]); + const dataViewSignature = getDataView$1(new Uint8Array(4)); + dataViewSignature.setUint32(0, crc32.get(), true); + extraFieldUnicode[propertyName] = (new TextDecoder()).decode(extraFieldUnicode.data.subarray(5)); + extraFieldUnicode.valid = !fileEntry.bitFlag.languageEncodingFlag && extraFieldUnicode.signature == getUint32(dataViewSignature, 0); + if (extraFieldUnicode.valid) { + directory[propertyName] = extraFieldUnicode[propertyName]; + directory[propertyName + "UTF8"] = true; + } + } + + function readExtraFieldAES(extraFieldAES, directory, compressionMethod) { + if (extraFieldAES) { + const extraFieldView = getDataView$1(extraFieldAES.data); + extraFieldAES.vendorVersion = getUint8(extraFieldView, 0); + extraFieldAES.vendorId = getUint8(extraFieldView, 2); + const strength = getUint8(extraFieldView, 4); + extraFieldAES.strength = strength; + extraFieldAES.originalCompressionMethod = compressionMethod; + directory.compressionMethod = extraFieldAES.compressionMethod = getUint16(extraFieldView, 5); + } else { + directory.compressionMethod = compressionMethod; + } + } + + async function seekSignature(reader, signature, startOffset, minimumBytes, maximumLength) { + const signatureArray = new Uint8Array(4); + const signatureView = getDataView$1(signatureArray); + setUint32$1(signatureView, 0, signature); + const maximumBytes = minimumBytes + maximumLength; + return (await seek(minimumBytes)) || await seek(Math.min(maximumBytes, startOffset)); + + async function seek(length) { + const offset = startOffset - length; + const bytes = await readUint8Array(reader, offset, length); + for (let indexByte = bytes.length - minimumBytes; indexByte >= 0; indexByte--) { + if (bytes[indexByte] == signatureArray[0] && bytes[indexByte + 1] == signatureArray[1] && + bytes[indexByte + 2] == signatureArray[2] && bytes[indexByte + 3] == signatureArray[3]) { + return { + offset: offset + indexByte, + buffer: bytes.slice(indexByte, indexByte + minimumBytes).buffer + }; + } + } + } + } + + function getOptionValue$1(zipReader, options, name) { + return options[name] === undefined ? zipReader.options[name] : options[name]; + } + + function decodeString(value, encoding) { + if (!encoding || encoding.trim().toLowerCase() == "cp437") { + return decodeCP437(value); + } else { + return (new TextDecoder(encoding)).decode(value); + } + } + + function getDate(timeRaw) { + const date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff; + try { + return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, (time & 0x001F) * 2, 0); + } catch (error) { + // ignored + } + } + + function getUint8(view, offset) { + return view.getUint8(offset); + } + + function getUint16(view, offset) { + return view.getUint16(offset, true); + } + + function getUint32(view, offset) { + return view.getUint32(offset, true); + } + + function getBigUint64(view, offset) { + return Number(view.getBigUint64(offset, true)); + } + + function setUint32$1(view, offset, value) { + view.setUint32(offset, value, true); + } + + function getDataView$1(array) { + return new DataView(array.buffer); + } + + function readUint8Array(reader, offset, size) { + return reader.readUint8Array(offset, size); + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const ERR_DUPLICATED_NAME = "File already exists"; + const ERR_INVALID_COMMENT = "Zip file comment exceeds 64KB"; + const ERR_INVALID_ENTRY_COMMENT = "File entry comment exceeds 64KB"; + const ERR_INVALID_ENTRY_NAME = "File entry name exceeds 64KB"; + const ERR_INVALID_VERSION = "Version exceeds 65535"; + const ERR_INVALID_DATE = "The modification date must be between 1/1/1980 and 12/31/2107"; + const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3"; + const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535"; + const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB"; + + const EXTRAFIELD_DATA_AES = new Uint8Array([0x07, 0x00, 0x02, 0x00, 0x41, 0x45, 0x03, 0x00, 0x00]); + const EXTRAFIELD_LENGTH_ZIP64 = 24; + + class ZipWriter { + + constructor(writer, options = {}) { + Object.assign(this, { + writer, + options, + config: getConfiguration(), + files: new Map(), + offset: writer.size, + pendingOutputSize: 0 + }); + } + + async add(name = "", reader, options = {}) { + const zipWriter = this; + name = name.trim(); + if (options.directory && (!name.endsWith(DIRECTORY_SIGNATURE))) { + name += DIRECTORY_SIGNATURE; + } else { + options.directory = name.endsWith(DIRECTORY_SIGNATURE); + } + if (zipWriter.files.has(name)) { + throw new Error(ERR_DUPLICATED_NAME); + } + const rawFilename = (new TextEncoder()).encode(name); + if (rawFilename.length > MAX_16_BITS) { + throw new Error(ERR_INVALID_ENTRY_NAME); + } + const comment = options.comment || ""; + const rawComment = (new TextEncoder()).encode(comment); + if (rawComment.length > MAX_16_BITS) { + throw new Error(ERR_INVALID_ENTRY_COMMENT); + } + const version = zipWriter.options.version || options.version || 0; + if (version > MAX_16_BITS) { + throw new Error(ERR_INVALID_VERSION); + } + const lastModDate = options.lastModDate || new Date(); + if (lastModDate < MIN_DATE || lastModDate > MAX_DATE) { + throw new Error(ERR_INVALID_DATE); + } + const password = getOptionValue(zipWriter, options, "password"); + const encryptionStrength = getOptionValue(zipWriter, options, "encryptionStrength") || 3; + const zipCrypto = getOptionValue(zipWriter, options, "zipCrypto"); + if (password !== undefined && encryptionStrength !== undefined && (encryptionStrength < 1 || encryptionStrength > 3)) { + throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH); + } + let rawExtraField = new Uint8Array(0); + const extraField = options.extraField; + if (extraField) { + let extraFieldSize = 0; + let offset = 0; + extraField.forEach(data => extraFieldSize += 4 + data.length); + rawExtraField = new Uint8Array(extraFieldSize); + extraField.forEach((data, type) => { + if (type > MAX_16_BITS) { + throw new Error(ERR_INVALID_EXTRAFIELD_TYPE); + } + if (data.length > MAX_16_BITS) { + throw new Error(ERR_INVALID_EXTRAFIELD_DATA); + } + arraySet(rawExtraField, new Uint16Array([type]), offset); + arraySet(rawExtraField, new Uint16Array([data.length]), offset + 2); + arraySet(rawExtraField, data, offset + 4); + offset += 4 + data.length; + }); + } + let zip64 = false; + let outputSize = 0; + const zip64Enabled = reader && options.zip64 !== false && zipWriter.options.zip64 !== false; + if (zip64Enabled) { + zip64 = options.zip64 || zipWriter.options.zip64; + if (!zip64) { + if (!reader.initialized) { + await reader.init(); + } + outputSize = Math.floor(reader.size * 1.05); + zipWriter.pendingOutputSize += outputSize; + zip64 = zipWriter.offset >= MAX_32_BITS || outputSize >= MAX_32_BITS || zipWriter.offset + zipWriter.pendingOutputSize >= MAX_32_BITS; + await Promise.resolve(); + } + } + const level = getOptionValue(zipWriter, options, "level"); + const useWebWorkers = getOptionValue(zipWriter, options, "useWebWorkers"); + const bufferedWrite = getOptionValue(zipWriter, options, "bufferedWrite"); + let keepOrder = getOptionValue(zipWriter, options, "keepOrder"); + let dataDescriptor = getOptionValue(zipWriter, options, "dataDescriptor"); + const signal = getOptionValue(zipWriter, options, "signal"); + if (dataDescriptor === undefined) { + dataDescriptor = true; + } + if (keepOrder === undefined) { + keepOrder = true; + } + const fileEntry = await addFile(zipWriter, name, reader, Object.assign({}, options, { + rawFilename, + rawComment, + version, + lastModDate, + rawExtraField, + zip64, + password, + level, + useWebWorkers, + encryptionStrength, + zipCrypto, + bufferedWrite, + keepOrder, + dataDescriptor, + signal + })); + if (zip64Enabled) { + zipWriter.pendingOutputSize -= outputSize; + } + Object.assign(fileEntry, { name, comment, extraField }); + return new Entry(fileEntry); + } + + async close(comment = new Uint8Array(0)) { + const zipWriter = this; + const writer = zipWriter.writer; + const files = zipWriter.files; + let offset = 0; + let directoryDataLength = 0; + let directoryOffset = zipWriter.offset; + let filesLength = files.size; + for (const [, fileEntry] of files) { + directoryDataLength += 46 + + fileEntry.rawFilename.length + + fileEntry.rawComment.length + + fileEntry.rawExtraFieldZip64.length + + fileEntry.rawExtraFieldAES.length + + fileEntry.rawExtraField.length; + } + const zip64 = zipWriter.options.zip64 || directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || filesLength >= MAX_16_BITS; + const directoryArray = new Uint8Array(directoryDataLength + (zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH)); + const directoryView = getDataView(directoryArray); + if (comment.length) { + if (comment.length <= MAX_16_BITS) { + setUint16(directoryView, offset + 20, comment.length); + } else { + throw new Error(ERR_INVALID_COMMENT); + } + } + for (const [, fileEntry] of files) { + const { + rawFilename, + rawExtraFieldZip64, + rawExtraFieldAES, + rawExtraField, + rawComment, + version, + headerArray, + directory, + zip64 + } = fileEntry; + const extraFieldLength = rawExtraFieldZip64.length + rawExtraFieldAES.length + rawExtraField.length; + setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE); + setUint16(directoryView, offset + 4, version); + arraySet(directoryArray, headerArray, offset + 6); + setUint16(directoryView, offset + 30, extraFieldLength); + setUint16(directoryView, offset + 32, rawComment.length); + if (directory) { + setUint8(directoryView, offset + 38, FILE_ATTR_MSDOS_DIR_MASK); + } + if (zip64) { + setUint32(directoryView, offset + 42, MAX_32_BITS); + } else { + setUint32(directoryView, offset + 42, fileEntry.offset); + } + arraySet(directoryArray, rawFilename, offset + 46); + arraySet(directoryArray, rawExtraFieldZip64, offset + 46 + rawFilename.length); + arraySet(directoryArray, rawExtraFieldAES, offset + 46 + rawFilename.length + rawExtraFieldZip64.length); + arraySet(directoryArray, rawExtraField, 46 + rawFilename.length + rawExtraFieldZip64.length + rawExtraFieldAES.length); + arraySet(directoryArray, rawComment, offset + 46 + rawFilename.length + extraFieldLength); + offset += 46 + rawFilename.length + extraFieldLength + rawComment.length; + } + if (zip64) { + setUint32(directoryView, offset, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE); + setBigUint64(directoryView, offset + 4, BigInt(44)); + setUint16(directoryView, offset + 12, 45); + setUint16(directoryView, offset + 14, 45); + setBigUint64(directoryView, offset + 24, BigInt(filesLength)); + setBigUint64(directoryView, offset + 32, BigInt(filesLength)); + setBigUint64(directoryView, offset + 40, BigInt(directoryDataLength)); + setBigUint64(directoryView, offset + 48, BigInt(directoryOffset)); + setUint32(directoryView, offset + 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE); + setBigUint64(directoryView, offset + 64, BigInt(directoryOffset) + BigInt(directoryDataLength)); + setUint32(directoryView, offset + 72, ZIP64_TOTAL_NUMBER_OF_DISKS); + filesLength = MAX_16_BITS; + directoryOffset = MAX_32_BITS; + directoryDataLength = MAX_32_BITS; + offset += 76; + } + setUint32(directoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE); + setUint16(directoryView, offset + 8, filesLength); + setUint16(directoryView, offset + 10, filesLength); + setUint32(directoryView, offset + 12, directoryDataLength); + setUint32(directoryView, offset + 16, directoryOffset); + await writer.writeUint8Array(directoryArray); + if (comment.length) { + await writer.writeUint8Array(comment); + } + return writer.getData(); + } + } + + async function addFile(zipWriter, name, reader, options) { + const files = zipWriter.files; + const writer = zipWriter.writer; + files.set(name, null); + let resolveLockWrite; + let resolveLockPreviousFile; + try { + let lockPreviousFile; + let fileWriter; + let fileEntry; + try { + if (options.keepOrder) { + lockPreviousFile = zipWriter.lockPreviousFile; + zipWriter.lockPreviousFile = new Promise(resolve => resolveLockPreviousFile = resolve); + } + if (options.bufferedWrite || zipWriter.lockWrite || !options.dataDescriptor) { + fileWriter = new BlobWriter(); + fileWriter.init(); + } else { + zipWriter.lockWrite = new Promise(resolve => resolveLockWrite = resolve); + if (!writer.initialized) { + await writer.init(); + } + fileWriter = writer; + } + fileEntry = await createFileEntry(reader, fileWriter, zipWriter.config, options); + } catch (error) { + files.delete(name); + throw error; + } + files.set(name, fileEntry); + if (fileWriter != writer) { + const blob = fileWriter.getData(); + const fileReader = new FileReader(); + const arrayBufferPromise = new Promise((resolve, reject) => { + fileReader.onload = event => resolve(event.target.result); + fileReader.onerror = reject; + fileReader.readAsArrayBuffer(blob); + }); + const [arrayBuffer] = await Promise.all([arrayBufferPromise, zipWriter.lockWrite, lockPreviousFile]); + if (!options.dataDescriptor) { + const arrayBufferView = new DataView(arrayBuffer); + if (!fileEntry.encrypted || options.zipCrypto) { + setUint32(arrayBufferView, 14, fileEntry.signature); + } + if (fileEntry.zip64) { + setUint32(arrayBufferView, 18, MAX_32_BITS); + setUint32(arrayBufferView, 22, MAX_32_BITS); + } else { + setUint32(arrayBufferView, 18, fileEntry.compressedSize); + setUint32(arrayBufferView, 22, fileEntry.uncompressedSize); + } + } + await writer.writeUint8Array(new Uint8Array(arrayBuffer)); + } + fileEntry.offset = zipWriter.offset; + if (fileEntry.zip64) { + const rawExtraFieldZip64View = getDataView(fileEntry.rawExtraFieldZip64); + setBigUint64(rawExtraFieldZip64View, 20, BigInt(fileEntry.offset)); + } + zipWriter.offset += fileEntry.length; + return fileEntry; + } finally { + if (resolveLockPreviousFile) { + resolveLockPreviousFile(); + } + if (resolveLockWrite) { + resolveLockWrite(); + } + } + } + + async function createFileEntry(reader, writer, config, options) { + const { + rawFilename, + lastModDate, + password, + level, + zip64, + zipCrypto, + dataDescriptor, + directory, + version, + rawComment, + rawExtraField, + useWebWorkers, + onprogress, + signal, + encryptionStrength + } = options; + const encrypted = Boolean(password && password.length); + const compressed = level !== 0 && !directory; + let rawExtraFieldAES; + if (encrypted && !zipCrypto) { + rawExtraFieldAES = new Uint8Array(EXTRAFIELD_DATA_AES.length + 2); + const extraFieldAESView = getDataView(rawExtraFieldAES); + setUint16(extraFieldAESView, 0, EXTRAFIELD_TYPE_AES); + arraySet(rawExtraFieldAES, EXTRAFIELD_DATA_AES, 2); + setUint8(extraFieldAESView, 8, encryptionStrength); + } else { + rawExtraFieldAES = new Uint8Array(0); + } + const fileEntry = { + version: version || VERSION_DEFLATE, + zip64, + directory: Boolean(directory), + filenameUTF8: true, + rawFilename, + commentUTF8: true, + rawComment, + rawExtraFieldZip64: zip64 ? new Uint8Array(EXTRAFIELD_LENGTH_ZIP64 + 4) : new Uint8Array(0), + rawExtraFieldAES, + rawExtraField + }; + let bitFlag = BITFLAG_LANG_ENCODING_FLAG; + if (dataDescriptor) { + bitFlag = bitFlag | BITFLAG_DATA_DESCRIPTOR; + } + let compressionMethod = COMPRESSION_METHOD_STORE; + if (compressed) { + compressionMethod = COMPRESSION_METHOD_DEFLATE; + } + if (zip64) { + fileEntry.version = fileEntry.version > VERSION_ZIP64 ? fileEntry.version : VERSION_ZIP64; + } + if (encrypted) { + bitFlag = bitFlag | BITFLAG_ENCRYPTED; + if (!zipCrypto) { + fileEntry.version = fileEntry.version > VERSION_AES ? fileEntry.version : VERSION_AES; + compressionMethod = COMPRESSION_METHOD_AES; + if (compressed) { + fileEntry.rawExtraFieldAES[9] = COMPRESSION_METHOD_DEFLATE; + } + } + } + const headerArray = fileEntry.headerArray = new Uint8Array(26); + const headerView = getDataView(headerArray); + setUint16(headerView, 0, fileEntry.version); + setUint16(headerView, 2, bitFlag); + setUint16(headerView, 4, compressionMethod); + const dateArray = new Uint32Array(1); + const dateView = getDataView(dateArray); + setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2); + setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate()); + const rawLastModDate = dateArray[0]; + setUint32(headerView, 6, rawLastModDate); + setUint16(headerView, 22, rawFilename.length); + setUint16(headerView, 24, 0); + setUint16(headerView, 24, rawExtraFieldAES.length + fileEntry.rawExtraField.length); + const localHeaderArray = new Uint8Array(30 + rawFilename.length + rawExtraFieldAES.length + fileEntry.rawExtraField.length); + const localHeaderView = getDataView(localHeaderArray); + setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE); + arraySet(localHeaderArray, headerArray, 4); + arraySet(localHeaderArray, rawFilename, 30); + arraySet(localHeaderArray, rawExtraFieldAES, 30 + rawFilename.length); + arraySet(localHeaderArray, fileEntry.rawExtraField, 30 + rawFilename.length + rawExtraFieldAES.length); + let result; + let uncompressedSize = 0; + let compressedSize = 0; + if (reader) { + uncompressedSize = reader.size; + const codec = await createCodec(config.Deflate, { + codecType: CODEC_DEFLATE, + level, + password, + encryptionStrength, + zipCrypto: encrypted && zipCrypto, + passwordVerification: encrypted && zipCrypto && (rawLastModDate >> 8) & 0xFF, + signed: true, + compressed, + encrypted, + useWebWorkers + }, config); + await writer.writeUint8Array(localHeaderArray); + if (!reader.initialized) { + await reader.init(); + } + result = await processData(codec, reader, writer, 0, uncompressedSize, config, { onprogress, signal }); + compressedSize = result.length; + } else { + await writer.writeUint8Array(localHeaderArray); + } + let dataDescriptorArray = new Uint8Array(0); + let dataDescriptorView; + if (dataDescriptor) { + dataDescriptorArray = new Uint8Array(zip64 ? 24 : 16); + dataDescriptorView = getDataView(dataDescriptorArray); + setUint32(dataDescriptorView, 0, DATA_DESCRIPTOR_RECORD_SIGNATURE); + } + if (reader) { + const signature = result.signature; + if ((!encrypted || zipCrypto) && signature !== undefined) { + setUint32(headerView, 10, signature); + fileEntry.signature = signature; + if (dataDescriptor) { + setUint32(dataDescriptorView, 4, signature); + } + } + if (zip64) { + const rawExtraFieldZip64View = getDataView(fileEntry.rawExtraFieldZip64); + setUint16(rawExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64); + setUint16(rawExtraFieldZip64View, 2, EXTRAFIELD_LENGTH_ZIP64); + setUint32(headerView, 14, MAX_32_BITS); + setBigUint64(rawExtraFieldZip64View, 12, BigInt(compressedSize)); + setUint32(headerView, 18, MAX_32_BITS); + setBigUint64(rawExtraFieldZip64View, 4, BigInt(uncompressedSize)); + if (dataDescriptor) { + setBigUint64(dataDescriptorView, 8, BigInt(compressedSize)); + setBigUint64(dataDescriptorView, 16, BigInt(uncompressedSize)); + } + } else { + setUint32(headerView, 14, compressedSize); + setUint32(headerView, 18, uncompressedSize); + if (dataDescriptor) { + setUint32(dataDescriptorView, 8, compressedSize); + setUint32(dataDescriptorView, 12, uncompressedSize); + } + } + } + if (dataDescriptor) { + await writer.writeUint8Array(dataDescriptorArray); + } + const length = localHeaderArray.length + compressedSize + dataDescriptorArray.length; + Object.assign(fileEntry, { compressedSize, uncompressedSize, lastModDate, rawLastModDate, encrypted, length }); + return fileEntry; + } + + function getOptionValue(zipWriter, options, name) { + return options[name] === undefined ? zipWriter.options[name] : options[name]; + } + + function setUint8(view, offset, value) { + view.setUint8(offset, value); + } + + function setUint16(view, offset, value) { + view.setUint16(offset, value, true); + } + + function setUint32(view, offset, value) { + view.setUint32(offset, value, true); + } + + function setBigUint64(view, offset, value) { + view.setBigUint64(offset, value, true); + } + + function arraySet(array, typedArray, offset) { + array.set(typedArray, offset); + } + + function getDataView(array) { + return new DataView(array.buffer); + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + const CHUNK_SIZE = 512 * 1024; + + class ZipEntry { + + constructor(fs, name, params, parent) { + const zipEntry = this; + if (fs.root && parent && parent.getChildByName(name)) { + throw new Error("Entry filename already exists"); + } + if (!params) { + params = {}; + } + Object.assign(zipEntry, { + fs, + name, + data: params.data, + id: fs.entries.length, + parent, + children: [], + uncompressedSize: 0 + }); + fs.entries.push(zipEntry); + if (parent) { + zipEntry.parent.children.push(zipEntry); + } + } + + moveTo(target) { + // deprecated + const zipEntry = this; + zipEntry.fs.move(zipEntry, target); + } + + getFullname() { + return this.getRelativeName(); + } + + getRelativeName(ancestor = this.fs.root) { + const zipEntry = this; + let relativeName = zipEntry.name; + let entry = zipEntry.parent; + while (entry && entry != ancestor) { + relativeName = (entry.name ? entry.name + "/" : "") + relativeName; + entry = entry.parent; + } + return relativeName; + } + + isDescendantOf(ancestor) { + let entry = this.parent; + while (entry && entry.id != ancestor.id) { + entry = entry.parent; + } + return Boolean(entry); + } + } + + class ZipFileEntry extends ZipEntry { + + constructor(fs, name, params, parent) { + super(fs, name, params, parent); + const zipEntry = this; + zipEntry.Reader = params.Reader; + zipEntry.Writer = params.Writer; + if (params.getData) { + zipEntry.getData = params.getData; + } + } + + async getData(writer, options = {}) { + const zipEntry = this; + if (!writer || (writer.constructor == zipEntry.Writer && zipEntry.data)) { + return zipEntry.data; + } else { + zipEntry.reader = new zipEntry.Reader(zipEntry.data, options); + await zipEntry.reader.init(); + if (!writer.initialized) { + await writer.init(); + } + zipEntry.uncompressedSize = zipEntry.reader.size; + return pipe(zipEntry.reader, writer); + } + } + + getText(encoding, options) { + return this.getData(new TextWriter(encoding), options); + } + + getBlob(mimeType, options) { + return this.getData(new BlobWriter(mimeType), options); + } + + getData64URI(mimeType, options) { + return this.getData(new Data64URIWriter(mimeType), options); + } + + getUint8Array(options) { + return this.getData(new Uint8ArrayWriter(), options); + } + + replaceBlob(blob) { + Object.assign(this, { + data: blob, + Reader: BlobReader, + Writer: BlobWriter, + reader: null + }); + } + + replaceText(text) { + Object.assign(this, { + data: text, + Reader: TextReader, + Writer: TextWriter, + reader: null + }); + } + + replaceData64URI(dataURI) { + Object.assign(this, { + data: dataURI, + Reader: Data64URIReader, + Writer: Data64URIWriter, + reader: null + }); + } + + replaceUint8Array(array) { + Object.assign(this, { + data: array, + Reader: Uint8ArrayReader, + Writer: Uint8ArrayWriter, + reader: null + }); + } + } + + class ZipDirectoryEntry extends ZipEntry { + + constructor(fs, name, params, parent) { + super(fs, name, params, parent); + this.directory = true; + } + + addDirectory(name) { + return addChild(this, name, null, true); + } + + addText(name, text) { + return addChild(this, name, { + data: text, + Reader: TextReader, + Writer: TextWriter + }); + } + + addBlob(name, blob) { + return addChild(this, name, { + data: blob, + Reader: BlobReader, + Writer: BlobWriter + }); + } + + addData64URI(name, dataURI) { + return addChild(this, name, { + data: dataURI, + Reader: Data64URIReader, + Writer: Data64URIWriter + }); + } + + addUint8Array(name, array) { + return addChild(this, name, { + data: array, + Reader: Uint8ArrayReader, + Writer: Uint8ArrayWriter + }); + } + + addHttpContent(name, url, options = {}) { + return addChild(this, name, { + data: url, + Reader: class extends HttpReader { + constructor(url) { + super(url, options); + } + } + }); + } + + async addFileSystemEntry(fileSystemEntry) { + return addFileSystemEntry(this, fileSystemEntry); + } + + async addData(name, params) { + return addChild(this, name, params); + } + + async importBlob(blob, options = {}) { + await this.importZip(new BlobReader(blob), options); + } + + async importData64URI(dataURI, options = {}) { + await this.importZip(new Data64URIReader(dataURI), options); + } + + async importUint8Array(array, options = {}) { + await this.importZip(new Uint8ArrayReader(array), options); + } + + async importHttpContent(url, options = {}) { + await this.importZip(new HttpReader(url, options), options); + } + + async exportBlob(options = {}) { + return this.exportZip(new BlobWriter("application/zip"), options); + } + + async exportData64URI(options = {}) { + return this.exportZip(new Data64URIWriter("application/zip"), options); + } + + async exportUint8Array(options = {}) { + return this.exportZip(new Uint8ArrayWriter(), options); + } + + async importZip(reader, options) { + if (!reader.initialized) { + await reader.init(); + } + const zipReader = new ZipReader(reader, options); + const entries = await zipReader.getEntries(); + entries.forEach((entry) => { + let parent = this; + const path = entry.filename.split("/"); + const name = path.pop(); + path.forEach(pathPart => parent = parent.getChildByName(pathPart) || new ZipDirectoryEntry(this.fs, pathPart, null, parent)); + if (!entry.directory) { + addChild(parent, name, { + data: entry, + Reader: getZipBlobReader(Object.assign({}, options)) + }); + } + }); + } + + async exportZip(writer, options) { + const zipEntry = this; + await initReaders(zipEntry); + await writer.init(); + const zipWriter = new ZipWriter(writer, options); + await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options); + await zipWriter.close(); + return writer.getData(); + } + + getChildByName(name) { + const children = this.children; + for (let childIndex = 0; childIndex < children.length; childIndex++) { + const child = children[childIndex]; + if (child.name == name) { + return child; + } + } + } + } + + + class FS { + + constructor() { + resetFS(this); + } + + get children() { + return this.root.children; + } + + remove(entry) { + detach(entry); + this.entries[entry.id] = null; + } + + move(entry, destination) { + if (entry == this.root) { + throw new Error("Root directory cannot be moved"); + } else { + if (destination.directory) { + if (!destination.isDescendantOf(entry)) { + if (entry != destination) { + if (destination.getChildByName(entry.name)) { + throw new Error("Entry filename already exists"); + } + detach(entry); + entry.parent = destination; + destination.children.push(entry); + } + } else { + throw new Error("Entry is a ancestor of target entry"); + } + } else { + throw new Error("Target entry is not a directory"); + } + } + } + + find(fullname) { + const path = fullname.split("/"); + let node = this.root; + for (let index = 0; node && index < path.length; index++) { + node = node.getChildByName(path[index]); + } + return node; + } + + getById(id) { + return this.entries[id]; + } + + getChildByName(name) { + return this.root.getChildByName(name); + } + + addDirectory(name) { + return this.root.addDirectory(name); + } + + addText(name, text) { + return this.root.addText(name, text); + } + + addBlob(name, blob) { + return this.root.addBlob(name, blob); + } + + addData64URI(name, dataURI) { + return this.root.addData64URI(name, dataURI); + } + + addHttpContent(name, url, options) { + return this.root.addHttpContent(name, url, options); + } + + async addFileSystemEntry(fileSystemEntry) { + return this.root.addFileSystemEntry(fileSystemEntry); + } + + async addData(name, params) { + return this.root.addData(name, params); + } + + async importBlob(blob, options) { + resetFS(this); + await this.root.importBlob(blob, options); + } + + async importData64URI(dataURI, options) { + resetFS(this); + await this.root.importData64URI(dataURI, options); + } + + async importHttpContent(url, options) { + resetFS(this); + await this.root.importHttpContent(url, options); + } + + async exportBlob(options) { + return this.root.exportBlob(options); + } + + async exportData64URI(options) { + return this.root.exportData64URI(options); + } + } + + const fs = { FS, ZipDirectoryEntry, ZipFileEntry }; + + function getTotalSize(entries, propertyName) { + let size = 0; + entries.forEach(process); + return size; + + function process(entry) { + size += entry[propertyName]; + if (entry.children) { + entry.children.forEach(process); + } + } + } + + function getZipBlobReader(options) { + return class extends Reader { + + constructor(entry, options = {}) { + super(); + this.entry = entry; + this.options = options; + } + + async init() { + const zipBlobReader = this; + zipBlobReader.size = zipBlobReader.entry.uncompressedSize; + const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options)); + zipBlobReader.data = data; + zipBlobReader.blobReader = new BlobReader(data); + } + + async readUint8Array(index, length) { + return this.blobReader.readUint8Array(index, length); + } + }; + } + + async function initReaders(entry) { + if (entry.children.length) { + for (const child of entry.children) { + if (child.directory) { + await initReaders(child); + } else { + child.reader = new child.Reader(child.data); + await child.reader.init(); + child.uncompressedSize = child.reader.size; + } + } + } + } + + function detach(entry) { + const children = entry.parent.children; + children.forEach((child, index) => { + if (child.id == entry.id) { + children.splice(index, 1); + } + }); + } + + async function exportZip(zipWriter, entry, totalSize, options) { + const selectedEntry = entry; + const entryOffsets = new Map(); + await process(zipWriter, entry); + + async function process(zipWriter, entry) { + await exportChild(); + + async function exportChild() { + if (options.bufferedWrite) { + await Promise.all(entry.children.map(processChild)); + } else { + for (const child of entry.children) { + await processChild(child); + } + } + } + + async function processChild(child) { + const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname(); + await zipWriter.add(name, child.reader, Object.assign({ + directory: child.directory + }, Object.assign({}, options, { + onprogress: indexProgress => { + if (options.onprogress) { + entryOffsets.set(name, indexProgress); + try { + options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize); + } catch (error) { + // ignored + } + } + } + }))); + await process(zipWriter, child); + } + } + } + + async function addFileSystemEntry(zipEntry, fileSystemEntry) { + if (fileSystemEntry.isDirectory) { + const entry = zipEntry.addDirectory(fileSystemEntry.name); + await addDirectory(entry, fileSystemEntry); + return entry; + } else { + return new Promise((resolve, reject) => fileSystemEntry.file(file => resolve(zipEntry.addBlob(fileSystemEntry.name, file)), reject)); + } + + async function addDirectory(zipEntry, fileEntry) { + const children = await getChildren(fileEntry); + for (const child of children) { + if (child.isDirectory) { + await addDirectory(zipEntry.addDirectory(child.name), child); + } else { + await new Promise((resolve, reject) => { + child.file(file => { + const childZipEntry = zipEntry.addBlob(child.name, file); + childZipEntry.uncompressedSize = file.size; + resolve(childZipEntry); + }, reject); + }); + } + } + } + + function getChildren(fileEntry) { + return new Promise((resolve, reject) => { + let entries = []; + if (fileEntry.isDirectory) { + readEntries(fileEntry.createReader()); + } + if (fileEntry.isFile) { + resolve(entries); + } + + function readEntries(directoryReader) { + directoryReader.readEntries(temporaryEntries => { + if (!temporaryEntries.length) { + resolve(entries); + } else { + entries = entries.concat(temporaryEntries); + readEntries(directoryReader); + } + }, reject); + } + }); + } + } + + function resetFS(fs) { + fs.entries = []; + fs.root = new ZipDirectoryEntry(fs); + } + + async function pipe(reader, writer) { + return copyChunk(); + + async function copyChunk(chunkIndex = 0) { + const index = chunkIndex * CHUNK_SIZE; + if (index < reader.size) { + const array = await reader.readUint8Array(index, Math.min(CHUNK_SIZE, reader.size - index)); + await writer.writeUint8Array(array); + return copyChunk(chunkIndex + 1); + } else { + return writer.getData(); + } + } + } + + function addChild(parent, name, params, directory) { + if (parent.directory) { + return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent); + } else { + throw new Error("Parent entry is not a directory"); + } + } + + /* + Copyright (c) 2021 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + configureWebWorker(); + + exports.BlobReader = BlobReader; + exports.BlobWriter = BlobWriter; + exports.Data64URIReader = Data64URIReader; + exports.Data64URIWriter = Data64URIWriter; + exports.ERR_ABORT = ERR_ABORT; + exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT; + exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND; + exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME; + exports.ERR_ENCRYPTED = ERR_ENCRYPTED; + exports.ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND = ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND; + exports.ERR_EOCDR_NOT_FOUND = ERR_EOCDR_NOT_FOUND; + exports.ERR_EOCDR_ZIP64_NOT_FOUND = ERR_EOCDR_ZIP64_NOT_FOUND; + exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND; + exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE; + exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT; + exports.ERR_INVALID_DATE = ERR_INVALID_DATE; + exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH; + exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT; + exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME; + exports.ERR_INVALID_EXTRAFIELD_DATA = ERR_INVALID_EXTRAFIELD_DATA; + exports.ERR_INVALID_EXTRAFIELD_TYPE = ERR_INVALID_EXTRAFIELD_TYPE; + exports.ERR_INVALID_PASSWORD = ERR_INVALID_PASSWORD; + exports.ERR_INVALID_SIGNATURE = ERR_INVALID_SIGNATURE; + exports.ERR_INVALID_VERSION = ERR_INVALID_VERSION; + exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND; + exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION; + exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION; + exports.HttpRangeReader = HttpRangeReader; + exports.HttpReader = HttpReader; + exports.Reader = Reader; + exports.TextReader = TextReader; + exports.TextWriter = TextWriter; + exports.Uint8ArrayReader = Uint8ArrayReader; + exports.Uint8ArrayWriter = Uint8ArrayWriter; + exports.Writer = Writer; + exports.ZipReader = ZipReader; + exports.ZipWriter = ZipWriter; + exports.configure = configure; + exports.fs = fs; + exports.getMimeType = getMimeType; + exports.initShimAsyncCodec = streamCodecShim; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html b/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html index 6ce50adac3e075c58dc2600456583e6455e978c2..385883b0473605a1c7892871717df61cf82b6918 100644 --- a/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html +++ b/o2web/source/x_component_process_FormDesigner/Module/Attachment/attachment.html @@ -147,6 +147,13 @@ 不允许 + + 允许预览: + + 允许 + 不允许
+ + 允许下载: diff --git a/o2web/source/x_component_process_Xform/Attachment.js b/o2web/source/x_component_process_Xform/Attachment.js index 63f3fe432c10704601cbca2ecc9d9f1877d12693..516fffc6e6237c1a742ae0b8c4558d15f56c803d 100644 --- a/o2web/source/x_component_process_Xform/Attachment.js +++ b/o2web/source/x_component_process_Xform/Attachment.js @@ -4,6 +4,7 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ Extends: MWF.widget.ATTER, "options": { "officeFiles": ["doc", "docx", "dotx", "dot", "xls", "xlsx", "xlsm", "xlt", "xltx", "pptx", "ppt", "pot", "potx", "potm", "pdf"], + "allowPreviewExtension" : ["zip","pdf", "ofd", "png", "jpg", "bmp", "jpeg", "gif", "js", "css", "java", "json", "xml", "php", "html", "htm", "xhtml", "log", "md", "txt"], "checkTextEnable": true }, checkAttachmentDeleteAction: function () { @@ -139,6 +140,31 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ // } } }, + checkPreviewAttAction: function () { + if (!this.options.isPreviewAtt){ + this.setActionDisabled(this.previewAttAction); + //this.setActionDisabled(this.min_downloadAction); + }else{ + if (this.selectedAttachments.length){ + var flag = false; + for (var i = 0; i < this.selectedAttachments.length; i++) { + var att = this.selectedAttachments[i]; + if (this.options.allowPreviewExtension.contains(att.data.extension)) { + flag = true; + break; + } + } + if(flag){ + this.setActionEnabled(this.previewAttAction); + //this.setActionEnabled(this.min_downloadAction); + } + + }else{ + this.setActionDisabled(this.previewAttAction); + //this.setActionDisabled(this.min_downloadAction); + } + } + }, isAttDeleteAvailable: function (att) { if (this.options.readonly) return false; if (this.options.toolbarGroupHidden.contains("edit")) return false; @@ -413,6 +439,7 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ this.checkUploadAction(); this.checkDeleteAction(); this.checkReplaceAction(); + this.checkPreviewAttAction(); //this.checkOfficeAction(); this.checkDownloadAction(); this.checkSizeAction(); @@ -511,7 +538,9 @@ MWF.xApplication.process.Xform.AttachmentController = new Class({ this.deleteAction = this.createAction(this.editActionsGroupNode, "delete", o2.LP.widget["delete"], function (e, node) { this.deleteAttachment(e, node); }.bind(this)); - + this.previewAttAction = this.createAction(this.editActionsGroupNode, "previewAtt", o2.LP.widget["previewAtt"], function (e, node) { + this.previewAttachment(e, node); + }.bind(this)); if (!this.options.isReplaceHidden) { this.replaceAction = this.createAction(this.editActionsGroupNode, "replace", o2.LP.widget.replace, function (e, node) { this.replaceAttachment(e, node); @@ -1147,6 +1176,7 @@ MWF.xApplication.process.Xform.Attachment = MWF.APPAttachment = new Class( "isDelete": (this.json.isDelete === "y" || this.json.isDelete === "true"), "isReplace": (this.json.isReplace === "y" || this.json.isReplace === "true"), "isDownload": (this.json.isDownload === "y" || this.json.isDownload === "true"), + "isPreviewAtt": (this.json.isPreviewAtt === "y" || this.json.isPreviewAtt === "true"), "isSizeChange": (this.json.isSizeChange === "y" || this.json.isSizeChange === "true"), "readonly": (this.json.readonly === "y" || this.json.readonly === "true" || this.json.isReadonly ), "availableListStyles": this.json.availableListStyles ? this.json.availableListStyles : ["list", "seq", "icon", "preview"], @@ -1410,6 +1440,10 @@ MWF.xApplication.process.Xform.Attachment = MWF.APPAttachment = new Class( this.close(); }, null, null, this.form.json.confirmStyle); }, + previewAttachment: function (attachments) { + var att = attachments[0].data; + new MWF.xApplication.process.Xform.AttachmenPreview(att,this); + }, deleteAttachment: function (attachment) { this.fireEvent("delete", [attachment.data]); var id = attachment.data.id; @@ -1896,7 +1930,217 @@ MWF.xApplication.process.Xform.Attachment = MWF.APPAttachment = new Class( } }); +MWF.xApplication.process.Xform.AttachmenPreview = new Class({ + Implements: [Options, Events], + + initialize : function(att,app ){ + this.att = att; + this.app = app; + this.load(); + }, + load:function(){ + + var extension = this.att.extension; + if(extension === "ofd"){ + this.previewOfd(); + } + if(extension === "zip"){ + this.previewZip(); + } + if(extension === "pdf"){ + this.previewPdf(); + } + if(["png","jpg","bmp","jpeg","gif"].contains(extension)){ + this.previewImage(); + } + if(extension === "js"){ + this.previewAce("javascript"); + } + if(extension === "css"){ + this.previewAce("css"); + } + if(extension === "java"){ + this.previewAce("java"); + } + if(extension === "json"){ + this.previewAce("json"); + } + if(extension === "xml"){ + this.previewAce("xml"); + } + if(extension === "php"){ + this.previewAce("php"); + } + if(["html","htm","xhtml"].contains(extension)){ + this.previewAce("html"); + } + if(["log","md","txt"].contains(extension)){ + this.previewAce("text"); + } + }, + previewZip : function (){ + //zip压缩包预览 + var _self = this; + var zipViewNode = new Element("div.ztree").inject(document.body); + o2.load("/o2_lib/zipjs/zip-fs.js",function(){ + + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + var cookie = Cookie.read("x-token"); + url = url + "?x-token=" + cookie; + unzip().catch(error => console.error(error)); + async function unzip() { + zip.configure({ chunkSize: 128 }); + let zipFs = new zip.fs.FS(); + let directory = zipFs.addDirectory("import"); + await directory.importHttpContent(url); + + o2.loadCss("/o2_lib/zTree/zTreeStyle.css",function(){ + o2.load(["/o2_lib/jquery/jquery.min.js","/o2_lib/zTree/jquery.ztree.core.min.js"], {"sequence": true}, function(){ + jQuery = jQuery.noConflict(true); //避免js框架冲突 + var nodes = []; + loadNodes(directory,nodes); + jQuery.fn.zTree.init(jQuery(zipViewNode), {}, nodes); + + var dlg = o2.DL.open({ + "title": _self.att.name, + "width": "660px", + "height": "510px", + "mask": true, + "content": zipViewNode, + "container": null, + "positionNode": document.body, + "onQueryClose": function () { + zipViewNode.destroy(); + }, + "buttonList": [ + { + "text": "关闭", + "action": function () { + dlg.close(); + } + } + ], + "onPostShow": function () { + dlg.reCenter(); + } + }); + + }.bind(this)); + }) + } + + function loadNodes(directory,nodes){ + var folderList = []; + var fileList = []; + directory.children.each(function(file){ + if(file.directory){ + folderList.push(file) + } + }) + directory.children.each(function(file){ + if(!file.directory){ + fileList.push(file) + } + }) + folderList.append(fileList); + folderList.each(function(file){ + var node = { + name : file.name + } + if(nodes.children){ + nodes.children.push(node); + }else{ + nodes.push(node); + } + if(file.directory){ + node.children = []; + loadNodes(file,node); + } + }) + } + }.bind(this)); + }.bind(this)); + }, + previewPdf : function(){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + window.open("../o2_lib/pdfjs/web/viewer.html?file=" + url) + }); + }, + previewOfd : function(){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + window.open("../o2_lib/ofdjs/index.html?file=" + url) + }); + }, + previewImage : function(){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + var imgNode = new Element("img",{"src":url,"alt":this.att.name}).inject(document.body).hide(); + o2.loadCss("../m_app/yunFile/css/viewer.css", document.body,function(){ + o2.load("../m_app/yunFile/js/viewer.js", function(){ + this.viewer = new Viewer(imgNode,{ + navbar : false, + toolbar : false, + hidden : function(){ + imgNode.destroy(); + this.viewer.destroy(); + }.bind(this) + }); + this.viewer.show(); + }.bind(this)); + }.bind(this)); + }.bind(this)); + }, + previewAce:function(type){ + this.app.form.workAction.getAttachmentUrl(this.att.id, this.app.form.businessData.work.id, function (url) { + o2.require("o2.widget.ace", null, false); + var fileRequest = new Request({ + url: url, + method: 'get', + withCredentials: true, + onSuccess: function(responseText){ + var editorNode = new Element("div",{"style":"padding:10px"}); + editorNode.set("text",responseText); + + o2.widget.ace.load(function(){ + o2.load("../o2_lib/ace/src-min-noconflict/ext-static_highlight.js", function(){ + var highlight = ace.require("ace/ext/static_highlight"); + highlight(editorNode, {mode: "ace/mode/"+ type , theme: "ace/theme/tomorrow", "fontSize": 30,"showLineNumbers":true}); + }.bind(this)); + + }.bind(this)); + var dlg = o2.DL.open({ + "title": this.att.name, + "width": "960px", + "height": "610px", + "mask": true, + "content": editorNode, + "container": null, + "positionNode": document.body, + "onQueryClose": function () { + editorNode.destroy(); + }.bind(this), + "buttonList": [ + { + "text": "关闭", + "action": function () { + dlg.close(); + }.bind(this) + } + ], + "onPostShow": function () { + dlg.reCenter(); + }.bind(this) + }); + }.bind(this), + onFailure: function(){ + console.log('text', 'Sorry, your request failed :('); + } + }); + fileRequest.send(); + }.bind(this)); + + }, +}); MWF.xApplication.process.Xform.AttachmentDg = MWF.APPAttachmentDg = new Class({ Extends: MWF.APPAttachment, loadAttachmentController: function () {