e-hentai retriever

e-hentai & exhentai image url retriever

2017-07-23 기준 버전입니다. 최신 버전을 확인하세요.

// ==UserScript==
// @name        e-hentai retriever
// @namespace   http://e-hentai.org
// @description e-hentai & exhentai image url retriever
// @include     /^https?:\/\/e-hentai.org\/s\/.*/
// @include     /^https?:\/\/exhentai.org\/s\/.*/
// @version     3.0.3
// @grant       GM_xmlhttpRequest
// @grant       unsafeWindow
// ==/UserScript==

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}


/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	__webpack_require__(1);

	var _ehretriever = __webpack_require__(3);

	var _ehretriever2 = _interopRequireDefault(_ehretriever);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	var LoadTimeout = 10000;
	var AutoReload = true;

	// helper functions
	var $ = function $(selector) {
	  return document.querySelector(selector);
	};
	var $$ = function $$(selector) {
	  return Array.from(document.querySelectorAll(selector));
	};

	var buttonDoubleFrame = document.createElement('button');
	buttonDoubleFrame.textContent = "Double Frame";
	$('#i1').insertBefore(buttonDoubleFrame, $('#i2'));

	var buttonRetrieve = document.createElement('button');
	buttonRetrieve.textContent = 'Retrieve!';
	$('#i1').insertBefore(buttonRetrieve, $('#i2'));

	var buttonRange = document.createElement('button');
	buttonRange.textContent = 'Set Range';
	$('#i1').insertBefore(buttonRange, $('#i2'));

	var ehentaiResize = void 0;
	var maxImageWidth = void 0;
	var originalWidth = void 0;

	buttonDoubleFrame.addEventListener('click', function (event) {
	  if (!ehentaiResize) {
	    try {
	      ehentaiResize = unsafeWindow.onresize;
	    } catch (e) {
	      console.log(e);
	    }
	  }

	  if (!maxImageWidth) {
	    maxImageWidth = Math.max.apply(null, $$('#i3 a img').map(function (e) {
	      return parseInt(e.style.width, 10);
	    }));
	  }

	  if (!originalWidth) {
	    originalWidth = parseInt($('#i1').style.width, 10);
	  }

	  if (buttonDoubleFrame.textContent === 'Double Frame') {
	    buttonDoubleFrame.textContent = 'Reset Frame';

	    try {
	      unsafeWindow.onresize = null;
	    } catch (e) {
	      console.log(e);
	    };

	    $('#i1').style.maxWidth = maxImageWidth * 2 + 20 + 'px';
	    $('#i1').style.width = maxImageWidth * 2 + 20 + 'px';
	  } else {
	    buttonDoubleFrame.textContent = 'Double Frame';

	    try {
	      unsafeWindow.onresize = ehentaiResize;
	      ehentaiResize();
	    } catch (e) {
	      console.log(e);
	      $('#i1').style.maxWidth = originalWidth + 'px';
	      $('#i1').style.width = originalWidth + 'px';
	    }
	  }
	});

	var ehr = void 0;

	buttonRetrieve.addEventListener('click', function (event) {
	  buttonRetrieve.setAttribute('disabled', '');
	  buttonRange.setAttribute('disabled', '');
	  buttonRetrieve.textContent = 'Initializing...';

	  if (!ehr) {
	    ehr = new _ehretriever2.default(location.href, document.body.innerHTML);
	    console.log(ehr);
	  }

	  ehr.onPageLoad(function (page, total) {
	    buttonRetrieve.textContent = page + '/' + total;
	  });

	  var retrieve = void 0;

	  if (document.getElementById('ehrstart')) {
	    var start = parseInt(document.getElementById('ehrstart').value, 10);
	    var stop = parseInt(document.getElementById('ehrstop').value, 10);
	    var pageNumMax = parseInt($('div.sn').textContent.match(/\/\s*(\d+)/)[1], 10);

	    if (stop < start || start <= 0 || start > pageNumMax || stop > pageNumMax) {
	      alert('invalid range: ' + start + ' - ' + stop + ', accepted range: 1 - ' + pageNumMax);
	      buttonRetrieve.textContent = 'Retrieve!';
	      buttonRetrieve.removeAttribute('disabled');
	      return;
	    }

	    retrieve = ehr.retrieve(start - 1, stop - 1);
	    $('#ehrsetrange').parentNode.removeChild($('#ehrsetrange'));
	  } else {
	    retrieve = ehr.retrieve();
	    buttonRange.parentNode.removeChild(buttonRange);
	  }

	  retrieve.then(function (pages) {
	    console.log(pages);

	    $('#i3 a').style.display = 'none';

	    var reload = function reload(event) {
	      event.stopPropagation();
	      event.preventDefault();

	      if (event.target.dataset.locked === 'true') return;

	      event.target.dataset.locked = 'true';

	      ehr.fail(parseInt(event.target.dataset.page, 10)).then(function (imgInfo) {
	        console.log(imgInfo);

	        event.target.src = imgInfo.imgsrc;
	        event.target.parentNode.href = imgInfo.imgsrc;
	        event.target.dataset.locked = 'false';
	      });
	    };

	    pages.forEach(function (e) {
	      var pageNode = document.createElement('a');

	      pageNode.setAttribute('href', e.imgsrc);
	      pageNode.innerHTML = '<img src="' + e.imgsrc + '" style="' + e.style + '" />';
	      $('#i3').appendChild(pageNode);

	      pageNode.childNodes[0].dataset.page = e.page;
	      pageNode.childNodes[0].dataset.locked = 'false';

	      pageNode.childNodes[0].addEventListener('error', reload);
	      pageNode.childNodes[0].addEventListener('click', reload);

	      var timeout = void 0;
	      if (AutoReload) {
	        timeout = setTimeout(function () {
	          console.log('timeout: page ' + e.page);
	          var clickEvent = new MouseEvent('click');
	          pageNode.childNodes[0].dispatchEvent(clickEvent);
	        }, LoadTimeout);
	      }

	      pageNode.childNodes[0].addEventListener('load', function onload() {
	        pageNode.removeEventListener('load', onload);
	        if (AutoReload) {
	          clearTimeout(timeout);
	        }
	      });
	    });

	    buttonRetrieve.textContent = 'Done!';
	    buttonDoubleFrame.removeAttribute('disabled');
	  }).catch(function (e) {
	    console.log(e);
	  });
	});

	buttonRange.addEventListener('click', function (event) {
	  // override e-hentai's viewing shortcut
	  document.onkeydown = undefined;

	  var pageNum = $('div.sn').textContent.match(/(\d+)\s*\/\s*(\d+)/).slice(1);
	  buttonRange.insertAdjacentHTML('afterend', '<span id="ehrsetrange"><input type="number" id="ehrstart" value="' + pageNum[0] + '" min="1" max="' + pageNum[1] + '"> - <input type="number" id="ehrstop" value="' + pageNum[1] + '" min="1" max="' + pageNum[1] + '"></span>');

	  buttonRange.parentNode.removeChild(buttonRange);
	});

