[
  {
    "path": ".babelrc",
    "content": "{\n    \"presets\": [ \"env\" ],\n    \"plugins\": [ \"transform-class-properties\" ]\n}\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n    \"env\": { \"es6\": true, \"browser\": true },\n    \"parser\": \"@typescript-eslint/parser\",\n    \"parserOptions\": {\n      \"ecmaVersion\": 6,\n      \"sourceType\": \"module\",\n      \"ecmaFeatures\": {\n        \"modules\": true\n      }\n    },\n    \"extends\": [\n        \"eslint:recommended\",\n        \"plugin:@typescript-eslint/eslint-recommended\"\n    ]\n}"
  },
  {
    "path": ".gitignore",
    "content": ".*\n!.npmignore\n!.gitignore\n!.babelrc\n!.eslintrc.json\nnode_modules\nlib/"
  },
  {
    "path": ".npmignore",
    "content": ".*\n!.npmignore\n!.gitignore\n!.babelrc\nnode_modules\nsrc/\ndocs/"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 David Mzareulyan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# apng-js\n\n`apng-js` provides functions for parse and render animated PNG's \n([APNG](https://en.wikipedia.org/wiki/APNG)).\n \n## Demo page\n\n[https://davidmz.github.io/apng-js/](https://davidmz.github.io/apng-js/)\n \n## Usage\n`npm install apng-js`\n \n## API\n\n### parseAPNG(buf: ArrayBuffer): (APNG|Error)\n\n**Default exported function**. Parses APNG data, returns APNG object (see below) or Error.\nThis function can be used in node.js environment.\nObject methods relies on browser features (canvas, requestAnimationFrame…)\nand should work only in browser.\n\nUsage:\n```\nimport parseAPNG from 'apng-js';\n\nconst apng = parseAPNG(buffer);\nif (apng instanceof Error) {\n    // handle error\n}\n// work with apng object\n```\n\n### isNotPNG(err: Error): boolean\n\nChecks if Error is 'Not a PNG' error.\n\n### isNotAPNG(err: Error): boolean\n\nChecks if Error is 'Not an animated PNG' error.\n\n## Classes\n\n### APNG\nStructure of APNG file.\n````\nclass APNG {\n    width: number     // with of canvas, pixels\n    height: number    // height of canvas, pixels\n    numPlays: number  // number of times to loop animation (0 = infinite looping)\n    playTime: number  // total duration of one loop in milliseconds\n    frames: Frame[]   // array of frames\n\n    // Methods\n    createImages(): Promise // create imageElement's for all frames\n    getPlayer(context: CanvasRenderingContext2D, autoPlay: boolean = false): Promise.<Player>\n        // Create Player (see below) on given context and start playing\n        // if autoPlay is true.\n}\n````\n\n### Frame\nIndividual APNG frame.\n````\nclass Frame {\n    left: number      // left offset of frame, pixels\n    top: number       // top offset of frame, pixels\n    width: number     // with of frame, pixels\n    height: number    // height of frame, pixels\n    delay: number     // time to show frame in milliseconds\n    disposeOp: number // type of dispose operation (see APNG spec.)\n    blendOp: number   // type of blend operation (see APNG spec.)\n    imageData: Blob   // image data in PNG (not animated) format\n    \n    imageElement: HTMLImageElement // image data rendered as HTML Image element.\n                                   // This field is null right after 'parse',\n                                   // use Frame.createImage() or APNG.createImages()\n                                   // to fill this field.\n                                   \n    // Methods\n    createImage(): Promise // create imageElement for this frame\n}\n````\n### Player\nPlayer renders APNG frames on given rendering context and plays APNG animation.\n````\nclass Player {\n    context: CanvasRenderingContext2D\n    playbackRate: number = 1.0 // animation playback rate\n           \n    currFrameNumber: number // current frame number (read only)\n    currFrame: Frame        // current frame (read only)\n    paused: boolean         // playback is paused (read only)\n    ended: boolean          // playback is ended (read only)\n\n    // Methods\n    play()      // start or resume playback\n    pause()     // pause playback\n    stop()      // stop playback and rewind to start\n    \n    renderNextFrame()       // move to next frame and render it on context\n                            // Use this method to manual, frame by frame, rendering.\n}\n````\n\nPlayer object is an [EventEmitter](https://nodejs.org/api/events.html). You can listen to following events:\n\n  * **play** — playback started;\n  * **frame** — frame played (frame number passed as event parameter);\n  * **pause** — playback paused;\n  * **stop** — playback stopped;\n  * **end** — playback ended (for APNG with finite count of plays).\n"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n    <title>apng-js demo page</title>\n    <link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\">\n    <!-- link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css\"-->\n</head>\n<body>\n<div class=\"container\">\n    <h1>apng-js demo</h1>\n    <p>\n        See <a href=\"https://github.com/davidmz/apng-js\" target=\"_blank\">github.com/davidmz/apng-js</a>.\n    </p>\n    <p>\n        <button id=\"choose-btn\" class=\"btn btn-primary\">Choose APNG file</button>\n    </p>\n    <div class=\"container apng-error hidden\">\n        <div class=\"alert alert-danger\"></div>\n    </div>\n    <div class=\"container apng-result hidden\">\n        <div class=\"row\">\n            <div class=\"col-md-8\">\n                <p>Animation on canvas</p>\n                <div class=\"apng-ani\"></div>\n                <div>\n                    <button class=\"btn\" id=\"play-pause-btn\">Play / Pause</button>\n                    <button class=\"btn\" id=\"stop-btn\">Stop</button>\n                    Playback rate (<span id=\"playback-rate-display\">1.0</span>)\n                    <input id=\"playback-rate\" type=\"range\" min=\"0.1\" max=\"2.0\" step=\"0.1\" value=\"1.0\">\n                </div>\n            </div>\n            <div class=\"col-md-4\">\n                <p> Events: </p>\n                <pre class=\"apng-log\"></pre>\n            </div>\n        </div>\n        <div class=\"row\">\n            <div class=\"col-md-4\">\n                <p> APNG info: </p>\n                <pre class=\"apng-info\"></pre>\n            </div>\n            <div class=\"col-md-8\">\n                <p>Frames</p>\n                <p class=\"apng-frames\"></p>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"index.js\"></script>\n</body>\n</html>"
  },
  {
    "path": "docs/index.js",
    "content": "/******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n\n\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\tvar _parser = __webpack_require__(1);\n\n\tvar _parser2 = _interopRequireDefault(_parser);\n\n\t__webpack_require__(6);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n\tvar fileInput = document.createElement('input');\n\tfileInput.type = 'file';\n\tfileInput.accept = 'image/png';\n\n\tdocument.getElementById('choose-btn').addEventListener('click', function () {\n\t  return fileInput.click();\n\t});\n\n\tfileInput.addEventListener('change', function () {\n\t  if (fileInput.files.length > 0) {\n\t    processFile(fileInput.files[0]);\n\t  }\n\t  fileInput.value = '';\n\t});\n\n\tvar player = null;\n\n\tdocument.getElementById('play-pause-btn').addEventListener('click', function () {\n\t  if (player) {\n\t    if (player.paused) {\n\t      player.play();\n\t    } else {\n\t      player.pause();\n\t    }\n\t  }\n\t});\n\n\tdocument.getElementById('stop-btn').addEventListener('click', function () {\n\t  return player && player.stop();\n\t});\n\n\tvar playbackRate = 1.0;\n\tdocument.getElementById('playback-rate').addEventListener('change', function (e) {\n\t  playbackRate = parseFloat(e.target.value);\n\t  document.getElementById('playback-rate-display').innerHTML = playbackRate.toString();\n\t  if (player) {\n\t    player.playbackRate = playbackRate;\n\t  }\n\t});\n\n\tfunction processFile(file) {\n\t  var resultBlock = document.querySelector('.apng-result');\n\t  var errorBlock = document.querySelector('.apng-error');\n\t  var errDiv = errorBlock.querySelector('.alert');\n\t  var infoDiv = document.querySelector('.apng-info');\n\t  var framesDiv = document.querySelector('.apng-frames');\n\t  var canvasDiv = document.querySelector('.apng-ani');\n\t  var logDiv = document.querySelector('.apng-log');\n\n\t  resultBlock.classList.add('hidden');\n\t  errorBlock.classList.add('hidden');\n\t  emptyEl(infoDiv);\n\t  emptyEl(framesDiv);\n\t  emptyEl(canvasDiv);\n\t  emptyEl(errDiv);\n\t  emptyEl(logDiv);\n\t  if (player) {\n\t    player.stop();\n\t  }\n\n\t  var log = [];\n\n\t  var reader = new FileReader();\n\t  reader.onload = function () {\n\t    var apng = (0, _parser2.default)(reader.result);\n\t    if (apng instanceof Error) {\n\t      errDiv.appendChild(document.createTextNode(apng.message));\n\t      errorBlock.classList.remove('hidden');\n\t      return;\n\t    }\n\t    apng.createImages().then(function () {\n\t      infoDiv.appendChild(document.createTextNode(JSON.stringify(apng, null, '  ')));\n\t      apng.frames.forEach(function (f) {\n\t        var div = framesDiv.appendChild(document.createElement('div'));\n\t        div.appendChild(f.imageElement);\n\t        div.style.width = apng.width + 'px';\n\t        div.style.height = apng.height + 'px';\n\t        f.imageElement.style.left = f.left + 'px';\n\t        f.imageElement.style.top = f.top + 'px';\n\t      });\n\n\t      var canvas = document.createElement('canvas');\n\t      canvas.width = apng.width;\n\t      canvas.height = apng.height;\n\t      canvasDiv.appendChild(canvas);\n\n\t      apng.getPlayer(canvas.getContext('2d')).then(function (p) {\n\t        player = p;\n\t        player.playbackRate = playbackRate;\n\t        var em = player.emit;\n\t        player.emit = function (event) {\n\t          for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n\t            args[_key - 1] = arguments[_key];\n\t          }\n\n\t          log.unshift({ event: event, args: args });\n\t          if (log.length > 10) {\n\t            log.splice(10, log.length - 10);\n\t          }\n\t          logDiv.textContent = log.map(function (_ref) {\n\t            var event = _ref.event,\n\t                args = _ref.args;\n\t            return event + ': ' + JSON.stringify(args);\n\t          }).join(\"\\n\");\n\n\t          em.call.apply(em, [player, event].concat(args));\n\t        };\n\t        player.play();\n\t      });\n\t    });\n\t    resultBlock.classList.remove('hidden');\n\t  };\n\t  reader.readAsArrayBuffer(file);\n\t}\n\n\tfunction emptyEl(el) {\n\t  var c = void 0;\n\t  while ((c = el.firstChild) !== null) {\n\t    el.removeChild(c);\n\t  }\n\t}\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\tObject.defineProperty(exports, \"__esModule\", {\n\t    value: true\n\t});\n\texports.isNotPNG = isNotPNG;\n\texports.isNotAPNG = isNotAPNG;\n\texports.default = parseAPNG;\n\n\tvar _crc = __webpack_require__(2);\n\n\tvar _crc2 = _interopRequireDefault(_crc);\n\n\tvar _structs = __webpack_require__(3);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n\tvar errNotPNG = new Error('Not a PNG');\n\tvar errNotAPNG = new Error('Not an animated PNG');\n\n\tfunction isNotPNG(err) {\n\t    return err === errNotPNG;\n\t}\n\tfunction isNotAPNG(err) {\n\t    return err === errNotAPNG;\n\t}\n\n\t// '\\x89PNG\\x0d\\x0a\\x1a\\x0a'\n\tvar PNGSignature = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n\n\t/**\n\t * Parse APNG data\n\t * @param {ArrayBuffer} buffer\n\t * @return {APNG|Error}\n\t */\n\tfunction parseAPNG(buffer) {\n\t    var bytes = new Uint8Array(buffer);\n\n\t    if (Array.prototype.some.call(PNGSignature, function (b, i) {\n\t        return b !== bytes[i];\n\t    })) {\n\t        return errNotPNG;\n\t    }\n\n\t    // fast animation test\n\t    var isAnimated = false;\n\t    eachChunk(bytes, function (type) {\n\t        return !(isAnimated = type === 'acTL');\n\t    });\n\t    if (!isAnimated) {\n\t        return errNotAPNG;\n\t    }\n\n\t    var preDataParts = [],\n\t        postDataParts = [];\n\t    var headerDataBytes = null,\n\t        frame = null,\n\t        frameNumber = 0,\n\t        apng = new _structs.APNG();\n\n\t    eachChunk(bytes, function (type, bytes, off, length) {\n\t        var dv = new DataView(bytes.buffer);\n\t        switch (type) {\n\t            case 'IHDR':\n\t                headerDataBytes = bytes.subarray(off + 8, off + 8 + length);\n\t                apng.width = dv.getUint32(off + 8);\n\t                apng.height = dv.getUint32(off + 12);\n\t                break;\n\t            case 'acTL':\n\t                apng.numPlays = dv.getUint32(off + 8 + 4);\n\t                break;\n\t            case 'fcTL':\n\t                if (frame) {\n\t                    apng.frames.push(frame);\n\t                    frameNumber++;\n\t                }\n\t                frame = new _structs.Frame();\n\t                frame.width = dv.getUint32(off + 8 + 4);\n\t                frame.height = dv.getUint32(off + 8 + 8);\n\t                frame.left = dv.getUint32(off + 8 + 12);\n\t                frame.top = dv.getUint32(off + 8 + 16);\n\t                var delayN = dv.getUint16(off + 8 + 20);\n\t                var delayD = dv.getUint16(off + 8 + 22);\n\t                if (delayD === 0) {\n\t                    delayD = 100;\n\t                }\n\t                frame.delay = 1000 * delayN / delayD;\n\t                // https://bugzilla.mozilla.org/show_bug.cgi?id=125137\n\t                // https://bugzilla.mozilla.org/show_bug.cgi?id=139677\n\t                // https://bugzilla.mozilla.org/show_bug.cgi?id=207059\n\t                if (frame.delay <= 10) {\n\t                    frame.delay = 100;\n\t                }\n\t                apng.playTime += frame.delay;\n\t                frame.disposeOp = dv.getUint8(off + 8 + 24);\n\t                frame.blendOp = dv.getUint8(off + 8 + 25);\n\t                frame.dataParts = [];\n\t                if (frameNumber === 0 && frame.disposeOp === 2) {\n\t                    frame.disposeOp = 1;\n\t                }\n\t                break;\n\t            case 'fdAT':\n\t                if (frame) {\n\t                    frame.dataParts.push(bytes.subarray(off + 8 + 4, off + 8 + length));\n\t                }\n\t                break;\n\t            case 'IDAT':\n\t                if (frame) {\n\t                    frame.dataParts.push(bytes.subarray(off + 8, off + 8 + length));\n\t                }\n\t                break;\n\t            case 'IEND':\n\t                postDataParts.push(subBuffer(bytes, off, 12 + length));\n\t                break;\n\t            default:\n\t                preDataParts.push(subBuffer(bytes, off, 12 + length));\n\t        }\n\t    });\n\n\t    if (frame) {\n\t        apng.frames.push(frame);\n\t    }\n\n\t    if (apng.frames.length == 0) {\n\t        return errNotAPNG;\n\t    }\n\n\t    var preBlob = new Blob(preDataParts),\n\t        postBlob = new Blob(postDataParts);\n\n\t    apng.frames.forEach(function (frame) {\n\t        var bb = [];\n\t        bb.push(PNGSignature);\n\t        headerDataBytes.set(makeDWordArray(frame.width), 0);\n\t        headerDataBytes.set(makeDWordArray(frame.height), 4);\n\t        bb.push(makeChunkBytes('IHDR', headerDataBytes));\n\t        bb.push(preBlob);\n\t        frame.dataParts.forEach(function (p) {\n\t            return bb.push(makeChunkBytes('IDAT', p));\n\t        });\n\t        bb.push(postBlob);\n\t        frame.imageData = new Blob(bb, { 'type': 'image/png' });\n\t        delete frame.dataParts;\n\t        bb = null;\n\t    });\n\n\t    return apng;\n\t}\n\n\t/**\n\t * @param {Uint8Array} bytes\n\t * @param {function(string, Uint8Array, int, int): boolean} callback\n\t */\n\tfunction eachChunk(bytes, callback) {\n\t    var dv = new DataView(bytes.buffer);\n\t    var off = 8,\n\t        type = void 0,\n\t        length = void 0,\n\t        res = void 0;\n\t    do {\n\t        length = dv.getUint32(off);\n\t        type = readString(bytes, off + 4, 4);\n\t        res = callback(type, bytes, off, length);\n\t        off += 12 + length;\n\t    } while (res !== false && type != 'IEND' && off < bytes.length);\n\t}\n\n\t/**\n\t *\n\t * @param {Uint8Array} bytes\n\t * @param {number} off\n\t * @param {number} length\n\t * @return {string}\n\t */\n\tfunction readString(bytes, off, length) {\n\t    var chars = Array.prototype.slice.call(bytes.subarray(off, off + length));\n\t    return String.fromCharCode.apply(String, chars);\n\t}\n\n\t/**\n\t *\n\t * @param {string} x\n\t * @return {Uint8Array}\n\t */\n\tfunction makeStringArray(x) {\n\t    var res = new Uint8Array(x.length);\n\t    for (var i = 0; i < x.length; i++) {\n\t        res[i] = x.charCodeAt(i);\n\t    }\n\t    return res;\n\t}\n\n\t/**\n\t * @param {Uint8Array} bytes\n\t * @param {int} start\n\t * @param {int} length\n\t * @return {Uint8Array}\n\t */\n\tfunction subBuffer(bytes, start, length) {\n\t    var a = new Uint8Array(length);\n\t    a.set(bytes.subarray(start, start + length));\n\t    return a;\n\t}\n\n\t/**\n\t * @param {string} type\n\t * @param {Uint8Array} dataBytes\n\t * @return {Uint8Array}\n\t */\n\tvar makeChunkBytes = function makeChunkBytes(type, dataBytes) {\n\t    var crcLen = type.length + dataBytes.length;\n\t    var bytes = new Uint8Array(crcLen + 8);\n\t    var dv = new DataView(bytes.buffer);\n\n\t    dv.setUint32(0, dataBytes.length);\n\t    bytes.set(makeStringArray(type), 4);\n\t    bytes.set(dataBytes, 8);\n\t    var crc = (0, _crc2.default)(bytes, 4, crcLen);\n\t    dv.setUint32(crcLen + 4, crc);\n\t    return bytes;\n\t};\n\n\tvar makeDWordArray = function makeDWordArray(x) {\n\t    return new Uint8Array([x >>> 24 & 0xff, x >>> 16 & 0xff, x >>> 8 & 0xff, x & 0xff]);\n\t};\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\n\t\"use strict\";\n\n\tObject.defineProperty(exports, \"__esModule\", {\n\t  value: true\n\t});\n\n\texports.default = function (bytes) {\n\t  var start = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;\n\t  var length = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : bytes.length - start;\n\n\t  var crc = -1;\n\t  for (var _i = start, l = start + length; _i < l; _i++) {\n\t    crc = crc >>> 8 ^ table[(crc ^ bytes[_i]) & 0xFF];\n\t  }\n\t  return crc ^ -1;\n\t};\n\n\tvar table = new Uint32Array(256);\n\n\tfor (var i = 0; i < 256; i++) {\n\t  var c = i;\n\t  for (var k = 0; k < 8; k++) {\n\t    c = (c & 1) !== 0 ? 0xEDB88320 ^ c >>> 1 : c >>> 1;\n\t  }\n\t  table[i] = c;\n\t}\n\n\t/**\n\t *\n\t * @param {Uint8Array} bytes\n\t * @param {number} start\n\t * @param {number} length\n\t * @return {number}\n\t */\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\tObject.defineProperty(exports, \"__esModule\", {\n\t    value: true\n\t});\n\texports.Frame = exports.APNG = undefined;\n\n\tvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\n\tvar _player = __webpack_require__(4);\n\n\tvar _player2 = _interopRequireDefault(_player);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n\t/**\n\t * @property {number} currFrameNumber\n\t * @property {Frame} currFrame\n\t * @property {boolean} paused\n\t * @property {boolean} ended\n\t */\n\tvar APNG = exports.APNG = function () {\n\t    function APNG() {\n\t        _classCallCheck(this, APNG);\n\n\t        this.width = 0;\n\t        this.height = 0;\n\t        this.numPlays = 0;\n\t        this.playTime = 0;\n\t        this.frames = [];\n\t    }\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {Frame[]} */\n\n\n\t    _createClass(APNG, [{\n\t        key: 'createImages',\n\n\n\t        /**\n\t         *\n\t         * @return {Promise.<*>}\n\t         */\n\t        value: function createImages() {\n\t            return Promise.all(this.frames.map(function (f) {\n\t                return f.createImage();\n\t            }));\n\t        }\n\n\t        /**\n\t         *\n\t         * @param {CanvasRenderingContext2D} context\n\t         * @param {boolean} autoPlay\n\t         * @return {Promise.<Player>}\n\t         */\n\n\t    }, {\n\t        key: 'getPlayer',\n\t        value: function getPlayer(context) {\n\t            var _this = this;\n\n\t            var autoPlay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n\t            return this.createImages().then(function () {\n\t                return new _player2.default(_this, context, autoPlay);\n\t            });\n\t        }\n\t    }]);\n\n\t    return APNG;\n\t}();\n\n\tvar Frame = exports.Frame = function () {\n\t    function Frame() {\n\t        _classCallCheck(this, Frame);\n\n\t        this.left = 0;\n\t        this.top = 0;\n\t        this.width = 0;\n\t        this.height = 0;\n\t        this.delay = 0;\n\t        this.disposeOp = 0;\n\t        this.blendOp = 0;\n\t        this.imageData = null;\n\t        this.imageElement = null;\n\t    }\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {number} */\n\n\t    /** @type {Blob} */\n\n\t    /** @type {HTMLImageElement} */\n\n\n\t    _createClass(Frame, [{\n\t        key: 'createImage',\n\t        value: function createImage() {\n\t            var _this2 = this;\n\n\t            if (this.imageElement) {\n\t                return Promise.resolve();\n\t            }\n\t            return new Promise(function (resolve, reject) {\n\t                var url = URL.createObjectURL(_this2.imageData);\n\t                _this2.imageElement = document.createElement('img');\n\t                _this2.imageElement.onload = function () {\n\t                    URL.revokeObjectURL(url);\n\t                    resolve();\n\t                };\n\t                _this2.imageElement.onerror = function () {\n\t                    URL.revokeObjectURL(url);\n\t                    _this2.imageElement = null;\n\t                    reject(new Error(\"Image creation error\"));\n\t                };\n\t                _this2.imageElement.src = url;\n\t            });\n\t        }\n\t    }]);\n\n\t    return Frame;\n\t}();\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\n\tObject.defineProperty(exports, \"__esModule\", {\n\t    value: true\n\t});\n\n\tvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\n\tvar _events = __webpack_require__(5);\n\n\tvar _events2 = _interopRequireDefault(_events);\n\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\n\tfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\n\tfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\n\tvar _class = function (_EventEmitter) {\n\t    _inherits(_class, _EventEmitter);\n\n\t    /**\n\t     * @param {APNG} apng\n\t     * @param {CanvasRenderingContext2D} context\n\t     * @param {boolean} autoPlay\n\t     */\n\n\t    /** @type {number} */\n\n\n\t    /** @type {boolean} */\n\n\t    /** @type {ImageData} */\n\n\n\t    /** @type {APNG} */\n\n\t    /** @type {CanvasRenderingContext2D} */\n\t    function _class(apng, context, autoPlay) {\n\t        _classCallCheck(this, _class);\n\n\t        var _this = _possibleConstructorReturn(this, (_class.__proto__ || Object.getPrototypeOf(_class)).call(this));\n\n\t        _this.playbackRate = 1.0;\n\t        _this._currentFrameNumber = 0;\n\t        _this._ended = false;\n\t        _this._paused = true;\n\t        _this._numPlays = 0;\n\t        _this._rafId = null;\n\n\t        _this._apng = apng;\n\t        _this.context = context;\n\t        _this.stop();\n\t        if (autoPlay) {\n\t            _this.play();\n\t        }\n\t        return _this;\n\t    }\n\n\t    /**\n\t     *\n\t     * @return {number}\n\t     */\n\n\t    /** @type {number|null} */\n\n\t    /** @type {boolean} */\n\n\t    /** @type {number} */\n\n\t    /** @type {Frame} */\n\n\t    /** @type {number} */\n\n\n\t    _createClass(_class, [{\n\t        key: 'renderNextFrame',\n\t        value: function renderNextFrame() {\n\t            this._currentFrameNumber = (this._currentFrameNumber + 1) % this._apng.frames.length;\n\t            if (this._currentFrameNumber === this._apng.frames.length - 1) {\n\t                this._numPlays++;\n\t                if (this._apng.numPlays !== 0 && this._numPlays >= this._apng.numPlays) {\n\t                    this._ended = true;\n\t                    this._paused = true;\n\t                }\n\t            }\n\n\t            if (this._prevFrame && this._prevFrame.disposeOp == 1) {\n\t                this.context.clearRect(this._prevFrame.left, this._prevFrame.top, this._prevFrame.width, this._prevFrame.height);\n\t            } else if (this._prevFrame && this._prevFrame.disposeOp == 2) {\n\t                this.context.putImageData(this._prevFrameData, this._prevFrame.left, this._prevFrame.top);\n\t            }\n\n\t            var frame = this.currentFrame;\n\t            this._prevFrame = frame;\n\t            this._prevFrameData = null;\n\t            if (frame.disposeOp == 2) {\n\t                this._prevFrameData = this.context.getImageData(frame.left, frame.top, frame.width, frame.height);\n\t            }\n\t            if (frame.blendOp == 0) {\n\t                this.context.clearRect(frame.left, frame.top, frame.width, frame.height);\n\t            }\n\n\t            this.context.drawImage(frame.imageElement, frame.left, frame.top);\n\n\t            this.emit('frame', this._currentFrameNumber);\n\t            if (this._ended) {\n\t                this.emit('end');\n\t            }\n\t        }\n\n\t        // playback\n\n\t    }, {\n\t        key: 'play',\n\t        value: function play() {\n\t            var _this2 = this;\n\n\t            if (this._rafId) {\n\t                cancelAnimationFrame(this._rafId);\n\t            }\n\n\t            this.emit('play');\n\n\t            if (this._ended) {\n\t                this.stop();\n\t            }\n\t            this._paused = false;\n\n\t            var nextRenderTime = performance.now() + this.currentFrame.delay / this.playbackRate;\n\t            var tick = function tick(now) {\n\t                if (_this2._ended || _this2._paused) {\n\t                    return;\n\t                }\n\t                if (now >= nextRenderTime) {\n\t                    while (now - nextRenderTime >= _this2._apng.playTime / _this2.playbackRate) {\n\t                        nextRenderTime += _this2._apng.playTime / _this2.playbackRate;\n\t                        _this2._numPlays++;\n\t                    }\n\t                    do {\n\t                        _this2.renderNextFrame();\n\t                        nextRenderTime += _this2.currentFrame.delay / _this2.playbackRate;\n\t                    } while (!_this2._ended && !_this2._paused && now > nextRenderTime);\n\t                }\n\t                _this2._rafId = requestAnimationFrame(tick);\n\t            };\n\t            this._rafId = requestAnimationFrame(tick);\n\t        }\n\t    }, {\n\t        key: 'pause',\n\t        value: function pause() {\n\t            if (!this._paused) {\n\t                if (this._rafId) {\n\t                    cancelAnimationFrame(this._rafId);\n\t                    this._rafId = null;\n\t                }\n\t                this.emit('pause');\n\t                this._paused = true;\n\t            }\n\t        }\n\t    }, {\n\t        key: 'stop',\n\t        value: function stop() {\n\t            if (this._rafId) {\n\t                cancelAnimationFrame(this._rafId);\n\t                this._rafId = null;\n\t            }\n\t            this.emit('stop');\n\t            this._numPlays = 0;\n\t            this._ended = false;\n\t            this._paused = true;\n\t            // render first frame\n\t            this._currentFrameNumber = -1;\n\t            this.context.clearRect(0, 0, this._apng.width, this._apng.height);\n\t            this.renderNextFrame();\n\t        }\n\t    }, {\n\t        key: 'currentFrameNumber',\n\t        get: function get() {\n\t            return this._currentFrameNumber;\n\t        }\n\n\t        /**\n\t         *\n\t         * @return {Frame}\n\t         */\n\n\t    }, {\n\t        key: 'currentFrame',\n\t        get: function get() {\n\t            return this._apng.frames[this._currentFrameNumber];\n\t        }\n\t    }, {\n\t        key: 'paused',\n\t        get: function get() {\n\t            return this._paused;\n\t        }\n\t    }, {\n\t        key: 'ended',\n\t        get: function get() {\n\t            return this._ended;\n\t        }\n\t    }]);\n\n\t    return _class;\n\t}(_events2.default);\n\n\texports.default = _class;\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports) {\n\n\t// Copyright Joyent, Inc. and other Node contributors.\n\t//\n\t// Permission is hereby granted, free of charge, to any person obtaining a\n\t// copy of this software and associated documentation files (the\n\t// \"Software\"), to deal in the Software without restriction, including\n\t// without limitation the rights to use, copy, modify, merge, publish,\n\t// distribute, sublicense, and/or sell copies of the Software, and to permit\n\t// persons to whom the Software is furnished to do so, subject to the\n\t// following conditions:\n\t//\n\t// The above copyright notice and this permission notice shall be included\n\t// in all copies or substantial portions of the Software.\n\t//\n\t// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n\t// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n\t// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n\t// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n\t// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n\t// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n\t// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\tfunction EventEmitter() {\n\t  this._events = this._events || {};\n\t  this._maxListeners = this._maxListeners || undefined;\n\t}\n\tmodule.exports = EventEmitter;\n\n\t// Backwards-compat with node 0.10.x\n\tEventEmitter.EventEmitter = EventEmitter;\n\n\tEventEmitter.prototype._events = undefined;\n\tEventEmitter.prototype._maxListeners = undefined;\n\n\t// By default EventEmitters will print a warning if more than 10 listeners are\n\t// added to it. This is a useful default which helps finding memory leaks.\n\tEventEmitter.defaultMaxListeners = 10;\n\n\t// Obviously not all Emitters should be limited to 10. This function allows\n\t// that to be increased. Set to zero for unlimited.\n\tEventEmitter.prototype.setMaxListeners = function(n) {\n\t  if (!isNumber(n) || n < 0 || isNaN(n))\n\t    throw TypeError('n must be a positive number');\n\t  this._maxListeners = n;\n\t  return this;\n\t};\n\n\tEventEmitter.prototype.emit = function(type) {\n\t  var er, handler, len, args, i, listeners;\n\n\t  if (!this._events)\n\t    this._events = {};\n\n\t  // If there is no 'error' event listener then throw.\n\t  if (type === 'error') {\n\t    if (!this._events.error ||\n\t        (isObject(this._events.error) && !this._events.error.length)) {\n\t      er = arguments[1];\n\t      if (er instanceof Error) {\n\t        throw er; // Unhandled 'error' event\n\t      } else {\n\t        // At least give some kind of context to the user\n\t        var err = new Error('Uncaught, unspecified \"error\" event. (' + er + ')');\n\t        err.context = er;\n\t        throw err;\n\t      }\n\t    }\n\t  }\n\n\t  handler = this._events[type];\n\n\t  if (isUndefined(handler))\n\t    return false;\n\n\t  if (isFunction(handler)) {\n\t    switch (arguments.length) {\n\t      // fast cases\n\t      case 1:\n\t        handler.call(this);\n\t        break;\n\t      case 2:\n\t        handler.call(this, arguments[1]);\n\t        break;\n\t      case 3:\n\t        handler.call(this, arguments[1], arguments[2]);\n\t        break;\n\t      // slower\n\t      default:\n\t        args = Array.prototype.slice.call(arguments, 1);\n\t        handler.apply(this, args);\n\t    }\n\t  } else if (isObject(handler)) {\n\t    args = Array.prototype.slice.call(arguments, 1);\n\t    listeners = handler.slice();\n\t    len = listeners.length;\n\t    for (i = 0; i < len; i++)\n\t      listeners[i].apply(this, args);\n\t  }\n\n\t  return true;\n\t};\n\n\tEventEmitter.prototype.addListener = function(type, listener) {\n\t  var m;\n\n\t  if (!isFunction(listener))\n\t    throw TypeError('listener must be a function');\n\n\t  if (!this._events)\n\t    this._events = {};\n\n\t  // To avoid recursion in the case that type === \"newListener\"! Before\n\t  // adding it to the listeners, first emit \"newListener\".\n\t  if (this._events.newListener)\n\t    this.emit('newListener', type,\n\t              isFunction(listener.listener) ?\n\t              listener.listener : listener);\n\n\t  if (!this._events[type])\n\t    // Optimize the case of one listener. Don't need the extra array object.\n\t    this._events[type] = listener;\n\t  else if (isObject(this._events[type]))\n\t    // If we've already got an array, just append.\n\t    this._events[type].push(listener);\n\t  else\n\t    // Adding the second element, need to change to array.\n\t    this._events[type] = [this._events[type], listener];\n\n\t  // Check for listener leak\n\t  if (isObject(this._events[type]) && !this._events[type].warned) {\n\t    if (!isUndefined(this._maxListeners)) {\n\t      m = this._maxListeners;\n\t    } else {\n\t      m = EventEmitter.defaultMaxListeners;\n\t    }\n\n\t    if (m && m > 0 && this._events[type].length > m) {\n\t      this._events[type].warned = true;\n\t      console.error('(node) warning: possible EventEmitter memory ' +\n\t                    'leak detected. %d listeners added. ' +\n\t                    'Use emitter.setMaxListeners() to increase limit.',\n\t                    this._events[type].length);\n\t      if (typeof console.trace === 'function') {\n\t        // not supported in IE 10\n\t        console.trace();\n\t      }\n\t    }\n\t  }\n\n\t  return this;\n\t};\n\n\tEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\n\tEventEmitter.prototype.once = function(type, listener) {\n\t  if (!isFunction(listener))\n\t    throw TypeError('listener must be a function');\n\n\t  var fired = false;\n\n\t  function g() {\n\t    this.removeListener(type, g);\n\n\t    if (!fired) {\n\t      fired = true;\n\t      listener.apply(this, arguments);\n\t    }\n\t  }\n\n\t  g.listener = listener;\n\t  this.on(type, g);\n\n\t  return this;\n\t};\n\n\t// emits a 'removeListener' event iff the listener was removed\n\tEventEmitter.prototype.removeListener = function(type, listener) {\n\t  var list, position, length, i;\n\n\t  if (!isFunction(listener))\n\t    throw TypeError('listener must be a function');\n\n\t  if (!this._events || !this._events[type])\n\t    return this;\n\n\t  list = this._events[type];\n\t  length = list.length;\n\t  position = -1;\n\n\t  if (list === listener ||\n\t      (isFunction(list.listener) && list.listener === listener)) {\n\t    delete this._events[type];\n\t    if (this._events.removeListener)\n\t      this.emit('removeListener', type, listener);\n\n\t  } else if (isObject(list)) {\n\t    for (i = length; i-- > 0;) {\n\t      if (list[i] === listener ||\n\t          (list[i].listener && list[i].listener === listener)) {\n\t        position = i;\n\t        break;\n\t      }\n\t    }\n\n\t    if (position < 0)\n\t      return this;\n\n\t    if (list.length === 1) {\n\t      list.length = 0;\n\t      delete this._events[type];\n\t    } else {\n\t      list.splice(position, 1);\n\t    }\n\n\t    if (this._events.removeListener)\n\t      this.emit('removeListener', type, listener);\n\t  }\n\n\t  return this;\n\t};\n\n\tEventEmitter.prototype.removeAllListeners = function(type) {\n\t  var key, listeners;\n\n\t  if (!this._events)\n\t    return this;\n\n\t  // not listening for removeListener, no need to emit\n\t  if (!this._events.removeListener) {\n\t    if (arguments.length === 0)\n\t      this._events = {};\n\t    else if (this._events[type])\n\t      delete this._events[type];\n\t    return this;\n\t  }\n\n\t  // emit removeListener for all listeners on all events\n\t  if (arguments.length === 0) {\n\t    for (key in this._events) {\n\t      if (key === 'removeListener') continue;\n\t      this.removeAllListeners(key);\n\t    }\n\t    this.removeAllListeners('removeListener');\n\t    this._events = {};\n\t    return this;\n\t  }\n\n\t  listeners = this._events[type];\n\n\t  if (isFunction(listeners)) {\n\t    this.removeListener(type, listeners);\n\t  } else if (listeners) {\n\t    // LIFO order\n\t    while (listeners.length)\n\t      this.removeListener(type, listeners[listeners.length - 1]);\n\t  }\n\t  delete this._events[type];\n\n\t  return this;\n\t};\n\n\tEventEmitter.prototype.listeners = function(type) {\n\t  var ret;\n\t  if (!this._events || !this._events[type])\n\t    ret = [];\n\t  else if (isFunction(this._events[type]))\n\t    ret = [this._events[type]];\n\t  else\n\t    ret = this._events[type].slice();\n\t  return ret;\n\t};\n\n\tEventEmitter.prototype.listenerCount = function(type) {\n\t  if (this._events) {\n\t    var evlistener = this._events[type];\n\n\t    if (isFunction(evlistener))\n\t      return 1;\n\t    else if (evlistener)\n\t      return evlistener.length;\n\t  }\n\t  return 0;\n\t};\n\n\tEventEmitter.listenerCount = function(emitter, type) {\n\t  return emitter.listenerCount(type);\n\t};\n\n\tfunction isFunction(arg) {\n\t  return typeof arg === 'function';\n\t}\n\n\tfunction isNumber(arg) {\n\t  return typeof arg === 'number';\n\t}\n\n\tfunction isObject(arg) {\n\t  return typeof arg === 'object' && arg !== null;\n\t}\n\n\tfunction isUndefined(arg) {\n\t  return arg === void 0;\n\t}\n\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t// style-loader: Adds some css to the DOM by adding a <style> tag\n\n\t// load the styles\n\tvar content = __webpack_require__(7);\n\tif(typeof content === 'string') content = [[module.id, content, '']];\n\t// add the styles to the DOM\n\tvar update = __webpack_require__(9)(content, {});\n\tif(content.locals) module.exports = content.locals;\n\t// Hot Module Replacement\n\tif(false) {\n\t\t// When the styles change, update the <style> tags\n\t\tif(!content.locals) {\n\t\t\tmodule.hot.accept(\"!!../../node_modules/css-loader/index.js!./style.css\", function() {\n\t\t\t\tvar newContent = require(\"!!../../node_modules/css-loader/index.js!./style.css\");\n\t\t\t\tif(typeof newContent === 'string') newContent = [[module.id, newContent, '']];\n\t\t\t\tupdate(newContent);\n\t\t\t});\n\t\t}\n\t\t// When the module is disposed, remove the <style> tags\n\t\tmodule.hot.dispose(function() { update(); });\n\t}\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\texports = module.exports = __webpack_require__(8)(false);\n\t// imports\n\n\n\t// module\n\texports.push([module.id, \".apng-info,\\r\\n.apng-frames {\\r\\n    max-height: 600px;\\r\\n    overflow:   auto;\\r\\n}\\r\\n\\r\\n.apng-frames > div {\\r\\n    float:            left;\\r\\n    margin:           1px 1px 8px 8px;\\r\\n    box-shadow:       0 0 0 1px;\\r\\n    position:         relative;\\r\\n    background:       linear-gradient(45deg, #fff 25%, transparent 26%, transparent 75%, #fff 76%),\\r\\n                      linear-gradient(-45deg, #fff 25%, transparent 26%, transparent 75%, #fff 76%);\\r\\n    background-color: #eee;\\r\\n    background-size:  20px 20px;\\r\\n}\\r\\n\\r\\n.apng-frames > div > img {\\r\\n    position:   absolute;\\r\\n    box-shadow: 0 0 0 1px rgba(255, 0, 0, 0.75);\\r\\n}\\r\\n\\r\\n#playback-rate {\\r\\n    width:   12em;\\r\\n    display: inline-block;\\r\\n}\\r\\n\\r\\n.apng-log {\\r\\n    height: 10em;\\r\\n}\", \"\"]);\n\n\t// exports\n\n\n/***/ }),\n/* 8 */\n/***/ (function(module, exports) {\n\n\t/*\n\t\tMIT License http://www.opensource.org/licenses/mit-license.php\n\t\tAuthor Tobias Koppers @sokra\n\t*/\n\t// css base code, injected by the css-loader\n\tmodule.exports = function(useSourceMap) {\n\t\tvar list = [];\n\n\t\t// return the list of modules as css string\n\t\tlist.toString = function toString() {\n\t\t\treturn this.map(function (item) {\n\t\t\t\tvar content = cssWithMappingToString(item, useSourceMap);\n\t\t\t\tif(item[2]) {\n\t\t\t\t\treturn \"@media \" + item[2] + \"{\" + content + \"}\";\n\t\t\t\t} else {\n\t\t\t\t\treturn content;\n\t\t\t\t}\n\t\t\t}).join(\"\");\n\t\t};\n\n\t\t// import a list of modules into the list\n\t\tlist.i = function(modules, mediaQuery) {\n\t\t\tif(typeof modules === \"string\")\n\t\t\t\tmodules = [[null, modules, \"\"]];\n\t\t\tvar alreadyImportedModules = {};\n\t\t\tfor(var i = 0; i < this.length; i++) {\n\t\t\t\tvar id = this[i][0];\n\t\t\t\tif(typeof id === \"number\")\n\t\t\t\t\talreadyImportedModules[id] = true;\n\t\t\t}\n\t\t\tfor(i = 0; i < modules.length; i++) {\n\t\t\t\tvar item = modules[i];\n\t\t\t\t// skip already imported module\n\t\t\t\t// this implementation is not 100% perfect for weird media query combinations\n\t\t\t\t//  when a module is imported multiple times with different media queries.\n\t\t\t\t//  I hope this will never occur (Hey this way we have smaller bundles)\n\t\t\t\tif(typeof item[0] !== \"number\" || !alreadyImportedModules[item[0]]) {\n\t\t\t\t\tif(mediaQuery && !item[2]) {\n\t\t\t\t\t\titem[2] = mediaQuery;\n\t\t\t\t\t} else if(mediaQuery) {\n\t\t\t\t\t\titem[2] = \"(\" + item[2] + \") and (\" + mediaQuery + \")\";\n\t\t\t\t\t}\n\t\t\t\t\tlist.push(item);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\treturn list;\n\t};\n\n\tfunction cssWithMappingToString(item, useSourceMap) {\n\t\tvar content = item[1] || '';\n\t\tvar cssMapping = item[3];\n\t\tif (!cssMapping) {\n\t\t\treturn content;\n\t\t}\n\n\t\tif (useSourceMap && typeof btoa === 'function') {\n\t\t\tvar sourceMapping = toComment(cssMapping);\n\t\t\tvar sourceURLs = cssMapping.sources.map(function (source) {\n\t\t\t\treturn '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'\n\t\t\t});\n\n\t\t\treturn [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n\t\t}\n\n\t\treturn [content].join('\\n');\n\t}\n\n\t// Adapted from convert-source-map (MIT)\n\tfunction toComment(sourceMap) {\n\t\t// eslint-disable-next-line no-undef\n\t\tvar base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n\t\tvar data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;\n\n\t\treturn '/*# ' + data + ' */';\n\t}\n\n\n/***/ }),\n/* 9 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t/*\n\t\tMIT License http://www.opensource.org/licenses/mit-license.php\n\t\tAuthor Tobias Koppers @sokra\n\t*/\n\tvar stylesInDom = {},\n\t\tmemoize = function(fn) {\n\t\t\tvar memo;\n\t\t\treturn function () {\n\t\t\t\tif (typeof memo === \"undefined\") memo = fn.apply(this, arguments);\n\t\t\t\treturn memo;\n\t\t\t};\n\t\t},\n\t\tisOldIE = memoize(function() {\n\t\t\treturn /msie [6-9]\\b/.test(self.navigator.userAgent.toLowerCase());\n\t\t}),\n\t\tgetHeadElement = memoize(function () {\n\t\t\treturn document.head || document.getElementsByTagName(\"head\")[0];\n\t\t}),\n\t\tsingletonElement = null,\n\t\tsingletonCounter = 0,\n\t\tstyleElementsInsertedAtTop = [];\n\n\tmodule.exports = function(list, options) {\n\t\tif(false) {\n\t\t\tif(typeof document !== \"object\") throw new Error(\"The style-loader cannot be used in a non-browser environment\");\n\t\t}\n\n\t\toptions = options || {};\n\t\t// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>\n\t\t// tags it will allow on a page\n\t\tif (typeof options.singleton === \"undefined\") options.singleton = isOldIE();\n\n\t\t// By default, add <style> tags to the bottom of <head>.\n\t\tif (typeof options.insertAt === \"undefined\") options.insertAt = \"bottom\";\n\n\t\tvar styles = listToStyles(list);\n\t\taddStylesToDom(styles, options);\n\n\t\treturn function update(newList) {\n\t\t\tvar mayRemove = [];\n\t\t\tfor(var i = 0; i < styles.length; i++) {\n\t\t\t\tvar item = styles[i];\n\t\t\t\tvar domStyle = stylesInDom[item.id];\n\t\t\t\tdomStyle.refs--;\n\t\t\t\tmayRemove.push(domStyle);\n\t\t\t}\n\t\t\tif(newList) {\n\t\t\t\tvar newStyles = listToStyles(newList);\n\t\t\t\taddStylesToDom(newStyles, options);\n\t\t\t}\n\t\t\tfor(var i = 0; i < mayRemove.length; i++) {\n\t\t\t\tvar domStyle = mayRemove[i];\n\t\t\t\tif(domStyle.refs === 0) {\n\t\t\t\t\tfor(var j = 0; j < domStyle.parts.length; j++)\n\t\t\t\t\t\tdomStyle.parts[j]();\n\t\t\t\t\tdelete stylesInDom[domStyle.id];\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tfunction addStylesToDom(styles, options) {\n\t\tfor(var i = 0; i < styles.length; i++) {\n\t\t\tvar item = styles[i];\n\t\t\tvar domStyle = stylesInDom[item.id];\n\t\t\tif(domStyle) {\n\t\t\t\tdomStyle.refs++;\n\t\t\t\tfor(var j = 0; j < domStyle.parts.length; j++) {\n\t\t\t\t\tdomStyle.parts[j](item.parts[j]);\n\t\t\t\t}\n\t\t\t\tfor(; j < item.parts.length; j++) {\n\t\t\t\t\tdomStyle.parts.push(addStyle(item.parts[j], options));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvar parts = [];\n\t\t\t\tfor(var j = 0; j < item.parts.length; j++) {\n\t\t\t\t\tparts.push(addStyle(item.parts[j], options));\n\t\t\t\t}\n\t\t\t\tstylesInDom[item.id] = {id: item.id, refs: 1, parts: parts};\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction listToStyles(list) {\n\t\tvar styles = [];\n\t\tvar newStyles = {};\n\t\tfor(var i = 0; i < list.length; i++) {\n\t\t\tvar item = list[i];\n\t\t\tvar id = item[0];\n\t\t\tvar css = item[1];\n\t\t\tvar media = item[2];\n\t\t\tvar sourceMap = item[3];\n\t\t\tvar part = {css: css, media: media, sourceMap: sourceMap};\n\t\t\tif(!newStyles[id])\n\t\t\t\tstyles.push(newStyles[id] = {id: id, parts: [part]});\n\t\t\telse\n\t\t\t\tnewStyles[id].parts.push(part);\n\t\t}\n\t\treturn styles;\n\t}\n\n\tfunction insertStyleElement(options, styleElement) {\n\t\tvar head = getHeadElement();\n\t\tvar lastStyleElementInsertedAtTop = styleElementsInsertedAtTop[styleElementsInsertedAtTop.length - 1];\n\t\tif (options.insertAt === \"top\") {\n\t\t\tif(!lastStyleElementInsertedAtTop) {\n\t\t\t\thead.insertBefore(styleElement, head.firstChild);\n\t\t\t} else if(lastStyleElementInsertedAtTop.nextSibling) {\n\t\t\t\thead.insertBefore(styleElement, lastStyleElementInsertedAtTop.nextSibling);\n\t\t\t} else {\n\t\t\t\thead.appendChild(styleElement);\n\t\t\t}\n\t\t\tstyleElementsInsertedAtTop.push(styleElement);\n\t\t} else if (options.insertAt === \"bottom\") {\n\t\t\thead.appendChild(styleElement);\n\t\t} else {\n\t\t\tthrow new Error(\"Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'.\");\n\t\t}\n\t}\n\n\tfunction removeStyleElement(styleElement) {\n\t\tstyleElement.parentNode.removeChild(styleElement);\n\t\tvar idx = styleElementsInsertedAtTop.indexOf(styleElement);\n\t\tif(idx >= 0) {\n\t\t\tstyleElementsInsertedAtTop.splice(idx, 1);\n\t\t}\n\t}\n\n\tfunction createStyleElement(options) {\n\t\tvar styleElement = document.createElement(\"style\");\n\t\tstyleElement.type = \"text/css\";\n\t\tinsertStyleElement(options, styleElement);\n\t\treturn styleElement;\n\t}\n\n\tfunction createLinkElement(options) {\n\t\tvar linkElement = document.createElement(\"link\");\n\t\tlinkElement.rel = \"stylesheet\";\n\t\tinsertStyleElement(options, linkElement);\n\t\treturn linkElement;\n\t}\n\n\tfunction addStyle(obj, options) {\n\t\tvar styleElement, update, remove;\n\n\t\tif (options.singleton) {\n\t\t\tvar styleIndex = singletonCounter++;\n\t\t\tstyleElement = singletonElement || (singletonElement = createStyleElement(options));\n\t\t\tupdate = applyToSingletonTag.bind(null, styleElement, styleIndex, false);\n\t\t\tremove = applyToSingletonTag.bind(null, styleElement, styleIndex, true);\n\t\t} else if(obj.sourceMap &&\n\t\t\ttypeof URL === \"function\" &&\n\t\t\ttypeof URL.createObjectURL === \"function\" &&\n\t\t\ttypeof URL.revokeObjectURL === \"function\" &&\n\t\t\ttypeof Blob === \"function\" &&\n\t\t\ttypeof btoa === \"function\") {\n\t\t\tstyleElement = createLinkElement(options);\n\t\t\tupdate = updateLink.bind(null, styleElement);\n\t\t\tremove = function() {\n\t\t\t\tremoveStyleElement(styleElement);\n\t\t\t\tif(styleElement.href)\n\t\t\t\t\tURL.revokeObjectURL(styleElement.href);\n\t\t\t};\n\t\t} else {\n\t\t\tstyleElement = createStyleElement(options);\n\t\t\tupdate = applyToTag.bind(null, styleElement);\n\t\t\tremove = function() {\n\t\t\t\tremoveStyleElement(styleElement);\n\t\t\t};\n\t\t}\n\n\t\tupdate(obj);\n\n\t\treturn function updateStyle(newObj) {\n\t\t\tif(newObj) {\n\t\t\t\tif(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap)\n\t\t\t\t\treturn;\n\t\t\t\tupdate(obj = newObj);\n\t\t\t} else {\n\t\t\t\tremove();\n\t\t\t}\n\t\t};\n\t}\n\n\tvar replaceText = (function () {\n\t\tvar textStore = [];\n\n\t\treturn function (index, replacement) {\n\t\t\ttextStore[index] = replacement;\n\t\t\treturn textStore.filter(Boolean).join('\\n');\n\t\t};\n\t})();\n\n\tfunction applyToSingletonTag(styleElement, index, remove, obj) {\n\t\tvar css = remove ? \"\" : obj.css;\n\n\t\tif (styleElement.styleSheet) {\n\t\t\tstyleElement.styleSheet.cssText = replaceText(index, css);\n\t\t} else {\n\t\t\tvar cssNode = document.createTextNode(css);\n\t\t\tvar childNodes = styleElement.childNodes;\n\t\t\tif (childNodes[index]) styleElement.removeChild(childNodes[index]);\n\t\t\tif (childNodes.length) {\n\t\t\t\tstyleElement.insertBefore(cssNode, childNodes[index]);\n\t\t\t} else {\n\t\t\t\tstyleElement.appendChild(cssNode);\n\t\t\t}\n\t\t}\n\t}\n\n\tfunction applyToTag(styleElement, obj) {\n\t\tvar css = obj.css;\n\t\tvar media = obj.media;\n\n\t\tif(media) {\n\t\t\tstyleElement.setAttribute(\"media\", media)\n\t\t}\n\n\t\tif(styleElement.styleSheet) {\n\t\t\tstyleElement.styleSheet.cssText = css;\n\t\t} else {\n\t\t\twhile(styleElement.firstChild) {\n\t\t\t\tstyleElement.removeChild(styleElement.firstChild);\n\t\t\t}\n\t\t\tstyleElement.appendChild(document.createTextNode(css));\n\t\t}\n\t}\n\n\tfunction updateLink(linkElement, obj) {\n\t\tvar css = obj.css;\n\t\tvar sourceMap = obj.sourceMap;\n\n\t\tif(sourceMap) {\n\t\t\t// http://stackoverflow.com/a/26603875\n\t\t\tcss += \"\\n/*# sourceMappingURL=data:application/json;base64,\" + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + \" */\";\n\t\t}\n\n\t\tvar blob = new Blob([css], { type: \"text/css\" });\n\n\t\tvar oldSrc = linkElement.href;\n\n\t\tlinkElement.href = URL.createObjectURL(blob);\n\n\t\tif(oldSrc)\n\t\t\tURL.revokeObjectURL(oldSrc);\n\t}\n\n\n/***/ })\n/******/ ]);"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"apng-js\",\n  \"version\": \"1.1.5\",\n  \"description\": \"Parse and play animated PNG (APNG)\",\n  \"homepage\": \"https://github.com/davidmz/apng-js\",\n  \"repository\": \"davidmz/apng-js\",\n  \"main\": \"lib/index.js\",\n  \"types\": \"types/library/parser.d.ts\",\n  \"scripts\": {\n    \"build\": \"webpack\",\n    \"prepublish\": \"yarn build\"\n  },\n  \"author\": {\n    \"name\": \"David Mzareulyan\",\n    \"email\": \"david@hiero.ru\",\n    \"url\": \"https://github.com/davidmz\"\n  },\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"@typescript-eslint/eslint-plugin\": \"~2.27.0\",\n    \"@typescript-eslint/parser\": \"~2.27.0\",\n    \"babel-core\": \"^6.26.0\",\n    \"babel-eslint\": \"^8.2.6\",\n    \"babel-loader\": \"^6.4.1\",\n    \"babel-plugin-transform-class-properties\": \"^6.24.1\",\n    \"babel-preset-env\": \"^1.7.0\",\n    \"css-loader\": \"^1.0.1\",\n    \"eslint\": \"^5.16.0\",\n    \"eslint-config-standard\": \"^12.0.0\",\n    \"eslint-plugin-import\": \"^2.17.3\",\n    \"eslint-plugin-node\": \"^9.1.0\",\n    \"eslint-plugin-promise\": \"^4.1.1\",\n    \"eslint-plugin-standard\": \"^4.0.0\",\n    \"style-loader\": \"^0.13.2\",\n    \"typescript\": \"~3.8.3\",\n    \"webpack\": \"^1.15.0\"\n  },\n  \"dependencies\": {}\n}\n"
  },
  {
    "path": "src/demo-page/index.js",
    "content": "import parseAPNG from '../library/parser'\nimport './style.css'\n\nconst fileInput = document.createElement('input')\nfileInput.type = 'file'\nfileInput.accept = 'image/png'\n\ndocument.getElementById('choose-btn').addEventListener('click', () => fileInput.click())\n\nfileInput.addEventListener('change', () => {\n  if (fileInput.files.length > 0) {\n    processFile(fileInput.files[0])\n  }\n  fileInput.value = ''\n})\n\nlet player = null\n\ndocument.getElementById('play-pause-btn').addEventListener('click', () => {\n  if (player) {\n    if (player.paused) {\n      player.play()\n    } else {\n      player.pause()\n    }\n  }\n})\n\ndocument.getElementById('stop-btn').addEventListener('click', () => player && player.stop())\n\nlet playbackRate = 1.0\ndocument.getElementById('playback-rate').addEventListener('change', e => {\n  playbackRate = parseFloat(e.target.value)\n  document.getElementById('playback-rate-display').innerHTML = playbackRate.toString()\n  if (player) {\n    player.playbackRate = playbackRate\n  }\n})\n\nfunction processFile (file) {\n  const resultBlock = document.querySelector('.apng-result')\n  const errorBlock = document.querySelector('.apng-error')\n  const errDiv = errorBlock.querySelector('.alert')\n  const infoDiv = document.querySelector('.apng-info')\n  const framesDiv = document.querySelector('.apng-frames')\n  const canvasDiv = document.querySelector('.apng-ani')\n  const logDiv = document.querySelector('.apng-log')\n\n  resultBlock.classList.add('hidden')\n  errorBlock.classList.add('hidden')\n  emptyEl(infoDiv)\n  emptyEl(framesDiv)\n  emptyEl(canvasDiv)\n  emptyEl(errDiv)\n  emptyEl(logDiv)\n  if (player) {\n    player.stop()\n  }\n\n  const log = [];\n\n  const reader = new FileReader()\n  reader.onload = () => {\n    const apng = parseAPNG(reader.result)\n    if (apng instanceof Error) {\n      errDiv.appendChild(document.createTextNode(apng.message))\n      errorBlock.classList.remove('hidden')\n      return\n    }\n    apng.createImages().then(() => {\n      infoDiv.appendChild(document.createTextNode(JSON.stringify(apng, null, '  ')))\n      apng.frames.forEach(f => {\n        const div = framesDiv.appendChild(document.createElement('div'))\n        div.appendChild(f.imageElement)\n        div.style.width = `${apng.width}px`\n        div.style.height = `${apng.height}px`\n        f.imageElement.style.left = `${f.left}px`\n        f.imageElement.style.top = `${f.top}px`\n      })\n\n      const canvas = document.createElement('canvas')\n      canvas.width = apng.width\n      canvas.height = apng.height\n      canvasDiv.appendChild(canvas)\n\n      apng.getPlayer(canvas.getContext('2d')).then(p => {\n        player = p\n        player.playbackRate = playbackRate\n        const em = player.emit;\n        player.emit = (event, ...args) => {\n          log.unshift({event, args});\n          if (log.length > 10) {\n            log.splice(10, log.length - 10);\n          }\n          logDiv.textContent = log.map(({event, args}) => `${event}: ${JSON.stringify(args)}`).join(\"\\n\");\n\n          em.call(player, event, ...args);\n        }\n        player.play()\n      })\n    })\n    resultBlock.classList.remove('hidden')\n  }\n  reader.readAsArrayBuffer(file)\n}\n\nfunction emptyEl (el) {\n  let c\n  while ((c = el.firstChild) !== null) {\n    el.removeChild(c)\n  }\n}\n"
  },
  {
    "path": "src/demo-page/style.css",
    "content": ".apng-info,\n.apng-frames {\n    max-height: 600px;\n    overflow:   auto;\n}\n\n.apng-frames > div {\n    float:            left;\n    margin:           1px 1px 8px 8px;\n    box-shadow:       0 0 0 1px;\n    position:         relative;\n    background:       linear-gradient(45deg, #fff 25%, transparent 26%, transparent 75%, #fff 76%),\n                      linear-gradient(-45deg, #fff 25%, transparent 26%, transparent 75%, #fff 76%);\n    background-color: #eee;\n    background-size:  20px 20px;\n}\n\n.apng-frames > div > img {\n    position:   absolute;\n    box-shadow: 0 0 0 1px rgba(255, 0, 0, 0.75);\n}\n\n#playback-rate {\n    width:   12em;\n    display: inline-block;\n}\n\n.apng-log {\n    height: 10em;\n}"
  },
  {
    "path": "src/library/crc32.js",
    "content": "const table = new Uint32Array(256)\n\nfor (let i = 0; i < 256; i++) {\n  let c = i\n  for (let k = 0; k < 8; k++) {\n    c = ((c & 1) !== 0) ? 0xEDB88320 ^ (c >>> 1) : c >>> 1\n  }\n  table[i] = c\n}\n\n/**\n *\n * @param {Uint8Array} bytes\n * @param {number} start\n * @param {number} length\n * @return {number}\n */\nexport default function (bytes, start = 0, length = bytes.length - start) {\n  let crc = -1\n  for (let i = start, l = start + length; i < l; i++) {\n    crc = (crc >>> 8) ^ table[(crc ^ bytes[i]) & 0xFF]\n  }\n  return crc ^ (-1)\n}\n"
  },
  {
    "path": "src/library/parser.js",
    "content": "import crc32 from './crc32';\nimport {APNG, Frame} from './structs';\n\nconst errNotPNG = new Error('Not a PNG');\nconst errNotAPNG = new Error('Not an animated PNG');\n\nexport function isNotPNG(err) { return err === errNotPNG; }\nexport function isNotAPNG(err) { return err === errNotAPNG; }\n\n// '\\x89PNG\\x0d\\x0a\\x1a\\x0a'\nconst PNGSignature = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\n\n/**\n * Parse APNG data\n * @param {ArrayBuffer} buffer\n * @return {APNG|Error}\n */\nexport default function parseAPNG(buffer) {\n    const bytes = new Uint8Array(buffer);\n\n    if (Array.prototype.some.call(PNGSignature, (b, i) => b !== bytes[i])) {\n        return errNotPNG;\n    }\n\n    // fast animation test\n    let isAnimated = false;\n    eachChunk(bytes, type => !(isAnimated = (type === 'acTL')));\n    if (!isAnimated) {\n        return errNotAPNG;\n    }\n\n    const\n        preDataParts = [],\n        postDataParts = [];\n    let\n        headerDataBytes = null,\n        frame = null,\n        frameNumber = 0,\n        apng = new APNG();\n\n    eachChunk(bytes, (type, bytes, off, length) => {\n        const dv = new DataView(bytes.buffer);\n        switch (type) {\n            case 'IHDR':\n                headerDataBytes = bytes.subarray(off + 8, off + 8 + length);\n                apng.width = dv.getUint32(off + 8);\n                apng.height = dv.getUint32(off + 12);\n                break;\n            case 'acTL':\n                apng.numPlays = dv.getUint32(off + 8 + 4);\n                break;\n            case 'fcTL':\n                if (frame) {\n                    apng.frames.push(frame);\n                    frameNumber++;\n                }\n                frame = new Frame();\n                frame.width = dv.getUint32(off + 8 + 4);\n                frame.height = dv.getUint32(off + 8 + 8);\n                frame.left = dv.getUint32(off + 8 + 12);\n                frame.top = dv.getUint32(off + 8 + 16);\n                var delayN = dv.getUint16(off + 8 + 20);\n                var delayD = dv.getUint16(off + 8 + 22);\n                if (delayD === 0) {\n                    delayD = 100;\n                }\n                frame.delay = 1000 * delayN / delayD;\n                // https://bugzilla.mozilla.org/show_bug.cgi?id=125137\n                // https://bugzilla.mozilla.org/show_bug.cgi?id=139677\n                // https://bugzilla.mozilla.org/show_bug.cgi?id=207059\n                if (frame.delay <= 10) {\n                    frame.delay = 100;\n                }\n                apng.playTime += frame.delay;\n                frame.disposeOp = dv.getUint8(off + 8 + 24);\n                frame.blendOp = dv.getUint8(off + 8 + 25);\n                frame.dataParts = [];\n                if (frameNumber === 0 && frame.disposeOp === 2) {\n                    frame.disposeOp = 1;\n                }\n                break;\n            case 'fdAT':\n                if (frame) {\n                    frame.dataParts.push(bytes.subarray(off + 8 + 4, off + 8 + length));\n                }\n                break;\n            case 'IDAT':\n                if (frame) {\n                    frame.dataParts.push(bytes.subarray(off + 8, off + 8 + length));\n                }\n                break;\n            case 'IEND':\n                postDataParts.push(subBuffer(bytes, off, 12 + length));\n                break;\n            default:\n                preDataParts.push(subBuffer(bytes, off, 12 + length));\n        }\n    });\n\n    if (frame) {\n        apng.frames.push(frame);\n    }\n\n    if (apng.frames.length == 0) {\n        return errNotAPNG;\n    }\n\n    const preBlob = new Blob(preDataParts),\n        postBlob = new Blob(postDataParts);\n\n    apng.frames.forEach(frame => {\n        var bb = [];\n        bb.push(PNGSignature);\n        headerDataBytes.set(makeDWordArray(frame.width), 0);\n        headerDataBytes.set(makeDWordArray(frame.height), 4);\n        bb.push(makeChunkBytes('IHDR', headerDataBytes));\n        bb.push(preBlob);\n        frame.dataParts.forEach(p => bb.push(makeChunkBytes('IDAT', p)));\n        bb.push(postBlob);\n        frame.imageData = new Blob(bb, {'type': 'image/png'});\n        delete frame.dataParts;\n        bb = null;\n    });\n\n    return apng;\n}\n\n/**\n * @param {Uint8Array} bytes\n * @param {function(string, Uint8Array, int, int): boolean} callback\n */\nfunction eachChunk(bytes, callback) {\n    const dv = new DataView(bytes.buffer);\n    let off = 8, type, length, res;\n    do {\n        length = dv.getUint32(off);\n        type = readString(bytes, off + 4, 4);\n        res = callback(type, bytes, off, length);\n        off += 12 + length;\n    } while (res !== false && type != 'IEND' && off < bytes.length);\n}\n\n/**\n *\n * @param {Uint8Array} bytes\n * @param {number} off\n * @param {number} length\n * @return {string}\n */\nfunction readString(bytes, off, length) {\n    const chars = Array.prototype.slice.call(bytes.subarray(off, off + length));\n    return String.fromCharCode.apply(String, chars);\n}\n\n/**\n *\n * @param {string} x\n * @return {Uint8Array}\n */\nfunction makeStringArray(x) {\n    const res = new Uint8Array(x.length);\n    for (let i = 0; i < x.length; i++) {\n        res[i] = x.charCodeAt(i);\n    }\n    return res;\n}\n\n\n/**\n * @param {Uint8Array} bytes\n * @param {int} start\n * @param {int} length\n * @return {Uint8Array}\n */\nfunction subBuffer(bytes, start, length) {\n    const a = new Uint8Array(length);\n    a.set(bytes.subarray(start, start + length));\n    return a;\n}\n\n/**\n * @param {string} type\n * @param {Uint8Array} dataBytes\n * @return {Uint8Array}\n */\nvar makeChunkBytes = function (type, dataBytes) {\n    const crcLen = type.length + dataBytes.length;\n    const bytes = new Uint8Array(crcLen + 8);\n    const dv = new DataView(bytes.buffer);\n\n    dv.setUint32(0, dataBytes.length);\n    bytes.set(makeStringArray(type), 4);\n    bytes.set(dataBytes, 8);\n    var crc = crc32(bytes, 4, crcLen);\n    dv.setUint32(crcLen + 4, crc);\n    return bytes;\n};\n\nvar makeDWordArray = function (x) {\n    return new Uint8Array([(x >>> 24) & 0xff, (x >>> 16) & 0xff, (x >>> 8) & 0xff, x & 0xff]);\n};\n"
  },
  {
    "path": "src/library/player.js",
    "content": "import EventEmitter from 'events';\n\nexport default class extends EventEmitter {\n    /** @type {CanvasRenderingContext2D} */\n    context;\n    /** @type {number} */\n    playbackRate = 1.0;\n\n    /** @type {APNG} */\n    _apng;\n    /** @type {Frame} */\n    _prevFrame;\n    /** @type {ImageData} */\n    _prevFrameData;\n    /** @type {number} */\n    _currentFrameNumber = 0;\n\n    /** @type {boolean} */\n    _ended = false;\n    /** @type {boolean} */\n    _paused = true;\n    /** @type {number} */\n    _numPlays = 0;\n    /** @type {number|null} */\n    _rafId = null;\n\n    /**\n     * @param {APNG} apng\n     * @param {CanvasRenderingContext2D} context\n     * @param {boolean} autoPlay\n     */\n    constructor(apng, context, autoPlay) {\n        super();\n        this._apng = apng;\n        this.context = context;\n        this.stop();\n        if (autoPlay) {\n            this.play();\n        }\n    }\n\n    /**\n     *\n     * @return {number}\n     */\n    get currentFrameNumber() {\n        return this._currentFrameNumber;\n    }\n\n    /**\n     *\n     * @return {Frame}\n     */\n    get currentFrame() {\n        return this._apng.frames[this._currentFrameNumber];\n    }\n\n    renderNextFrame() {\n        this._currentFrameNumber = (this._currentFrameNumber + 1) % this._apng.frames.length;\n        if (this._currentFrameNumber === this._apng.frames.length - 1) {\n            this._numPlays++;\n            if (this._apng.numPlays !== 0 && this._numPlays >= this._apng.numPlays) {\n                this._ended = true;\n                this._paused = true;\n            }\n        }\n\n        if (this._prevFrame && this._prevFrame.disposeOp == 1) {\n            this.context.clearRect(this._prevFrame.left, this._prevFrame.top, this._prevFrame.width, this._prevFrame.height);\n        } else if (this._prevFrame && this._prevFrame.disposeOp == 2) {\n            this.context.putImageData(this._prevFrameData, this._prevFrame.left, this._prevFrame.top);\n        }\n\n        const frame = this.currentFrame;\n        this._prevFrame = frame;\n        this._prevFrameData = null;\n        if (frame.disposeOp == 2) {\n            this._prevFrameData = this.context.getImageData(frame.left, frame.top, frame.width, frame.height);\n        }\n        if (frame.blendOp == 0) {\n            this.context.clearRect(frame.left, frame.top, frame.width, frame.height);\n        }\n\n        this.context.drawImage(frame.imageElement, frame.left, frame.top);\n\n        this.emit('frame', this._currentFrameNumber);\n        if (this._ended) {\n            this.emit('end');\n        }\n    }\n\n    // playback\n\n    get paused() { return this._paused; }\n\n    get ended() { return this._ended; }\n\n    play() {\n        if (this._rafId) {\n            cancelAnimationFrame(this._rafId);\n        }\n\n        this.emit('play');\n\n        if (this._ended) {\n            this.stop();\n        }\n        this._paused = false;\n\n        let nextRenderTime = performance.now() + this.currentFrame.delay / this.playbackRate;\n        const tick = now => {\n            if (this._ended || this._paused) {\n                return;\n            }\n            if (now >= nextRenderTime) {\n                while (now - nextRenderTime >= this._apng.playTime / this.playbackRate) {\n                    nextRenderTime += this._apng.playTime / this.playbackRate;\n                    this._numPlays++;\n                }\n                do {\n                    this.renderNextFrame();\n                    nextRenderTime += this.currentFrame.delay / this.playbackRate;\n                } while (!this._ended && !this._paused && now > nextRenderTime);\n            }\n            this._rafId = requestAnimationFrame(tick);\n        };\n        this._rafId = requestAnimationFrame(tick);\n    }\n\n    pause() {\n        if (!this._paused) {\n            if (this._rafId) {\n                cancelAnimationFrame(this._rafId);\n                this._rafId = null;\n            }\n            this.emit('pause');\n            this._paused = true;\n        }\n    }\n\n    stop() {\n        if (this._rafId) {\n            cancelAnimationFrame(this._rafId);\n            this._rafId = null;\n        }\n        this.emit('stop');\n        this._numPlays = 0;\n        this._ended = false;\n        this._paused = true;\n        // render first frame\n        this._currentFrameNumber = -1;\n        this.context.clearRect(0, 0, this._apng.width, this._apng.height);\n        this.renderNextFrame();\n    }\n}"
  },
  {
    "path": "src/library/structs.js",
    "content": "import Player from './player';\n\n/**\n * @property {number} currFrameNumber\n * @property {Frame} currFrame\n * @property {boolean} paused\n * @property {boolean} ended\n */\nexport class APNG {\n    /** @type {number} */\n    width = 0;\n    /** @type {number} */\n    height = 0;\n    /** @type {number} */\n    numPlays = 0;\n    /** @type {number} */\n    playTime = 0;\n    /** @type {Frame[]} */\n    frames = [];\n\n    /**\n     *\n     * @return {Promise.<*>}\n     */\n    createImages() {\n        return Promise.all(this.frames.map(f => f.createImage()));\n    }\n\n    /**\n     *\n     * @param {CanvasRenderingContext2D} context\n     * @param {boolean} autoPlay\n     * @return {Promise.<Player>}\n     */\n    getPlayer(context, autoPlay = false) {\n        return this.createImages().then(() => new Player(this, context, autoPlay));\n    }\n}\n\nexport class Frame {\n    /** @type {number} */\n    left = 0;\n    /** @type {number} */\n    top = 0;\n    /** @type {number} */\n    width = 0;\n    /** @type {number} */\n    height = 0;\n    /** @type {number} */\n    delay = 0;\n    /** @type {number} */\n    disposeOp = 0;\n    /** @type {number} */\n    blendOp = 0;\n    /** @type {Blob} */\n    imageData = null;\n    /** @type {HTMLImageElement} */\n    imageElement = null;\n\n    createImage() {\n        if (this.imageElement) {\n            return Promise.resolve();\n        }\n        return new Promise((resolve, reject) => {\n            const url = URL.createObjectURL(this.imageData);\n            this.imageElement = document.createElement('img');\n            this.imageElement.onload = () => {\n                URL.revokeObjectURL(url);\n                resolve();\n            };\n            this.imageElement.onerror = () => {\n                URL.revokeObjectURL(url);\n                this.imageElement = null;\n                reject(new Error(\"Image creation error\"));\n            };\n            this.imageElement.src = url;\n        });\n    }\n}\n"
  },
  {
    "path": "types/library/crc32.d.ts",
    "content": "export default function crc32(bytes: Uint8Array, start?: number, length?: number): number;\n"
  },
  {
    "path": "types/library/parser.d.ts",
    "content": "import { APNG, Frame } from './structs';\nexport declare function isNotPNG(err: unknown): boolean;\nexport declare function isNotAPNG(err: unknown): boolean;\n/**\n * Parse APNG data\n *\n */\nexport default function parseAPNG(buffer: ArrayBuffer): Error | APNG;\n\nexport { APNG, Frame };\n"
  },
  {
    "path": "types/library/player.d.ts",
    "content": "import { EventEmitter } from 'events';\nimport { APNG, Frame } from './structs';\ndeclare class Player extends EventEmitter {\n    context: CanvasRenderingContext2D;\n    /**\n     * animation playback rate\n     */\n    playbackRate: number;\n    private _apng;\n    private _prevFrame?;\n    private _prevFrameData;\n    private _currentFrameNumber;\n    private _ended;\n    private _paused;\n    private _numPlays;\n    constructor(apng: APNG, context: CanvasRenderingContext2D, autoPlay: boolean);\n    /**\n     * current frame number\n     */\n    get currentFrameNumber(): number;\n    /**\n     * current frame\n     */\n    get currentFrame(): Frame;\n    /**\n     * move to next frame and render it on context\n     *\n     *  Use this method to manual, frame by frame, rendering.\n     */\n    renderNextFrame(): void;\n    /**\n     * playback is paused\n     */\n    get paused(): boolean;\n    /**\n     * playback is ended\n     */\n    get ended(): boolean;\n    /**\n     * start or resume playback\n     */\n    play(): void;\n    /**\n     * pause playback\n     */\n    pause(): void;\n    /**\n     * stop playback and rewind to start\n     */\n    stop(): void;\n}\ninterface Player {\n    /**\n     * playback started\n     */\n    addListener(event: 'play', listener: () => void): this;\n    /**\n     * frame played\n     */\n    addListener(event: 'frame', listener: (currentFrameNumber: number) => void): this;\n    /**\n     * playback paused\n     */\n    addListener(event: 'pause', listener: () => void): this;\n    /**\n     * playback stopped\n     */\n    addListener(event: 'stop', listener: () => void): this;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    addListener(event: 'end', listener: () => void): this;\n    /**\n     * playback started\n     */\n    on(event: 'play', listener: () => void): this;\n    /**\n     * frame played\n     */\n    on(event: 'frame', listener: (currentFrameNumber: number) => void): this;\n    /**\n     * playback paused\n     */\n    on(event: 'pause', listener: () => void): this;\n    /**\n     * playback stopped\n     */\n    on(event: 'stop', listener: () => void): this;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    on(event: 'end', listener: () => void): this;\n    /**\n     * playback started\n     */\n    once(event: 'play', listener: () => void): this;\n    /**\n     * frame played\n     */\n    once(event: 'frame', listener: (currentFrameNumber: number) => void): this;\n    /**\n     * playback paused\n     */\n    once(event: 'pause', listener: () => void): this;\n    /**\n     * playback stopped\n     */\n    once(event: 'stop', listener: () => void): this;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    once(event: 'end', listener: () => void): this;\n    /**\n     * playback started\n     */\n    removeListener(event: 'play', listener: () => void): this;\n    /**\n     * frame played\n     */\n    removeListener(event: 'frame', listener: (currentFrameNumber: number) => void): this;\n    /**\n     * playback paused\n     */\n    removeListener(event: 'pause', listener: () => void): this;\n    /**\n     * playback stopped\n     */\n    removeListener(event: 'stop', listener: () => void): this;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    removeListener(event: 'end', listener: () => void): this;\n    /**\n     * playback started\n     */\n    off(event: 'play', listener: () => void): this;\n    /**\n     * frame played\n     */\n    off(event: 'frame', listener: (currentFrameNumber: number) => void): this;\n    /**\n     * playback paused\n     */\n    off(event: 'pause', listener: () => void): this;\n    /**\n     * playback stopped\n     */\n    off(event: 'stop', listener: () => void): this;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    off(event: 'end', listener: () => void): this;\n    /**\n     * playback started\n     */\n    emit(event: 'play'): boolean;\n    /**\n     * frame played\n     */\n    emit(event: 'frame', currentFrameNumber: number): boolean;\n    /**\n     * playback paused\n     */\n    emit(event: 'pause'): boolean;\n    /**\n     * playback stopped\n     */\n    emit(event: 'stop'): boolean;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    emit(event: 'end'): boolean;\n    /**\n     * playback started\n     */\n    prependListener(event: 'play', listener: () => void): this;\n    /**\n     * frame played\n     */\n    prependListener(event: 'frame', listener: (currentFrameNumber: number) => void): this;\n    /**\n     * playback paused\n     */\n    prependListener(event: 'pause', listener: () => void): this;\n    /**\n     * playback stopped\n     */\n    prependListener(event: 'stop', listener: () => void): this;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    prependListener(event: 'end', listener: () => void): this;\n    /**\n     * playback started\n     */\n    prependOnceListener(event: 'play', listener: () => void): this;\n    /**\n     * frame played\n     */\n    prependOnceListener(event: 'frame', listener: (currentFrameNumber: number) => void): this;\n    /**\n     * playback paused\n     */\n    prependOnceListener(event: 'pause', listener: () => void): this;\n    /**\n     * playback stopped\n     */\n    prependOnceListener(event: 'stop', listener: () => void): this;\n    /**\n     * playback ended (for APNG with finite count of plays)\n     */\n    prependOnceListener(event: 'end', listener: () => void): this;\n}\nexport default Player;\n"
  },
  {
    "path": "types/library/structs.d.ts",
    "content": "import Player from './player';\nexport declare class APNG {\n    /**\n     * with of canvas, pixels\n     */\n    width: number;\n    /**\n     * height of canvas, pixels\n     */\n    height: number;\n    /**\n     * number of times to loop animation (0 = infinite looping)\n     */\n    numPlays: number;\n    /**\n     * total duration of one loop in milliseconds\n     */\n    playTime: number;\n    /**\n     * array of frames\n     */\n    frames: Frame[];\n    /**\n     * create imageElement's for all frames\n     */\n    createImages(): Promise<void[]>;\n    /**\n     * Create Player on given context and start playing if autoPlay is true.\n     * @param context CanvasRenderingContext2D\n     * @param autoPlay default is `false`\n     */\n    getPlayer(context: CanvasRenderingContext2D, autoPlay?: boolean): Promise<Player>;\n}\nexport declare class Frame {\n    /**\n     * left offset of frame, pixels\n     */\n    left: number;\n    /**\n     * top offset of frame, pixels\n     */\n    top: number;\n    /**\n     * with of frame, pixels\n     */\n    width: number;\n    /**\n     * height of frame, pixels\n     */\n    height: number;\n    /**\n     * time to show frame in milliseconds\n     */\n    delay: number;\n    /**\n     * type of dispose operation (see APNG spec.)\n     */\n    disposeOp: number;\n    /**\n     * type of blend operation (see APNG spec.)\n     */\n    blendOp: number;\n    /**\n     * image data in PNG (not animated) format\n     */\n    imageData: Blob | null;\n    /**\n     * image data rendered as HTML Image element.\n     *\n     * This field is null right after 'parse', use `Frame.createImage()` or `APNG.createImages()` to fill this field.\n     */\n    imageElement: HTMLImageElement | null;\n    dataParts?: Array<Uint8Array>;\n    /**\n     * create imageElement for this frame\n     */\n    createImage(): Promise<void>;\n}\n"
  },
  {
    "path": "webpack.config.js",
    "content": "var path = require('path')\n\nmodule.exports = [\n  {\n    entry: path.join(__dirname, 'src', 'library', 'parser.js'),\n    output: {\n      path: path.join(__dirname, 'lib'),\n      filename: 'index.js',\n      library: 'apng-js',\n      libraryTarget: 'umd'\n    },\n    module: {\n      loaders: [\n        {\n          test: /\\.js$/,\n          loader: 'babel-loader',\n          exclude: /[\\\\\\/](node_modules|lib)[\\\\\\/]/\n        }\n      ]\n    }\n  },\n  {\n    entry: path.join(__dirname, 'src', 'demo-page', 'index.js'),\n    output: {\n      path: path.join(__dirname, 'docs'),\n      filename: 'index.js'\n    },\n    module: {\n      loaders: [\n        {\n          test: /\\.js$/,\n          loader: 'babel-loader',\n          exclude: /[\\\\\\/](node_modules|lib)[\\\\\\/]/\n        },\n        {\n          test: /\\.css$/,\n          exclude: /[\\\\\\/](node_modules|lib)[\\\\\\/]/,\n          loader: 'style-loader!css-loader'\n        }\n      ]\n    }/*,\n     plugins: [\n     new webpack.optimize.UglifyJsPlugin({\n     compress: {\n     warnings: false,\n     screw_ie8: true\n     },\n     comments: false\n     })\n     ] */\n  }\n]\n"
  }
]