/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

	/* WEBPACK VAR INJECTION */(function(global, process) {/**
	 * Copyright (c) 2014, Facebook, Inc.
	 * All rights reserved.
	 *
	 * This source code is licensed under the BSD-style license found in the
	 * https://raw.github.com/facebook/regenerator/master/LICENSE file. An
	 * additional grant of patent rights can be found in the PATENTS file in
	 * the same directory.
	 */

	!(function(global) {
	  "use strict";

	  var hasOwn = Object.prototype.hasOwnProperty;
	  var undefined; // More compressible than void 0.
	  var $Symbol = typeof Symbol === "function" ? Symbol : {};
	  var iteratorSymbol = $Symbol.iterator || "@@iterator";
	  var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";

	  var inModule = typeof module === "object";
	  var runtime = global.regeneratorRuntime;
	  if (runtime) {
	    if (inModule) {
	      // If regeneratorRuntime is defined globally and we're in a module,
	      // make the exports object identical to regeneratorRuntime.
	      module.exports = runtime;
	    }
	    // Don't bother evaluating the rest of this file if the runtime was
	    // already defined globally.
	    return;
	  }

	  // Define the runtime globally (as expected by generated code) as either
	  // module.exports (if we're in a module) or a new, empty object.
	  runtime = global.regeneratorRuntime = inModule ? module.exports : {};

	  function wrap(innerFn, outerFn, self, tryLocsList) {
	    // If outerFn provided, then outerFn.prototype instanceof Generator.
	    var generator = Object.create((outerFn || Generator).prototype);
	    var context = new Context(tryLocsList || []);

	    // The ._invoke method unifies the implementations of the .next,
	    // .throw, and .return methods.
	    generator._invoke = makeInvokeMethod(innerFn, self, context);

	    return generator;
	  }
	  runtime.wrap = wrap;

	  // Try/catch helper to minimize deoptimizations. Returns a completion
	  // record like context.tryEntries[i].completion. This interface could
	  // have been (and was previously) designed to take a closure to be
	  // invoked without arguments, but in all the cases we care about we
	  // already have an existing method we want to call, so there's no need
	  // to create a new function object. We can even get away with assuming
	  // the method takes exactly one argument, since that happens to be true
	  // in every case, so we don't have to touch the arguments object. The
	  // only additional allocation required is the completion record, which
	  // has a stable shape and so hopefully should be cheap to allocate.
	  function tryCatch(fn, obj, arg) {
	    try {
	      return { type: "normal", arg: fn.call(obj, arg) };
	    } catch (err) {
	      return { type: "throw", arg: err };
	    }
	  }

	  var GenStateSuspendedStart = "suspendedStart";
	  var GenStateSuspendedYield = "suspendedYield";
	  var GenStateExecuting = "executing";
	  var GenStateCompleted = "completed";

	  // Returning this object from the innerFn has the same effect as
	  // breaking out of the dispatch switch statement.
	  var ContinueSentinel = {};

	  // Dummy constructor functions that we use as the .constructor and
	  // .constructor.prototype properties for functions that return Generator
	  // objects. For full spec compliance, you may wish to configure your
	  // minifier not to mangle the names of these two functions.
	  function Generator() {}
	  function GeneratorFunction() {}
	  function GeneratorFunctionPrototype() {}

	  var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype;
	  GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
	  GeneratorFunctionPrototype.constructor = GeneratorFunction;
	  GeneratorFunctionPrototype[toStringTagSymbol] = GeneratorFunction.displayName = "GeneratorFunction";

	  // Helper for defining the .next, .throw, and .return methods of the
	  // Iterator interface in terms of a single ._invoke method.
	  function defineIteratorMethods(prototype) {
	    ["next", "throw", "return"].forEach(function(method) {
	      prototype[method] = function(arg) {
	        return this._invoke(method, arg);
	      };
	    });
	  }

	  runtime.isGeneratorFunction = function(genFun) {
	    var ctor = typeof genFun === "function" && genFun.constructor;
	    return ctor
	      ? ctor === GeneratorFunction ||
	        // For the native GeneratorFunction constructor, the best we can
	        // do is to check its .name property.
	        (ctor.displayName || ctor.name) === "GeneratorFunction"
	      : false;
	  };

	  runtime.mark = function(genFun) {
	    if (Object.setPrototypeOf) {
	      Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
	    } else {
	      genFun.__proto__ = GeneratorFunctionPrototype;
	      if (!(toStringTagSymbol in genFun)) {
	        genFun[toStringTagSymbol] = "GeneratorFunction";
	      }
	    }
	    genFun.prototype = Object.create(Gp);
	    return genFun;
	  };

	  // Within the body of any async function, `await x` is transformed to
	  // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
	  // `value instanceof AwaitArgument` to determine if the yielded value is
	  // meant to be awaited. Some may consider the name of this method too
	  // cutesy, but they are curmudgeons.
	  runtime.awrap = function(arg) {
	    return new AwaitArgument(arg);
	  };

	  function AwaitArgument(arg) {
	    this.arg = arg;
	  }

	  function AsyncIterator(generator) {
	    function invoke(method, arg, resolve, reject) {
	      var record = tryCatch(generator[method], generator, arg);
	      if (record.type === "throw") {
	        reject(record.arg);
	      } else {
	        var result = record.arg;
	        var value = result.value;
	        if (value instanceof AwaitArgument) {
	          return Promise.resolve(value.arg).then(function(value) {
	            invoke("next", value, resolve, reject);
	          }, function(err) {
	            invoke("throw", err, resolve, reject);
	          });
	        }

	        return Promise.resolve(value).then(function(unwrapped) {
	          // When a yielded Promise is resolved, its final value becomes
	          // the .value of the Promise<{value,done}> result for the
	          // current iteration. If the Promise is rejected, however, the
	          // result for this iteration will be rejected with the same
	          // reason. Note that rejections of yielded Promises are not
	          // thrown back into the generator function, as is the case
	          // when an awaited Promise is rejected. This difference in
	          // behavior between yield and await is important, because it
	          // allows the consumer to decide what to do with the yielded
	          // rejection (swallow it and continue, manually .throw it back
	          // into the generator, abandon iteration, whatever). With
	          // await, by contrast, there is no opportunity to examine the
	          // rejection reason outside the generator function, so the
	          // only option is to throw it from the await expression, and
	          // let the generator function handle the exception.
	          result.value = unwrapped;
	          resolve(result);
	        }, reject);
	      }
	    }

	    if (typeof process === "object" && process.domain) {
	      invoke = process.domain.bind(invoke);
	    }

	    var previousPromise;

	    function enqueue(method, arg) {
	      function callInvokeWithMethodAndArg() {
	        return new Promise(function(resolve, reject) {
	          invoke(method, arg, resolve, reject);
	        });
	      }

	      return previousPromise =
	        // If enqueue has been called before, then we want to wait until
	        // all previous Promises have been resolved before calling invoke,
	        // so that results are always delivered in the correct order. If
	        // enqueue has not been called before, then it is important to
	        // call invoke immediately, without waiting on a callback to fire,
	        // so that the async generator function has the opportunity to do
	        // any necessary setup in a predictable way. This predictability
	        // is why the Promise constructor synchronously invokes its
	        // executor callback, and why async functions synchronously
	        // execute code before the first await. Since we implement simple
	        // async functions in terms of async generators, it is especially
	        // important to get this right, even though it requires care.
	        previousPromise ? previousPromise.then(
	          callInvokeWithMethodAndArg,
	          // Avoid propagating failures to Promises returned by later
	          // invocations of the iterator.
	          callInvokeWithMethodAndArg
	        ) : callInvokeWithMethodAndArg();
	    }

	    // Define the unified helper method that is used to implement .next,
	    // .throw, and .return (see defineIteratorMethods).
	    this._invoke = enqueue;
	  }

	  defineIteratorMethods(AsyncIterator.prototype);

	  // Note that simple async functions are implemented on top of
	  // AsyncIterator objects; they just return a Promise for the value of
	  // the final result produced by the iterator.
	  runtime.async = function(innerFn, outerFn, self, tryLocsList) {
	    var iter = new AsyncIterator(
	      wrap(innerFn, outerFn, self, tryLocsList)
	    );

	    return runtime.isGeneratorFunction(outerFn)
	      ? iter // If outerFn is a generator, return the full iterator.
	      : iter.next().then(function(result) {
	          return result.done ? result.value : iter.next();
	        });
	  };

	  function makeInvokeMethod(innerFn, self, context) {
	    var state = GenStateSuspendedStart;

	    return function invoke(method, arg) {
	      if (state === GenStateExecuting) {
	        throw new Error("Generator is already running");
	      }

	      if (state === GenStateCompleted) {
	        if (method === "throw") {
	          throw arg;
	        }

	        // Be forgiving, per 25.3.3.3.3 of the spec:
	        // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
	        return doneResult();
	      }

	      while (true) {
	        var delegate = context.delegate;
	        if (delegate) {
	          if (method === "return" ||
	              (method === "throw" && delegate.iterator[method] === undefined)) {
	            // A return or throw (when the delegate iterator has no throw
	            // method) always terminates the yield* loop.
	            context.delegate = null;

	            // If the delegate iterator has a return method, give it a
	            // chance to clean up.
	            var returnMethod = delegate.iterator["return"];
	            if (returnMethod) {
	              var record = tryCatch(returnMethod, delegate.iterator, arg);
	              if (record.type === "throw") {
	                // If the return method threw an exception, let that
	                // exception prevail over the original return or throw.
	                method = "throw";
	                arg = record.arg;
	                continue;
	              }
	            }

	            if (method === "return") {
	              // Continue with the outer return, now that the delegate
	              // iterator has been terminated.
	              continue;
	            }
	          }

	          var record = tryCatch(
	            delegate.iterator[method],
	            delegate.iterator,
	            arg
	          );

	          if (record.type === "throw") {
	            context.delegate = null;

	            // Like returning generator.throw(uncaught), but without the
	            // overhead of an extra function call.
	            method = "throw";
	            arg = record.arg;
	            continue;
	          }

	          // Delegate generator ran and handled its own exceptions so
	          // regardless of what the method was, we continue as if it is
	          // "next" with an undefined arg.
	          method = "next";
	          arg = undefined;

	          var info = record.arg;
	          if (info.done) {
	            context[delegate.resultName] = info.value;
	            context.next = delegate.nextLoc;
	          } else {
	            state = GenStateSuspendedYield;
	            return info;
	          }

	          context.delegate = null;
	        }

	        if (method === "next") {
	          // Setting context._sent for legacy support of Babel's
	          // function.sent implementation.
	          context.sent = context._sent = arg;

	        } else if (method === "throw") {
	          if (state === GenStateSuspendedStart) {
	            state = GenStateCompleted;
	            throw arg;
	          }

	          if (context.dispatchException(arg)) {
	            // If the dispatched exception was caught by a catch block,
	            // then let that catch block handle the exception normally.
	            method = "next";
	            arg = undefined;
	          }

	        } else if (method === "return") {
	          context.abrupt("return", arg);
	        }

	        state = GenStateExecuting;

	        var record = tryCatch(innerFn, self, context);
	        if (record.type === "normal") {
	          // If an exception is thrown from innerFn, we leave state ===
	          // GenStateExecuting and loop back for another invocation.
	          state = context.done
	            ? GenStateCompleted
	            : GenStateSuspendedYield;

	          var info = {
	            value: record.arg,
	            done: context.done
	          };

	          if (record.arg === ContinueSentinel) {
	            if (context.delegate && method === "next") {
	              // Deliberately forget the last sent value so that we don't
	              // accidentally pass it on to the delegate.
	              arg = undefined;
	            }
	          } else {
	            return info;
	          }

	        } else if (record.type === "throw") {
	          state = GenStateCompleted;
	          // Dispatch the exception by looping back around to the
	          // context.dispatchException(arg) call above.
	          method = "throw";
	          arg = record.arg;
	        }
	      }
	    };
	  }

	  // Define Generator.prototype.{next,throw,return} in terms of the
	  // unified ._invoke helper method.
	  defineIteratorMethods(Gp);

	  Gp[iteratorSymbol] = function() {
	    return this;
	  };

	  Gp[toStringTagSymbol] = "Generator";

	  Gp.toString = function() {
	    return "[object Generator]";
	  };

	  function pushTryEntry(locs) {
	    var entry = { tryLoc: locs[0] };

	    if (1 in locs) {
	      entry.catchLoc = locs[1];
	    }

	    if (2 in locs) {
	      entry.finallyLoc = locs[2];
	      entry.afterLoc = locs[3];
	    }

	    this.tryEntries.push(entry);
	  }

	  function resetTryEntry(entry) {
	    var record = entry.completion || {};
	    record.type = "normal";
	    delete record.arg;
	    entry.completion = record;
	  }

	  function Context(tryLocsList) {
	    // The root entry object (effectively a try statement without a catch
	    // or a finally block) gives us a place to store values thrown from
	    // locations where there is no enclosing try statement.
	    this.tryEntries = [{ tryLoc: "root" }];
	    tryLocsList.forEach(pushTryEntry, this);
	    this.reset(true);
	  }

	  runtime.keys = function(object) {
	    var keys = [];
	    for (var key in object) {
	      keys.push(key);
	    }
	    keys.reverse();

	    // Rather than returning an object with a next method, we keep
	    // things simple and return the next function itself.
	    return function next() {
	      while (keys.length) {
	        var key = keys.pop();
	        if (key in object) {
	          next.value = key;
	          next.done = false;
	          return next;
	        }
	      }

	      // To avoid creating an additional object, we just hang the .value
	      // and .done properties off the next function object itself. This
	      // also ensures that the minifier will not anonymize the function.
	      next.done = true;
	      return next;
	    };
	  };

	  function values(iterable) {
	    if (iterable) {
	      var iteratorMethod = iterable[iteratorSymbol];
	      if (iteratorMethod) {
	        return iteratorMethod.call(iterable);
	      }

	      if (typeof iterable.next === "function") {
	        return iterable;
	      }

	      if (!isNaN(iterable.length)) {
	        var i = -1, next = function next() {
	          while (++i < iterable.length) {
	            if (hasOwn.call(iterable, i)) {
	              next.value = iterable[i];
	              next.done = false;
	              return next;
	            }
	          }

	          next.value = undefined;
	          next.done = true;

	          return next;
	        };

	        return next.next = next;
	      }
	    }

	    // Return an iterator with no values.
	    return { next: doneResult };
	  }
	  runtime.values = values;

	  function doneResult() {
	    return { value: undefined, done: true };
	  }

	  Context.prototype = {
	    constructor: Context,

	    reset: function(skipTempReset) {
	      this.prev = 0;
	      this.next = 0;
	      // Resetting context._sent for legacy support of Babel's
	      // function.sent implementation.
	      this.sent = this._sent = undefined;
	      this.done = false;
	      this.delegate = null;

	      this.tryEntries.forEach(resetTryEntry);

	      if (!skipTempReset) {
	        for (var name in this) {
	          // Not sure about the optimal order of these conditions:
	          if (name.charAt(0) === "t" &&
	              hasOwn.call(this, name) &&
	              !isNaN(+name.slice(1))) {
	            this[name] = undefined;
	          }
	        }
	      }
	    },

	    stop: function() {
	      this.done = true;

	      var rootEntry = this.tryEntries[0];
	      var rootRecord = rootEntry.completion;
	      if (rootRecord.type === "throw") {
	        throw rootRecord.arg;
	      }

	      return this.rval;
	    },

	    dispatchException: function(exception) {
	      if (this.done) {
	        throw exception;
	      }

	      var context = this;
	      function handle(loc, caught) {
	        record.type = "throw";
	        record.arg = exception;
	        context.next = loc;
	        return !!caught;
	      }

	      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
	        var entry = this.tryEntries[i];
	        var record = entry.completion;

	        if (entry.tryLoc === "root") {
	          // Exception thrown outside of any try block that could handle
	          // it, so set the completion value of the entire function to
	          // throw the exception.
	          return handle("end");
	        }

	        if (entry.tryLoc <= this.prev) {
	          var hasCatch = hasOwn.call(entry, "catchLoc");
	          var hasFinally = hasOwn.call(entry, "finallyLoc");

	          if (hasCatch && hasFinally) {
	            if (this.prev < entry.catchLoc) {
	              return handle(entry.catchLoc, true);
	            } else if (this.prev < entry.finallyLoc) {
	              return handle(entry.finallyLoc);
	            }

	          } else if (hasCatch) {
	            if (this.prev < entry.catchLoc) {
	              return handle(entry.catchLoc, true);
	            }

	          } else if (hasFinally) {
	            if (this.prev < entry.finallyLoc) {
	              return handle(entry.finallyLoc);
	            }

	          } else {
	            throw new Error("try statement without catch or finally");
	          }
	        }
	      }
	    },

	    abrupt: function(type, arg) {
	      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
	        var entry = this.tryEntries[i];
	        if (entry.tryLoc <= this.prev &&
	            hasOwn.call(entry, "finallyLoc") &&
	            this.prev < entry.finallyLoc) {
	          var finallyEntry = entry;
	          break;
	        }
	      }

	      if (finallyEntry &&
	          (type === "break" ||
	           type === "continue") &&
	          finallyEntry.tryLoc <= arg &&
	          arg <= finallyEntry.finallyLoc) {
	        // Ignore the finally entry if control is not jumping to a
	        // location outside the try/catch block.
	        finallyEntry = null;
	      }

	      var record = finallyEntry ? finallyEntry.completion : {};
	      record.type = type;
	      record.arg = arg;

	      if (finallyEntry) {
	        this.next = finallyEntry.finallyLoc;
	      } else {
	        this.complete(record);
	      }

	      return ContinueSentinel;
	    },

	    complete: function(record, afterLoc) {
	      if (record.type === "throw") {
	        throw record.arg;
	      }

	      if (record.type === "break" ||
	          record.type === "continue") {
	        this.next = record.arg;
	      } else if (record.type === "return") {
	        this.rval = record.arg;
	        this.next = "end";
	      } else if (record.type === "normal" && afterLoc) {
	        this.next = afterLoc;
	      }
	    },

	    finish: function(finallyLoc) {
	      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
	        var entry = this.tryEntries[i];
	        if (entry.finallyLoc === finallyLoc) {
	          this.complete(entry.completion, entry.afterLoc);
	          resetTryEntry(entry);
	          return ContinueSentinel;
	        }
	      }
	    },

	    "catch": function(tryLoc) {
	      for (var i = this.tryEntries.length - 1; i >= 0; --i) {
	        var entry = this.tryEntries[i];
	        if (entry.tryLoc === tryLoc) {
	          var record = entry.completion;
	          if (record.type === "throw") {
	            var thrown = record.arg;
	            resetTryEntry(entry);
	          }
	          return thrown;
	        }
	      }

	      // The context.catch method must only be called with a location
	      // argument that corresponds to a known catch block.
	      throw new Error("illegal catch attempt");
	    },

	    delegateYield: function(iterable, resultName, nextLoc) {
	      this.delegate = {
	        iterator: values(iterable),
	        resultName: resultName,
	        nextLoc: nextLoc
	      };

	      return ContinueSentinel;
	    }
	  };
	})(
	  // Among the various tricks for obtaining a reference to the global
	  // object, this seems to be the most reliable technique that does not
	  // use indirect eval (which violates Content Security Policy).
	  typeof global === "object" ? global :
	  typeof window === "object" ? window :
	  typeof self === "object" ? self : this
	);

	/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(2)))

/***/ },
/* 2 */
/***/ function(module, exports) {

	// shim for using process in browser

	var process = module.exports = {};
	var queue = [];
	var draining = false;
	var currentQueue;
	var queueIndex = -1;

	function cleanUpNextTick() {
	    draining = false;
	    if (currentQueue.length) {
	        queue = currentQueue.concat(queue);
	    } else {
	        queueIndex = -1;
	    }
	    if (queue.length) {
	        drainQueue();
	    }
	}

	function drainQueue() {
	    if (draining) {
	        return;
	    }
	    var timeout = setTimeout(cleanUpNextTick);
	    draining = true;

	    var len = queue.length;
	    while(len) {
	        currentQueue = queue;
	        queue = [];
	        while (++queueIndex < len) {
	            if (currentQueue) {
	                currentQueue[queueIndex].run();
	            }
	        }
	        queueIndex = -1;
	        len = queue.length;
	    }
	    currentQueue = null;
	    draining = false;
	    clearTimeout(timeout);
	}

	process.nextTick = function (fun) {
	    var args = new Array(arguments.length - 1);
	    if (arguments.length > 1) {
	        for (var i = 1; i < arguments.length; i++) {
	            args[i - 1] = arguments[i];
	        }
	    }
	    queue.push(new Item(fun, args));
	    if (queue.length === 1 && !draining) {
	        setTimeout(drainQueue, 0);
	    }
	};

	// v8 likes predictible objects
	function Item(fun, array) {
	    this.fun = fun;
	    this.array = array;
	}
	Item.prototype.run = function () {
	    this.fun.apply(null, this.array);
	};
	process.title = 'browser';
	process.browser = true;
	process.env = {};
	process.argv = [];
	process.version = ''; // empty string to avoid regexp issues
	process.versions = {};

	function noop() {}

	process.on = noop;
	process.addListener = noop;
	process.once = noop;
	process.off = noop;
	process.removeListener = noop;
	process.removeAllListeners = noop;
	process.emit = noop;

	process.binding = function (name) {
	    throw new Error('process.binding is not supported');
	};

	process.cwd = function () { return '/' };
	process.chdir = function (dir) {
	    throw new Error('process.chdir is not supported');
	};
	process.umask = function() { return 0; };


/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	var _queue = __webpack_require__(4);

	var _queue2 = _interopRequireDefault(_queue);

	var _cofetch = __webpack_require__(5);

	var _cofetch2 = _interopRequireDefault(_cofetch);

	function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

	function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { return step("next", value); }, function (err) { return step("throw", err); }); } } return step("next"); }); }; }

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	var ehRetriever = function () {
	  function ehRetriever(url, html) {
	    _classCallCheck(this, ehRetriever);

	    if (typeof url !== 'string') throw new TypeError('invalid `url`, expected a string');
	    if (url.search(/^https?:\/\//) < 0) throw new TypeError('invalid url: ' + url);

	    this.url = url;
	    this.html = html;
	    this.gallery = {
	      'gid': undefined,
	      'token': undefined
	    };
	    this.referer = url;
	    this.showkey = undefined;
	    this.exprefix = url.search(/exhentai/) >= 0 ? 'ex' : 'e-';
	    this.pages = [];
	    this.q = new _queue2.default(3, { 'timeout': 3000, 'delay': 1000 });
	    this.onPageLoadCallback = [];

	    this.promiseInit = this.init();
	  }

	  _createClass(ehRetriever, [{
	    key: 'init',
	    value: function () {
	      var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
	        var galleryURL, showkey;
	        return regeneratorRuntime.wrap(function _callee$(_context) {
	          while (1) {
	            switch (_context.prev = _context.next) {
	              case 0:
	                if (this.html) {
	                  _context.next = 4;
	                  break;
	                }

	                _context.next = 3;
	                return this.fetch(this.url).then(function (res) {
	                  return res.text();
	                });

	              case 3:
	                this.html = _context.sent;

	              case 4:
	                galleryURL = this.html.match(/hentai\.org\/g\/(\d+)\/([a-z0-9]+)/i);
	                showkey = this.html.match(/showkey="([^"]+)"/i);

	                if (!galleryURL) {
	                  _context.next = 11;
	                  break;
	                }

	                this.gallery.gid = galleryURL[1];
	                this.gallery.token = galleryURL[2];
	                _context.next = 12;
	                break;

	              case 11:
	                throw new Error("Can't get gallery URL");

	              case 12:
	                if (!showkey) {
	                  _context.next = 16;
	                  break;
	                }

	                this.showkey = showkey[1];
	                _context.next = 17;
	                break;

	              case 16:
	                throw new Error("Can't get showkey");

	              case 17:
	                _context.next = 19;
	                return this.getAllPageURL();

	              case 19:
	                this.pages = _context.sent;

	              case 20:
	              case 'end':
	                return _context.stop();
	            }
	          }
	        }, _callee, this);
	      }));

	      function init() {
	        return ref.apply(this, arguments);
	      }

	      return init;
	    }()
	  }, {
	    key: 'getAllPageURL',
	    value: function () {
	      var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee2() {
	        var _this = this;

	        var firstPage, pageNum, pageNumMax, allPages;
	        return regeneratorRuntime.wrap(function _callee2$(_context2) {
	          while (1) {
	            switch (_context2.prev = _context2.next) {
	              case 0:
	                _context2.next = 2;
	                return this.fetch('http://' + this.exprefix + 'hentai.org/g/' + this.gallery.gid + '/' + this.gallery.token).then(function (res) {
	                  return res.text();
	                });

	              case 2:
	                firstPage = _context2.sent;
	                pageNum = firstPage.match(/<table[^>]*class="ptt"[^>]*>((?:[^<]*)(?:<(?!\/table>)[^<]*)*)<\/table>/);

	                if (!pageNum) {
	                  _context2.next = 8;
	                  break;
	                }

	                pageNum = pageNum[1].match(/g\/[^/]+\/[^/]+\/\?p=\d+/g);
	                _context2.next = 9;
	                break;

	              case 8:
	                throw new Error('Cant get page numbers');

	              case 9:

	                // A gallery containing only one page won't have page number in gallery link.
	                // So, if pageNum is null, the gallery has only one page.
	                if (pageNum) {
	                  pageNum = pageNum.map(function (e) {
	                    return parseInt(e.match(/(\d+)$/)[1], 10);
	                  });
	                }
	                pageNumMax = pageNum ? Math.max.apply(null, pageNum) : 0;
	                _context2.next = 13;
	                return Promise.all(Array(pageNumMax).fill().map(function (e, i) {
	                  return _this.fetch('http://' + _this.exprefix + 'hentai.org/g/' + _this.gallery.gid + '/' + _this.gallery.token + '/?p=' + (i + 1)).then(function (res) {
	                    return res.text();
	                  });
	                }));

	              case 13:
	                allPages = _context2.sent;

	                allPages.unshift(firstPage);

	                return _context2.abrupt('return', allPages.map(function (e) {
	                  return e.match(/<div[^>]*class="gdt[lm]"[^>]*>(?:(?:[^<]*)(?:<(?!\/div>)[^<]*)*)<\/div>/g);
	                }).reduce(function (p, c) {
	                  return p.concat(c);
	                }).map(function (e) {
	                  var tokens = e.match(/s\/[a-z0-9]+\/\d+-\d+/)[0].split('/');
	                  return {
	                    'imgkey': tokens[1],
	                    'page': parseInt(tokens[2].split('-')[1], 10)
	                  };
	                }));

	              case 16:
	              case 'end':
	                return _context2.stop();
	            }
	          }
	        }, _callee2, this);
	      }));

	      function getAllPageURL() {
	        return ref.apply(this, arguments);
	      }

	      return getAllPageURL;
	    }()
	  }, {
	    key: 'fetch',
	    value: function fetch(url) {
	      var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

	      if (typeof url !== 'string') return Promise.reject(new TypeError('invalid `url`, expected a string'));
	      if (url.search(/^https?:\/\//) < 0) return Promise.reject(new TypeError('invalid url: ' + url));

	      var defaultOptions = {
	        'method': 'GET',
	        'credentials': 'include',
	        'headers': {
	          'User-Agent': navigator.userAgent,
	          'Referer': this.referer
	        }
	      };
	      if (options.headers) {
	        Object.assign(defaultOptions.headers, options.headers);
	        delete options.headers;
	      }
	      options = Object.assign(defaultOptions, options);
	      console.log('fetch', url, options);

	      return this.q.queue(function (resolve, reject) {
	        (0, _cofetch2.default)(url, options).then(resolve).catch(reject);
	      }, 'fetch ' + url);
	    }
	  }, {
	    key: 'retrieve',
	    value: function () {
	      var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee3() {
	        var _this2 = this;

	        var start = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
	        var stop = arguments.length <= 1 || arguments[1] === undefined ? -1 : arguments[1];
	        var retrievePages, loadPage, imagePages, imageInfo;
	        return regeneratorRuntime.wrap(function _callee3$(_context3) {
	          while (1) {
	            switch (_context3.prev = _context3.next) {
	              case 0:
	                _context3.next = 2;
	                return this.promiseInit;

	              case 2:
	                if (!(start < 0 || start >= this.pages.length || isNaN(start))) {
	                  _context3.next = 4;
	                  break;
	                }

	                throw new RangeError('invalid start number: ' + start);

	              case 4:
	                if (!(stop < 0)) {
	                  _context3.next = 8;
	                  break;
	                }

	                stop = this.pages.length - 1;
	                _context3.next = 10;
	                break;

	              case 8:
	                if (!(stop < start || stop >= this.pages.length || isNaN(stop))) {
	                  _context3.next = 10;
	                  break;
	                }

	                throw new RangeError('invalid stop number: ' + stop + ', start: ' + start);

	              case 10:
	                retrievePages = this.pages.slice(start, stop + 1);

	                loadPage = function loadPage(e) {
	                  if (e.imgsrc && img.filename) return Promise.resolve(e);

	                  var fetchPage = _this2.fetch('http://' + _this2.exprefix + 'hentai.org/api.php', {
	                    'method': 'POST',
	                    'headers': { 'Content-Type': 'application/json' },
	                    // assign e = {'imgkey': ..., 'page': ...} to object literal {'method': ..., 'gid': ..., 'showkey': ...}
	                    // does not modify e
	                    'data': JSON.stringify(Object.assign({
	                      'method': 'showpage',
	                      'gid': _this2.gallery.gid,
	                      'showkey': _this2.showkey
	                    }, e))
	                  }).then(function (res) {
	                    return res.json();
	                  });

	                  return fetchPage.then(function (data) {
	                    // insert callback invocations
	                    _this2.onPageLoadCallback.forEach(function (callback) {
	                      callback(e.page - start, stop - start + 1);
	                    });
	                    return Promise.resolve(data);
	                  });
	                };

	                _context3.next = 14;
	                return Promise.all(retrievePages.map(function (e) {
	                  return loadPage(e);
	                }));

	              case 14:
	                imagePages = _context3.sent;
	                imageInfo = imagePages.map(function (e) {
	                  return {
	                    'filename': e.i.match(/>([^:]+):/)[1].trim(),
	                    'imgsrc': e.i3.match(/src="([^"]+)"/)[1],
	                    'failnl': [e.i6.match(/nl\('([^']+)'/)[1]],
	                    'style': e.i3.match(/style="([^"]+)"/)[1],
	                    'url': e.s
	                  };
	                });


	                retrievePages.forEach(function (e, i) {
	                  return Object.assign(e, imageInfo[i]);
	                });

	                return _context3.abrupt('return', retrievePages);

	              case 18:
	              case 'end':
	                return _context3.stop();
	            }
	          }
	        }, _callee3, this);
	      }));

	      function retrieve(_x2, _x3) {
	        return ref.apply(this, arguments);
	      }

	      return retrieve;
	    }()
	  }, {
	    key: 'fail',
	    value: function () {
	      var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(index) {
	        var page, failnl, res, parsed;
	        return regeneratorRuntime.wrap(function _callee4$(_context4) {
	          while (1) {
	            switch (_context4.prev = _context4.next) {
	              case 0:
	                page = this.pages[index - 1];
	                failnl = page.failnl.map(function (e) {
	                  return 'nl=' + e;
	                }).join('&');
	                _context4.next = 4;
	                return this.fetch('http://' + this.exprefix + 'hentai.org/' + page.url + '?' + failnl).then(function (res) {
	                  return res.text();
	                });

	              case 4:
	                res = _context4.sent;
	                parsed = res.match(/<img[^>]*id="img"[^>]*src="([^"]+)"[^>]*.*onclick="return nl\('([0-9-]+)'\)/i);

	                if (!parsed) {
	                  _context4.next = 10;
	                  break;
	                }

	                page.imgsrc = parsed[1];
	                page.failnl.push(parsed[2]);

	                return _context4.abrupt('return', page);

	              case 10:
	                return _context4.abrupt('return', null);

	              case 11:
	              case 'end':
	                return _context4.stop();
	            }
	          }
	        }, _callee4, this);
	      }));

	      function fail(_x6) {
	        return ref.apply(this, arguments);
	      }

	      return fail;
	    }()
	  }, {
	    key: 'onPageLoad',
	    value: function onPageLoad(callback) {
	      this.onPageLoadCallback.push(callback);
	    }
	  }]);

	  return ehRetriever;
	}();

	exports.default = ehRetriever;

/***/ },
/* 4 */
/***/ function(module, exports) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});

	var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };

	var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

	function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

	var Queue = function () {
	  function Queue(limit) {
	    _classCallCheck(this, Queue);

	    var timeout = void 0,
	        delay = void 0;

	    for (var _len = arguments.length, options = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
	      options[_key - 1] = arguments[_key];
	    }

	    if (options.length) {
	      if (_typeof(options[0]) === 'object') {
	        var _options$ = options[0];
	        timeout = _options$.timeout;
	        delay = _options$.delay;
	      } else {
	        timeout = options[0];
	        delay = options[1];
	      }
	    }

	    this.limit = limit;
	    this.timeout = timeout || 0;
	    this.delay = delay || 0;
	    this.slot = [];
	    this.q = [];
	  }

	  _createClass(Queue, [{
	    key: 'queue',
	    value: function queue(executor, name) {
	      var _this = this;

	      console.log('queue: job ' + name + ' queued');

	      var job = new Promise(function (resolve, reject) {
	        _this.q.push({
	          'name': name || '',
	          'run': executor,
	          'resolve': resolve,
	          'reject': reject,
	          'timeout': false,
	          'timeoutid': undefined
	        });
	      });
	      this.dequeue();

	      return job;
	    }
	  }, {
	    key: 'dequeue',
	    value: function dequeue() {
	      var _this2 = this;

	      var q = this.q;
	      var slot = this.slot;
	      var limit = this.limit;
	      var timeout = this.timeout;
	      var delay = this.delay;


	      if (slot.length < limit && q.length >= 1) {
	        (function () {
	          var job = q.shift();
	          slot.push(job);
	          console.log('queue: job ' + job.name + ' started');

	          if (timeout) job.timeoutid = setTimeout(_this2.jobTimeout.bind(_this2, job), timeout);

	          var onFulfilled = function onFulfilled(data) {
	            if (job.timeout) {
	              return;
	            }

	            _this2.removeJob(job);
	            setTimeout(_this2.dequeue.bind(_this2), delay); // force dequeue() run after current dequeue()
	            if (job.timeoutid) clearTimeout(job.timeoutid);
	            console.log('queue: job ' + job.name + ' resolved');

	            job.resolve(data);
	          };

	          var onRejected = function onRejected(reason) {
	            if (job.timeout) {
	              return;
	            }

	            _this2.removeJob(job);
	            setTimeout(_this2.dequeue.bind(_this2), delay);
	            if (job.timeoutid) clearTimeout(job.timeoutid);
	            console.log('queue: job ' + job.name + ' rejected');

	            job.reject(reason);
	          };

	          job.run(onFulfilled, onRejected);
	        })();
	      }
	    }
	  }, {
	    key: 'jobTimeout',
	    value: function jobTimeout(job) {
	      this.removeJob(job);
	      console.log('queue: job ' + job.name + ' timeout');
	      job.reject(new Error('queue: job ' + (job.name || '') + ' timeout'));
	      job = null;
	    }
	  }, {
	    key: 'removeJob',
	    value: function removeJob(job) {
	      var index = this.slot.indexOf(job);
	      if (index >= 0) {
	        this.slot.splice(index, 1);
	        return;
	      }

	      index = this.q.indexOf(job);
	      if (index >= 0) this.q.splice(index, 1);
	    }
	  }]);

	  return Queue;
	}();

	exports.default = Queue;

/***/ },
/* 5 */
/***/ function(module, exports) {

	'use strict';

	Object.defineProperty(exports, "__esModule", {
	  value: true
	});

	var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

	// Origin from window.fetch polyfill
	// https://github.com/github/fetch
	// License https://github.com/github/fetch/blob/master/LICENSE

	var COFetch = function COFetch(input) {
	  var init = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

	  var request = void 0;
	  if (Request.prototype.isPrototypeOf(input) && !init) {
	    request = input;
	  } else {
	    request = new Request(input, init);
	  }

	  var headers = {};
	  var _iteratorNormalCompletion = true;
	  var _didIteratorError = false;
	  var _iteratorError = undefined;

	  try {
	    for (var _iterator = request.headers[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
	      var _step$value = _slicedToArray(_step.value, 2);

	      var key = _step$value[0];
	      var value = _step$value[1];

	      headers[key] = value;
	    }
	  } catch (err) {
	    _didIteratorError = true;
	    _iteratorError = err;
	  } finally {
	    try {
	      if (!_iteratorNormalCompletion && _iterator.return) {
	        _iterator.return();
	      }
	    } finally {
	      if (_didIteratorError) {
	        throw _iteratorError;
	      }
	    }
	  }

	  if (request.credentials === 'include') {
	    headers['Cookie'] = document.cookie;
	  }

	  var onload = function onload(resolve, reject, gmxhr) {
	    var init = {
	      'url': gmxhr.finalUrl || request.url,
	      'status': gmxhr.status,
	      'statusText': gmxhr.statusText,
	      'headers': undefined
	    };

	    try {
	      (function () {
	        var rawHeaders = gmxhr.responseHeaders.trim().replace(/\r\n(\s+)/g, '$1').split('\r\n').map(function (e) {
	          return e.split(/:/);
	        });
	        var header = new Headers();
	        rawHeaders.forEach(function (e) {
	          header.append(e[0].trim(), e[1].trim());
	        });
	        init.headers = header;

	        var res = new Response(gmxhr.response, init);
	        resolve(res);
	      })();
	    } catch (e) {
	      reject(e);
	    }
	  };

	  var onerror = function onerror(resolve, reject, gmxhr) {
	    reject(new TypeError('Network request failed'));
	  };

	  return new Promise(function (resolve, reject) {
	    GM_xmlhttpRequest({
	      'method': request.method,
	      'url': request.url,
	      'headers': headers,
	      'binary': init.binary,
	      'responseType': 'blob',
	      'data': init.data,
	      'onload': onload.bind(null, resolve, reject),
	      'onerror': onerror.bind(null, resolve, reject)
	    });
	  });
	};

	exports.default = COFetch;

/***/ }
/******/ ]);