var Mercury = (function() {
  'use strict';

  function commonjsRequire() {
    throw new Error(
      'Dynamic requires are not currently supported by rollup-plugin-commonjs'
    );
  }

  function createCommonjsModule(fn, module) {
    return (
      (module = { exports: {} }), fn(module, module.exports), module.exports
    );
  }

  var runtime = createCommonjsModule(function(module) {
    /**
     * Copyright (c) 2014-present, Facebook, Inc.
     *
     * This source code is licensed under the MIT license found in the
     * LICENSE file in the root directory of this source tree.
     */
    !(function(global) {
      var Op = Object.prototype;
      var hasOwn = Op.hasOwnProperty;
      var undefined; // More compressible than void 0.

      var $Symbol = typeof Symbol === 'function' ? Symbol : {};
      var iteratorSymbol = $Symbol.iterator || '@@iterator';
      var asyncIteratorSymbol = $Symbol.asyncIterator || '@@asyncIterator';
      var toStringTagSymbol = $Symbol.toStringTag || '@@toStringTag';
      var runtime = global.regeneratorRuntime;

      if (runtime) {
        {
          // 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 = module.exports;

      function wrap(innerFn, outerFn, self, tryLocsList) {
        // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
        var protoGenerator =
          outerFn && outerFn.prototype instanceof Generator
            ? outerFn
            : Generator;
        var generator = Object.create(protoGenerator.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() {} // This is a polyfill for %IteratorPrototype% for environments that
      // don't natively support it.

      var IteratorPrototype = {};

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

      var getProto = Object.getPrototypeOf;
      var NativeIteratorPrototype = getProto && getProto(getProto(values([])));

      if (
        NativeIteratorPrototype &&
        NativeIteratorPrototype !== Op &&
        hasOwn.call(NativeIteratorPrototype, iteratorSymbol)
      ) {
        // This environment has a native %IteratorPrototype%; use it instead
        // of the polyfill.
        IteratorPrototype = NativeIteratorPrototype;
      }

      var Gp = (GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(
        IteratorPrototype
      ));
      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
      // `hasOwn.call(value, "__await")` to determine if the yielded value is
      // meant to be awaited.

      runtime.awrap = function(arg) {
        return {
          __await: 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 &&
              typeof value === 'object' &&
              hasOwn.call(value, '__await')
            ) {
              return Promise.resolve(value.__await).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.
                result.value = unwrapped;
                resolve(result);
              },
              function(error) {
                // If a rejected Promise was yielded, throw the rejection back
                // into the async generator function so it can be handled there.
                return invoke('throw', error, resolve, reject);
              }
            );
          }
        }

        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);

      AsyncIterator.prototype[asyncIteratorSymbol] = function() {
        return this;
      };

      runtime.AsyncIterator = AsyncIterator; // 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();
          }

          context.method = method;
          context.arg = arg;

          while (true) {
            var delegate = context.delegate;

            if (delegate) {
              var delegateResult = maybeInvokeDelegate(delegate, context);

              if (delegateResult) {
                if (delegateResult === ContinueSentinel) continue;
                return delegateResult;
              }
            }

            if (context.method === 'next') {
              // Setting context._sent for legacy support of Babel's
              // function.sent implementation.
              context.sent = context._sent = context.arg;
            } else if (context.method === 'throw') {
              if (state === GenStateSuspendedStart) {
                state = GenStateCompleted;
                throw context.arg;
              }

              context.dispatchException(context.arg);
            } else if (context.method === 'return') {
              context.abrupt('return', context.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;

              if (record.arg === ContinueSentinel) {
                continue;
              }

              return {
                value: record.arg,
                done: context.done,
              };
            } else if (record.type === 'throw') {
              state = GenStateCompleted; // Dispatch the exception by looping back around to the
              // context.dispatchException(context.arg) call above.

              context.method = 'throw';
              context.arg = record.arg;
            }
          }
        };
      } // Call delegate.iterator[context.method](context.arg) and handle the
      // result, either by returning a { value, done } result from the
      // delegate iterator, or by modifying context.method and context.arg,
      // setting context.delegate to null, and returning the ContinueSentinel.

      function maybeInvokeDelegate(delegate, context) {
        var method = delegate.iterator[context.method];

        if (method === undefined) {
          // A .throw or .return when the delegate iterator has no .throw
          // method always terminates the yield* loop.
          context.delegate = null;

          if (context.method === 'throw') {
            if (delegate.iterator.return) {
              // If the delegate iterator has a return method, give it a
              // chance to clean up.
              context.method = 'return';
              context.arg = undefined;
              maybeInvokeDelegate(delegate, context);

              if (context.method === 'throw') {
                // If maybeInvokeDelegate(context) changed context.method from
                // "return" to "throw", let that override the TypeError below.
                return ContinueSentinel;
              }
            }

            context.method = 'throw';
            context.arg = new TypeError(
              "The iterator does not provide a 'throw' method"
            );
          }

          return ContinueSentinel;
        }

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

        if (record.type === 'throw') {
          context.method = 'throw';
          context.arg = record.arg;
          context.delegate = null;
          return ContinueSentinel;
        }

        var info = record.arg;

        if (!info) {
          context.method = 'throw';
          context.arg = new TypeError('iterator result is not an object');
          context.delegate = null;
          return ContinueSentinel;
        }

        if (info.done) {
          // Assign the result of the finished delegate to the temporary
          // variable specified by delegate.resultName (see delegateYield).
          context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).

          context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
          // exception, let the outer generator proceed normally. If
          // context.method was "next", forget context.arg since it has been
          // "consumed" by the delegate iterator. If context.method was
          // "return", allow the original .return call to continue in the
          // outer generator.

          if (context.method !== 'return') {
            context.method = 'next';
            context.arg = undefined;
          }
        } else {
          // Re-yield the result returned by the delegate method.
          return info;
        } // The delegate iterator is finished, so forget it and continue with
        // the outer generator.

        context.delegate = null;
        return ContinueSentinel;
      } // Define Generator.prototype.{next,throw,return} in terms of the
      // unified ._invoke helper method.

      defineIteratorMethods(Gp);
      Gp[toStringTagSymbol] = 'Generator'; // A Generator should always return itself as the iterator object when the
      // @@iterator function is called on it. Some browsers' implementations of the
      // iterator prototype chain incorrectly implement this, causing the Generator
      // object to not be returned from this call. This ensures that doesn't happen.
      // See https://github.com/facebook/regenerator/issues/274 for more details.

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

      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.method = 'next';
          this.arg = undefined;
          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;

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

            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.method = 'next';
            this.next = finallyEntry.finallyLoc;
            return ContinueSentinel;
          }

          return this.complete(record);
        },
        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 = this.arg = record.arg;
            this.method = 'return';
            this.next = 'end';
          } else if (record.type === 'normal' && afterLoc) {
            this.next = afterLoc;
          }

          return ContinueSentinel;
        },
        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,
          };

          if (this.method === 'next') {
            // Deliberately forget the last sent value so that we don't
            // accidentally pass it on to the delegate.
            this.arg = undefined;
          }

          return ContinueSentinel;
        },
      };
    })(
      // In sloppy mode, unbound `this` refers to the global object, fallback to
      // Function constructor if we're in global strict mode. That is sadly a form
      // of indirect eval which violates Content Security Policy.
      (function() {
        return this || (typeof self === 'object' && self);
      })() || Function('return this')()
    );
  });

  /**
   * Copyright (c) 2014-present, Facebook, Inc.
   *
   * This source code is licensed under the MIT license found in the
   * LICENSE file in the root directory of this source tree.
   */
  // This method of obtaining a reference to the global object needs to be
  // kept identical to the way it is obtained in runtime.js
  var g =
    (function() {
      return this || (typeof self === 'object' && self);
    })() || Function('return this')(); // Use `getOwnPropertyNames` because not all browsers support calling
  // `hasOwnProperty` on the global `self` object in a worker. See #183.

  var hadRuntime =
    g.regeneratorRuntime &&
    Object.getOwnPropertyNames(g).indexOf('regeneratorRuntime') >= 0; // Save the old regeneratorRuntime in case it needs to be restored later.

  var oldRuntime = hadRuntime && g.regeneratorRuntime; // Force reevalutation of runtime.js.

  g.regeneratorRuntime = undefined;
  var runtimeModule = runtime;

  if (hadRuntime) {
    // Restore the original runtime.
    g.regeneratorRuntime = oldRuntime;
  } else {
    // Remove the global property added by runtime.js.
    try {
      delete g.regeneratorRuntime;
    } catch (e) {
      g.regeneratorRuntime = undefined;
    }
  }

  var regenerator = runtimeModule;

  var toString = {}.toString;

  var _cof = function(it) {
    return toString.call(it).slice(8, -1);
  };

  // fallback for non-array-like ES3 and non-enumerable old V8 strings
  // eslint-disable-next-line no-prototype-builtins

  var _iobject = Object('z').propertyIsEnumerable(0)
    ? Object
    : function(it) {
        return _cof(it) == 'String' ? it.split('') : Object(it);
      };

  // 7.2.1 RequireObjectCoercible(argument)
  var _defined = function(it) {
    if (it == undefined) throw TypeError("Can't call method on  " + it);
    return it;
  };

  // to indexed object, toObject with fallback for non-array-like ES3 strings

  var _toIobject = function(it) {
    return _iobject(_defined(it));
  };

  var f = {}.propertyIsEnumerable;

  var _objectPie = {
    f: f,
  };

  var _propertyDesc = function(bitmap, value) {
    return {
      enumerable: !(bitmap & 1),
      configurable: !(bitmap & 2),
      writable: !(bitmap & 4),
      value: value,
    };
  };

  var _isObject = function(it) {
    return typeof it === 'object' ? it !== null : typeof it === 'function';
  };

  // 7.1.1 ToPrimitive(input [, PreferredType])
  // instead of the ES6 spec version, we didn't implement @@toPrimitive case
  // and the second argument - flag - preferred type is a string

  var _toPrimitive = function(it, S) {
    if (!_isObject(it)) return it;
    var fn, val;
    if (
      S &&
      typeof (fn = it.toString) == 'function' &&
      !_isObject((val = fn.call(it)))
    )
      return val;
    if (
      typeof (fn = it.valueOf) == 'function' &&
      !_isObject((val = fn.call(it)))
    )
      return val;
    if (
      !S &&
      typeof (fn = it.toString) == 'function' &&
      !_isObject((val = fn.call(it)))
    )
      return val;
    throw TypeError("Can't convert object to primitive value");
  };

  var hasOwnProperty = {}.hasOwnProperty;

  var _has = function(it, key) {
    return hasOwnProperty.call(it, key);
  };

  var _fails = function(exec) {
    try {
      return !!exec();
    } catch (e) {
      return true;
    }
  };

  // Thank's IE8 for his funny defineProperty
  var _descriptors = !_fails(function() {
    return (
      Object.defineProperty({}, 'a', {
        get: function() {
          return 7;
        },
      }).a != 7
    );
  });

  var _global = createCommonjsModule(function(module) {
    // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
    var global = (module.exports =
      typeof window != 'undefined' && window.Math == Math
        ? window
        : typeof self != 'undefined' && self.Math == Math
        ? self // eslint-disable-next-line no-new-func
        : Function('return this')());
    if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef
  });

  var document$1 = _global.document; // typeof document.createElement is 'object' in old IE

  var is = _isObject(document$1) && _isObject(document$1.createElement);

  var _domCreate = function(it) {
    return is ? document$1.createElement(it) : {};
  };

  var _ie8DomDefine =
    !_descriptors &&
    !_fails(function() {
      return (
        Object.defineProperty(_domCreate('div'), 'a', {
          get: function() {
            return 7;
          },
        }).a != 7
      );
    });

  var gOPD = Object.getOwnPropertyDescriptor;
  var f$1 = _descriptors
    ? gOPD
    : function getOwnPropertyDescriptor(O, P) {
        O = _toIobject(O);
        P = _toPrimitive(P, true);
        if (_ie8DomDefine)
          try {
            return gOPD(O, P);
          } catch (e) {
            /* empty */
          }
        if (_has(O, P)) return _propertyDesc(!_objectPie.f.call(O, P), O[P]);
      };

  var _objectGopd = {
    f: f$1,
  };

  var _core = createCommonjsModule(function(module) {
    var core = (module.exports = {
      version: '2.6.2',
    });
    if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
  });
  var _core_1 = _core.version;

  var _aFunction = function(it) {
    if (typeof it != 'function') throw TypeError(it + ' is not a function!');
    return it;
  };

  // optional / simple context binding

  var _ctx = function(fn, that, length) {
    _aFunction(fn);
    if (that === undefined) return fn;

    switch (length) {
      case 1:
        return function(a) {
          return fn.call(that, a);
        };

      case 2:
        return function(a, b) {
          return fn.call(that, a, b);
        };

      case 3:
        return function(a, b, c) {
          return fn.call(that, a, b, c);
        };
    }

    return function() /* ...args */
    {
      return fn.apply(that, arguments);
    };
  };

  var _anObject = function(it) {
    if (!_isObject(it)) throw TypeError(it + ' is not an object!');
    return it;
  };

  var dP = Object.defineProperty;
  var f$2 = _descriptors
    ? Object.defineProperty
    : function defineProperty(O, P, Attributes) {
        _anObject(O);
        P = _toPrimitive(P, true);
        _anObject(Attributes);
        if (_ie8DomDefine)
          try {
            return dP(O, P, Attributes);
          } catch (e) {
            /* empty */
          }
        if ('get' in Attributes || 'set' in Attributes)
          throw TypeError('Accessors not supported!');
        if ('value' in Attributes) O[P] = Attributes.value;
        return O;
      };

  var _objectDp = {
    f: f$2,
  };

  var _hide = _descriptors
    ? function(object, key, value) {
        return _objectDp.f(object, key, _propertyDesc(1, value));
      }
    : function(object, key, value) {
        object[key] = value;
        return object;
      };

  var PROTOTYPE = 'prototype';

  var $export = function(type, name, source) {
    var IS_FORCED = type & $export.F;
    var IS_GLOBAL = type & $export.G;
    var IS_STATIC = type & $export.S;
    var IS_PROTO = type & $export.P;
    var IS_BIND = type & $export.B;
    var IS_WRAP = type & $export.W;
    var exports = IS_GLOBAL ? _core : _core[name] || (_core[name] = {});
    var expProto = exports[PROTOTYPE];
    var target = IS_GLOBAL
      ? _global
      : IS_STATIC
      ? _global[name]
      : (_global[name] || {})[PROTOTYPE];
    var key, own, out;
    if (IS_GLOBAL) source = name;

    for (key in source) {
      // contains in native
      own = !IS_FORCED && target && target[key] !== undefined;
      if (own && _has(exports, key)) continue; // export native or passed

      out = own ? target[key] : source[key]; // prevent global pollution for namespaces

      exports[key] =
        IS_GLOBAL && typeof target[key] != 'function'
          ? source[key] // bind timers to global for call from export context
          : IS_BIND && own
          ? _ctx(out, _global) // wrap global constructors for prevent change them in library
          : IS_WRAP && target[key] == out
          ? (function(C) {
              var F = function(a, b, c) {
                if (this instanceof C) {
                  switch (arguments.length) {
                    case 0:
                      return new C();

                    case 1:
                      return new C(a);

                    case 2:
                      return new C(a, b);
                  }

                  return new C(a, b, c);
                }

                return C.apply(this, arguments);
              };

              F[PROTOTYPE] = C[PROTOTYPE];
              return F; // make static versions for prototype methods
            })(out)
          : IS_PROTO && typeof out == 'function'
          ? _ctx(Function.call, out)
          : out; // export proto methods to core.%CONSTRUCTOR%.methods.%NAME%

      if (IS_PROTO) {
        (exports.virtual || (exports.virtual = {}))[key] = out; // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%

        if (type & $export.R && expProto && !expProto[key])
          _hide(expProto, key, out);
      }
    }
  }; // type bitmap

  $export.F = 1; // forced

  $export.G = 2; // global

  $export.S = 4; // static

  $export.P = 8; // proto

  $export.B = 16; // bind

  $export.W = 32; // wrap

  $export.U = 64; // safe

  $export.R = 128; // real proto method for `library`

  var _export = $export;

  // most Object methods by ES6 should accept primitives

  var _objectSap = function(KEY, exec) {
    var fn = (_core.Object || {})[KEY] || Object[KEY];
    var exp = {};
    exp[KEY] = exec(fn);
    _export(
      _export.S +
        _export.F *
          _fails(function() {
            fn(1);
          }),
      'Object',
      exp
    );
  };

  // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)

  var $getOwnPropertyDescriptor = _objectGopd.f;

  _objectSap('getOwnPropertyDescriptor', function() {
    return function getOwnPropertyDescriptor(it, key) {
      return $getOwnPropertyDescriptor(_toIobject(it), key);
    };
  });

  var $Object = _core.Object;

  var getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key) {
    return $Object.getOwnPropertyDescriptor(it, key);
  };

  var getOwnPropertyDescriptor$1 = getOwnPropertyDescriptor;

  var _redefine = _hide;

  var id = 0;
  var px = Math.random();

  var _uid = function(key) {
    return 'Symbol('.concat(
      key === undefined ? '' : key,
      ')_',
      (++id + px).toString(36)
    );
  };

  var _meta = createCommonjsModule(function(module) {
    var META = _uid('meta');

    var setDesc = _objectDp.f;

    var id = 0;

    var isExtensible =
      Object.isExtensible ||
      function() {
        return true;
      };

    var FREEZE = !_fails(function() {
      return isExtensible(Object.preventExtensions({}));
    });

    var setMeta = function(it) {
      setDesc(it, META, {
        value: {
          i: 'O' + ++id,
          // object ID
          w: {}, // weak collections IDs
        },
      });
    };

    var fastKey = function(it, create) {
      // return primitive with prefix
      if (!_isObject(it))
        return typeof it == 'symbol'
          ? it
          : (typeof it == 'string' ? 'S' : 'P') + it;

      if (!_has(it, META)) {
        // can't set metadata to uncaught frozen object
        if (!isExtensible(it)) return 'F'; // not necessary to add metadata

        if (!create) return 'E'; // add missing metadata

        setMeta(it); // return object ID
      }

      return it[META].i;
    };

    var getWeak = function(it, create) {
      if (!_has(it, META)) {
        // can't set metadata to uncaught frozen object
        if (!isExtensible(it)) return true; // not necessary to add metadata

        if (!create) return false; // add missing metadata

        setMeta(it); // return hash weak collections IDs
      }

      return it[META].w;
    }; // add metadata on freeze-family methods calling

    var onFreeze = function(it) {
      if (FREEZE && meta.NEED && isExtensible(it) && !_has(it, META))
        setMeta(it);
      return it;
    };

    var meta = (module.exports = {
      KEY: META,
      NEED: false,
      fastKey: fastKey,
      getWeak: getWeak,
      onFreeze: onFreeze,
    });
  });
  var _meta_1 = _meta.KEY;
  var _meta_2 = _meta.NEED;
  var _meta_3 = _meta.fastKey;
  var _meta_4 = _meta.getWeak;
  var _meta_5 = _meta.onFreeze;

  var _library = true;

  var _shared = createCommonjsModule(function(module) {
    var SHARED = '__core-js_shared__';
    var store = _global[SHARED] || (_global[SHARED] = {});
    (module.exports = function(key, value) {
      return store[key] || (store[key] = value !== undefined ? value : {});
    })('versions', []).push({
      version: _core.version,
      mode: 'pure',
      copyright: '© 2019 Denis Pushkarev (zloirock.ru)',
    });
  });

  var _wks = createCommonjsModule(function(module) {
    var store = _shared('wks');

    var Symbol = _global.Symbol;

    var USE_SYMBOL = typeof Symbol == 'function';

    var $exports = (module.exports = function(name) {
      return (
        store[name] ||
        (store[name] =
          (USE_SYMBOL && Symbol[name]) ||
          (USE_SYMBOL ? Symbol : _uid)('Symbol.' + name))
      );
    });

    $exports.store = store;
  });

  var def = _objectDp.f;

  var TAG = _wks('toStringTag');

  var _setToStringTag = function(it, tag, stat) {
    if (it && !_has((it = stat ? it : it.prototype), TAG))
      def(it, TAG, {
        configurable: true,
        value: tag,
      });
  };

  var f$3 = _wks;

  var _wksExt = {
    f: f$3,
  };

  var defineProperty = _objectDp.f;

  var _wksDefine = function(name) {
    var $Symbol = _core.Symbol || (_core.Symbol = {});
    if (name.charAt(0) != '_' && !(name in $Symbol))
      defineProperty($Symbol, name, {
        value: _wksExt.f(name),
      });
  };

  // 7.1.4 ToInteger
  var ceil = Math.ceil;
  var floor = Math.floor;

  var _toInteger = function(it) {
    return isNaN((it = +it)) ? 0 : (it > 0 ? floor : ceil)(it);
  };

  // 7.1.15 ToLength

  var min = Math.min;

  var _toLength = function(it) {
    return it > 0 ? min(_toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
  };

  var max = Math.max;
  var min$1 = Math.min;

  var _toAbsoluteIndex = function(index, length) {
    index = _toInteger(index);
    return index < 0 ? max(index + length, 0) : min$1(index, length);
  };

  // false -> Array#indexOf
  // true  -> Array#includes

  var _arrayIncludes = function(IS_INCLUDES) {
    return function($this, el, fromIndex) {
      var O = _toIobject($this);
      var length = _toLength(O.length);
      var index = _toAbsoluteIndex(fromIndex, length);
      var value; // Array#includes uses SameValueZero equality algorithm
      // eslint-disable-next-line no-self-compare

      if (IS_INCLUDES && el != el)
        while (length > index) {
          value = O[index++]; // eslint-disable-next-line no-self-compare

          if (value != value) return true; // Array#indexOf ignores holes, Array#includes - not
        }
      else
        for (; length > index; index++)
          if (IS_INCLUDES || index in O) {
            if (O[index] === el) return IS_INCLUDES || index || 0;
          }
      return !IS_INCLUDES && -1;
    };
  };

  var shared = _shared('keys');

  var _sharedKey = function(key) {
    return shared[key] || (shared[key] = _uid(key));
  };

  var arrayIndexOf = _arrayIncludes(false);

  var IE_PROTO = _sharedKey('IE_PROTO');

  var _objectKeysInternal = function(object, names) {
    var O = _toIobject(object);
    var i = 0;
    var result = [];
    var key;

    for (key in O) if (key != IE_PROTO) _has(O, key) && result.push(key); // Don't enum bug & hidden keys

    while (names.length > i)
      if (_has(O, (key = names[i++]))) {
        ~arrayIndexOf(result, key) || result.push(key);
      }

    return result;
  };

  // IE 8- don't enum bug keys
  var _enumBugKeys = 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'.split(
    ','
  );

  // 19.1.2.14 / 15.2.3.14 Object.keys(O)

  var _objectKeys =
    Object.keys ||
    function keys(O) {
      return _objectKeysInternal(O, _enumBugKeys);
    };

  var f$4 = Object.getOwnPropertySymbols;

  var _objectGops = {
    f: f$4,
  };

  // all enumerable object keys, includes symbols

  var _enumKeys = function(it) {
    var result = _objectKeys(it);
    var getSymbols = _objectGops.f;

    if (getSymbols) {
      var symbols = getSymbols(it);
      var isEnum = _objectPie.f;
      var i = 0;
      var key;

      while (symbols.length > i)
        if (isEnum.call(it, (key = symbols[i++]))) result.push(key);
    }

    return result;
  };

  // 7.2.2 IsArray(argument)

  var _isArray =
    Array.isArray ||
    function isArray(arg) {
      return _cof(arg) == 'Array';
    };

  var _objectDps = _descriptors
    ? Object.defineProperties
    : function defineProperties(O, Properties) {
        _anObject(O);
        var keys = _objectKeys(Properties);
        var length = keys.length;
        var i = 0;
        var P;

        while (length > i) _objectDp.f(O, (P = keys[i++]), Properties[P]);

        return O;
      };

  var document$2 = _global.document;

  var _html = document$2 && document$2.documentElement;

  // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])

  var IE_PROTO$1 = _sharedKey('IE_PROTO');

  var Empty = function() {
    /* empty */
  };

  var PROTOTYPE$1 = 'prototype'; // Create object with fake `null` prototype: use iframe Object with cleared prototype

  var createDict = function() {
    // Thrash, waste and sodomy: IE GC bug
    var iframe = _domCreate('iframe');

    var i = _enumBugKeys.length;
    var lt = '<';
    var gt = '>';
    var iframeDocument;
    iframe.style.display = 'none';

    _html.appendChild(iframe);

    iframe.src = 'javascript:'; // eslint-disable-line no-script-url
    // createDict = iframe.contentWindow.Object;
    // html.removeChild(iframe);

    iframeDocument = iframe.contentWindow.document;
    iframeDocument.open();
    iframeDocument.write(
      lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt
    );
    iframeDocument.close();
    createDict = iframeDocument.F;

    while (i--) delete createDict[PROTOTYPE$1][_enumBugKeys[i]];

    return createDict();
  };

  var _objectCreate =
    Object.create ||
    function create(O, Properties) {
      var result;

      if (O !== null) {
        Empty[PROTOTYPE$1] = _anObject(O);
        result = new Empty();
        Empty[PROTOTYPE$1] = null; // add "__proto__" for Object.getPrototypeOf polyfill

        result[IE_PROTO$1] = O;
      } else result = createDict();

      return Properties === undefined ? result : _objectDps(result, Properties);
    };

  // 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O)

  var hiddenKeys = _enumBugKeys.concat('length', 'prototype');

  var f$5 =
    Object.getOwnPropertyNames ||
    function getOwnPropertyNames(O) {
      return _objectKeysInternal(O, hiddenKeys);
    };

  var _objectGopn = {
    f: f$5,
  };

  // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window

  var gOPN = _objectGopn.f;

  var toString$1 = {}.toString;
  var windowNames =
    typeof window == 'object' && window && Object.getOwnPropertyNames
      ? Object.getOwnPropertyNames(window)
      : [];

  var getWindowNames = function(it) {
    try {
      return gOPN(it);
    } catch (e) {
      return windowNames.slice();
    }
  };

  var f$6 = function getOwnPropertyNames(it) {
    return windowNames && toString$1.call(it) == '[object Window]'
      ? getWindowNames(it)
      : gOPN(_toIobject(it));
  };

  var _objectGopnExt = {
    f: f$6,
  };

  var META = _meta.KEY;

  var gOPD$1 = _objectGopd.f;
  var dP$1 = _objectDp.f;
  var gOPN$1 = _objectGopnExt.f;
  var $Symbol = _global.Symbol;
  var $JSON = _global.JSON;

  var _stringify = $JSON && $JSON.stringify;

  var PROTOTYPE$2 = 'prototype';
  var HIDDEN = _wks('_hidden');
  var TO_PRIMITIVE = _wks('toPrimitive');
  var isEnum = {}.propertyIsEnumerable;
  var SymbolRegistry = _shared('symbol-registry');
  var AllSymbols = _shared('symbols');
  var OPSymbols = _shared('op-symbols');
  var ObjectProto = Object[PROTOTYPE$2];
  var USE_NATIVE = typeof $Symbol == 'function';
  var QObject = _global.QObject; // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173

  var setter =
    !QObject || !QObject[PROTOTYPE$2] || !QObject[PROTOTYPE$2].findChild; // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687

  var setSymbolDesc =
    _descriptors &&
    _fails(function() {
      return (
        _objectCreate(
          dP$1({}, 'a', {
            get: function() {
              return dP$1(this, 'a', {
                value: 7,
              }).a;
            },
          })
        ).a != 7
      );
    })
      ? function(it, key, D) {
          var protoDesc = gOPD$1(ObjectProto, key);
          if (protoDesc) delete ObjectProto[key];
          dP$1(it, key, D);
          if (protoDesc && it !== ObjectProto)
            dP$1(ObjectProto, key, protoDesc);
        }
      : dP$1;

  var wrap = function(tag) {
    var sym = (AllSymbols[tag] = _objectCreate($Symbol[PROTOTYPE$2]));

    sym._k = tag;
    return sym;
  };

  var isSymbol =
    USE_NATIVE && typeof $Symbol.iterator == 'symbol'
      ? function(it) {
          return typeof it == 'symbol';
        }
      : function(it) {
          return it instanceof $Symbol;
        };

  var $defineProperty = function defineProperty(it, key, D) {
    if (it === ObjectProto) $defineProperty(OPSymbols, key, D);
    _anObject(it);
    key = _toPrimitive(key, true);
    _anObject(D);

    if (_has(AllSymbols, key)) {
      if (!D.enumerable) {
        if (!_has(it, HIDDEN)) dP$1(it, HIDDEN, _propertyDesc(1, {}));
        it[HIDDEN][key] = true;
      } else {
        if (_has(it, HIDDEN) && it[HIDDEN][key]) it[HIDDEN][key] = false;
        D = _objectCreate(D, {
          enumerable: _propertyDesc(0, false),
        });
      }

      return setSymbolDesc(it, key, D);
    }

    return dP$1(it, key, D);
  };

  var $defineProperties = function defineProperties(it, P) {
    _anObject(it);
    var keys = _enumKeys((P = _toIobject(P)));
    var i = 0;
    var l = keys.length;
    var key;

    while (l > i) $defineProperty(it, (key = keys[i++]), P[key]);

    return it;
  };

  var $create = function create(it, P) {
    return P === undefined
      ? _objectCreate(it)
      : $defineProperties(_objectCreate(it), P);
  };

  var $propertyIsEnumerable = function propertyIsEnumerable(key) {
    var E = isEnum.call(this, (key = _toPrimitive(key, true)));
    if (this === ObjectProto && _has(AllSymbols, key) && !_has(OPSymbols, key))
      return false;
    return E ||
      !_has(this, key) ||
      !_has(AllSymbols, key) ||
      (_has(this, HIDDEN) && this[HIDDEN][key])
      ? E
      : true;
  };

  var $getOwnPropertyDescriptor$1 = function getOwnPropertyDescriptor(it, key) {
    it = _toIobject(it);
    key = _toPrimitive(key, true);
    if (it === ObjectProto && _has(AllSymbols, key) && !_has(OPSymbols, key))
      return;
    var D = gOPD$1(it, key);
    if (D && _has(AllSymbols, key) && !(_has(it, HIDDEN) && it[HIDDEN][key]))
      D.enumerable = true;
    return D;
  };

  var $getOwnPropertyNames = function getOwnPropertyNames(it) {
    var names = gOPN$1(_toIobject(it));
    var result = [];
    var i = 0;
    var key;

    while (names.length > i) {
      if (!_has(AllSymbols, (key = names[i++])) && key != HIDDEN && key != META)
        result.push(key);
    }

    return result;
  };

  var $getOwnPropertySymbols = function getOwnPropertySymbols(it) {
    var IS_OP = it === ObjectProto;
    var names = gOPN$1(IS_OP ? OPSymbols : _toIobject(it));
    var result = [];
    var i = 0;
    var key;

    while (names.length > i) {
      if (
        _has(AllSymbols, (key = names[i++])) &&
        (IS_OP ? _has(ObjectProto, key) : true)
      )
        result.push(AllSymbols[key]);
    }

    return result;
  }; // 19.4.1.1 Symbol([description])

  if (!USE_NATIVE) {
    $Symbol = function Symbol() {
      if (this instanceof $Symbol)
        throw TypeError('Symbol is not a constructor!');
      var tag = _uid(arguments.length > 0 ? arguments[0] : undefined);

      var $set = function(value) {
        if (this === ObjectProto) $set.call(OPSymbols, value);
        if (_has(this, HIDDEN) && _has(this[HIDDEN], tag))
          this[HIDDEN][tag] = false;
        setSymbolDesc(this, tag, _propertyDesc(1, value));
      };

      if (_descriptors && setter)
        setSymbolDesc(ObjectProto, tag, {
          configurable: true,
          set: $set,
        });
      return wrap(tag);
    };

    _redefine($Symbol[PROTOTYPE$2], 'toString', function toString() {
      return this._k;
    });
    _objectGopd.f = $getOwnPropertyDescriptor$1;
    _objectDp.f = $defineProperty;
    _objectGopn.f = _objectGopnExt.f = $getOwnPropertyNames;
    _objectPie.f = $propertyIsEnumerable;
    _objectGops.f = $getOwnPropertySymbols;

    if (_descriptors && !_library) {
      _redefine(
        ObjectProto,
        'propertyIsEnumerable',
        $propertyIsEnumerable,
        true
      );
    }

    _wksExt.f = function(name) {
      return wrap(_wks(name));
    };
  }

  _export(_export.G + _export.W + _export.F * !USE_NATIVE, {
    Symbol: $Symbol,
  });

  for (
    var es6Symbols = 'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables'.split( // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14
        ','
      ),
      j = 0;
    es6Symbols.length > j;

  )
    _wks(es6Symbols[j++]);

  for (
    var wellKnownSymbols = _objectKeys(_wks.store), k = 0;
    wellKnownSymbols.length > k;

  )
    _wksDefine(wellKnownSymbols[k++]);

  _export(_export.S + _export.F * !USE_NATIVE, 'Symbol', {
    // 19.4.2.1 Symbol.for(key)
    for: function(key) {
      return _has(SymbolRegistry, (key += ''))
        ? SymbolRegistry[key]
        : (SymbolRegistry[key] = $Symbol(key));
    },
    // 19.4.2.5 Symbol.keyFor(sym)
    keyFor: function keyFor(sym) {
      if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol!');

      for (var key in SymbolRegistry)
        if (SymbolRegistry[key] === sym) return key;
    },
    useSetter: function() {
      setter = true;
    },
    useSimple: function() {
      setter = false;
    },
  });
  _export(_export.S + _export.F * !USE_NATIVE, 'Object', {
    // 19.1.2.2 Object.create(O [, Properties])
    create: $create,
    // 19.1.2.4 Object.defineProperty(O, P, Attributes)
    defineProperty: $defineProperty,
    // 19.1.2.3 Object.defineProperties(O, Properties)
    defineProperties: $defineProperties,
    // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)
    getOwnPropertyDescriptor: $getOwnPropertyDescriptor$1,
    // 19.1.2.7 Object.getOwnPropertyNames(O)
    getOwnPropertyNames: $getOwnPropertyNames,
    // 19.1.2.8 Object.getOwnPropertySymbols(O)
    getOwnPropertySymbols: $getOwnPropertySymbols,
  }); // 24.3.2 JSON.stringify(value [, replacer [, space]])

  $JSON &&
    _export(
      _export.S +
        _export.F *
          (!USE_NATIVE ||
            _fails(function() {
              var S = $Symbol(); // MS Edge converts symbol values to JSON as {}
              // WebKit converts symbol values to JSON as null
              // V8 throws on boxed symbols

              return (
                _stringify([S]) != '[null]' ||
                _stringify({
                  a: S,
                }) != '{}' ||
                _stringify(Object(S)) != '{}'
              );
            })),
      'JSON',
      {
        stringify: function stringify(it) {
          var args = [it];
          var i = 1;
          var replacer, $replacer;

          while (arguments.length > i) args.push(arguments[i++]);

          $replacer = replacer = args[1];
          if ((!_isObject(replacer) && it === undefined) || isSymbol(it))
            return; // IE8 returns string on undefined

          if (!_isArray(replacer))
            replacer = function(key, value) {
              if (typeof $replacer == 'function')
                value = $replacer.call(this, key, value);
              if (!isSymbol(value)) return value;
            };
          args[1] = replacer;
          return _stringify.apply($JSON, args);
        },
      }
    ); // 19.4.3.4 Symbol.prototype[@@toPrimitive](hint)

  $Symbol[PROTOTYPE$2][TO_PRIMITIVE] ||
    _hide($Symbol[PROTOTYPE$2], TO_PRIMITIVE, $Symbol[PROTOTYPE$2].valueOf); // 19.4.3.5 Symbol.prototype[@@toStringTag]

  _setToStringTag($Symbol, 'Symbol'); // 20.2.1.9 Math[@@toStringTag]

  _setToStringTag(Math, 'Math', true); // 24.3.3 JSON[@@toStringTag]

  _setToStringTag(_global.JSON, 'JSON', true);

  var getOwnPropertySymbols = _core.Object.getOwnPropertySymbols;

  var getOwnPropertySymbols$1 = getOwnPropertySymbols;

  // 7.1.13 ToObject(argument)

  var _toObject = function(it) {
    return Object(_defined(it));
  };

  // 19.1.2.14 Object.keys(O)

  _objectSap('keys', function() {
    return function keys(it) {
      return _objectKeys(_toObject(it));
    };
  });

  var keys = _core.Object.keys;

  var keys$1 = keys;

  // 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes)

  _export(_export.S + _export.F * !_descriptors, 'Object', {
    defineProperty: _objectDp.f,
  });

  var $Object$1 = _core.Object;

  var defineProperty$1 = function defineProperty(it, key, desc) {
    return $Object$1.defineProperty(it, key, desc);
  };

  var defineProperty$2 = defineProperty$1;

  function _defineProperty(obj, key, value) {
    if (key in obj) {
      defineProperty$2(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true,
      });
    } else {
      obj[key] = value;
    }

    return obj;
  }

  var defineProperty$3 = _defineProperty;

  function _objectSpread(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i] != null ? arguments[i] : {};

      var ownKeys = keys$1(source);

      if (typeof getOwnPropertySymbols$1 === 'function') {
        ownKeys = ownKeys.concat(
          getOwnPropertySymbols$1(source).filter(function(sym) {
            return getOwnPropertyDescriptor$1(source, sym).enumerable;
          })
        );
      }

      ownKeys.forEach(function(key) {
        defineProperty$3(target, key, source[key]);
      });
    }

    return target;
  }

  var objectSpread = _objectSpread;

  // true  -> String#at
  // false -> String#codePointAt

  var _stringAt = function(TO_STRING) {
    return function(that, pos) {
      var s = String(_defined(that));
      var i = _toInteger(pos);
      var l = s.length;
      var a, b;
      if (i < 0 || i >= l) return TO_STRING ? '' : undefined;
      a = s.charCodeAt(i);
      return a < 0xd800 ||
        a > 0xdbff ||
        i + 1 === l ||
        (b = s.charCodeAt(i + 1)) < 0xdc00 ||
        b > 0xdfff
        ? TO_STRING
          ? s.charAt(i)
          : a
        : TO_STRING
        ? s.slice(i, i + 2)
        : ((a - 0xd800) << 10) + (b - 0xdc00) + 0x10000;
    };
  };

  var _iterators = {};

  var IteratorPrototype = {}; // 25.1.2.1.1 %IteratorPrototype%[@@iterator]()

  _hide(IteratorPrototype, _wks('iterator'), function() {
    return this;
  });

  var _iterCreate = function(Constructor, NAME, next) {
    Constructor.prototype = _objectCreate(IteratorPrototype, {
      next: _propertyDesc(1, next),
    });
    _setToStringTag(Constructor, NAME + ' Iterator');
  };

  // 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)

  var IE_PROTO$2 = _sharedKey('IE_PROTO');

  var ObjectProto$1 = Object.prototype;

  var _objectGpo =
    Object.getPrototypeOf ||
    function(O) {
      O = _toObject(O);
      if (_has(O, IE_PROTO$2)) return O[IE_PROTO$2];

      if (typeof O.constructor == 'function' && O instanceof O.constructor) {
        return O.constructor.prototype;
      }

      return O instanceof Object ? ObjectProto$1 : null;
    };

  var ITERATOR = _wks('iterator');

  var BUGGY = !([].keys && 'next' in [].keys()); // Safari has buggy iterators w/o `next`

  var FF_ITERATOR = '@@iterator';
  var KEYS = 'keys';
  var VALUES = 'values';

  var returnThis = function() {
    return this;
  };

  var _iterDefine = function(
    Base,
    NAME,
    Constructor,
    next,
    DEFAULT,
    IS_SET,
    FORCED
  ) {
    _iterCreate(Constructor, NAME, next);

    var getMethod = function(kind) {
      if (!BUGGY && kind in proto) return proto[kind];

      switch (kind) {
        case KEYS:
          return function keys() {
            return new Constructor(this, kind);
          };

        case VALUES:
          return function values() {
            return new Constructor(this, kind);
          };
      }

      return function entries() {
        return new Constructor(this, kind);
      };
    };

    var TAG = NAME + ' Iterator';
    var DEF_VALUES = DEFAULT == VALUES;
    var VALUES_BUG = false;
    var proto = Base.prototype;
    var $native =
      proto[ITERATOR] || proto[FF_ITERATOR] || (DEFAULT && proto[DEFAULT]);
    var $default = $native || getMethod(DEFAULT);
    var $entries = DEFAULT
      ? !DEF_VALUES
        ? $default
        : getMethod('entries')
      : undefined;
    var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
    var methods, key, IteratorPrototype; // Fix native

    if ($anyNative) {
      IteratorPrototype = _objectGpo($anyNative.call(new Base()));

      if (IteratorPrototype !== Object.prototype && IteratorPrototype.next) {
        // Set @@toStringTag to native iterators
        _setToStringTag(IteratorPrototype, TAG, true); // fix for some old engines

        if (!_library && typeof IteratorPrototype[ITERATOR] != 'function')
          _hide(IteratorPrototype, ITERATOR, returnThis);
      }
    } // fix Array#{values, @@iterator}.name in V8 / FF

    if (DEF_VALUES && $native && $native.name !== VALUES) {
      VALUES_BUG = true;

      $default = function values() {
        return $native.call(this);
      };
    } // Define iterator

    if ((!_library || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])) {
      _hide(proto, ITERATOR, $default);
    } // Plug for library

    _iterators[NAME] = $default;
    _iterators[TAG] = returnThis;

    if (DEFAULT) {
      methods = {
        values: DEF_VALUES ? $default : getMethod(VALUES),
        keys: IS_SET ? $default : getMethod(KEYS),
        entries: $entries,
      };
      if (FORCED)
        for (key in methods) {
          if (!(key in proto)) _redefine(proto, key, methods[key]);
        }
      else
        _export(_export.P + _export.F * (BUGGY || VALUES_BUG), NAME, methods);
    }

    return methods;
  };

  var $at = _stringAt(true); // 21.1.3.27 String.prototype[@@iterator]()

  _iterDefine(
    String,
    'String',
    function(iterated) {
      this._t = String(iterated); // target

      this._i = 0; // next index
      // 21.1.5.2.1 %StringIteratorPrototype%.next()
    },
    function() {
      var O = this._t;
      var index = this._i;
      var point;
      if (index >= O.length)
        return {
          value: undefined,
          done: true,
        };
      point = $at(O, index);
      this._i += point.length;
      return {
        value: point,
        done: false,
      };
    }
  );

  var _iterStep = function(done, value) {
    return {
      value: value,
      done: !!done,
    };
  };

  // 22.1.3.4 Array.prototype.entries()
  // 22.1.3.13 Array.prototype.keys()
  // 22.1.3.29 Array.prototype.values()
  // 22.1.3.30 Array.prototype[@@iterator]()

  var es6_array_iterator = _iterDefine(
    Array,
    'Array',
    function(iterated, kind) {
      this._t = _toIobject(iterated); // target

      this._i = 0; // next index

      this._k = kind; // kind
      // 22.1.5.2.1 %ArrayIteratorPrototype%.next()
    },
    function() {
      var O = this._t;
      var kind = this._k;
      var index = this._i++;

      if (!O || index >= O.length) {
        this._t = undefined;
        return _iterStep(1);
      }

      if (kind == 'keys') return _iterStep(0, index);
      if (kind == 'values') return _iterStep(0, O[index]);
      return _iterStep(0, [index, O[index]]);
    },
    'values'
  ); // argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)

  _iterators.Arguments = _iterators.Array;

  var TO_STRING_TAG = _wks('toStringTag');

  var DOMIterables = (
    'CSSRuleList,CSSStyleDeclaration,CSSValueList,ClientRectList,DOMRectList,DOMStringList,' +
    'DOMTokenList,DataTransferItemList,FileList,HTMLAllCollection,HTMLCollection,HTMLFormElement,HTMLSelectElement,' +
    'MediaList,MimeTypeArray,NamedNodeMap,NodeList,PaintRequestList,Plugin,PluginArray,SVGLengthList,SVGNumberList,' +
    'SVGPathSegList,SVGPointList,SVGStringList,SVGTransformList,SourceBufferList,StyleSheetList,TextTrackCueList,' +
    'TextTrackList,TouchList'
  ).split(',');

  for (var i = 0; i < DOMIterables.length; i++) {
    var NAME = DOMIterables[i];
    var Collection = _global[NAME];
    var proto = Collection && Collection.prototype;
    if (proto && !proto[TO_STRING_TAG]) _hide(proto, TO_STRING_TAG, NAME);
    _iterators[NAME] = _iterators.Array;
  }

  // getting tag from 19.1.3.6 Object.prototype.toString()

  var TAG$1 = _wks('toStringTag'); // ES3 wrong here

  var ARG =
    _cof(
      (function() {
        return arguments;
      })()
    ) == 'Arguments'; // fallback for IE11 Script Access Denied error

  var tryGet = function(it, key) {
    try {
      return it[key];
    } catch (e) {
      /* empty */
    }
  };

  var _classof = function(it) {
    var O, T, B;
    return it === undefined
      ? 'Undefined'
      : it === null
      ? 'Null' // @@toStringTag case
      : typeof (T = tryGet((O = Object(it)), TAG$1)) == 'string'
      ? T // builtinTag case
      : ARG
      ? _cof(O) // ES3 arguments fallback
      : (B = _cof(O)) == 'Object' && typeof O.callee == 'function'
      ? 'Arguments'
      : B;
  };

  var _anInstance = function(it, Constructor, name, forbiddenField) {
    if (
      !(it instanceof Constructor) ||
      (forbiddenField !== undefined && forbiddenField in it)
    ) {
      throw TypeError(name + ': incorrect invocation!');
    }

    return it;
  };

  // call something on iterator step with safe closing on error

  var _iterCall = function(iterator, fn, value, entries) {
    try {
      return entries ? fn(_anObject(value)[0], value[1]) : fn(value); // 7.4.6 IteratorClose(iterator, completion)
    } catch (e) {
      var ret = iterator['return'];
      if (ret !== undefined) _anObject(ret.call(iterator));
      throw e;
    }
  };

  // check on default Array iterator

  var ITERATOR$1 = _wks('iterator');

  var ArrayProto = Array.prototype;

  var _isArrayIter = function(it) {
    return (
      it !== undefined &&
      (_iterators.Array === it || ArrayProto[ITERATOR$1] === it)
    );
  };

  var ITERATOR$2 = _wks('iterator');

  var core_getIteratorMethod = (_core.getIteratorMethod = function(it) {
    if (it != undefined)
      return it[ITERATOR$2] || it['@@iterator'] || _iterators[_classof(it)];
  });

  var _forOf = createCommonjsModule(function(module) {
    var BREAK = {};
    var RETURN = {};

    var exports = (module.exports = function(
      iterable,
      entries,
      fn,
      that,
      ITERATOR
    ) {
      var iterFn = ITERATOR
        ? function() {
            return iterable;
          }
        : core_getIteratorMethod(iterable);
      var f = _ctx(fn, that, entries ? 2 : 1);
      var index = 0;
      var length, step, iterator, result;
      if (typeof iterFn != 'function')
        throw TypeError(iterable + ' is not iterable!'); // fast case for arrays with default iterator

      if (_isArrayIter(iterFn))
        for (length = _toLength(iterable.length); length > index; index++) {
          result = entries
            ? f(_anObject((step = iterable[index]))[0], step[1])
            : f(iterable[index]);
          if (result === BREAK || result === RETURN) return result;
        }
      else
        for (
          iterator = iterFn.call(iterable);
          !(step = iterator.next()).done;

        ) {
          result = _iterCall(iterator, f, step.value, entries);
          if (result === BREAK || result === RETURN) return result;
        }
    });

    exports.BREAK = BREAK;
    exports.RETURN = RETURN;
  });

  // 7.3.20 SpeciesConstructor(O, defaultConstructor)

  var SPECIES = _wks('species');

  var _speciesConstructor = function(O, D) {
    var C = _anObject(O).constructor;
    var S;
    return C === undefined || (S = _anObject(C)[SPECIES]) == undefined
      ? D
      : _aFunction(S);
  };

  // fast apply, http://jsperf.lnkit.com/fast-apply/5
  var _invoke = function(fn, args, that) {
    var un = that === undefined;

    switch (args.length) {
      case 0:
        return un ? fn() : fn.call(that);

      case 1:
        return un ? fn(args[0]) : fn.call(that, args[0]);

      case 2:
        return un ? fn(args[0], args[1]) : fn.call(that, args[0], args[1]);

      case 3:
        return un
          ? fn(args[0], args[1], args[2])
          : fn.call(that, args[0], args[1], args[2]);

      case 4:
        return un
          ? fn(args[0], args[1], args[2], args[3])
          : fn.call(that, args[0], args[1], args[2], args[3]);
    }

    return fn.apply(that, args);
  };

  var process = _global.process;
  var setTask = _global.setImmediate;
  var clearTask = _global.clearImmediate;
  var MessageChannel = _global.MessageChannel;
  var Dispatch = _global.Dispatch;
  var counter = 0;
  var queue = {};
  var ONREADYSTATECHANGE = 'onreadystatechange';
  var defer, channel, port;

  var run = function() {
    var id = +this; // eslint-disable-next-line no-prototype-builtins

    if (queue.hasOwnProperty(id)) {
      var fn = queue[id];
      delete queue[id];
      fn();
    }
  };

  var listener = function(event) {
    run.call(event.data);
  }; // Node.js 0.9+ & IE10+ has setImmediate, otherwise:

  if (!setTask || !clearTask) {
    setTask = function setImmediate(fn) {
      var args = [];
      var i = 1;

      while (arguments.length > i) args.push(arguments[i++]);

      queue[++counter] = function() {
        // eslint-disable-next-line no-new-func
        _invoke(typeof fn == 'function' ? fn : Function(fn), args);
      };

      defer(counter);
      return counter;
    };

    clearTask = function clearImmediate(id) {
      delete queue[id];
    }; // Node.js 0.8-

    if (_cof(process) == 'process') {
      defer = function(id) {
        process.nextTick(_ctx(run, id, 1));
      }; // Sphere (JS game engine) Dispatch API
    } else if (Dispatch && Dispatch.now) {
      defer = function(id) {
        Dispatch.now(_ctx(run, id, 1));
      }; // Browsers with MessageChannel, includes WebWorkers
    } else if (MessageChannel) {
      channel = new MessageChannel();
      port = channel.port2;
      channel.port1.onmessage = listener;
      defer = _ctx(port.postMessage, port, 1); // Browsers with postMessage, skip WebWorkers
      // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
    } else if (
      _global.addEventListener &&
      typeof postMessage == 'function' &&
      !_global.importScripts
    ) {
      defer = function(id) {
        _global.postMessage(id + '', '*');
      };

      _global.addEventListener('message', listener, false); // IE8-
    } else if (ONREADYSTATECHANGE in _domCreate('script')) {
      defer = function(id) {
        _html.appendChild(_domCreate('script'))[
          ONREADYSTATECHANGE
        ] = function() {
          _html.removeChild(this);
          run.call(id);
        };
      }; // Rest old browsers
    } else {
      defer = function(id) {
        setTimeout(_ctx(run, id, 1), 0);
      };
    }
  }

  var _task = {
    set: setTask,
    clear: clearTask,
  };

  var macrotask = _task.set;

  var Observer = _global.MutationObserver || _global.WebKitMutationObserver;
  var process$1 = _global.process;
  var Promise$1 = _global.Promise;
  var isNode = _cof(process$1) == 'process';

  var _microtask = function() {
    var head, last, notify;

    var flush = function() {
      var parent, fn;
      if (isNode && (parent = process$1.domain)) parent.exit();

      while (head) {
        fn = head.fn;
        head = head.next;

        try {
          fn();
        } catch (e) {
          if (head) notify();
          else last = undefined;
          throw e;
        }
      }

      last = undefined;
      if (parent) parent.enter();
    }; // Node.js

    if (isNode) {
      notify = function() {
        process$1.nextTick(flush);
      }; // browsers with MutationObserver, except iOS Safari - https://github.com/zloirock/core-js/issues/339
    } else if (
      Observer &&
      !(_global.navigator && _global.navigator.standalone)
    ) {
      var toggle = true;
      var node = document.createTextNode('');
      new Observer(flush).observe(node, {
        characterData: true,
      }); // eslint-disable-line no-new

      notify = function() {
        node.data = toggle = !toggle;
      }; // environments with maybe non-completely correct, but existent Promise
    } else if (Promise$1 && Promise$1.resolve) {
      // Promise.resolve without an argument throws an error in LG WebOS 2
      var promise = Promise$1.resolve(undefined);

      notify = function() {
        promise.then(flush);
      }; // for other environments - macrotask based on:
      // - setImmediate
      // - MessageChannel
      // - window.postMessag
      // - onreadystatechange
      // - setTimeout
    } else {
      notify = function() {
        // strange IE + webpack dev server bug - use .call(global)
        macrotask.call(_global, flush);
      };
    }

    return function(fn) {
      var task = {
        fn: fn,
        next: undefined,
      };
      if (last) last.next = task;

      if (!head) {
        head = task;
        notify();
      }

      last = task;
    };
  };

  function PromiseCapability(C) {
    var resolve, reject;
    this.promise = new C(function($$resolve, $$reject) {
      if (resolve !== undefined || reject !== undefined)
        throw TypeError('Bad Promise constructor');
      resolve = $$resolve;
      reject = $$reject;
    });
    this.resolve = _aFunction(resolve);
    this.reject = _aFunction(reject);
  }

  var f$7 = function(C) {
    return new PromiseCapability(C);
  };

  var _newPromiseCapability = {
    f: f$7,
  };

  var _perform = function(exec) {
    try {
      return {
        e: false,
        v: exec(),
      };
    } catch (e) {
      return {
        e: true,
        v: e,
      };
    }
  };

  var navigator = _global.navigator;
  var _userAgent = (navigator && navigator.userAgent) || '';

  var _promiseResolve = function(C, x) {
    _anObject(C);
    if (_isObject(x) && x.constructor === C) return x;
    var promiseCapability = _newPromiseCapability.f(C);
    var resolve = promiseCapability.resolve;
    resolve(x);
    return promiseCapability.promise;
  };

  var _redefineAll = function(target, src, safe) {
    for (var key in src) {
      if (safe && target[key]) target[key] = src[key];
      else _hide(target, key, src[key]);
    }

    return target;
  };

  var SPECIES$1 = _wks('species');

  var _setSpecies = function(KEY) {
    var C = typeof _core[KEY] == 'function' ? _core[KEY] : _global[KEY];
    if (_descriptors && C && !C[SPECIES$1])
      _objectDp.f(C, SPECIES$1, {
        configurable: true,
        get: function() {
          return this;
        },
      });
  };

  var ITERATOR$3 = _wks('iterator');

  var SAFE_CLOSING = false;

  try {
    var riter = [7][ITERATOR$3]();

    riter['return'] = function() {
      SAFE_CLOSING = true;
    }; // eslint-disable-next-line no-throw-literal
  } catch (e) {
    /* empty */
  }

  var _iterDetect = function(exec, skipClosing) {
    if (!skipClosing && !SAFE_CLOSING) return false;
    var safe = false;

    try {
      var arr = [7];
      var iter = arr[ITERATOR$3]();

      iter.next = function() {
        return {
          done: (safe = true),
        };
      };

      arr[ITERATOR$3] = function() {
        return iter;
      };

      exec(arr);
    } catch (e) {
      /* empty */
    }

    return safe;
  };

  var task = _task.set;

  var microtask = _microtask();

  var PROMISE = 'Promise';
  var TypeError$1 = _global.TypeError;
  var process$2 = _global.process;
  var versions = process$2 && process$2.versions;
  var v8 = (versions && versions.v8) || '';
  var $Promise = _global[PROMISE];
  var isNode$1 = _classof(process$2) == 'process';

  var empty = function() {
    /* empty */
  };

  var Internal, newGenericPromiseCapability, OwnPromiseCapability, Wrapper;
  var newPromiseCapability = (newGenericPromiseCapability =
    _newPromiseCapability.f);
  var USE_NATIVE$1 = !!(function() {
    try {
      // correct subclassing with @@species support
      var promise = $Promise.resolve(1);

      var FakePromise = ((promise.constructor = {})[_wks('species')] = function(
        exec
      ) {
        exec(empty, empty);
      }); // unhandled rejections tracking support, NodeJS Promise without it fails @@species test

      return (
        (isNode$1 || typeof PromiseRejectionEvent == 'function') &&
        promise.then(empty) instanceof FakePromise && // v8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
        // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
        // we can't detect it synchronously, so just check versions
        v8.indexOf('6.6') !== 0 &&
        _userAgent.indexOf('Chrome/66') === -1
      );
    } catch (e) {
      /* empty */
    }
  })(); // helpers

  var isThenable = function(it) {
    var then;
    return _isObject(it) && typeof (then = it.then) == 'function'
      ? then
      : false;
  };

  var notify = function(promise, isReject) {
    if (promise._n) return;
    promise._n = true;
    var chain = promise._c;
    microtask(function() {
      var value = promise._v;
      var ok = promise._s == 1;
      var i = 0;

      var run = function(reaction) {
        var handler = ok ? reaction.ok : reaction.fail;
        var resolve = reaction.resolve;
        var reject = reaction.reject;
        var domain = reaction.domain;
        var result, then, exited;

        try {
          if (handler) {
            if (!ok) {
              if (promise._h == 2) onHandleUnhandled(promise);
              promise._h = 1;
            }

            if (handler === true) result = value;
            else {
              if (domain) domain.enter();
              result = handler(value); // may throw

              if (domain) {
                domain.exit();
                exited = true;
              }
            }

            if (result === reaction.promise) {
              reject(TypeError$1('Promise-chain cycle'));
            } else if ((then = isThenable(result))) {
              then.call(result, resolve, reject);
            } else resolve(result);
          } else reject(value);
        } catch (e) {
          if (domain && !exited) domain.exit();
          reject(e);
        }
      };

      while (chain.length > i) run(chain[i++]); // variable length - can't use forEach

      promise._c = [];
      promise._n = false;
      if (isReject && !promise._h) onUnhandled(promise);
    });
  };

  var onUnhandled = function(promise) {
    task.call(_global, function() {
      var value = promise._v;
      var unhandled = isUnhandled(promise);
      var result, handler, console;

      if (unhandled) {
        result = _perform(function() {
          if (isNode$1) {
            process$2.emit('unhandledRejection', value, promise);
          } else if ((handler = _global.onunhandledrejection)) {
            handler({
              promise: promise,
              reason: value,
            });
          } else if ((console = _global.console) && console.error) {
            console.error('Unhandled promise rejection', value);
          }
        }); // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should

        promise._h = isNode$1 || isUnhandled(promise) ? 2 : 1;
      }

      promise._a = undefined;
      if (unhandled && result.e) throw result.v;
    });
  };

  var isUnhandled = function(promise) {
    return promise._h !== 1 && (promise._a || promise._c).length === 0;
  };

  var onHandleUnhandled = function(promise) {
    task.call(_global, function() {
      var handler;

      if (isNode$1) {
        process$2.emit('rejectionHandled', promise);
      } else if ((handler = _global.onrejectionhandled)) {
        handler({
          promise: promise,
          reason: promise._v,
        });
      }
    });
  };

  var $reject = function(value) {
    var promise = this;
    if (promise._d) return;
    promise._d = true;
    promise = promise._w || promise; // unwrap

    promise._v = value;
    promise._s = 2;
    if (!promise._a) promise._a = promise._c.slice();
    notify(promise, true);
  };

  var $resolve = function(value) {
    var promise = this;
    var then;
    if (promise._d) return;
    promise._d = true;
    promise = promise._w || promise; // unwrap

    try {
      if (promise === value)
        throw TypeError$1("Promise can't be resolved itself");

      if ((then = isThenable(value))) {
        microtask(function() {
          var wrapper = {
            _w: promise,
            _d: false,
          }; // wrap

          try {
            then.call(
              value,
              _ctx($resolve, wrapper, 1),
              _ctx($reject, wrapper, 1)
            );
          } catch (e) {
            $reject.call(wrapper, e);
          }
        });
      } else {
        promise._v = value;
        promise._s = 1;
        notify(promise, false);
      }
    } catch (e) {
      $reject.call(
        {
          _w: promise,
          _d: false,
        },
        e
      ); // wrap
    }
  }; // constructor polyfill

  if (!USE_NATIVE$1) {
    // 25.4.3.1 Promise(executor)
    $Promise = function Promise(executor) {
      _anInstance(this, $Promise, PROMISE, '_h');
      _aFunction(executor);
      Internal.call(this);

      try {
        executor(_ctx($resolve, this, 1), _ctx($reject, this, 1));
      } catch (err) {
        $reject.call(this, err);
      }
    }; // eslint-disable-next-line no-unused-vars

    Internal = function Promise(executor) {
      this._c = []; // <- awaiting reactions

      this._a = undefined; // <- checked in isUnhandled reactions

      this._s = 0; // <- state

      this._d = false; // <- done

      this._v = undefined; // <- value

      this._h = 0; // <- rejection state, 0 - default, 1 - handled, 2 - unhandled

      this._n = false; // <- notify
    };

    Internal.prototype = _redefineAll($Promise.prototype, {
      // 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
      then: function then(onFulfilled, onRejected) {
        var reaction = newPromiseCapability(
          _speciesConstructor(this, $Promise)
        );
        reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
        reaction.fail = typeof onRejected == 'function' && onRejected;
        reaction.domain = isNode$1 ? process$2.domain : undefined;

        this._c.push(reaction);

        if (this._a) this._a.push(reaction);
        if (this._s) notify(this, false);
        return reaction.promise;
      },
      // 25.4.5.1 Promise.prototype.catch(onRejected)
      catch: function(onRejected) {
        return this.then(undefined, onRejected);
      },
    });

    OwnPromiseCapability = function() {
      var promise = new Internal();
      this.promise = promise;
      this.resolve = _ctx($resolve, promise, 1);
      this.reject = _ctx($reject, promise, 1);
    };

    _newPromiseCapability.f = newPromiseCapability = function(C) {
      return C === $Promise || C === Wrapper
        ? new OwnPromiseCapability(C)
        : newGenericPromiseCapability(C);
    };
  }

  _export(_export.G + _export.W + _export.F * !USE_NATIVE$1, {
    Promise: $Promise,
  });

  _setToStringTag($Promise, PROMISE);

  _setSpecies(PROMISE);

  Wrapper = _core[PROMISE]; // statics

  _export(_export.S + _export.F * !USE_NATIVE$1, PROMISE, {
    // 25.4.4.5 Promise.reject(r)
    reject: function reject(r) {
      var capability = newPromiseCapability(this);
      var $$reject = capability.reject;
      $$reject(r);
      return capability.promise;
    },
  });
  _export(_export.S + _export.F * (_library || !USE_NATIVE$1), PROMISE, {
    // 25.4.4.6 Promise.resolve(x)
    resolve: function resolve(x) {
      return _promiseResolve(_library && this === Wrapper ? $Promise : this, x);
    },
  });
  _export(
    _export.S +
      _export.F *
        !(
          USE_NATIVE$1 &&
          _iterDetect(function(iter) {
            $Promise.all(iter)['catch'](empty);
          })
        ),
    PROMISE,
    {
      // 25.4.4.1 Promise.all(iterable)
      all: function all(iterable) {
        var C = this;
        var capability = newPromiseCapability(C);
        var resolve = capability.resolve;
        var reject = capability.reject;
        var result = _perform(function() {
          var values = [];
          var index = 0;
          var remaining = 1;
          _forOf(iterable, false, function(promise) {
            var $index = index++;
            var alreadyCalled = false;
            values.push(undefined);
            remaining++;
            C.resolve(promise).then(function(value) {
              if (alreadyCalled) return;
              alreadyCalled = true;
              values[$index] = value;
              --remaining || resolve(values);
            }, reject);
          });
          --remaining || resolve(values);
        });
        if (result.e) reject(result.v);
        return capability.promise;
      },
      // 25.4.4.4 Promise.race(iterable)
      race: function race(iterable) {
        var C = this;
        var capability = newPromiseCapability(C);
        var reject = capability.reject;
        var result = _perform(function() {
          _forOf(iterable, false, function(promise) {
            C.resolve(promise).then(capability.resolve, reject);
          });
        });
        if (result.e) reject(result.v);
        return capability.promise;
      },
    }
  );

  _export(_export.P + _export.R, 'Promise', {
    finally: function(onFinally) {
      var C = _speciesConstructor(this, _core.Promise || _global.Promise);
      var isFunction = typeof onFinally == 'function';
      return this.then(
        isFunction
          ? function(x) {
              return _promiseResolve(C, onFinally()).then(function() {
                return x;
              });
            }
          : onFinally,
        isFunction
          ? function(e) {
              return _promiseResolve(C, onFinally()).then(function() {
                throw e;
              });
            }
          : onFinally
      );
    },
  });

  _export(_export.S, 'Promise', {
    try: function(callbackfn) {
      var promiseCapability = _newPromiseCapability.f(this);
      var result = _perform(callbackfn);
      (result.e ? promiseCapability.reject : promiseCapability.resolve)(
        result.v
      );
      return promiseCapability.promise;
    },
  });

  var promise = _core.Promise;

  var promise$1 = promise;

  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
    try {
      var info = gen[key](arg);
      var value = info.value;
    } catch (error) {
      reject(error);
      return;
    }

    if (info.done) {
      resolve(value);
    } else {
      promise$1.resolve(value).then(_next, _throw);
    }
  }

  function _asyncToGenerator(fn) {
    return function() {
      var self = this,
        args = arguments;
      return new promise$1(function(resolve, reject) {
        var gen = fn.apply(self, args);

        function _next(value) {
          asyncGeneratorStep(
            gen,
            resolve,
            reject,
            _next,
            _throw,
            'next',
            value
          );
        }

        function _throw(err) {
          asyncGeneratorStep(gen, resolve, reject, _next, _throw, 'throw', err);
        }

        _next(undefined);
      });
    };
  }

  var asyncToGenerator = _asyncToGenerator;

  var util = {
    isString: function(arg) {
      return typeof arg === 'string';
    },
    isObject: function(arg) {
      return typeof arg === 'object' && arg !== null;
    },
    isNull: function(arg) {
      return arg === null;
    },
    isNullOrUndefined: function(arg) {
      return arg == null;
    },
  };

  // Copyright Joyent, Inc. and other Node contributors.
  // obj.hasOwnProperty(prop) will break.
  // See: https://github.com/joyent/node/issues/1707

  function hasOwnProperty$1(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
  }

  var decode = function(qs, sep, eq, options) {
    sep = sep || '&';
    eq = eq || '=';
    var obj = {};

    if (typeof qs !== 'string' || qs.length === 0) {
      return obj;
    }

    var regexp = /\+/g;
    qs = qs.split(sep);
    var maxKeys = 1000;

    if (options && typeof options.maxKeys === 'number') {
      maxKeys = options.maxKeys;
    }

    var len = qs.length; // maxKeys <= 0 means that we should not limit keys count

    if (maxKeys > 0 && len > maxKeys) {
      len = maxKeys;
    }

    for (var i = 0; i < len; ++i) {
      var x = qs[i].replace(regexp, '%20'),
        idx = x.indexOf(eq),
        kstr,
        vstr,
        k,
        v;

      if (idx >= 0) {
        kstr = x.substr(0, idx);
        vstr = x.substr(idx + 1);
      } else {
        kstr = x;
        vstr = '';
      }

      k = decodeURIComponent(kstr);
      v = decodeURIComponent(vstr);

      if (!hasOwnProperty$1(obj, k)) {
        obj[k] = v;
      } else if (Array.isArray(obj[k])) {
        obj[k].push(v);
      } else {
        obj[k] = [obj[k], v];
      }
    }

    return obj;
  };

  // Copyright Joyent, Inc. and other Node contributors.

  var stringifyPrimitive = function(v) {
    switch (typeof v) {
      case 'string':
        return v;

      case 'boolean':
        return v ? 'true' : 'false';

      case 'number':
        return isFinite(v) ? v : '';

      default:
        return '';
    }
  };

  var encode = function(obj, sep, eq, name) {
    sep = sep || '&';
    eq = eq || '=';

    if (obj === null) {
      obj = undefined;
    }

    if (typeof obj === 'object') {
      return Object.keys(obj)
        .map(function(k) {
          var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;

          if (Array.isArray(obj[k])) {
            return obj[k]
              .map(function(v) {
                return ks + encodeURIComponent(stringifyPrimitive(v));
              })
              .join(sep);
          } else {
            return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
          }
        })
        .join(sep);
    }

    if (!name) return '';
    return (
      encodeURIComponent(stringifyPrimitive(name)) +
      eq +
      encodeURIComponent(stringifyPrimitive(obj))
    );
  };

  var querystring = createCommonjsModule(function(module, exports) {
    exports.decode = exports.parse = decode;
    exports.encode = exports.stringify = encode;
  });
  var querystring_1 = querystring.decode;
  var querystring_2 = querystring.parse;
  var querystring_3 = querystring.encode;
  var querystring_4 = querystring.stringify;

  var parse = urlParse;
  var resolve = urlResolve;
  var resolveObject = urlResolveObject;
  var format = urlFormat;
  var Url_1 = Url;

  function Url() {
    this.protocol = null;
    this.slashes = null;
    this.auth = null;
    this.host = null;
    this.port = null;
    this.hostname = null;
    this.hash = null;
    this.search = null;
    this.query = null;
    this.pathname = null;
    this.path = null;
    this.href = null;
  } // Reference: RFC 3986, RFC 1808, RFC 2396
  // define these here so at least they only have to be
  // compiled once on the first module load.

  var protocolPattern = /^([a-z0-9.+-]+:)/i,
    portPattern = /:[0-9]*$/,
    // Special case for a simple path URL
    simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
    // RFC 2396: characters reserved for delimiting URLs.
    // We actually just auto-escape these.
    delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
    // RFC 2396: characters not allowed for various reasons.
    unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
    // Allowed by RFCs, but cause of XSS attacks.  Always escape these.
    autoEscape = ["'"].concat(unwise),
    // Characters that are never ever allowed in a hostname.
    // Note that any invalid chars are also handled, but these
    // are the ones that are *expected* to be seen, so we fast-path
    // them.
    nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
    hostEndingChars = ['/', '?', '#'],
    hostnameMaxLen = 255,
    hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,
    hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,
    // protocols that can allow "unsafe" and "unwise" chars.
    unsafeProtocol = {
      javascript: true,
      'javascript:': true,
    },
    // protocols that never have a hostname.
    hostlessProtocol = {
      javascript: true,
      'javascript:': true,
    },
    // protocols that always contain a // bit.
    slashedProtocol = {
      http: true,
      https: true,
      ftp: true,
      gopher: true,
      file: true,
      'http:': true,
      'https:': true,
      'ftp:': true,
      'gopher:': true,
      'file:': true,
    };

  function urlParse(url, parseQueryString, slashesDenoteHost) {
    if (url && util.isObject(url) && url instanceof Url) return url;
    var u = new Url();
    u.parse(url, parseQueryString, slashesDenoteHost);
    return u;
  }

  Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
    if (!util.isString(url)) {
      throw new TypeError(
        "Parameter 'url' must be a string, not " + typeof url
      );
    } // Copy chrome, IE, opera backslash-handling behavior.
    // Back slashes before the query string get converted to forward slashes
    // See: https://code.google.com/p/chromium/issues/detail?id=25916

    var queryIndex = url.indexOf('?'),
      splitter = queryIndex !== -1 && queryIndex < url.indexOf('#') ? '?' : '#',
      uSplit = url.split(splitter),
      slashRegex = /\\/g;
    uSplit[0] = uSplit[0].replace(slashRegex, '/');
    url = uSplit.join(splitter);
    var rest = url; // trim before proceeding.
    // This is to support parse stuff like "  http://foo.com  \n"

    rest = rest.trim();

    if (!slashesDenoteHost && url.split('#').length === 1) {
      // Try fast path regexp
      var simplePath = simplePathPattern.exec(rest);

      if (simplePath) {
        this.path = rest;
        this.href = rest;
        this.pathname = simplePath[1];

        if (simplePath[2]) {
          this.search = simplePath[2];

          if (parseQueryString) {
            this.query = querystring.parse(this.search.substr(1));
          } else {
            this.query = this.search.substr(1);
          }
        } else if (parseQueryString) {
          this.search = '';
          this.query = {};
        }

        return this;
      }
    }

    var proto = protocolPattern.exec(rest);

    if (proto) {
      proto = proto[0];
      var lowerProto = proto.toLowerCase();
      this.protocol = lowerProto;
      rest = rest.substr(proto.length);
    } // figure out if it's got a host
    // user@server is *always* interpreted as a hostname, and url
    // resolution will treat //foo/bar as host=foo,path=bar because that's
    // how the browser resolves relative URLs.

    if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
      var slashes = rest.substr(0, 2) === '//';

      if (slashes && !(proto && hostlessProtocol[proto])) {
        rest = rest.substr(2);
        this.slashes = true;
      }
    }

    if (
      !hostlessProtocol[proto] &&
      (slashes || (proto && !slashedProtocol[proto]))
    ) {
      // there's a hostname.
      // the first instance of /, ?, ;, or # ends the host.
      //
      // If there is an @ in the hostname, then non-host chars *are* allowed
      // to the left of the last @ sign, unless some host-ending character
      // comes *before* the @-sign.
      // URLs are obnoxious.
      //
      // ex:
      // http://a@b@c/ => user:a@b host:c
      // http://a@b?@c => user:a host:c path:/?@c
      // v0.12 TODO(isaacs): This is not quite how Chrome does things.
      // Review our test case against browsers more comprehensively.
      // find the first instance of any hostEndingChars
      var hostEnd = -1;

      for (var i = 0; i < hostEndingChars.length; i++) {
        var hec = rest.indexOf(hostEndingChars[i]);
        if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) hostEnd = hec;
      } // at this point, either we have an explicit point where the
      // auth portion cannot go past, or the last @ char is the decider.

      var auth, atSign;

      if (hostEnd === -1) {
        // atSign can be anywhere.
        atSign = rest.lastIndexOf('@');
      } else {
        // atSign must be in auth portion.
        // http://a@b/c@d => host:b auth:a path:/c@d
        atSign = rest.lastIndexOf('@', hostEnd);
      } // Now we have a portion which is definitely the auth.
      // Pull that off.

      if (atSign !== -1) {
        auth = rest.slice(0, atSign);
        rest = rest.slice(atSign + 1);
        this.auth = decodeURIComponent(auth);
      } // the host is the remaining to the left of the first non-host char

      hostEnd = -1;

      for (var i = 0; i < nonHostChars.length; i++) {
        var hec = rest.indexOf(nonHostChars[i]);
        if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) hostEnd = hec;
      } // if we still have not hit it, then the entire thing is a host.

      if (hostEnd === -1) hostEnd = rest.length;
      this.host = rest.slice(0, hostEnd);
      rest = rest.slice(hostEnd); // pull out port.

      this.parseHost(); // we've indicated that there is a hostname,
      // so even if it's empty, it has to be present.

      this.hostname = this.hostname || ''; // if hostname begins with [ and ends with ]
      // assume that it's an IPv6 address.

      var ipv6Hostname =
        this.hostname[0] === '[' &&
        this.hostname[this.hostname.length - 1] === ']'; // validate a little.

      if (!ipv6Hostname) {
        var hostparts = this.hostname.split(/\./);

        for (var i = 0, l = hostparts.length; i < l; i++) {
          var part = hostparts[i];
          if (!part) continue;

          if (!part.match(hostnamePartPattern)) {
            var newpart = '';

            for (var j = 0, k = part.length; j < k; j++) {
              if (part.charCodeAt(j) > 127) {
                // we replace non-ASCII char with a temporary placeholder
                // we need this to make sure size of hostname is not
                // broken by replacing non-ASCII by nothing
                newpart += 'x';
              } else {
                newpart += part[j];
              }
            } // we test again with ASCII char only

            if (!newpart.match(hostnamePartPattern)) {
              var validParts = hostparts.slice(0, i);
              var notHost = hostparts.slice(i + 1);
              var bit = part.match(hostnamePartStart);

              if (bit) {
                validParts.push(bit[1]);
                notHost.unshift(bit[2]);
              }

              if (notHost.length) {
                rest = '/' + notHost.join('.') + rest;
              }

              this.hostname = validParts.join('.');
              break;
            }
          }
        }
      }

      if (this.hostname.length > hostnameMaxLen) {
        this.hostname = '';
      } else {
        // hostnames are always lower case.
        this.hostname = this.hostname.toLowerCase();
      }

      var p = this.port ? ':' + this.port : '';
      var h = this.hostname || '';
      this.host = h + p;
      this.href += this.host; // strip [ and ] from the hostname
      // the host field still retains them, though

      if (ipv6Hostname) {
        this.hostname = this.hostname.substr(1, this.hostname.length - 2);

        if (rest[0] !== '/') {
          rest = '/' + rest;
        }
      }
    } // now rest is set to the post-host stuff.
    // chop off any delim chars.

    if (!unsafeProtocol[lowerProto]) {
      // First, make 100% sure that any "autoEscape" chars get
      // escaped, even if encodeURIComponent doesn't think they
      // need to be.
      for (var i = 0, l = autoEscape.length; i < l; i++) {
        var ae = autoEscape[i];
        if (rest.indexOf(ae) === -1) continue;
        var esc = encodeURIComponent(ae);

        if (esc === ae) {
          esc = escape(ae);
        }

        rest = rest.split(ae).join(esc);
      }
    } // chop off from the tail first.

    var hash = rest.indexOf('#');

    if (hash !== -1) {
      // got a fragment string.
      this.hash = rest.substr(hash);
      rest = rest.slice(0, hash);
    }

    var qm = rest.indexOf('?');

    if (qm !== -1) {
      this.search = rest.substr(qm);
      this.query = rest.substr(qm + 1);

      if (parseQueryString) {
        this.query = querystring.parse(this.query);
      }

      rest = rest.slice(0, qm);
    } else if (parseQueryString) {
      // no query string, but parseQueryString still requested
      this.search = '';
      this.query = {};
    }

    if (rest) this.pathname = rest;

    if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) {
      this.pathname = '/';
    } //to support http.request

    if (this.pathname || this.search) {
      var p = this.pathname || '';
      var s = this.search || '';
      this.path = p + s;
    } // finally, reconstruct the href based on what has been validated.

    this.href = this.format();
    return this;
  }; // format a parsed object into a url string

  function urlFormat(obj) {
    // ensure it's an object, and not a string url.
    // If it's an obj, this is a no-op.
    // this way, you can call url_format() on strings
    // to clean up potentially wonky urls.
    if (util.isString(obj)) obj = urlParse(obj);
    if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
    return obj.format();
  }

  Url.prototype.format = function() {
    var auth = this.auth || '';

    if (auth) {
      auth = encodeURIComponent(auth);
      auth = auth.replace(/%3A/i, ':');
      auth += '@';
    }

    var protocol = this.protocol || '',
      pathname = this.pathname || '',
      hash = this.hash || '',
      host = false,
      query = '';

    if (this.host) {
      host = auth + this.host;
    } else if (this.hostname) {
      host =
        auth +
        (this.hostname.indexOf(':') === -1
          ? this.hostname
          : '[' + this.hostname + ']');

      if (this.port) {
        host += ':' + this.port;
      }
    }

    if (
      this.query &&
      util.isObject(this.query) &&
      Object.keys(this.query).length
    ) {
      query = querystring.stringify(this.query);
    }

    var search = this.search || (query && '?' + query) || '';
    if (protocol && protocol.substr(-1) !== ':') protocol += ':'; // only the slashedProtocols get the //.  Not mailto:, xmpp:, etc.
    // unless they had them to begin with.

    if (
      this.slashes ||
      ((!protocol || slashedProtocol[protocol]) && host !== false)
    ) {
      host = '//' + (host || '');
      if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
    } else if (!host) {
      host = '';
    }

    if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
    if (search && search.charAt(0) !== '?') search = '?' + search;
    pathname = pathname.replace(/[?#]/g, function(match) {
      return encodeURIComponent(match);
    });
    search = search.replace('#', '%23');
    return protocol + host + pathname + search + hash;
  };

  function urlResolve(source, relative) {
    return urlParse(source, false, true).resolve(relative);
  }

  Url.prototype.resolve = function(relative) {
    return this.resolveObject(urlParse(relative, false, true)).format();
  };

  function urlResolveObject(source, relative) {
    if (!source) return relative;
    return urlParse(source, false, true).resolveObject(relative);
  }

  Url.prototype.resolveObject = function(relative) {
    if (util.isString(relative)) {
      var rel = new Url();
      rel.parse(relative, false, true);
      relative = rel;
    }

    var result = new Url();
    var tkeys = Object.keys(this);

    for (var tk = 0; tk < tkeys.length; tk++) {
      var tkey = tkeys[tk];
      result[tkey] = this[tkey];
    } // hash is always overridden, no matter what.
    // even href="" will remove it.

    result.hash = relative.hash; // if the relative url is empty, then there's nothing left to do here.

    if (relative.href === '') {
      result.href = result.format();
      return result;
    } // hrefs like //foo/bar always cut to the protocol.

    if (relative.slashes && !relative.protocol) {
      // take everything except the protocol from relative
      var rkeys = Object.keys(relative);

      for (var rk = 0; rk < rkeys.length; rk++) {
        var rkey = rkeys[rk];
        if (rkey !== 'protocol') result[rkey] = relative[rkey];
      } //urlParse appends trailing / to urls like http://www.example.com

      if (
        slashedProtocol[result.protocol] &&
        result.hostname &&
        !result.pathname
      ) {
        result.path = result.pathname = '/';
      }

      result.href = result.format();
      return result;
    }

    if (relative.protocol && relative.protocol !== result.protocol) {
      // if it's a known url protocol, then changing
      // the protocol does weird things
      // first, if it's not file:, then we MUST have a host,
      // and if there was a path
      // to begin with, then we MUST have a path.
      // if it is file:, then the host is dropped,
      // because that's known to be hostless.
      // anything else is assumed to be absolute.
      if (!slashedProtocol[relative.protocol]) {
        var keys = Object.keys(relative);

        for (var v = 0; v < keys.length; v++) {
          var k = keys[v];
          result[k] = relative[k];
        }

        result.href = result.format();
        return result;
      }

      result.protocol = relative.protocol;

      if (!relative.host && !hostlessProtocol[relative.protocol]) {
        var relPath = (relative.pathname || '').split('/');

        while (relPath.length && !(relative.host = relPath.shift()));

        if (!relative.host) relative.host = '';
        if (!relative.hostname) relative.hostname = '';
        if (relPath[0] !== '') relPath.unshift('');
        if (relPath.length < 2) relPath.unshift('');
        result.pathname = relPath.join('/');
      } else {
        result.pathname = relative.pathname;
      }

      result.search = relative.search;
      result.query = relative.query;
      result.host = relative.host || '';
      result.auth = relative.auth;
      result.hostname = relative.hostname || relative.host;
      result.port = relative.port; // to support http.request

      if (result.pathname || result.search) {
        var p = result.pathname || '';
        var s = result.search || '';
        result.path = p + s;
      }

      result.slashes = result.slashes || relative.slashes;
      result.href = result.format();
      return result;
    }

    var isSourceAbs = result.pathname && result.pathname.charAt(0) === '/',
      isRelAbs =
        relative.host ||
        (relative.pathname && relative.pathname.charAt(0) === '/'),
      mustEndAbs =
        isRelAbs || isSourceAbs || (result.host && relative.pathname),
      removeAllDots = mustEndAbs,
      srcPath = (result.pathname && result.pathname.split('/')) || [],
      relPath = (relative.pathname && relative.pathname.split('/')) || [],
      psychotic = result.protocol && !slashedProtocol[result.protocol]; // if the url is a non-slashed url, then relative
    // links like ../.. should be able
    // to crawl up to the hostname, as well.  This is strange.
    // result.protocol has already been set by now.
    // Later on, put the first path part into the host field.

    if (psychotic) {
      result.hostname = '';
      result.port = null;

      if (result.host) {
        if (srcPath[0] === '') srcPath[0] = result.host;
        else srcPath.unshift(result.host);
      }

      result.host = '';

      if (relative.protocol) {
        relative.hostname = null;
        relative.port = null;

        if (relative.host) {
          if (relPath[0] === '') relPath[0] = relative.host;
          else relPath.unshift(relative.host);
        }

        relative.host = null;
      }

      mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
    }

    if (isRelAbs) {
      // it's absolute.
      result.host =
        relative.host || relative.host === '' ? relative.host : result.host;
      result.hostname =
        relative.hostname || relative.hostname === ''
          ? relative.hostname
          : result.hostname;
      result.search = relative.search;
      result.query = relative.query;
      srcPath = relPath; // fall through to the dot-handling below.
    } else if (relPath.length) {
      // it's relative
      // throw away the existing file, and take the new path instead.
      if (!srcPath) srcPath = [];
      srcPath.pop();
      srcPath = srcPath.concat(relPath);
      result.search = relative.search;
      result.query = relative.query;
    } else if (!util.isNullOrUndefined(relative.search)) {
      // just pull out the search.
      // like href='?foo'.
      // Put this after the other two cases because it simplifies the booleans
      if (psychotic) {
        result.hostname = result.host = srcPath.shift(); //occationaly the auth can get stuck only in host
        //this especially happens in cases like
        //url.resolveObject('mailto:local1@domain1', 'local2@domain2')

        var authInHost =
          result.host && result.host.indexOf('@') > 0
            ? result.host.split('@')
            : false;

        if (authInHost) {
          result.auth = authInHost.shift();
          result.host = result.hostname = authInHost.shift();
        }
      }

      result.search = relative.search;
      result.query = relative.query; //to support http.request

      if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
        result.path =
          (result.pathname ? result.pathname : '') +
          (result.search ? result.search : '');
      }

      result.href = result.format();
      return result;
    }

    if (!srcPath.length) {
      // no path at all.  easy.
      // we've already handled the other stuff above.
      result.pathname = null; //to support http.request

      if (result.search) {
        result.path = '/' + result.search;
      } else {
        result.path = null;
      }

      result.href = result.format();
      return result;
    } // if a url ENDs in . or .., then it must get a trailing slash.
    // however, if it ends in anything else non-slashy,
    // then it must NOT get a trailing slash.

    var last = srcPath.slice(-1)[0];
    var hasTrailingSlash =
      ((result.host || relative.host || srcPath.length > 1) &&
        (last === '.' || last === '..')) ||
      last === ''; // strip single dots, resolve double dots to parent dir
    // if the path tries to go above the root, `up` ends up > 0

    var up = 0;

    for (var i = srcPath.length; i >= 0; i--) {
      last = srcPath[i];

      if (last === '.') {
        srcPath.splice(i, 1);
      } else if (last === '..') {
        srcPath.splice(i, 1);
        up++;
      } else if (up) {
        srcPath.splice(i, 1);
        up--;
      }
    } // if the path is allowed to go above the root, restore leading ..s

    if (!mustEndAbs && !removeAllDots) {
      for (; up--; up) {
        srcPath.unshift('..');
      }
    }

    if (
      mustEndAbs &&
      srcPath[0] !== '' &&
      (!srcPath[0] || srcPath[0].charAt(0) !== '/')
    ) {
      srcPath.unshift('');
    }

    if (hasTrailingSlash && srcPath.join('/').substr(-1) !== '/') {
      srcPath.push('');
    }

    var isAbsolute =
      srcPath[0] === '' || (srcPath[0] && srcPath[0].charAt(0) === '/'); // put the host back

    if (psychotic) {
      result.hostname = result.host = isAbsolute
        ? ''
        : srcPath.length
        ? srcPath.shift()
        : ''; //occationaly the auth can get stuck only in host
      //this especially happens in cases like
      //url.resolveObject('mailto:local1@domain1', 'local2@domain2')

      var authInHost =
        result.host && result.host.indexOf('@') > 0
          ? result.host.split('@')
          : false;

      if (authInHost) {
        result.auth = authInHost.shift();
        result.host = result.hostname = authInHost.shift();
      }
    }

    mustEndAbs = mustEndAbs || (result.host && srcPath.length);

    if (mustEndAbs && !isAbsolute) {
      srcPath.unshift('');
    }

    if (!srcPath.length) {
      result.pathname = null;
      result.path = null;
    } else {
      result.pathname = srcPath.join('/');
    } //to support request.http

    if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
      result.path =
        (result.pathname ? result.pathname : '') +
        (result.search ? result.search : '');
    }

    result.auth = relative.auth || result.auth;
    result.slashes = result.slashes || relative.slashes;
    result.href = result.format();
    return result;
  };

  Url.prototype.parseHost = function() {
    var host = this.host;
    var port = portPattern.exec(host);

    if (port) {
      port = port[0];

      if (port !== ':') {
        this.port = port.substr(1);
      }

      host = host.substr(0, host.length - port.length);
    }

    if (host) this.hostname = host;
  };

  var url = {
    parse: parse,
    resolve: resolve,
    resolveObject: resolveObject,
    format: format,
    Url: Url_1,
  };

  var jquery_min = createCommonjsModule(function(module) {
    /*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */
    !(function(e, t) {
      module.exports = e.document
        ? t(e, !0)
        : function(e) {
            if (!e.document)
              throw new Error('jQuery requires a window with a document');
            return t(e);
          };
    })('undefined' != typeof window ? window : this, function(e, t) {
      var n = [],
        r = e.document,
        i = Object.getPrototypeOf,
        o = n.slice,
        a = n.concat,
        s = n.push,
        u = n.indexOf,
        l = {},
        c = l.toString,
        f = l.hasOwnProperty,
        p = f.toString,
        d = p.call(Object),
        h = {},
        g = function e(t) {
          return 'function' == typeof t && 'number' != typeof t.nodeType;
        },
        y = function e(t) {
          return null != t && t === t.window;
        },
        v = {
          type: !0,
          src: !0,
          noModule: !0,
        };

      function m(e, t, n) {
        var i,
          o = (t = t || r).createElement('script');
        if (((o.text = e), n)) for (i in v) n[i] && (o[i] = n[i]);
        t.head.appendChild(o).parentNode.removeChild(o);
      }

      function x(e) {
        return null == e
          ? e + ''
          : 'object' == typeof e || 'function' == typeof e
          ? l[c.call(e)] || 'object'
          : typeof e;
      }

      var w = function(e, t) {
          return new w.fn.init(e, t);
        },
        T = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;

      (w.fn = w.prototype = {
        jquery: '3.3.1',
        constructor: w,
        length: 0,
        toArray: function() {
          return o.call(this);
        },
        get: function(e) {
          return null == e
            ? o.call(this)
            : e < 0
            ? this[e + this.length]
            : this[e];
        },
        pushStack: function(e) {
          var t = w.merge(this.constructor(), e);
          return (t.prevObject = this), t;
        },
        each: function(e) {
          return w.each(this, e);
        },
        map: function(e) {
          return this.pushStack(
            w.map(this, function(t, n) {
              return e.call(t, n, t);
            })
          );
        },
        slice: function() {
          return this.pushStack(o.apply(this, arguments));
        },
        first: function() {
          return this.eq(0);
        },
        last: function() {
          return this.eq(-1);
        },
        eq: function(e) {
          var t = this.length,
            n = +e + (e < 0 ? t : 0);
          return this.pushStack(n >= 0 && n < t ? [this[n]] : []);
        },
        end: function() {
          return this.prevObject || this.constructor();
        },
        push: s,
        sort: n.sort,
        splice: n.splice,
      }),
        (w.extend = w.fn.extend = function() {
          var e,
            t,
            n,
            r,
            i,
            o,
            a = arguments[0] || {},
            s = 1,
            u = arguments.length,
            l = !1;

          for (
            'boolean' == typeof a && ((l = a), (a = arguments[s] || {}), s++),
              'object' == typeof a || g(a) || (a = {}),
              s === u && ((a = this), s--);
            s < u;
            s++
          )
            if (null != (e = arguments[s]))
              for (t in e)
                (n = a[t]),
                  a !== (r = e[t]) &&
                    (l && r && (w.isPlainObject(r) || (i = Array.isArray(r)))
                      ? (i
                          ? ((i = !1), (o = n && Array.isArray(n) ? n : []))
                          : (o = n && w.isPlainObject(n) ? n : {}),
                        (a[t] = w.extend(l, o, r)))
                      : void 0 !== r && (a[t] = r));

          return a;
        }),
        w.extend({
          expando: 'jQuery' + ('3.3.1' + Math.random()).replace(/\D/g, ''),
          isReady: !0,
          error: function(e) {
            throw new Error(e);
          },
          noop: function() {},
          isPlainObject: function(e) {
            var t, n;
            return (
              !(!e || '[object Object]' !== c.call(e)) &&
              (!(t = i(e)) ||
                ('function' ==
                  typeof (n = f.call(t, 'constructor') && t.constructor) &&
                  p.call(n) === d))
            );
          },
          isEmptyObject: function(e) {
            var t;

            for (t in e) return !1;

            return !0;
          },
          globalEval: function(e) {
            m(e);
          },
          each: function(e, t) {
            var n,
              r = 0;

            if (C(e)) {
              for (n = e.length; r < n; r++)
                if (!1 === t.call(e[r], r, e[r])) break;
            } else for (r in e) if (!1 === t.call(e[r], r, e[r])) break;

            return e;
          },
          trim: function(e) {
            return null == e ? '' : (e + '').replace(T, '');
          },
          makeArray: function(e, t) {
            var n = t || [];
            return (
              null != e &&
                (C(Object(e))
                  ? w.merge(n, 'string' == typeof e ? [e] : e)
                  : s.call(n, e)),
              n
            );
          },
          inArray: function(e, t, n) {
            return null == t ? -1 : u.call(t, e, n);
          },
          merge: function(e, t) {
            for (var n = +t.length, r = 0, i = e.length; r < n; r++)
              e[i++] = t[r];

            return (e.length = i), e;
          },
          grep: function(e, t, n) {
            for (var r, i = [], o = 0, a = e.length, s = !n; o < a; o++)
              (r = !t(e[o], o)) !== s && i.push(e[o]);

            return i;
          },
          map: function(e, t, n) {
            var r,
              i,
              o = 0,
              s = [];
            if (C(e))
              for (r = e.length; o < r; o++)
                null != (i = t(e[o], o, n)) && s.push(i);
            else for (o in e) null != (i = t(e[o], o, n)) && s.push(i);
            return a.apply([], s);
          },
          guid: 1,
          support: h,
        }),
        'function' == typeof Symbol &&
          (w.fn[Symbol.iterator] = n[Symbol.iterator]),
        w.each(
          'Boolean Number String Function Array Date RegExp Object Error Symbol'.split(
            ' '
          ),
          function(e, t) {
            l['[object ' + t + ']'] = t.toLowerCase();
          }
        );

      function C(e) {
        var t = !!e && 'length' in e && e.length,
          n = x(e);
        return (
          !g(e) &&
          !y(e) &&
          ('array' === n ||
            0 === t ||
            ('number' == typeof t && t > 0 && t - 1 in e))
        );
      }

      var E = (function(e) {
        var t,
          n,
          r,
          i,
          o,
          a,
          s,
          u,
          l,
          c,
          f,
          p,
          d,
          h,
          g,
          y,
          v,
          m,
          x,
          b = 'sizzle' + 1 * new Date(),
          w = e.document,
          T = 0,
          C = 0,
          E = ae(),
          k = ae(),
          S = ae(),
          D = function(e, t) {
            return e === t && (f = !0), 0;
          },
          N = {}.hasOwnProperty,
          A = [],
          j = A.pop,
          q = A.push,
          L = A.push,
          H = A.slice,
          O = function(e, t) {
            for (var n = 0, r = e.length; n < r; n++) if (e[n] === t) return n;

            return -1;
          },
          P =
            'checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped',
          M = '[\\x20\\t\\r\\n\\f]',
          R = '(?:\\\\.|[\\w-]|[^\0-\\xa0])+',
          I =
            '\\[' +
            M +
            '*(' +
            R +
            ')(?:' +
            M +
            '*([*^$|!~]?=)' +
            M +
            '*(?:\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)"|(' +
            R +
            '))|)' +
            M +
            '*\\]',
          W =
            ':(' +
            R +
            ')(?:\\(((\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)")|((?:\\\\.|[^\\\\()[\\]]|' +
            I +
            ')*)|.*)\\)|)',
          $ = new RegExp(M + '+', 'g'),
          B = new RegExp(
            '^' + M + '+|((?:^|[^\\\\])(?:\\\\.)*)' + M + '+$',
            'g'
          ),
          F = new RegExp('^' + M + '*,' + M + '*'),
          _ = new RegExp('^' + M + '*([>+~]|' + M + ')' + M + '*'),
          z = new RegExp('=' + M + '*([^\\]\'"]*?)' + M + '*\\]', 'g'),
          X = new RegExp(W),
          U = new RegExp('^' + R + '$'),
          V = {
            ID: new RegExp('^#(' + R + ')'),
            CLASS: new RegExp('^\\.(' + R + ')'),
            TAG: new RegExp('^(' + R + '|[*])'),
            ATTR: new RegExp('^' + I),
            PSEUDO: new RegExp('^' + W),
            CHILD: new RegExp(
              '^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(' +
                M +
                '*(even|odd|(([+-]|)(\\d*)n|)' +
                M +
                '*(?:([+-]|)' +
                M +
                '*(\\d+)|))' +
                M +
                '*\\)|)',
              'i'
            ),
            bool: new RegExp('^(?:' + P + ')$', 'i'),
            needsContext: new RegExp(
              '^' +
                M +
                '*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(' +
                M +
                '*((?:-\\d)?\\d*)' +
                M +
                '*\\)|)(?=[^-]|$)',
              'i'
            ),
          },
          G = /^(?:input|select|textarea|button)$/i,
          Y = /^h\d$/i,
          Q = /^[^{]+\{\s*\[native \w/,
          J = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
          K = /[+~]/,
          Z = new RegExp('\\\\([\\da-f]{1,6}' + M + '?|(' + M + ')|.)', 'ig'),
          ee = function(e, t, n) {
            var r = '0x' + t - 65536;
            return r !== r || n
              ? t
              : r < 0
              ? String.fromCharCode(r + 65536)
              : String.fromCharCode((r >> 10) | 55296, (1023 & r) | 56320);
          },
          te = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
          ne = function(e, t) {
            return t
              ? '\0' === e
                ? '\ufffd'
                : e.slice(0, -1) +
                  '\\' +
                  e.charCodeAt(e.length - 1).toString(16) +
                  ' '
              : '\\' + e;
          },
          re = function() {
            p();
          },
          ie = me(
            function(e) {
              return !0 === e.disabled && ('form' in e || 'label' in e);
            },
            {
              dir: 'parentNode',
              next: 'legend',
            }
          );

        try {
          L.apply((A = H.call(w.childNodes)), w.childNodes),
            A[w.childNodes.length].nodeType;
        } catch (e) {
          L = {
            apply: A.length
              ? function(e, t) {
                  q.apply(e, H.call(t));
                }
              : function(e, t) {
                  var n = e.length,
                    r = 0;

                  while ((e[n++] = t[r++]));

                  e.length = n - 1;
                },
          };
        }

        function oe(e, t, r, i) {
          var o,
            s,
            l,
            c,
            f,
            h,
            v,
            m = t && t.ownerDocument,
            T = t ? t.nodeType : 9;
          if (
            ((r = r || []),
            'string' != typeof e || !e || (1 !== T && 9 !== T && 11 !== T))
          )
            return r;

          if (
            !i &&
            ((t ? t.ownerDocument || t : w) !== d && p(t), (t = t || d), g)
          ) {
            if (11 !== T && (f = J.exec(e)))
              if ((o = f[1])) {
                if (9 === T) {
                  if (!(l = t.getElementById(o))) return r;
                  if (l.id === o) return r.push(l), r;
                } else if (
                  m &&
                  (l = m.getElementById(o)) &&
                  x(t, l) &&
                  l.id === o
                )
                  return r.push(l), r;
              } else {
                if (f[2]) return L.apply(r, t.getElementsByTagName(e)), r;
                if (
                  (o = f[3]) &&
                  n.getElementsByClassName &&
                  t.getElementsByClassName
                )
                  return L.apply(r, t.getElementsByClassName(o)), r;
              }

            if (n.qsa && !S[e + ' '] && (!y || !y.test(e))) {
              if (1 !== T) (m = t), (v = e);
              else if ('object' !== t.nodeName.toLowerCase()) {
                (c = t.getAttribute('id'))
                  ? (c = c.replace(te, ne))
                  : t.setAttribute('id', (c = b)),
                  (s = (h = a(e)).length);

                while (s--) h[s] = '#' + c + ' ' + ve(h[s]);

                (v = h.join(',')), (m = (K.test(e) && ge(t.parentNode)) || t);
              }
              if (v)
                try {
                  return L.apply(r, m.querySelectorAll(v)), r;
                } catch (e) {
                } finally {
                  c === b && t.removeAttribute('id');
                }
            }
          }

          return u(e.replace(B, '$1'), t, r, i);
        }

        function ae() {
          var e = [];

          function t(n, i) {
            return (
              e.push(n + ' ') > r.cacheLength && delete t[e.shift()],
              (t[n + ' '] = i)
            );
          }

          return t;
        }

        function se(e) {
          return (e[b] = !0), e;
        }

        function ue(e) {
          var t = d.createElement('fieldset');

          try {
            return !!e(t);
          } catch (e) {
            return !1;
          } finally {
            t.parentNode && t.parentNode.removeChild(t), (t = null);
          }
        }

        function le(e, t) {
          var n = e.split('|'),
            i = n.length;

          while (i--) r.attrHandle[n[i]] = t;
        }

        function ce(e, t) {
          var n = t && e,
            r =
              n &&
              1 === e.nodeType &&
              1 === t.nodeType &&
              e.sourceIndex - t.sourceIndex;
          if (r) return r;
          if (n) while ((n = n.nextSibling)) if (n === t) return -1;
          return e ? 1 : -1;
        }

        function fe(e) {
          return function(t) {
            return 'input' === t.nodeName.toLowerCase() && t.type === e;
          };
        }

        function pe(e) {
          return function(t) {
            var n = t.nodeName.toLowerCase();
            return ('input' === n || 'button' === n) && t.type === e;
          };
        }

        function de(e) {
          return function(t) {
            return 'form' in t
              ? t.parentNode && !1 === t.disabled
                ? 'label' in t
                  ? 'label' in t.parentNode
                    ? t.parentNode.disabled === e
                    : t.disabled === e
                  : t.isDisabled === e || (t.isDisabled !== !e && ie(t) === e)
                : t.disabled === e
              : 'label' in t && t.disabled === e;
          };
        }

        function he(e) {
          return se(function(t) {
            return (
              (t = +t),
              se(function(n, r) {
                var i,
                  o = e([], n.length, t),
                  a = o.length;

                while (a--) n[(i = o[a])] && (n[i] = !(r[i] = n[i]));
              })
            );
          });
        }

        function ge(e) {
          return e && 'undefined' != typeof e.getElementsByTagName && e;
        }

        (n = oe.support = {}),
          (o = oe.isXML = function(e) {
            var t = e && (e.ownerDocument || e).documentElement;
            return !!t && 'HTML' !== t.nodeName;
          }),
          (p = oe.setDocument = function(e) {
            var t,
              i,
              a = e ? e.ownerDocument || e : w;
            return a !== d && 9 === a.nodeType && a.documentElement
              ? ((d = a),
                (h = d.documentElement),
                (g = !o(d)),
                w !== d &&
                  (i = d.defaultView) &&
                  i.top !== i &&
                  (i.addEventListener
                    ? i.addEventListener('unload', re, !1)
                    : i.attachEvent && i.attachEvent('onunload', re)),
                (n.attributes = ue(function(e) {
                  return (e.className = 'i'), !e.getAttribute('className');
                })),
                (n.getElementsByTagName = ue(function(e) {
                  return (
                    e.appendChild(d.createComment('')),
                    !e.getElementsByTagName('*').length
                  );
                })),
                (n.getElementsByClassName = Q.test(d.getElementsByClassName)),
                (n.getById = ue(function(e) {
                  return (
                    (h.appendChild(e).id = b),
                    !d.getElementsByName || !d.getElementsByName(b).length
                  );
                })),
                n.getById
                  ? ((r.filter.ID = function(e) {
                      var t = e.replace(Z, ee);
                      return function(e) {
                        return e.getAttribute('id') === t;
                      };
                    }),
                    (r.find.ID = function(e, t) {
                      if ('undefined' != typeof t.getElementById && g) {
                        var n = t.getElementById(e);
                        return n ? [n] : [];
                      }
                    }))
                  : ((r.filter.ID = function(e) {
                      var t = e.replace(Z, ee);
                      return function(e) {
                        var n =
                          'undefined' != typeof e.getAttributeNode &&
                          e.getAttributeNode('id');
                        return n && n.value === t;
                      };
                    }),
                    (r.find.ID = function(e, t) {
                      if ('undefined' != typeof t.getElementById && g) {
                        var n,
                          r,
                          i,
                          o = t.getElementById(e);

                        if (o) {
                          if ((n = o.getAttributeNode('id')) && n.value === e)
                            return [o];
                          (i = t.getElementsByName(e)), (r = 0);

                          while ((o = i[r++]))
                            if ((n = o.getAttributeNode('id')) && n.value === e)
                              return [o];
                        }

                        return [];
                      }
                    })),
                (r.find.TAG = n.getElementsByTagName
                  ? function(e, t) {
                      return 'undefined' != typeof t.getElementsByTagName
                        ? t.getElementsByTagName(e)
                        : n.qsa
                        ? t.querySelectorAll(e)
                        : void 0;
                    }
                  : function(e, t) {
                      var n,
                        r = [],
                        i = 0,
                        o = t.getElementsByTagName(e);

                      if ('*' === e) {
                        while ((n = o[i++])) 1 === n.nodeType && r.push(n);

                        return r;
                      }

                      return o;
                    }),
                (r.find.CLASS =
                  n.getElementsByClassName &&
                  function(e, t) {
                    if ('undefined' != typeof t.getElementsByClassName && g)
                      return t.getElementsByClassName(e);
                  }),
                (v = []),
                (y = []),
                (n.qsa = Q.test(d.querySelectorAll)) &&
                  (ue(function(e) {
                    (h.appendChild(e).innerHTML =
                      "<a id='" +
                      b +
                      "'></a><select id='" +
                      b +
                      "-\r\\' msallowcapture=''><option selected=''></option></select>"),
                      e.querySelectorAll("[msallowcapture^='']").length &&
                        y.push('[*^$]=' + M + '*(?:\'\'|"")'),
                      e.querySelectorAll('[selected]').length ||
                        y.push('\\[' + M + '*(?:value|' + P + ')'),
                      e.querySelectorAll('[id~=' + b + '-]').length ||
                        y.push('~='),
                      e.querySelectorAll(':checked').length ||
                        y.push(':checked'),
                      e.querySelectorAll('a#' + b + '+*').length ||
                        y.push('.#.+[+~]');
                  }),
                  ue(function(e) {
                    e.innerHTML =
                      "<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";
                    var t = d.createElement('input');
                    t.setAttribute('type', 'hidden'),
                      e.appendChild(t).setAttribute('name', 'D'),
                      e.querySelectorAll('[name=d]').length &&
                        y.push('name' + M + '*[*^$|!~]?='),
                      2 !== e.querySelectorAll(':enabled').length &&
                        y.push(':enabled', ':disabled'),
                      (h.appendChild(e).disabled = !0),
                      2 !== e.querySelectorAll(':disabled').length &&
                        y.push(':enabled', ':disabled'),
                      e.querySelectorAll('*,:x'),
                      y.push(',.*:');
                  })),
                (n.matchesSelector = Q.test(
                  (m =
                    h.matches ||
                    h.webkitMatchesSelector ||
                    h.mozMatchesSelector ||
                    h.oMatchesSelector ||
                    h.msMatchesSelector)
                )) &&
                  ue(function(e) {
                    (n.disconnectedMatch = m.call(e, '*')),
                      m.call(e, "[s!='']:x"),
                      v.push('!=', W);
                  }),
                (y = y.length && new RegExp(y.join('|'))),
                (v = v.length && new RegExp(v.join('|'))),
                (t = Q.test(h.compareDocumentPosition)),
                (x =
                  t || Q.test(h.contains)
                    ? function(e, t) {
                        var n = 9 === e.nodeType ? e.documentElement : e,
                          r = t && t.parentNode;
                        return (
                          e === r ||
                          !(
                            !r ||
                            1 !== r.nodeType ||
                            !(n.contains
                              ? n.contains(r)
                              : e.compareDocumentPosition &&
                                16 & e.compareDocumentPosition(r))
                          )
                        );
                      }
                    : function(e, t) {
                        if (t)
                          while ((t = t.parentNode)) if (t === e) return !0;
                        return !1;
                      }),
                (D = t
                  ? function(e, t) {
                      if (e === t) return (f = !0), 0;
                      var r =
                        !e.compareDocumentPosition - !t.compareDocumentPosition;
                      return (
                        r ||
                        (1 &
                          (r =
                            (e.ownerDocument || e) === (t.ownerDocument || t)
                              ? e.compareDocumentPosition(t)
                              : 1) ||
                        (!n.sortDetached && t.compareDocumentPosition(e) === r)
                          ? e === d || (e.ownerDocument === w && x(w, e))
                            ? -1
                            : t === d || (t.ownerDocument === w && x(w, t))
                            ? 1
                            : c
                            ? O(c, e) - O(c, t)
                            : 0
                          : 4 & r
                          ? -1
                          : 1)
                      );
                    }
                  : function(e, t) {
                      if (e === t) return (f = !0), 0;
                      var n,
                        r = 0,
                        i = e.parentNode,
                        o = t.parentNode,
                        a = [e],
                        s = [t];
                      if (!i || !o)
                        return e === d
                          ? -1
                          : t === d
                          ? 1
                          : i
                          ? -1
                          : o
                          ? 1
                          : c
                          ? O(c, e) - O(c, t)
                          : 0;
                      if (i === o) return ce(e, t);
                      n = e;

                      while ((n = n.parentNode)) a.unshift(n);

                      n = t;

                      while ((n = n.parentNode)) s.unshift(n);

                      while (a[r] === s[r]) r++;

                      return r
                        ? ce(a[r], s[r])
                        : a[r] === w
                        ? -1
                        : s[r] === w
                        ? 1
                        : 0;
                    }),
                d)
              : d;
          }),
          (oe.matches = function(e, t) {
            return oe(e, null, null, t);
          }),
          (oe.matchesSelector = function(e, t) {
            if (
              ((e.ownerDocument || e) !== d && p(e),
              (t = t.replace(z, "='$1']")),
              n.matchesSelector &&
                g &&
                !S[t + ' '] &&
                (!v || !v.test(t)) &&
                (!y || !y.test(t)))
            )
              try {
                var r = m.call(e, t);
                if (
                  r ||
                  n.disconnectedMatch ||
                  (e.document && 11 !== e.document.nodeType)
                )
                  return r;
              } catch (e) {}
            return oe(t, d, null, [e]).length > 0;
          }),
          (oe.contains = function(e, t) {
            return (e.ownerDocument || e) !== d && p(e), x(e, t);
          }),
          (oe.attr = function(e, t) {
            (e.ownerDocument || e) !== d && p(e);
            var i = r.attrHandle[t.toLowerCase()],
              o =
                i && N.call(r.attrHandle, t.toLowerCase())
                  ? i(e, t, !g)
                  : void 0;
            return void 0 !== o
              ? o
              : n.attributes || !g
              ? e.getAttribute(t)
              : (o = e.getAttributeNode(t)) && o.specified
              ? o.value
              : null;
          }),
          (oe.escape = function(e) {
            return (e + '').replace(te, ne);
          }),
          (oe.error = function(e) {
            throw new Error('Syntax error, unrecognized expression: ' + e);
          }),
          (oe.uniqueSort = function(e) {
            var t,
              r = [],
              i = 0,
              o = 0;

            if (
              ((f = !n.detectDuplicates),
              (c = !n.sortStable && e.slice(0)),
              e.sort(D),
              f)
            ) {
              while ((t = e[o++])) t === e[o] && (i = r.push(o));

              while (i--) e.splice(r[i], 1);
            }

            return (c = null), e;
          }),
          (i = oe.getText = function(e) {
            var t,
              n = '',
              r = 0,
              o = e.nodeType;

            if (o) {
              if (1 === o || 9 === o || 11 === o) {
                if ('string' == typeof e.textContent) return e.textContent;

                for (e = e.firstChild; e; e = e.nextSibling) n += i(e);
              } else if (3 === o || 4 === o) return e.nodeValue;
            } else while ((t = e[r++])) n += i(t);

            return n;
          }),
          ((r = oe.selectors = {
            cacheLength: 50,
            createPseudo: se,
            match: V,
            attrHandle: {},
            find: {},
            relative: {
              '>': {
                dir: 'parentNode',
                first: !0,
              },
              ' ': {
                dir: 'parentNode',
              },
              '+': {
                dir: 'previousSibling',
                first: !0,
              },
              '~': {
                dir: 'previousSibling',
              },
            },
            preFilter: {
              ATTR: function(e) {
                return (
                  (e[1] = e[1].replace(Z, ee)),
                  (e[3] = (e[3] || e[4] || e[5] || '').replace(Z, ee)),
                  '~=' === e[2] && (e[3] = ' ' + e[3] + ' '),
                  e.slice(0, 4)
                );
              },
              CHILD: function(e) {
                return (
                  (e[1] = e[1].toLowerCase()),
                  'nth' === e[1].slice(0, 3)
                    ? (e[3] || oe.error(e[0]),
                      (e[4] = +(e[4]
                        ? e[5] + (e[6] || 1)
                        : 2 * ('even' === e[3] || 'odd' === e[3]))),
                      (e[5] = +(e[7] + e[8] || 'odd' === e[3])))
                    : e[3] && oe.error(e[0]),
                  e
                );
              },
              PSEUDO: function(e) {
                var t,
                  n = !e[6] && e[2];
                return V.CHILD.test(e[0])
                  ? null
                  : (e[3]
                      ? (e[2] = e[4] || e[5] || '')
                      : n &&
                        X.test(n) &&
                        (t = a(n, !0)) &&
                        (t = n.indexOf(')', n.length - t) - n.length) &&
                        ((e[0] = e[0].slice(0, t)), (e[2] = n.slice(0, t))),
                    e.slice(0, 3));
              },
            },
            filter: {
              TAG: function(e) {
                var t = e.replace(Z, ee).toLowerCase();
                return '*' === e
                  ? function() {
                      return !0;
                    }
                  : function(e) {
                      return e.nodeName && e.nodeName.toLowerCase() === t;
                    };
              },
              CLASS: function(e) {
                var t = E[e + ' '];
                return (
                  t ||
                  ((t = new RegExp('(^|' + M + ')' + e + '(' + M + '|$)')) &&
                    E(e, function(e) {
                      return t.test(
                        ('string' == typeof e.className && e.className) ||
                          ('undefined' != typeof e.getAttribute &&
                            e.getAttribute('class')) ||
                          ''
                      );
                    }))
                );
              },
              ATTR: function(e, t, n) {
                return function(r) {
                  var i = oe.attr(r, e);
                  return null == i
                    ? '!=' === t
                    : !t ||
                        ((i += ''),
                        '=' === t
                          ? i === n
                          : '!=' === t
                          ? i !== n
                          : '^=' === t
                          ? n && 0 === i.indexOf(n)
                          : '*=' === t
                          ? n && i.indexOf(n) > -1
                          : '$=' === t
                          ? n && i.slice(-n.length) === n
                          : '~=' === t
                          ? (' ' + i.replace($, ' ') + ' ').indexOf(n) > -1
                          : '|=' === t &&
                            (i === n || i.slice(0, n.length + 1) === n + '-'));
                };
              },
              CHILD: function(e, t, n, r, i) {
                var o = 'nth' !== e.slice(0, 3),
                  a = 'last' !== e.slice(-4),
                  s = 'of-type' === t;
                return 1 === r && 0 === i
                  ? function(e) {
                      return !!e.parentNode;
                    }
                  : function(t, n, u) {
                      var l,
                        c,
                        f,
                        p,
                        d,
                        h,
                        g = o !== a ? 'nextSibling' : 'previousSibling',
                        y = t.parentNode,
                        v = s && t.nodeName.toLowerCase(),
                        m = !u && !s,
                        x = !1;

                      if (y) {
                        if (o) {
                          while (g) {
                            p = t;

                            while ((p = p[g]))
                              if (
                                s
                                  ? p.nodeName.toLowerCase() === v
                                  : 1 === p.nodeType
                              )
                                return !1;

                            h = g = 'only' === e && !h && 'nextSibling';
                          }

                          return !0;
                        }

                        if (((h = [a ? y.firstChild : y.lastChild]), a && m)) {
                          (x =
                            (d =
                              (l =
                                (c =
                                  (f = (p = y)[b] || (p[b] = {}))[p.uniqueID] ||
                                  (f[p.uniqueID] = {}))[e] || [])[0] === T &&
                              l[1]) && l[2]),
                            (p = d && y.childNodes[d]);

                          while (
                            (p = (++d && p && p[g]) || (x = d = 0) || h.pop())
                          )
                            if (1 === p.nodeType && ++x && p === t) {
                              c[e] = [T, d, x];
                              break;
                            }
                        } else if (
                          (m &&
                            (x = d =
                              (l =
                                (c =
                                  (f = (p = t)[b] || (p[b] = {}))[p.uniqueID] ||
                                  (f[p.uniqueID] = {}))[e] || [])[0] === T &&
                              l[1]),
                          !1 === x)
                        )
                          while (
                            (p = (++d && p && p[g]) || (x = d = 0) || h.pop())
                          )
                            if (
                              (s
                                ? p.nodeName.toLowerCase() === v
                                : 1 === p.nodeType) &&
                              ++x &&
                              (m &&
                                ((c =
                                  (f = p[b] || (p[b] = {}))[p.uniqueID] ||
                                  (f[p.uniqueID] = {}))[e] = [T, x]),
                              p === t)
                            )
                              break;

                        return (x -= i) === r || (x % r == 0 && x / r >= 0);
                      }
                    };
              },
              PSEUDO: function(e, t) {
                var n,
                  i =
                    r.pseudos[e] ||
                    r.setFilters[e.toLowerCase()] ||
                    oe.error('unsupported pseudo: ' + e);
                return i[b]
                  ? i(t)
                  : i.length > 1
                  ? ((n = [e, e, '', t]),
                    r.setFilters.hasOwnProperty(e.toLowerCase())
                      ? se(function(e, n) {
                          var r,
                            o = i(e, t),
                            a = o.length;

                          while (a--) e[(r = O(e, o[a]))] = !(n[r] = o[a]);
                        })
                      : function(e) {
                          return i(e, 0, n);
                        })
                  : i;
              },
            },
            pseudos: {
              not: se(function(e) {
                var t = [],
                  n = [],
                  r = s(e.replace(B, '$1'));
                return r[b]
                  ? se(function(e, t, n, i) {
                      var o,
                        a = r(e, null, i, []),
                        s = e.length;

                      while (s--) (o = a[s]) && (e[s] = !(t[s] = o));
                    })
                  : function(e, i, o) {
                      return (
                        (t[0] = e), r(t, null, o, n), (t[0] = null), !n.pop()
                      );
                    };
              }),
              has: se(function(e) {
                return function(t) {
                  return oe(e, t).length > 0;
                };
              }),
              contains: se(function(e) {
                return (
                  (e = e.replace(Z, ee)),
                  function(t) {
                    return (
                      (t.textContent || t.innerText || i(t)).indexOf(e) > -1
                    );
                  }
                );
              }),
              lang: se(function(e) {
                return (
                  U.test(e || '') || oe.error('unsupported lang: ' + e),
                  (e = e.replace(Z, ee).toLowerCase()),
                  function(t) {
                    var n;

                    do {
                      if (
                        (n = g
                          ? t.lang
                          : t.getAttribute('xml:lang') ||
                            t.getAttribute('lang'))
                      )
                        return (
                          (n = n.toLowerCase()) === e ||
                          0 === n.indexOf(e + '-')
                        );
                    } while ((t = t.parentNode) && 1 === t.nodeType);

                    return !1;
                  }
                );
              }),
              target: function(t) {
                var n = e.location && e.location.hash;
                return n && n.slice(1) === t.id;
              },
              root: function(e) {
                return e === h;
              },
              focus: function(e) {
                return (
                  e === d.activeElement &&
                  (!d.hasFocus || d.hasFocus()) &&
                  !!(e.type || e.href || ~e.tabIndex)
                );
              },
              enabled: de(!1),
              disabled: de(!0),
              checked: function(e) {
                var t = e.nodeName.toLowerCase();
                return (
                  ('input' === t && !!e.checked) ||
                  ('option' === t && !!e.selected)
                );
              },
              selected: function(e) {
                return (
                  e.parentNode && e.parentNode.selectedIndex, !0 === e.selected
                );
              },
              empty: function(e) {
                for (e = e.firstChild; e; e = e.nextSibling)
                  if (e.nodeType < 6) return !1;

                return !0;
              },
              parent: function(e) {
                return !r.pseudos.empty(e);
              },
              header: function(e) {
                return Y.test(e.nodeName);
              },
              input: function(e) {
                return G.test(e.nodeName);
              },
              button: function(e) {
                var t = e.nodeName.toLowerCase();
                return ('input' === t && 'button' === e.type) || 'button' === t;
              },
              text: function(e) {
                var t;
                return (
                  'input' === e.nodeName.toLowerCase() &&
                  'text' === e.type &&
                  (null == (t = e.getAttribute('type')) ||
                    'text' === t.toLowerCase())
                );
              },
              first: he(function() {
                return [0];
              }),
              last: he(function(e, t) {
                return [t - 1];
              }),
              eq: he(function(e, t, n) {
                return [n < 0 ? n + t : n];
              }),
              even: he(function(e, t) {
                for (var n = 0; n < t; n += 2) e.push(n);

                return e;
              }),
              odd: he(function(e, t) {
                for (var n = 1; n < t; n += 2) e.push(n);

                return e;
              }),
              lt: he(function(e, t, n) {
                for (var r = n < 0 ? n + t : n; --r >= 0; ) e.push(r);

                return e;
              }),
              gt: he(function(e, t, n) {
                for (var r = n < 0 ? n + t : n; ++r < t; ) e.push(r);

                return e;
              }),
            },
          }).pseudos.nth = r.pseudos.eq);

        for (t in {
          radio: !0,
          checkbox: !0,
          file: !0,
          password: !0,
          image: !0,
        })
          r.pseudos[t] = fe(t);

        for (t in {
          submit: !0,
          reset: !0,
        })
          r.pseudos[t] = pe(t);

        function ye() {}

        (ye.prototype = r.filters = r.pseudos),
          (r.setFilters = new ye()),
          (a = oe.tokenize = function(e, t) {
            var n,
              i,
              o,
              a,
              s,
              u,
              l,
              c = k[e + ' '];
            if (c) return t ? 0 : c.slice(0);
            (s = e), (u = []), (l = r.preFilter);

            while (s) {
              (n && !(i = F.exec(s))) ||
                (i && (s = s.slice(i[0].length) || s), u.push((o = []))),
                (n = !1),
                (i = _.exec(s)) &&
                  ((n = i.shift()),
                  o.push({
                    value: n,
                    type: i[0].replace(B, ' '),
                  }),
                  (s = s.slice(n.length)));

              for (a in r.filter)
                !(i = V[a].exec(s)) ||
                  (l[a] && !(i = l[a](i))) ||
                  ((n = i.shift()),
                  o.push({
                    value: n,
                    type: a,
                    matches: i,
                  }),
                  (s = s.slice(n.length)));

              if (!n) break;
            }

            return t ? s.length : s ? oe.error(e) : k(e, u).slice(0);
          });

        function ve(e) {
          for (var t = 0, n = e.length, r = ''; t < n; t++) r += e[t].value;

          return r;
        }

        function me(e, t, n) {
          var r = t.dir,
            i = t.next,
            o = i || r,
            a = n && 'parentNode' === o,
            s = C++;
          return t.first
            ? function(t, n, i) {
                while ((t = t[r])) if (1 === t.nodeType || a) return e(t, n, i);

                return !1;
              }
            : function(t, n, u) {
                var l,
                  c,
                  f,
                  p = [T, s];

                if (u) {
                  while ((t = t[r]))
                    if ((1 === t.nodeType || a) && e(t, n, u)) return !0;
                } else
                  while ((t = t[r]))
                    if (1 === t.nodeType || a)
                      if (
                        ((f = t[b] || (t[b] = {})),
                        (c = f[t.uniqueID] || (f[t.uniqueID] = {})),
                        i && i === t.nodeName.toLowerCase())
                      )
                        t = t[r] || t;
                      else {
                        if ((l = c[o]) && l[0] === T && l[1] === s)
                          return (p[2] = l[2]);
                        if (((c[o] = p), (p[2] = e(t, n, u)))) return !0;
                      }

                return !1;
              };
        }

        function xe(e) {
          return e.length > 1
            ? function(t, n, r) {
                var i = e.length;

                while (i--) if (!e[i](t, n, r)) return !1;

                return !0;
              }
            : e[0];
        }

        function be(e, t, n) {
          for (var r = 0, i = t.length; r < i; r++) oe(e, t[r], n);

          return n;
        }

        function we(e, t, n, r, i) {
          for (var o, a = [], s = 0, u = e.length, l = null != t; s < u; s++)
            (o = e[s]) && ((n && !n(o, r, i)) || (a.push(o), l && t.push(s)));

          return a;
        }

        function Te(e, t, n, r, i, o) {
          return (
            r && !r[b] && (r = Te(r)),
            i && !i[b] && (i = Te(i, o)),
            se(function(o, a, s, u) {
              var l,
                c,
                f,
                p = [],
                d = [],
                h = a.length,
                g = o || be(t || '*', s.nodeType ? [s] : s, []),
                y = !e || (!o && t) ? g : we(g, p, e, s, u),
                v = n ? (i || (o ? e : h || r) ? [] : a) : y;

              if ((n && n(y, v, s, u), r)) {
                (l = we(v, d)), r(l, [], s, u), (c = l.length);

                while (c--) (f = l[c]) && (v[d[c]] = !(y[d[c]] = f));
              }

              if (o) {
                if (i || e) {
                  if (i) {
                    (l = []), (c = v.length);

                    while (c--) (f = v[c]) && l.push((y[c] = f));

                    i(null, (v = []), l, u);
                  }

                  c = v.length;

                  while (c--)
                    (f = v[c]) &&
                      (l = i ? O(o, f) : p[c]) > -1 &&
                      (o[l] = !(a[l] = f));
                }
              } else (v = we(v === a ? v.splice(h, v.length) : v)), i ? i(null, a, v, u) : L.apply(a, v);
            })
          );
        }

        function Ce(e) {
          for (
            var t,
              n,
              i,
              o = e.length,
              a = r.relative[e[0].type],
              s = a || r.relative[' '],
              u = a ? 1 : 0,
              c = me(
                function(e) {
                  return e === t;
                },
                s,
                !0
              ),
              f = me(
                function(e) {
                  return O(t, e) > -1;
                },
                s,
                !0
              ),
              p = [
                function(e, n, r) {
                  var i =
                    (!a && (r || n !== l)) ||
                    ((t = n).nodeType ? c(e, n, r) : f(e, n, r));
                  return (t = null), i;
                },
              ];
            u < o;
            u++
          )
            if ((n = r.relative[e[u].type])) p = [me(xe(p), n)];
            else {
              if ((n = r.filter[e[u].type].apply(null, e[u].matches))[b]) {
                for (i = ++u; i < o; i++) if (r.relative[e[i].type]) break;

                return Te(
                  u > 1 && xe(p),
                  u > 1 &&
                    ve(
                      e.slice(0, u - 1).concat({
                        value: ' ' === e[u - 2].type ? '*' : '',
                      })
                    ).replace(B, '$1'),
                  n,
                  u < i && Ce(e.slice(u, i)),
                  i < o && Ce((e = e.slice(i))),
                  i < o && ve(e)
                );
              }

              p.push(n);
            }

          return xe(p);
        }

        function Ee(e, t) {
          var n = t.length > 0,
            i = e.length > 0,
            o = function(o, a, s, u, c) {
              var f,
                h,
                y,
                v = 0,
                m = '0',
                x = o && [],
                b = [],
                w = l,
                C = o || (i && r.find.TAG('*', c)),
                E = (T += null == w ? 1 : Math.random() || 0.1),
                k = C.length;

              for (
                c && (l = a === d || a || c);
                m !== k && null != (f = C[m]);
                m++
              ) {
                if (i && f) {
                  (h = 0), a || f.ownerDocument === d || (p(f), (s = !g));

                  while ((y = e[h++]))
                    if (y(f, a || d, s)) {
                      u.push(f);
                      break;
                    }

                  c && (T = E);
                }

                n && ((f = !y && f) && v--, o && x.push(f));
              }

              if (((v += m), n && m !== v)) {
                h = 0;

                while ((y = t[h++])) y(x, b, a, s);

                if (o) {
                  if (v > 0) while (m--) x[m] || b[m] || (b[m] = j.call(u));
                  b = we(b);
                }

                L.apply(u, b),
                  c &&
                    !o &&
                    b.length > 0 &&
                    v + t.length > 1 &&
                    oe.uniqueSort(u);
              }

              return c && ((T = E), (l = w)), x;
            };

          return n ? se(o) : o;
        }

        return (
          (s = oe.compile = function(e, t) {
            var n,
              r = [],
              i = [],
              o = S[e + ' '];

            if (!o) {
              t || (t = a(e)), (n = t.length);

              while (n--) (o = Ce(t[n]))[b] ? r.push(o) : i.push(o);

              (o = S(e, Ee(i, r))).selector = e;
            }

            return o;
          }),
          (u = oe.select = function(e, t, n, i) {
            var o,
              u,
              l,
              c,
              f,
              p = 'function' == typeof e && e,
              d = !i && a((e = p.selector || e));

            if (((n = n || []), 1 === d.length)) {
              if (
                (u = d[0] = d[0].slice(0)).length > 2 &&
                'ID' === (l = u[0]).type &&
                9 === t.nodeType &&
                g &&
                r.relative[u[1].type]
              ) {
                if (!(t = (r.find.ID(l.matches[0].replace(Z, ee), t) || [])[0]))
                  return n;
                p && (t = t.parentNode), (e = e.slice(u.shift().value.length));
              }

              o = V.needsContext.test(e) ? 0 : u.length;

              while (o--) {
                if (((l = u[o]), r.relative[(c = l.type)])) break;

                if (
                  (f = r.find[c]) &&
                  (i = f(
                    l.matches[0].replace(Z, ee),
                    (K.test(u[0].type) && ge(t.parentNode)) || t
                  ))
                ) {
                  if ((u.splice(o, 1), !(e = i.length && ve(u))))
                    return L.apply(n, i), n;
                  break;
                }
              }
            }

            return (
              (p || s(e, d))(
                i,
                t,
                !g,
                n,
                !t || (K.test(e) && ge(t.parentNode)) || t
              ),
              n
            );
          }),
          (n.sortStable =
            b
              .split('')
              .sort(D)
              .join('') === b),
          (n.detectDuplicates = !!f),
          p(),
          (n.sortDetached = ue(function(e) {
            return 1 & e.compareDocumentPosition(d.createElement('fieldset'));
          })),
          ue(function(e) {
            return (
              (e.innerHTML = "<a href='#'></a>"),
              '#' === e.firstChild.getAttribute('href')
            );
          }) ||
            le('type|href|height|width', function(e, t, n) {
              if (!n)
                return e.getAttribute(t, 'type' === t.toLowerCase() ? 1 : 2);
            }),
          (n.attributes &&
            ue(function(e) {
              return (
                (e.innerHTML = '<input/>'),
                e.firstChild.setAttribute('value', ''),
                '' === e.firstChild.getAttribute('value')
              );
            })) ||
            le('value', function(e, t, n) {
              if (!n && 'input' === e.nodeName.toLowerCase())
                return e.defaultValue;
            }),
          ue(function(e) {
            return null == e.getAttribute('disabled');
          }) ||
            le(P, function(e, t, n) {
              var r;
              if (!n)
                return !0 === e[t]
                  ? t.toLowerCase()
                  : (r = e.getAttributeNode(t)) && r.specified
                  ? r.value
                  : null;
            }),
          oe
        );
      })(e);

      (w.find = E),
        (w.expr = E.selectors),
        (w.expr[':'] = w.expr.pseudos),
        (w.uniqueSort = w.unique = E.uniqueSort),
        (w.text = E.getText),
        (w.isXMLDoc = E.isXML),
        (w.contains = E.contains),
        (w.escapeSelector = E.escape);

      var k = function(e, t, n) {
          var r = [],
            i = void 0 !== n;

          while ((e = e[t]) && 9 !== e.nodeType)
            if (1 === e.nodeType) {
              if (i && w(e).is(n)) break;
              r.push(e);
            }

          return r;
        },
        S = function(e, t) {
          for (var n = []; e; e = e.nextSibling)
            1 === e.nodeType && e !== t && n.push(e);

          return n;
        },
        D = w.expr.match.needsContext;

      function N(e, t) {
        return e.nodeName && e.nodeName.toLowerCase() === t.toLowerCase();
      }

      var A = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;

      function j(e, t, n) {
        return g(t)
          ? w.grep(e, function(e, r) {
              return !!t.call(e, r, e) !== n;
            })
          : t.nodeType
          ? w.grep(e, function(e) {
              return (e === t) !== n;
            })
          : 'string' != typeof t
          ? w.grep(e, function(e) {
              return u.call(t, e) > -1 !== n;
            })
          : w.filter(t, e, n);
      }

      (w.filter = function(e, t, n) {
        var r = t[0];
        return (
          n && (e = ':not(' + e + ')'),
          1 === t.length && 1 === r.nodeType
            ? w.find.matchesSelector(r, e)
              ? [r]
              : []
            : w.find.matches(
                e,
                w.grep(t, function(e) {
                  return 1 === e.nodeType;
                })
              )
        );
      }),
        w.fn.extend({
          find: function(e) {
            var t,
              n,
              r = this.length,
              i = this;
            if ('string' != typeof e)
              return this.pushStack(
                w(e).filter(function() {
                  for (t = 0; t < r; t++) if (w.contains(i[t], this)) return !0;
                })
              );

            for (n = this.pushStack([]), t = 0; t < r; t++) w.find(e, i[t], n);

            return r > 1 ? w.uniqueSort(n) : n;
          },
          filter: function(e) {
            return this.pushStack(j(this, e || [], !1));
          },
          not: function(e) {
            return this.pushStack(j(this, e || [], !0));
          },
          is: function(e) {
            return !!j(
              this,
              'string' == typeof e && D.test(e) ? w(e) : e || [],
              !1
            ).length;
          },
        });
      var q,
        L = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;
      ((w.fn.init = function(e, t, n) {
        var i, o;
        if (!e) return this;

        if (((n = n || q), 'string' == typeof e)) {
          if (
            !(i =
              '<' === e[0] && '>' === e[e.length - 1] && e.length >= 3
                ? [null, e, null]
                : L.exec(e)) ||
            (!i[1] && t)
          )
            return !t || t.jquery
              ? (t || n).find(e)
              : this.constructor(t).find(e);

          if (i[1]) {
            if (
              ((t = t instanceof w ? t[0] : t),
              w.merge(
                this,
                w.parseHTML(
                  i[1],
                  t && t.nodeType ? t.ownerDocument || t : r,
                  !0
                )
              ),
              A.test(i[1]) && w.isPlainObject(t))
            )
              for (i in t) g(this[i]) ? this[i](t[i]) : this.attr(i, t[i]);
            return this;
          }

          return (
            (o = r.getElementById(i[2])) && ((this[0] = o), (this.length = 1)),
            this
          );
        }

        return e.nodeType
          ? ((this[0] = e), (this.length = 1), this)
          : g(e)
          ? void 0 !== n.ready
            ? n.ready(e)
            : e(w)
          : w.makeArray(e, this);
      }).prototype = w.fn),
        (q = w(r));
      var H = /^(?:parents|prev(?:Until|All))/,
        O = {
          children: !0,
          contents: !0,
          next: !0,
          prev: !0,
        };
      w.fn.extend({
        has: function(e) {
          var t = w(e, this),
            n = t.length;
          return this.filter(function() {
            for (var e = 0; e < n; e++) if (w.contains(this, t[e])) return !0;
          });
        },
        closest: function(e, t) {
          var n,
            r = 0,
            i = this.length,
            o = [],
            a = 'string' != typeof e && w(e);
          if (!D.test(e))
            for (; r < i; r++)
              for (n = this[r]; n && n !== t; n = n.parentNode)
                if (
                  n.nodeType < 11 &&
                  (a
                    ? a.index(n) > -1
                    : 1 === n.nodeType && w.find.matchesSelector(n, e))
                ) {
                  o.push(n);
                  break;
                }
          return this.pushStack(o.length > 1 ? w.uniqueSort(o) : o);
        },
        index: function(e) {
          return e
            ? 'string' == typeof e
              ? u.call(w(e), this[0])
              : u.call(this, e.jquery ? e[0] : e)
            : this[0] && this[0].parentNode
            ? this.first().prevAll().length
            : -1;
        },
        add: function(e, t) {
          return this.pushStack(w.uniqueSort(w.merge(this.get(), w(e, t))));
        },
        addBack: function(e) {
          return this.add(
            null == e ? this.prevObject : this.prevObject.filter(e)
          );
        },
      });

      function P(e, t) {
        while ((e = e[t]) && 1 !== e.nodeType);

        return e;
      }

      w.each(
        {
          parent: function(e) {
            var t = e.parentNode;
            return t && 11 !== t.nodeType ? t : null;
          },
          parents: function(e) {
            return k(e, 'parentNode');
          },
          parentsUntil: function(e, t, n) {
            return k(e, 'parentNode', n);
          },
          next: function(e) {
            return P(e, 'nextSibling');
          },
          prev: function(e) {
            return P(e, 'previousSibling');
          },
          nextAll: function(e) {
            return k(e, 'nextSibling');
          },
          prevAll: function(e) {
            return k(e, 'previousSibling');
          },
          nextUntil: function(e, t, n) {
            return k(e, 'nextSibling', n);
          },
          prevUntil: function(e, t, n) {
            return k(e, 'previousSibling', n);
          },
          siblings: function(e) {
            return S((e.parentNode || {}).firstChild, e);
          },
          children: function(e) {
            return S(e.firstChild);
          },
          contents: function(e) {
            return N(e, 'iframe')
              ? e.contentDocument
              : (N(e, 'template') && (e = e.content || e),
                w.merge([], e.childNodes));
          },
        },
        function(e, t) {
          w.fn[e] = function(n, r) {
            var i = w.map(this, t, n);
            return (
              'Until' !== e.slice(-5) && (r = n),
              r && 'string' == typeof r && (i = w.filter(r, i)),
              this.length > 1 &&
                (O[e] || w.uniqueSort(i), H.test(e) && i.reverse()),
              this.pushStack(i)
            );
          };
        }
      );
      var M = /[^\x20\t\r\n\f]+/g;

      function R(e) {
        var t = {};
        return (
          w.each(e.match(M) || [], function(e, n) {
            t[n] = !0;
          }),
          t
        );
      }

      w.Callbacks = function(e) {
        e = 'string' == typeof e ? R(e) : w.extend({}, e);

        var t,
          n,
          r,
          i,
          o = [],
          a = [],
          s = -1,
          u = function() {
            for (i = i || e.once, r = t = !0; a.length; s = -1) {
              n = a.shift();

              while (++s < o.length)
                !1 === o[s].apply(n[0], n[1]) &&
                  e.stopOnFalse &&
                  ((s = o.length), (n = !1));
            }

            e.memory || (n = !1), (t = !1), i && (o = n ? [] : '');
          },
          l = {
            add: function() {
              return (
                o &&
                  (n && !t && ((s = o.length - 1), a.push(n)),
                  (function t(n) {
                    w.each(n, function(n, r) {
                      g(r)
                        ? (e.unique && l.has(r)) || o.push(r)
                        : r && r.length && 'string' !== x(r) && t(r);
                    });
                  })(arguments),
                  n && !t && u()),
                this
              );
            },
            remove: function() {
              return (
                w.each(arguments, function(e, t) {
                  var n;

                  while ((n = w.inArray(t, o, n)) > -1)
                    o.splice(n, 1), n <= s && s--;
                }),
                this
              );
            },
            has: function(e) {
              return e ? w.inArray(e, o) > -1 : o.length > 0;
            },
            empty: function() {
              return o && (o = []), this;
            },
            disable: function() {
              return (i = a = []), (o = n = ''), this;
            },
            disabled: function() {
              return !o;
            },
            lock: function() {
              return (i = a = []), n || t || (o = n = ''), this;
            },
            locked: function() {
              return !!i;
            },
            fireWith: function(e, n) {
              return (
                i ||
                  ((n = [e, (n = n || []).slice ? n.slice() : n]),
                  a.push(n),
                  t || u()),
                this
              );
            },
            fire: function() {
              return l.fireWith(this, arguments), this;
            },
            fired: function() {
              return !!r;
            },
          };

        return l;
      };

      function I(e) {
        return e;
      }

      function W(e) {
        throw e;
      }

      function $(e, t, n, r) {
        var i;

        try {
          e && g((i = e.promise))
            ? i
                .call(e)
                .done(t)
                .fail(n)
            : e && g((i = e.then))
            ? i.call(e, t, n)
            : t.apply(void 0, [e].slice(r));
        } catch (e) {
          n.apply(void 0, [e]);
        }
      }

      w.extend({
        Deferred: function(t) {
          var n = [
              [
                'notify',
                'progress',
                w.Callbacks('memory'),
                w.Callbacks('memory'),
                2,
              ],
              [
                'resolve',
                'done',
                w.Callbacks('once memory'),
                w.Callbacks('once memory'),
                0,
                'resolved',
              ],
              [
                'reject',
                'fail',
                w.Callbacks('once memory'),
                w.Callbacks('once memory'),
                1,
                'rejected',
              ],
            ],
            r = 'pending',
            i = {
              state: function() {
                return r;
              },
              always: function() {
                return o.done(arguments).fail(arguments), this;
              },
              catch: function(e) {
                return i.then(null, e);
              },
              pipe: function() {
                var e = arguments;
                return w
                  .Deferred(function(t) {
                    w.each(n, function(n, r) {
                      var i = g(e[r[4]]) && e[r[4]];
                      o[r[1]](function() {
                        var e = i && i.apply(this, arguments);
                        e && g(e.promise)
                          ? e
                              .promise()
                              .progress(t.notify)
                              .done(t.resolve)
                              .fail(t.reject)
                          : t[r[0] + 'With'](this, i ? [e] : arguments);
                      });
                    }),
                      (e = null);
                  })
                  .promise();
              },
              then: function(t, r, i) {
                var o = 0;

                function a(t, n, r, i) {
                  return function() {
                    var s = this,
                      u = arguments,
                      l = function() {
                        var e, l;

                        if (!(t < o)) {
                          if ((e = r.apply(s, u)) === n.promise())
                            throw new TypeError('Thenable self-resolution');
                          (l =
                            e &&
                            ('object' == typeof e || 'function' == typeof e) &&
                            e.then),
                            g(l)
                              ? i
                                ? l.call(e, a(o, n, I, i), a(o, n, W, i))
                                : (o++,
                                  l.call(
                                    e,
                                    a(o, n, I, i),
                                    a(o, n, W, i),
                                    a(o, n, I, n.notifyWith)
                                  ))
                              : (r !== I && ((s = void 0), (u = [e])),
                                (i || n.resolveWith)(s, u));
                        }
                      },
                      c = i
                        ? l
                        : function() {
                            try {
                              l();
                            } catch (e) {
                              w.Deferred.exceptionHook &&
                                w.Deferred.exceptionHook(e, c.stackTrace),
                                t + 1 >= o &&
                                  (r !== W && ((s = void 0), (u = [e])),
                                  n.rejectWith(s, u));
                            }
                          };

                    t
                      ? c()
                      : (w.Deferred.getStackHook &&
                          (c.stackTrace = w.Deferred.getStackHook()),
                        e.setTimeout(c));
                  };
                }

                return w
                  .Deferred(function(e) {
                    n[0][3].add(a(0, e, g(i) ? i : I, e.notifyWith)),
                      n[1][3].add(a(0, e, g(t) ? t : I)),
                      n[2][3].add(a(0, e, g(r) ? r : W));
                  })
                  .promise();
              },
              promise: function(e) {
                return null != e ? w.extend(e, i) : i;
              },
            },
            o = {};
          return (
            w.each(n, function(e, t) {
              var a = t[2],
                s = t[5];
              (i[t[1]] = a.add),
                s &&
                  a.add(
                    function() {
                      r = s;
                    },
                    n[3 - e][2].disable,
                    n[3 - e][3].disable,
                    n[0][2].lock,
                    n[0][3].lock
                  ),
                a.add(t[3].fire),
                (o[t[0]] = function() {
                  return (
                    o[t[0] + 'With'](this === o ? void 0 : this, arguments),
                    this
                  );
                }),
                (o[t[0] + 'With'] = a.fireWith);
            }),
            i.promise(o),
            t && t.call(o, o),
            o
          );
        },
        when: function(e) {
          var t = arguments.length,
            n = t,
            r = Array(n),
            i = o.call(arguments),
            a = w.Deferred(),
            s = function(e) {
              return function(n) {
                (r[e] = this),
                  (i[e] = arguments.length > 1 ? o.call(arguments) : n),
                  --t || a.resolveWith(r, i);
              };
            };

          if (
            t <= 1 &&
            ($(e, a.done(s(n)).resolve, a.reject, !t),
            'pending' === a.state() || g(i[n] && i[n].then))
          )
            return a.then();

          while (n--) $(i[n], s(n), a.reject);

          return a.promise();
        },
      });
      var B = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
      (w.Deferred.exceptionHook = function(t, n) {
        e.console &&
          e.console.warn &&
          t &&
          B.test(t.name) &&
          e.console.warn('jQuery.Deferred exception: ' + t.message, t.stack, n);
      }),
        (w.readyException = function(t) {
          e.setTimeout(function() {
            throw t;
          });
        });
      var F = w.Deferred();
      (w.fn.ready = function(e) {
        return (
          F.then(e)['catch'](function(e) {
            w.readyException(e);
          }),
          this
        );
      }),
        w.extend({
          isReady: !1,
          readyWait: 1,
          ready: function(e) {
            (!0 === e ? --w.readyWait : w.isReady) ||
              ((w.isReady = !0),
              (!0 !== e && --w.readyWait > 0) || F.resolveWith(r, [w]));
          },
        }),
        (w.ready.then = F.then);

      function _() {
        r.removeEventListener('DOMContentLoaded', _),
          e.removeEventListener('load', _),
          w.ready();
      }

      'complete' === r.readyState ||
      ('loading' !== r.readyState && !r.documentElement.doScroll)
        ? e.setTimeout(w.ready)
        : (r.addEventListener('DOMContentLoaded', _),
          e.addEventListener('load', _));

      var z = function(e, t, n, r, i, o, a) {
          var s = 0,
            u = e.length,
            l = null == n;

          if ('object' === x(n)) {
            i = !0;

            for (s in n) z(e, t, s, n[s], !0, o, a);
          } else if (
            void 0 !== r &&
            ((i = !0),
            g(r) || (a = !0),
            l &&
              (a
                ? (t.call(e, r), (t = null))
                : ((l = t),
                  (t = function(e, t, n) {
                    return l.call(w(e), n);
                  }))),
            t)
          )
            for (; s < u; s++) t(e[s], n, a ? r : r.call(e[s], s, t(e[s], n)));

          return i ? e : l ? t.call(e) : u ? t(e[0], n) : o;
        },
        X = /^-ms-/,
        U = /-([a-z])/g;

      function V(e, t) {
        return t.toUpperCase();
      }

      function G(e) {
        return e.replace(X, 'ms-').replace(U, V);
      }

      var Y = function(e) {
        return 1 === e.nodeType || 9 === e.nodeType || !+e.nodeType;
      };

      function Q() {
        this.expando = w.expando + Q.uid++;
      }

      (Q.uid = 1),
        (Q.prototype = {
          cache: function(e) {
            var t = e[this.expando];
            return (
              t ||
                ((t = {}),
                Y(e) &&
                  (e.nodeType
                    ? (e[this.expando] = t)
                    : Object.defineProperty(e, this.expando, {
                        value: t,
                        configurable: !0,
                      }))),
              t
            );
          },
          set: function(e, t, n) {
            var r,
              i = this.cache(e);
            if ('string' == typeof t) i[G(t)] = n;
            else for (r in t) i[G(r)] = t[r];
            return i;
          },
          get: function(e, t) {
            return void 0 === t
              ? this.cache(e)
              : e[this.expando] && e[this.expando][G(t)];
          },
          access: function(e, t, n) {
            return void 0 === t || (t && 'string' == typeof t && void 0 === n)
              ? this.get(e, t)
              : (this.set(e, t, n), void 0 !== n ? n : t);
          },
          remove: function(e, t) {
            var n,
              r = e[this.expando];

            if (void 0 !== r) {
              if (void 0 !== t) {
                n = (t = Array.isArray(t)
                  ? t.map(G)
                  : (t = G(t)) in r
                  ? [t]
                  : t.match(M) || []).length;

                while (n--) delete r[t[n]];
              }

              (void 0 === t || w.isEmptyObject(r)) &&
                (e.nodeType
                  ? (e[this.expando] = void 0)
                  : delete e[this.expando]);
            }
          },
          hasData: function(e) {
            var t = e[this.expando];
            return void 0 !== t && !w.isEmptyObject(t);
          },
        });
      var J = new Q(),
        K = new Q(),
        Z = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
        ee = /[A-Z]/g;

      function te(e) {
        return (
          'true' === e ||
          ('false' !== e &&
            ('null' === e
              ? null
              : e === +e + ''
              ? +e
              : Z.test(e)
              ? JSON.parse(e)
              : e))
        );
      }

      function ne(e, t, n) {
        var r;
        if (void 0 === n && 1 === e.nodeType)
          if (
            ((r = 'data-' + t.replace(ee, '-$&').toLowerCase()),
            'string' == typeof (n = e.getAttribute(r)))
          ) {
            try {
              n = te(n);
            } catch (e) {}

            K.set(e, t, n);
          } else n = void 0;
        return n;
      }

      w.extend({
        hasData: function(e) {
          return K.hasData(e) || J.hasData(e);
        },
        data: function(e, t, n) {
          return K.access(e, t, n);
        },
        removeData: function(e, t) {
          K.remove(e, t);
        },
        _data: function(e, t, n) {
          return J.access(e, t, n);
        },
        _removeData: function(e, t) {
          J.remove(e, t);
        },
      }),
        w.fn.extend({
          data: function(e, t) {
            var n,
              r,
              i,
              o = this[0],
              a = o && o.attributes;

            if (void 0 === e) {
              if (
                this.length &&
                ((i = K.get(o)), 1 === o.nodeType && !J.get(o, 'hasDataAttrs'))
              ) {
                n = a.length;

                while (n--)
                  a[n] &&
                    0 === (r = a[n].name).indexOf('data-') &&
                    ((r = G(r.slice(5))), ne(o, r, i[r]));

                J.set(o, 'hasDataAttrs', !0);
              }

              return i;
            }

            return 'object' == typeof e
              ? this.each(function() {
                  K.set(this, e);
                })
              : z(
                  this,
                  function(t) {
                    var n;

                    if (o && void 0 === t) {
                      if (void 0 !== (n = K.get(o, e))) return n;
                      if (void 0 !== (n = ne(o, e))) return n;
                    } else
                      this.each(function() {
                        K.set(this, e, t);
                      });
                  },
                  null,
                  t,
                  arguments.length > 1,
                  null,
                  !0
                );
          },
          removeData: function(e) {
            return this.each(function() {
              K.remove(this, e);
            });
          },
        }),
        w.extend({
          queue: function(e, t, n) {
            var r;
            if (e)
              return (
                (t = (t || 'fx') + 'queue'),
                (r = J.get(e, t)),
                n &&
                  (!r || Array.isArray(n)
                    ? (r = J.access(e, t, w.makeArray(n)))
                    : r.push(n)),
                r || []
              );
          },
          dequeue: function(e, t) {
            t = t || 'fx';

            var n = w.queue(e, t),
              r = n.length,
              i = n.shift(),
              o = w._queueHooks(e, t),
              a = function() {
                w.dequeue(e, t);
              };

            'inprogress' === i && ((i = n.shift()), r--),
              i &&
                ('fx' === t && n.unshift('inprogress'),
                delete o.stop,
                i.call(e, a, o)),
              !r && o && o.empty.fire();
          },
          _queueHooks: function(e, t) {
            var n = t + 'queueHooks';
            return (
              J.get(e, n) ||
              J.access(e, n, {
                empty: w.Callbacks('once memory').add(function() {
                  J.remove(e, [t + 'queue', n]);
                }),
              })
            );
          },
        }),
        w.fn.extend({
          queue: function(e, t) {
            var n = 2;
            return (
              'string' != typeof e && ((t = e), (e = 'fx'), n--),
              arguments.length < n
                ? w.queue(this[0], e)
                : void 0 === t
                ? this
                : this.each(function() {
                    var n = w.queue(this, e, t);
                    w._queueHooks(this, e),
                      'fx' === e && 'inprogress' !== n[0] && w.dequeue(this, e);
                  })
            );
          },
          dequeue: function(e) {
            return this.each(function() {
              w.dequeue(this, e);
            });
          },
          clearQueue: function(e) {
            return this.queue(e || 'fx', []);
          },
          promise: function(e, t) {
            var n,
              r = 1,
              i = w.Deferred(),
              o = this,
              a = this.length,
              s = function() {
                --r || i.resolveWith(o, [o]);
              };

            'string' != typeof e && ((t = e), (e = void 0)), (e = e || 'fx');

            while (a--)
              (n = J.get(o[a], e + 'queueHooks')) &&
                n.empty &&
                (r++, n.empty.add(s));

            return s(), i.promise(t);
          },
        });

      var re = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
        ie = new RegExp('^(?:([+-])=|)(' + re + ')([a-z%]*)$', 'i'),
        oe = ['Top', 'Right', 'Bottom', 'Left'],
        ae = function(e, t) {
          return (
            'none' === (e = t || e).style.display ||
            ('' === e.style.display &&
              w.contains(e.ownerDocument, e) &&
              'none' === w.css(e, 'display'))
          );
        },
        se = function(e, t, n, r) {
          var i,
            o,
            a = {};

          for (o in t) (a[o] = e.style[o]), (e.style[o] = t[o]);

          i = n.apply(e, r || []);

          for (o in t) e.style[o] = a[o];

          return i;
        };

      function ue(e, t, n, r) {
        var i,
          o,
          a = 20,
          s = r
            ? function() {
                return r.cur();
              }
            : function() {
                return w.css(e, t, '');
              },
          u = s(),
          l = (n && n[3]) || (w.cssNumber[t] ? '' : 'px'),
          c = (w.cssNumber[t] || ('px' !== l && +u)) && ie.exec(w.css(e, t));

        if (c && c[3] !== l) {
          (u /= 2), (l = l || c[3]), (c = +u || 1);

          while (a--)
            w.style(e, t, c + l),
              (1 - o) * (1 - (o = s() / u || 0.5)) <= 0 && (a = 0),
              (c /= o);

          (c *= 2), w.style(e, t, c + l), (n = n || []);
        }

        return (
          n &&
            ((c = +c || +u || 0),
            (i = n[1] ? c + (n[1] + 1) * n[2] : +n[2]),
            r && ((r.unit = l), (r.start = c), (r.end = i))),
          i
        );
      }

      var le = {};

      function ce(e) {
        var t,
          n = e.ownerDocument,
          r = e.nodeName,
          i = le[r];
        return (
          i ||
          ((t = n.body.appendChild(n.createElement(r))),
          (i = w.css(t, 'display')),
          t.parentNode.removeChild(t),
          'none' === i && (i = 'block'),
          (le[r] = i),
          i)
        );
      }

      function fe(e, t) {
        for (var n, r, i = [], o = 0, a = e.length; o < a; o++)
          (r = e[o]).style &&
            ((n = r.style.display),
            t
              ? ('none' === n &&
                  ((i[o] = J.get(r, 'display') || null),
                  i[o] || (r.style.display = '')),
                '' === r.style.display && ae(r) && (i[o] = ce(r)))
              : 'none' !== n && ((i[o] = 'none'), J.set(r, 'display', n)));

        for (o = 0; o < a; o++) null != i[o] && (e[o].style.display = i[o]);

        return e;
      }

      w.fn.extend({
        show: function() {
          return fe(this, !0);
        },
        hide: function() {
          return fe(this);
        },
        toggle: function(e) {
          return 'boolean' == typeof e
            ? e
              ? this.show()
              : this.hide()
            : this.each(function() {
                ae(this) ? w(this).show() : w(this).hide();
              });
        },
      });
      var pe = /^(?:checkbox|radio)$/i,
        de = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i,
        he = /^$|^module$|\/(?:java|ecma)script/i,
        ge = {
          option: [1, "<select multiple='multiple'>", '</select>'],
          thead: [1, '<table>', '</table>'],
          col: [2, '<table><colgroup>', '</colgroup></table>'],
          tr: [2, '<table><tbody>', '</tbody></table>'],
          td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
          _default: [0, '', ''],
        };
      (ge.optgroup = ge.option),
        (ge.tbody = ge.tfoot = ge.colgroup = ge.caption = ge.thead),
        (ge.th = ge.td);

      function ye(e, t) {
        var n;
        return (
          (n =
            'undefined' != typeof e.getElementsByTagName
              ? e.getElementsByTagName(t || '*')
              : 'undefined' != typeof e.querySelectorAll
              ? e.querySelectorAll(t || '*')
              : []),
          void 0 === t || (t && N(e, t)) ? w.merge([e], n) : n
        );
      }

      function ve(e, t) {
        for (var n = 0, r = e.length; n < r; n++)
          J.set(e[n], 'globalEval', !t || J.get(t[n], 'globalEval'));
      }

      var me = /<|&#?\w+;/;

      function xe(e, t, n, r, i) {
        for (
          var o,
            a,
            s,
            u,
            l,
            c,
            f = t.createDocumentFragment(),
            p = [],
            d = 0,
            h = e.length;
          d < h;
          d++
        )
          if ((o = e[d]) || 0 === o)
            if ('object' === x(o)) w.merge(p, o.nodeType ? [o] : o);
            else if (me.test(o)) {
              (a = a || f.appendChild(t.createElement('div'))),
                (s = (de.exec(o) || ['', ''])[1].toLowerCase()),
                (u = ge[s] || ge._default),
                (a.innerHTML = u[1] + w.htmlPrefilter(o) + u[2]),
                (c = u[0]);

              while (c--) a = a.lastChild;

              w.merge(p, a.childNodes), ((a = f.firstChild).textContent = '');
            } else p.push(t.createTextNode(o));

        (f.textContent = ''), (d = 0);

        while ((o = p[d++]))
          if (r && w.inArray(o, r) > -1) i && i.push(o);
          else if (
            ((l = w.contains(o.ownerDocument, o)),
            (a = ye(f.appendChild(o), 'script')),
            l && ve(a),
            n)
          ) {
            c = 0;

            while ((o = a[c++])) he.test(o.type || '') && n.push(o);
          }

        return f;
      }

      !(function() {
        var e = r.createDocumentFragment().appendChild(r.createElement('div')),
          t = r.createElement('input');
        t.setAttribute('type', 'radio'),
          t.setAttribute('checked', 'checked'),
          t.setAttribute('name', 't'),
          e.appendChild(t),
          (h.checkClone = e.cloneNode(!0).cloneNode(!0).lastChild.checked),
          (e.innerHTML = '<textarea>x</textarea>'),
          (h.noCloneChecked = !!e.cloneNode(!0).lastChild.defaultValue);
      })();
      var be = r.documentElement,
        we = /^key/,
        Te = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
        Ce = /^([^.]*)(?:\.(.+)|)/;

      function Ee() {
        return !0;
      }

      function ke() {
        return !1;
      }

      function Se() {
        try {
          return r.activeElement;
        } catch (e) {}
      }

      function De(e, t, n, r, i, o) {
        var a, s;

        if ('object' == typeof t) {
          'string' != typeof n && ((r = r || n), (n = void 0));

          for (s in t) De(e, s, n, r, t[s], o);

          return e;
        }

        if (
          (null == r && null == i
            ? ((i = n), (r = n = void 0))
            : null == i &&
              ('string' == typeof n
                ? ((i = r), (r = void 0))
                : ((i = r), (r = n), (n = void 0))),
          !1 === i)
        )
          i = ke;
        else if (!i) return e;
        return (
          1 === o &&
            ((a = i),
            ((i = function(e) {
              return w().off(e), a.apply(this, arguments);
            }).guid = a.guid || (a.guid = w.guid++))),
          e.each(function() {
            w.event.add(this, t, i, r, n);
          })
        );
      }

      (w.event = {
        global: {},
        add: function(e, t, n, r, i) {
          var o,
            a,
            s,
            u,
            l,
            c,
            f,
            p,
            d,
            h,
            g,
            y = J.get(e);

          if (y) {
            n.handler && ((n = (o = n).handler), (i = o.selector)),
              i && w.find.matchesSelector(be, i),
              n.guid || (n.guid = w.guid++),
              (u = y.events) || (u = y.events = {}),
              (a = y.handle) ||
                (a = y.handle = function(t) {
                  return 'undefined' != typeof w && w.event.triggered !== t.type
                    ? w.event.dispatch.apply(e, arguments)
                    : void 0;
                }),
              (l = (t = (t || '').match(M) || ['']).length);

            while (l--)
              (d = g = (s = Ce.exec(t[l]) || [])[1]),
                (h = (s[2] || '').split('.').sort()),
                d &&
                  ((f = w.event.special[d] || {}),
                  (d = (i ? f.delegateType : f.bindType) || d),
                  (f = w.event.special[d] || {}),
                  (c = w.extend(
                    {
                      type: d,
                      origType: g,
                      data: r,
                      handler: n,
                      guid: n.guid,
                      selector: i,
                      needsContext: i && w.expr.match.needsContext.test(i),
                      namespace: h.join('.'),
                    },
                    o
                  )),
                  (p = u[d]) ||
                    (((p = u[d] = []).delegateCount = 0),
                    (f.setup && !1 !== f.setup.call(e, r, h, a)) ||
                      (e.addEventListener && e.addEventListener(d, a))),
                  f.add &&
                    (f.add.call(e, c),
                    c.handler.guid || (c.handler.guid = n.guid)),
                  i ? p.splice(p.delegateCount++, 0, c) : p.push(c),
                  (w.event.global[d] = !0));
          }
        },
        remove: function(e, t, n, r, i) {
          var o,
            a,
            s,
            u,
            l,
            c,
            f,
            p,
            d,
            h,
            g,
            y = J.hasData(e) && J.get(e);

          if (y && (u = y.events)) {
            l = (t = (t || '').match(M) || ['']).length;

            while (l--)
              if (
                ((s = Ce.exec(t[l]) || []),
                (d = g = s[1]),
                (h = (s[2] || '').split('.').sort()),
                d)
              ) {
                (f = w.event.special[d] || {}),
                  (p = u[(d = (r ? f.delegateType : f.bindType) || d)] || []),
                  (s =
                    s[2] &&
                    new RegExp(
                      '(^|\\.)' + h.join('\\.(?:.*\\.|)') + '(\\.|$)'
                    )),
                  (a = o = p.length);

                while (o--)
                  (c = p[o]),
                    (!i && g !== c.origType) ||
                      (n && n.guid !== c.guid) ||
                      (s && !s.test(c.namespace)) ||
                      (r && r !== c.selector && ('**' !== r || !c.selector)) ||
                      (p.splice(o, 1),
                      c.selector && p.delegateCount--,
                      f.remove && f.remove.call(e, c));

                a &&
                  !p.length &&
                  ((f.teardown && !1 !== f.teardown.call(e, h, y.handle)) ||
                    w.removeEvent(e, d, y.handle),
                  delete u[d]);
              } else for (d in u) w.event.remove(e, d + t[l], n, r, !0);

            w.isEmptyObject(u) && J.remove(e, 'handle events');
          }
        },
        dispatch: function(e) {
          var t = w.event.fix(e),
            n,
            r,
            i,
            o,
            a,
            s,
            u = new Array(arguments.length),
            l = (J.get(this, 'events') || {})[t.type] || [],
            c = w.event.special[t.type] || {};

          for (u[0] = t, n = 1; n < arguments.length; n++) u[n] = arguments[n];

          if (
            ((t.delegateTarget = this),
            !c.preDispatch || !1 !== c.preDispatch.call(this, t))
          ) {
            (s = w.event.handlers.call(this, t, l)), (n = 0);

            while ((o = s[n++]) && !t.isPropagationStopped()) {
              (t.currentTarget = o.elem), (r = 0);

              while (
                (a = o.handlers[r++]) &&
                !t.isImmediatePropagationStopped()
              )
                (t.rnamespace && !t.rnamespace.test(a.namespace)) ||
                  ((t.handleObj = a),
                  (t.data = a.data),
                  void 0 !==
                    (i = (
                      (w.event.special[a.origType] || {}).handle || a.handler
                    ).apply(o.elem, u)) &&
                    !1 === (t.result = i) &&
                    (t.preventDefault(), t.stopPropagation()));
            }

            return c.postDispatch && c.postDispatch.call(this, t), t.result;
          }
        },
        handlers: function(e, t) {
          var n,
            r,
            i,
            o,
            a,
            s = [],
            u = t.delegateCount,
            l = e.target;
          if (u && l.nodeType && !('click' === e.type && e.button >= 1))
            for (; l !== this; l = l.parentNode || this)
              if (
                1 === l.nodeType &&
                ('click' !== e.type || !0 !== l.disabled)
              ) {
                for (o = [], a = {}, n = 0; n < u; n++)
                  void 0 === a[(i = (r = t[n]).selector + ' ')] &&
                    (a[i] = r.needsContext
                      ? w(i, this).index(l) > -1
                      : w.find(i, this, null, [l]).length),
                    a[i] && o.push(r);

                o.length &&
                  s.push({
                    elem: l,
                    handlers: o,
                  });
              }
          return (
            (l = this),
            u < t.length &&
              s.push({
                elem: l,
                handlers: t.slice(u),
              }),
            s
          );
        },
        addProp: function(e, t) {
          Object.defineProperty(w.Event.prototype, e, {
            enumerable: !0,
            configurable: !0,
            get: g(t)
              ? function() {
                  if (this.originalEvent) return t(this.originalEvent);
                }
              : function() {
                  if (this.originalEvent) return this.originalEvent[e];
                },
            set: function(t) {
              Object.defineProperty(this, e, {
                enumerable: !0,
                configurable: !0,
                writable: !0,
                value: t,
              });
            },
          });
        },
        fix: function(e) {
          return e[w.expando] ? e : new w.Event(e);
        },
        special: {
          load: {
            noBubble: !0,
          },
          focus: {
            trigger: function() {
              if (this !== Se() && this.focus) return this.focus(), !1;
            },
            delegateType: 'focusin',
          },
          blur: {
            trigger: function() {
              if (this === Se() && this.blur) return this.blur(), !1;
            },
            delegateType: 'focusout',
          },
          click: {
            trigger: function() {
              if ('checkbox' === this.type && this.click && N(this, 'input'))
                return this.click(), !1;
            },
            _default: function(e) {
              return N(e.target, 'a');
            },
          },
          beforeunload: {
            postDispatch: function(e) {
              void 0 !== e.result &&
                e.originalEvent &&
                (e.originalEvent.returnValue = e.result);
            },
          },
        },
      }),
        (w.removeEvent = function(e, t, n) {
          e.removeEventListener && e.removeEventListener(t, n);
        }),
        (w.Event = function(e, t) {
          if (!(this instanceof w.Event)) return new w.Event(e, t);
          e && e.type
            ? ((this.originalEvent = e),
              (this.type = e.type),
              (this.isDefaultPrevented =
                e.defaultPrevented ||
                (void 0 === e.defaultPrevented && !1 === e.returnValue)
                  ? Ee
                  : ke),
              (this.target =
                e.target && 3 === e.target.nodeType
                  ? e.target.parentNode
                  : e.target),
              (this.currentTarget = e.currentTarget),
              (this.relatedTarget = e.relatedTarget))
            : (this.type = e),
            t && w.extend(this, t),
            (this.timeStamp = (e && e.timeStamp) || Date.now()),
            (this[w.expando] = !0);
        }),
        (w.Event.prototype = {
          constructor: w.Event,
          isDefaultPrevented: ke,
          isPropagationStopped: ke,
          isImmediatePropagationStopped: ke,
          isSimulated: !1,
          preventDefault: function() {
            var e = this.originalEvent;
            (this.isDefaultPrevented = Ee),
              e && !this.isSimulated && e.preventDefault();
          },
          stopPropagation: function() {
            var e = this.originalEvent;
            (this.isPropagationStopped = Ee),
              e && !this.isSimulated && e.stopPropagation();
          },
          stopImmediatePropagation: function() {
            var e = this.originalEvent;
            (this.isImmediatePropagationStopped = Ee),
              e && !this.isSimulated && e.stopImmediatePropagation(),
              this.stopPropagation();
          },
        }),
        w.each(
          {
            altKey: !0,
            bubbles: !0,
            cancelable: !0,
            changedTouches: !0,
            ctrlKey: !0,
            detail: !0,
            eventPhase: !0,
            metaKey: !0,
            pageX: !0,
            pageY: !0,
            shiftKey: !0,
            view: !0,
            char: !0,
            charCode: !0,
            key: !0,
            keyCode: !0,
            button: !0,
            buttons: !0,
            clientX: !0,
            clientY: !0,
            offsetX: !0,
            offsetY: !0,
            pointerId: !0,
            pointerType: !0,
            screenX: !0,
            screenY: !0,
            targetTouches: !0,
            toElement: !0,
            touches: !0,
            which: function(e) {
              var t = e.button;
              return null == e.which && we.test(e.type)
                ? null != e.charCode
                  ? e.charCode
                  : e.keyCode
                : !e.which && void 0 !== t && Te.test(e.type)
                ? 1 & t
                  ? 1
                  : 2 & t
                  ? 3
                  : 4 & t
                  ? 2
                  : 0
                : e.which;
            },
          },
          w.event.addProp
        ),
        w.each(
          {
            mouseenter: 'mouseover',
            mouseleave: 'mouseout',
            pointerenter: 'pointerover',
            pointerleave: 'pointerout',
          },
          function(e, t) {
            w.event.special[e] = {
              delegateType: t,
              bindType: t,
              handle: function(e) {
                var n,
                  r = this,
                  i = e.relatedTarget,
                  o = e.handleObj;
                return (
                  (i && (i === r || w.contains(r, i))) ||
                    ((e.type = o.origType),
                    (n = o.handler.apply(this, arguments)),
                    (e.type = t)),
                  n
                );
              },
            };
          }
        ),
        w.fn.extend({
          on: function(e, t, n, r) {
            return De(this, e, t, n, r);
          },
          one: function(e, t, n, r) {
            return De(this, e, t, n, r, 1);
          },
          off: function(e, t, n) {
            var r, i;
            if (e && e.preventDefault && e.handleObj)
              return (
                (r = e.handleObj),
                w(e.delegateTarget).off(
                  r.namespace ? r.origType + '.' + r.namespace : r.origType,
                  r.selector,
                  r.handler
                ),
                this
              );

            if ('object' == typeof e) {
              for (i in e) this.off(i, t, e[i]);

              return this;
            }

            return (
              (!1 !== t && 'function' != typeof t) || ((n = t), (t = void 0)),
              !1 === n && (n = ke),
              this.each(function() {
                w.event.remove(this, e, n, t);
              })
            );
          },
        });
      var Ne = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
        Ae = /<script|<style|<link/i,
        je = /checked\s*(?:[^=]|=\s*.checked.)/i,
        qe = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;

      function Le(e, t) {
        return N(e, 'table') && N(11 !== t.nodeType ? t : t.firstChild, 'tr')
          ? w(e).children('tbody')[0] || e
          : e;
      }

      function He(e) {
        return (e.type = (null !== e.getAttribute('type')) + '/' + e.type), e;
      }

      function Oe(e) {
        return (
          'true/' === (e.type || '').slice(0, 5)
            ? (e.type = e.type.slice(5))
            : e.removeAttribute('type'),
          e
        );
      }

      function Pe(e, t) {
        var n, r, i, o, a, s, u, l;

        if (1 === t.nodeType) {
          if (
            J.hasData(e) &&
            ((o = J.access(e)), (a = J.set(t, o)), (l = o.events))
          ) {
            delete a.handle, (a.events = {});

            for (i in l)
              for (n = 0, r = l[i].length; n < r; n++)
                w.event.add(t, i, l[i][n]);
          }

          K.hasData(e) &&
            ((s = K.access(e)), (u = w.extend({}, s)), K.set(t, u));
        }
      }

      function Me(e, t) {
        var n = t.nodeName.toLowerCase();
        'input' === n && pe.test(e.type)
          ? (t.checked = e.checked)
          : ('input' !== n && 'textarea' !== n) ||
            (t.defaultValue = e.defaultValue);
      }

      function Re(e, t, n, r) {
        t = a.apply([], t);
        var i,
          o,
          s,
          u,
          l,
          c,
          f = 0,
          p = e.length,
          d = p - 1,
          y = t[0],
          v = g(y);
        if (v || (p > 1 && 'string' == typeof y && !h.checkClone && je.test(y)))
          return e.each(function(i) {
            var o = e.eq(i);
            v && (t[0] = y.call(this, i, o.html())), Re(o, t, n, r);
          });

        if (
          p &&
          ((i = xe(t, e[0].ownerDocument, !1, e, r)),
          (o = i.firstChild),
          1 === i.childNodes.length && (i = o),
          o || r)
        ) {
          for (u = (s = w.map(ye(i, 'script'), He)).length; f < p; f++)
            (l = i),
              f !== d &&
                ((l = w.clone(l, !0, !0)), u && w.merge(s, ye(l, 'script'))),
              n.call(e[f], l, f);

          if (u)
            for (
              c = s[s.length - 1].ownerDocument, w.map(s, Oe), f = 0;
              f < u;
              f++
            )
              (l = s[f]),
                he.test(l.type || '') &&
                  !J.access(l, 'globalEval') &&
                  w.contains(c, l) &&
                  (l.src && 'module' !== (l.type || '').toLowerCase()
                    ? w._evalUrl && w._evalUrl(l.src)
                    : m(l.textContent.replace(qe, ''), c, l));
        }

        return e;
      }

      function Ie(e, t, n) {
        for (var r, i = t ? w.filter(t, e) : e, o = 0; null != (r = i[o]); o++)
          n || 1 !== r.nodeType || w.cleanData(ye(r)),
            r.parentNode &&
              (n && w.contains(r.ownerDocument, r) && ve(ye(r, 'script')),
              r.parentNode.removeChild(r));

        return e;
      }

      w.extend({
        htmlPrefilter: function(e) {
          return e.replace(Ne, '<$1></$2>');
        },
        clone: function(e, t, n) {
          var r,
            i,
            o,
            a,
            s = e.cloneNode(!0),
            u = w.contains(e.ownerDocument, e);
          if (
            !(
              h.noCloneChecked ||
              (1 !== e.nodeType && 11 !== e.nodeType) ||
              w.isXMLDoc(e)
            )
          )
            for (a = ye(s), r = 0, i = (o = ye(e)).length; r < i; r++)
              Me(o[r], a[r]);
          if (t)
            if (n)
              for (
                o = o || ye(e), a = a || ye(s), r = 0, i = o.length;
                r < i;
                r++
              )
                Pe(o[r], a[r]);
            else Pe(e, s);
          return (
            (a = ye(s, 'script')).length > 0 && ve(a, !u && ye(e, 'script')), s
          );
        },
        cleanData: function(e) {
          for (
            var t, n, r, i = w.event.special, o = 0;
            void 0 !== (n = e[o]);
            o++
          )
            if (Y(n)) {
              if ((t = n[J.expando])) {
                if (t.events)
                  for (r in t.events)
                    i[r] ? w.event.remove(n, r) : w.removeEvent(n, r, t.handle);
                n[J.expando] = void 0;
              }

              n[K.expando] && (n[K.expando] = void 0);
            }
        },
      }),
        w.fn.extend({
          detach: function(e) {
            return Ie(this, e, !0);
          },
          remove: function(e) {
            return Ie(this, e);
          },
          text: function(e) {
            return z(
              this,
              function(e) {
                return void 0 === e
                  ? w.text(this)
                  : this.empty().each(function() {
                      (1 !== this.nodeType &&
                        11 !== this.nodeType &&
                        9 !== this.nodeType) ||
                        (this.textContent = e);
                    });
              },
              null,
              e,
              arguments.length
            );
          },
          append: function() {
            return Re(this, arguments, function(e) {
              (1 !== this.nodeType &&
                11 !== this.nodeType &&
                9 !== this.nodeType) ||
                Le(this, e).appendChild(e);
            });
          },
          prepend: function() {
            return Re(this, arguments, function(e) {
              if (
                1 === this.nodeType ||
                11 === this.nodeType ||
                9 === this.nodeType
              ) {
                var t = Le(this, e);
                t.insertBefore(e, t.firstChild);
              }
            });
          },
          before: function() {
            return Re(this, arguments, function(e) {
              this.parentNode && this.parentNode.insertBefore(e, this);
            });
          },
          after: function() {
            return Re(this, arguments, function(e) {
              this.parentNode &&
                this.parentNode.insertBefore(e, this.nextSibling);
            });
          },
          empty: function() {
            for (var e, t = 0; null != (e = this[t]); t++)
              1 === e.nodeType &&
                (w.cleanData(ye(e, !1)), (e.textContent = ''));

            return this;
          },
          clone: function(e, t) {
            return (
              (e = null != e && e),
              (t = null == t ? e : t),
              this.map(function() {
                return w.clone(this, e, t);
              })
            );
          },
          html: function(e) {
            return z(
              this,
              function(e) {
                var t = this[0] || {},
                  n = 0,
                  r = this.length;
                if (void 0 === e && 1 === t.nodeType) return t.innerHTML;

                if (
                  'string' == typeof e &&
                  !Ae.test(e) &&
                  !ge[(de.exec(e) || ['', ''])[1].toLowerCase()]
                ) {
                  e = w.htmlPrefilter(e);

                  try {
                    for (; n < r; n++)
                      1 === (t = this[n] || {}).nodeType &&
                        (w.cleanData(ye(t, !1)), (t.innerHTML = e));

                    t = 0;
                  } catch (e) {}
                }

                t && this.empty().append(e);
              },
              null,
              e,
              arguments.length
            );
          },
          replaceWith: function() {
            var e = [];
            return Re(
              this,
              arguments,
              function(t) {
                var n = this.parentNode;
                w.inArray(this, e) < 0 &&
                  (w.cleanData(ye(this)), n && n.replaceChild(t, this));
              },
              e
            );
          },
        }),
        w.each(
          {
            appendTo: 'append',
            prependTo: 'prepend',
            insertBefore: 'before',
            insertAfter: 'after',
            replaceAll: 'replaceWith',
          },
          function(e, t) {
            w.fn[e] = function(e) {
              for (
                var n, r = [], i = w(e), o = i.length - 1, a = 0;
                a <= o;
                a++
              )
                (n = a === o ? this : this.clone(!0)),
                  w(i[a])[t](n),
                  s.apply(r, n.get());

              return this.pushStack(r);
            };
          }
        );

      var We = new RegExp('^(' + re + ')(?!px)[a-z%]+$', 'i'),
        $e = function(t) {
          var n = t.ownerDocument.defaultView;
          return (n && n.opener) || (n = e), n.getComputedStyle(t);
        },
        Be = new RegExp(oe.join('|'), 'i');

      !(function() {
        function t() {
          if (c) {
            (l.style.cssText =
              'position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0'),
              (c.style.cssText =
                'position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%'),
              be.appendChild(l).appendChild(c);
            var t = e.getComputedStyle(c);
            (i = '1%' !== t.top),
              (u = 12 === n(t.marginLeft)),
              (c.style.right = '60%'),
              (s = 36 === n(t.right)),
              (o = 36 === n(t.width)),
              (c.style.position = 'absolute'),
              (a = 36 === c.offsetWidth || 'absolute'),
              be.removeChild(l),
              (c = null);
          }
        }

        function n(e) {
          return Math.round(parseFloat(e));
        }

        var i,
          o,
          a,
          s,
          u,
          l = r.createElement('div'),
          c = r.createElement('div');
        c.style &&
          ((c.style.backgroundClip = 'content-box'),
          (c.cloneNode(!0).style.backgroundClip = ''),
          (h.clearCloneStyle = 'content-box' === c.style.backgroundClip),
          w.extend(h, {
            boxSizingReliable: function() {
              return t(), o;
            },
            pixelBoxStyles: function() {
              return t(), s;
            },
            pixelPosition: function() {
              return t(), i;
            },
            reliableMarginLeft: function() {
              return t(), u;
            },
            scrollboxSize: function() {
              return t(), a;
            },
          }));
      })();

      function Fe(e, t, n) {
        var r,
          i,
          o,
          a,
          s = e.style;
        return (
          (n = n || $e(e)) &&
            ('' !== (a = n.getPropertyValue(t) || n[t]) ||
              w.contains(e.ownerDocument, e) ||
              (a = w.style(e, t)),
            !h.pixelBoxStyles() &&
              We.test(a) &&
              Be.test(t) &&
              ((r = s.width),
              (i = s.minWidth),
              (o = s.maxWidth),
              (s.minWidth = s.maxWidth = s.width = a),
              (a = n.width),
              (s.width = r),
              (s.minWidth = i),
              (s.maxWidth = o))),
          void 0 !== a ? a + '' : a
        );
      }

      function _e(e, t) {
        return {
          get: function() {
            if (!e()) return (this.get = t).apply(this, arguments);
            delete this.get;
          },
        };
      }

      var ze = /^(none|table(?!-c[ea]).+)/,
        Xe = /^--/,
        Ue = {
          position: 'absolute',
          visibility: 'hidden',
          display: 'block',
        },
        Ve = {
          letterSpacing: '0',
          fontWeight: '400',
        },
        Ge = ['Webkit', 'Moz', 'ms'],
        Ye = r.createElement('div').style;

      function Qe(e) {
        if (e in Ye) return e;
        var t = e[0].toUpperCase() + e.slice(1),
          n = Ge.length;

        while (n--) if ((e = Ge[n] + t) in Ye) return e;
      }

      function Je(e) {
        var t = w.cssProps[e];
        return t || (t = w.cssProps[e] = Qe(e) || e), t;
      }

      function Ke(e, t, n) {
        var r = ie.exec(t);
        return r ? Math.max(0, r[2] - (n || 0)) + (r[3] || 'px') : t;
      }

      function Ze(e, t, n, r, i, o) {
        var a = 'width' === t ? 1 : 0,
          s = 0,
          u = 0;
        if (n === (r ? 'border' : 'content')) return 0;

        for (; a < 4; a += 2)
          'margin' === n && (u += w.css(e, n + oe[a], !0, i)),
            r
              ? ('content' === n && (u -= w.css(e, 'padding' + oe[a], !0, i)),
                'margin' !== n &&
                  (u -= w.css(e, 'border' + oe[a] + 'Width', !0, i)))
              : ((u += w.css(e, 'padding' + oe[a], !0, i)),
                'padding' !== n
                  ? (u += w.css(e, 'border' + oe[a] + 'Width', !0, i))
                  : (s += w.css(e, 'border' + oe[a] + 'Width', !0, i)));

        return (
          !r &&
            o >= 0 &&
            (u += Math.max(
              0,
              Math.ceil(
                e['offset' + t[0].toUpperCase() + t.slice(1)] - o - u - s - 0.5
              )
            )),
          u
        );
      }

      function et(e, t, n) {
        var r = $e(e),
          i = Fe(e, t, r),
          o = 'border-box' === w.css(e, 'boxSizing', !1, r),
          a = o;

        if (We.test(i)) {
          if (!n) return i;
          i = 'auto';
        }

        return (
          (a = a && (h.boxSizingReliable() || i === e.style[t])),
          ('auto' === i ||
            (!parseFloat(i) && 'inline' === w.css(e, 'display', !1, r))) &&
            ((i = e['offset' + t[0].toUpperCase() + t.slice(1)]), (a = !0)),
          (i = parseFloat(i) || 0) +
            Ze(e, t, n || (o ? 'border' : 'content'), a, r, i) +
            'px'
        );
      }

      w.extend({
        cssHooks: {
          opacity: {
            get: function(e, t) {
              if (t) {
                var n = Fe(e, 'opacity');
                return '' === n ? '1' : n;
              }
            },
          },
        },
        cssNumber: {
          animationIterationCount: !0,
          columnCount: !0,
          fillOpacity: !0,
          flexGrow: !0,
          flexShrink: !0,
          fontWeight: !0,
          lineHeight: !0,
          opacity: !0,
          order: !0,
          orphans: !0,
          widows: !0,
          zIndex: !0,
          zoom: !0,
        },
        cssProps: {},
        style: function(e, t, n, r) {
          if (e && 3 !== e.nodeType && 8 !== e.nodeType && e.style) {
            var i,
              o,
              a,
              s = G(t),
              u = Xe.test(t),
              l = e.style;
            if (
              (u || (t = Je(s)),
              (a = w.cssHooks[t] || w.cssHooks[s]),
              void 0 === n)
            )
              return a && 'get' in a && void 0 !== (i = a.get(e, !1, r))
                ? i
                : l[t];
            'string' == (o = typeof n) &&
              (i = ie.exec(n)) &&
              i[1] &&
              ((n = ue(e, t, i)), (o = 'number')),
              null != n &&
                n === n &&
                ('number' === o &&
                  (n += (i && i[3]) || (w.cssNumber[s] ? '' : 'px')),
                h.clearCloneStyle ||
                  '' !== n ||
                  0 !== t.indexOf('background') ||
                  (l[t] = 'inherit'),
                (a && 'set' in a && void 0 === (n = a.set(e, n, r))) ||
                  (u ? l.setProperty(t, n) : (l[t] = n)));
          }
        },
        css: function(e, t, n, r) {
          var i,
            o,
            a,
            s = G(t);
          return (
            Xe.test(t) || (t = Je(s)),
            (a = w.cssHooks[t] || w.cssHooks[s]) &&
              'get' in a &&
              (i = a.get(e, !0, n)),
            void 0 === i && (i = Fe(e, t, r)),
            'normal' === i && t in Ve && (i = Ve[t]),
            '' === n || n
              ? ((o = parseFloat(i)), !0 === n || isFinite(o) ? o || 0 : i)
              : i
          );
        },
      }),
        w.each(['height', 'width'], function(e, t) {
          w.cssHooks[t] = {
            get: function(e, n, r) {
              if (n)
                return !ze.test(w.css(e, 'display')) ||
                  (e.getClientRects().length && e.getBoundingClientRect().width)
                  ? et(e, t, r)
                  : se(e, Ue, function() {
                      return et(e, t, r);
                    });
            },
            set: function(e, n, r) {
              var i,
                o = $e(e),
                a = 'border-box' === w.css(e, 'boxSizing', !1, o),
                s = r && Ze(e, t, r, a, o);
              return (
                a &&
                  h.scrollboxSize() === o.position &&
                  (s -= Math.ceil(
                    e['offset' + t[0].toUpperCase() + t.slice(1)] -
                      parseFloat(o[t]) -
                      Ze(e, t, 'border', !1, o) -
                      0.5
                  )),
                s &&
                  (i = ie.exec(n)) &&
                  'px' !== (i[3] || 'px') &&
                  ((e.style[t] = n), (n = w.css(e, t))),
                Ke(e, n, s)
              );
            },
          };
        }),
        (w.cssHooks.marginLeft = _e(h.reliableMarginLeft, function(e, t) {
          if (t)
            return (
              (parseFloat(Fe(e, 'marginLeft')) ||
                e.getBoundingClientRect().left -
                  se(
                    e,
                    {
                      marginLeft: 0,
                    },
                    function() {
                      return e.getBoundingClientRect().left;
                    }
                  )) + 'px'
            );
        })),
        w.each(
          {
            margin: '',
            padding: '',
            border: 'Width',
          },
          function(e, t) {
            (w.cssHooks[e + t] = {
              expand: function(n) {
                for (
                  var r = 0,
                    i = {},
                    o = 'string' == typeof n ? n.split(' ') : [n];
                  r < 4;
                  r++
                )
                  i[e + oe[r] + t] = o[r] || o[r - 2] || o[0];

                return i;
              },
            }),
              'margin' !== e && (w.cssHooks[e + t].set = Ke);
          }
        ),
        w.fn.extend({
          css: function(e, t) {
            return z(
              this,
              function(e, t, n) {
                var r,
                  i,
                  o = {},
                  a = 0;

                if (Array.isArray(t)) {
                  for (r = $e(e), i = t.length; a < i; a++)
                    o[t[a]] = w.css(e, t[a], !1, r);

                  return o;
                }

                return void 0 !== n ? w.style(e, t, n) : w.css(e, t);
              },
              e,
              t,
              arguments.length > 1
            );
          },
        });

      function tt(e, t, n, r, i) {
        return new tt.prototype.init(e, t, n, r, i);
      }

      (w.Tween = tt),
        (tt.prototype = {
          constructor: tt,
          init: function(e, t, n, r, i, o) {
            (this.elem = e),
              (this.prop = n),
              (this.easing = i || w.easing._default),
              (this.options = t),
              (this.start = this.now = this.cur()),
              (this.end = r),
              (this.unit = o || (w.cssNumber[n] ? '' : 'px'));
          },
          cur: function() {
            var e = tt.propHooks[this.prop];
            return e && e.get ? e.get(this) : tt.propHooks._default.get(this);
          },
          run: function(e) {
            var t,
              n = tt.propHooks[this.prop];
            return (
              this.options.duration
                ? (this.pos = t = w.easing[this.easing](
                    e,
                    this.options.duration * e,
                    0,
                    1,
                    this.options.duration
                  ))
                : (this.pos = t = e),
              (this.now = (this.end - this.start) * t + this.start),
              this.options.step &&
                this.options.step.call(this.elem, this.now, this),
              n && n.set ? n.set(this) : tt.propHooks._default.set(this),
              this
            );
          },
        }),
        (tt.prototype.init.prototype = tt.prototype),
        (tt.propHooks = {
          _default: {
            get: function(e) {
              var t;
              return 1 !== e.elem.nodeType ||
                (null != e.elem[e.prop] && null == e.elem.style[e.prop])
                ? e.elem[e.prop]
                : (t = w.css(e.elem, e.prop, '')) && 'auto' !== t
                ? t
                : 0;
            },
            set: function(e) {
              w.fx.step[e.prop]
                ? w.fx.step[e.prop](e)
                : 1 !== e.elem.nodeType ||
                  (null == e.elem.style[w.cssProps[e.prop]] &&
                    !w.cssHooks[e.prop])
                ? (e.elem[e.prop] = e.now)
                : w.style(e.elem, e.prop, e.now + e.unit);
            },
          },
        }),
        (tt.propHooks.scrollTop = tt.propHooks.scrollLeft = {
          set: function(e) {
            e.elem.nodeType && e.elem.parentNode && (e.elem[e.prop] = e.now);
          },
        }),
        (w.easing = {
          linear: function(e) {
            return e;
          },
          swing: function(e) {
            return 0.5 - Math.cos(e * Math.PI) / 2;
          },
          _default: 'swing',
        }),
        (w.fx = tt.prototype.init),
        (w.fx.step = {});
      var nt,
        rt,
        it = /^(?:toggle|show|hide)$/,
        ot = /queueHooks$/;

      function at() {
        rt &&
          (!1 === r.hidden && e.requestAnimationFrame
            ? e.requestAnimationFrame(at)
            : e.setTimeout(at, w.fx.interval),
          w.fx.tick());
      }

      function st() {
        return (
          e.setTimeout(function() {
            nt = void 0;
          }),
          (nt = Date.now())
        );
      }

      function ut(e, t) {
        var n,
          r = 0,
          i = {
            height: e,
          };

        for (t = t ? 1 : 0; r < 4; r += 2 - t)
          i['margin' + (n = oe[r])] = i['padding' + n] = e;

        return t && (i.opacity = i.width = e), i;
      }

      function lt(e, t, n) {
        for (
          var r,
            i = (pt.tweeners[t] || []).concat(pt.tweeners['*']),
            o = 0,
            a = i.length;
          o < a;
          o++
        )
          if ((r = i[o].call(n, t, e))) return r;
      }

      function ct(e, t, n) {
        var r,
          i,
          o,
          a,
          s,
          u,
          l,
          c,
          f = 'width' in t || 'height' in t,
          p = this,
          d = {},
          h = e.style,
          g = e.nodeType && ae(e),
          y = J.get(e, 'fxshow');
        n.queue ||
          (null == (a = w._queueHooks(e, 'fx')).unqueued &&
            ((a.unqueued = 0),
            (s = a.empty.fire),
            (a.empty.fire = function() {
              a.unqueued || s();
            })),
          a.unqueued++,
          p.always(function() {
            p.always(function() {
              a.unqueued--, w.queue(e, 'fx').length || a.empty.fire();
            });
          }));

        for (r in t)
          if (((i = t[r]), it.test(i))) {
            if (
              (delete t[r],
              (o = o || 'toggle' === i),
              i === (g ? 'hide' : 'show'))
            ) {
              if ('show' !== i || !y || void 0 === y[r]) continue;
              g = !0;
            }

            d[r] = (y && y[r]) || w.style(e, r);
          }

        if ((u = !w.isEmptyObject(t)) || !w.isEmptyObject(d)) {
          f &&
            1 === e.nodeType &&
            ((n.overflow = [h.overflow, h.overflowX, h.overflowY]),
            null == (l = y && y.display) && (l = J.get(e, 'display')),
            'none' === (c = w.css(e, 'display')) &&
              (l
                ? (c = l)
                : (fe([e], !0),
                  (l = e.style.display || l),
                  (c = w.css(e, 'display')),
                  fe([e]))),
            ('inline' === c || ('inline-block' === c && null != l)) &&
              'none' === w.css(e, 'float') &&
              (u ||
                (p.done(function() {
                  h.display = l;
                }),
                null == l && ((c = h.display), (l = 'none' === c ? '' : c))),
              (h.display = 'inline-block'))),
            n.overflow &&
              ((h.overflow = 'hidden'),
              p.always(function() {
                (h.overflow = n.overflow[0]),
                  (h.overflowX = n.overflow[1]),
                  (h.overflowY = n.overflow[2]);
              })),
            (u = !1);

          for (r in d)
            u ||
              (y
                ? 'hidden' in y && (g = y.hidden)
                : (y = J.access(e, 'fxshow', {
                    display: l,
                  })),
              o && (y.hidden = !g),
              g && fe([e], !0),
              p.done(function() {
                g || fe([e]), J.remove(e, 'fxshow');

                for (r in d) w.style(e, r, d[r]);
              })),
              (u = lt(g ? y[r] : 0, r, p)),
              r in y ||
                ((y[r] = u.start), g && ((u.end = u.start), (u.start = 0)));
        }
      }

      function ft(e, t) {
        var n, r, i, o, a;

        for (n in e)
          if (
            ((r = G(n)),
            (i = t[r]),
            (o = e[n]),
            Array.isArray(o) && ((i = o[1]), (o = e[n] = o[0])),
            n !== r && ((e[r] = o), delete e[n]),
            (a = w.cssHooks[r]) && 'expand' in a)
          ) {
            (o = a.expand(o)), delete e[r];

            for (n in o) n in e || ((e[n] = o[n]), (t[n] = i));
          } else t[r] = i;
      }

      function pt(e, t, n) {
        var r,
          i,
          o = 0,
          a = pt.prefilters.length,
          s = w.Deferred().always(function() {
            delete u.elem;
          }),
          u = function() {
            if (i) return !1;

            for (
              var t = nt || st(),
                n = Math.max(0, l.startTime + l.duration - t),
                r = 1 - (n / l.duration || 0),
                o = 0,
                a = l.tweens.length;
              o < a;
              o++
            )
              l.tweens[o].run(r);

            return (
              s.notifyWith(e, [l, r, n]),
              r < 1 && a
                ? n
                : (a || s.notifyWith(e, [l, 1, 0]), s.resolveWith(e, [l]), !1)
            );
          },
          l = s.promise({
            elem: e,
            props: w.extend({}, t),
            opts: w.extend(
              !0,
              {
                specialEasing: {},
                easing: w.easing._default,
              },
              n
            ),
            originalProperties: t,
            originalOptions: n,
            startTime: nt || st(),
            duration: n.duration,
            tweens: [],
            createTween: function(t, n) {
              var r = w.Tween(
                e,
                l.opts,
                t,
                n,
                l.opts.specialEasing[t] || l.opts.easing
              );
              return l.tweens.push(r), r;
            },
            stop: function(t) {
              var n = 0,
                r = t ? l.tweens.length : 0;
              if (i) return this;

              for (i = !0; n < r; n++) l.tweens[n].run(1);

              return (
                t
                  ? (s.notifyWith(e, [l, 1, 0]), s.resolveWith(e, [l, t]))
                  : s.rejectWith(e, [l, t]),
                this
              );
            },
          }),
          c = l.props;

        for (ft(c, l.opts.specialEasing); o < a; o++)
          if ((r = pt.prefilters[o].call(l, e, c, l.opts)))
            return (
              g(r.stop) &&
                (w._queueHooks(l.elem, l.opts.queue).stop = r.stop.bind(r)),
              r
            );

        return (
          w.map(c, lt, l),
          g(l.opts.start) && l.opts.start.call(e, l),
          l
            .progress(l.opts.progress)
            .done(l.opts.done, l.opts.complete)
            .fail(l.opts.fail)
            .always(l.opts.always),
          w.fx.timer(
            w.extend(u, {
              elem: e,
              anim: l,
              queue: l.opts.queue,
            })
          ),
          l
        );
      }

      (w.Animation = w.extend(pt, {
        tweeners: {
          '*': [
            function(e, t) {
              var n = this.createTween(e, t);
              return ue(n.elem, e, ie.exec(t), n), n;
            },
          ],
        },
        tweener: function(e, t) {
          g(e) ? ((t = e), (e = ['*'])) : (e = e.match(M));

          for (var n, r = 0, i = e.length; r < i; r++)
            (n = e[r]),
              (pt.tweeners[n] = pt.tweeners[n] || []),
              pt.tweeners[n].unshift(t);
        },
        prefilters: [ct],
        prefilter: function(e, t) {
          t ? pt.prefilters.unshift(e) : pt.prefilters.push(e);
        },
      })),
        (w.speed = function(e, t, n) {
          var r =
            e && 'object' == typeof e
              ? w.extend({}, e)
              : {
                  complete: n || (!n && t) || (g(e) && e),
                  duration: e,
                  easing: (n && t) || (t && !g(t) && t),
                };
          return (
            w.fx.off
              ? (r.duration = 0)
              : 'number' != typeof r.duration &&
                (r.duration in w.fx.speeds
                  ? (r.duration = w.fx.speeds[r.duration])
                  : (r.duration = w.fx.speeds._default)),
            (null != r.queue && !0 !== r.queue) || (r.queue = 'fx'),
            (r.old = r.complete),
            (r.complete = function() {
              g(r.old) && r.old.call(this), r.queue && w.dequeue(this, r.queue);
            }),
            r
          );
        }),
        w.fn.extend({
          fadeTo: function(e, t, n, r) {
            return this.filter(ae)
              .css('opacity', 0)
              .show()
              .end()
              .animate(
                {
                  opacity: t,
                },
                e,
                n,
                r
              );
          },
          animate: function(e, t, n, r) {
            var i = w.isEmptyObject(e),
              o = w.speed(t, n, r),
              a = function() {
                var t = pt(this, w.extend({}, e), o);
                (i || J.get(this, 'finish')) && t.stop(!0);
              };

            return (
              (a.finish = a),
              i || !1 === o.queue ? this.each(a) : this.queue(o.queue, a)
            );
          },
          stop: function(e, t, n) {
            var r = function(e) {
              var t = e.stop;
              delete e.stop, t(n);
            };

            return (
              'string' != typeof e && ((n = t), (t = e), (e = void 0)),
              t && !1 !== e && this.queue(e || 'fx', []),
              this.each(function() {
                var t = !0,
                  i = null != e && e + 'queueHooks',
                  o = w.timers,
                  a = J.get(this);
                if (i) a[i] && a[i].stop && r(a[i]);
                else for (i in a) a[i] && a[i].stop && ot.test(i) && r(a[i]);

                for (i = o.length; i--; )
                  o[i].elem !== this ||
                    (null != e && o[i].queue !== e) ||
                    (o[i].anim.stop(n), (t = !1), o.splice(i, 1));

                (!t && n) || w.dequeue(this, e);
              })
            );
          },
          finish: function(e) {
            return (
              !1 !== e && (e = e || 'fx'),
              this.each(function() {
                var t,
                  n = J.get(this),
                  r = n[e + 'queue'],
                  i = n[e + 'queueHooks'],
                  o = w.timers,
                  a = r ? r.length : 0;

                for (
                  n.finish = !0,
                    w.queue(this, e, []),
                    i && i.stop && i.stop.call(this, !0),
                    t = o.length;
                  t--;

                )
                  o[t].elem === this &&
                    o[t].queue === e &&
                    (o[t].anim.stop(!0), o.splice(t, 1));

                for (t = 0; t < a; t++)
                  r[t] && r[t].finish && r[t].finish.call(this);

                delete n.finish;
              })
            );
          },
        }),
        w.each(['toggle', 'show', 'hide'], function(e, t) {
          var n = w.fn[t];

          w.fn[t] = function(e, r, i) {
            return null == e || 'boolean' == typeof e
              ? n.apply(this, arguments)
              : this.animate(ut(t, !0), e, r, i);
          };
        }),
        w.each(
          {
            slideDown: ut('show'),
            slideUp: ut('hide'),
            slideToggle: ut('toggle'),
            fadeIn: {
              opacity: 'show',
            },
            fadeOut: {
              opacity: 'hide',
            },
            fadeToggle: {
              opacity: 'toggle',
            },
          },
          function(e, t) {
            w.fn[e] = function(e, n, r) {
              return this.animate(t, e, n, r);
            };
          }
        ),
        (w.timers = []),
        (w.fx.tick = function() {
          var e,
            t = 0,
            n = w.timers;

          for (nt = Date.now(); t < n.length; t++)
            (e = n[t])() || n[t] !== e || n.splice(t--, 1);

          n.length || w.fx.stop(), (nt = void 0);
        }),
        (w.fx.timer = function(e) {
          w.timers.push(e), w.fx.start();
        }),
        (w.fx.interval = 13),
        (w.fx.start = function() {
          rt || ((rt = !0), at());
        }),
        (w.fx.stop = function() {
          rt = null;
        }),
        (w.fx.speeds = {
          slow: 600,
          fast: 200,
          _default: 400,
        }),
        (w.fn.delay = function(t, n) {
          return (
            (t = w.fx ? w.fx.speeds[t] || t : t),
            (n = n || 'fx'),
            this.queue(n, function(n, r) {
              var i = e.setTimeout(n, t);

              r.stop = function() {
                e.clearTimeout(i);
              };
            })
          );
        }),
        (function() {
          var e = r.createElement('input'),
            t = r
              .createElement('select')
              .appendChild(r.createElement('option'));
          (e.type = 'checkbox'),
            (h.checkOn = '' !== e.value),
            (h.optSelected = t.selected),
            ((e = r.createElement('input')).value = 't'),
            (e.type = 'radio'),
            (h.radioValue = 't' === e.value);
        })();
      var dt,
        ht = w.expr.attrHandle;
      w.fn.extend({
        attr: function(e, t) {
          return z(this, w.attr, e, t, arguments.length > 1);
        },
        removeAttr: function(e) {
          return this.each(function() {
            w.removeAttr(this, e);
          });
        },
      }),
        w.extend({
          attr: function(e, t, n) {
            var r,
              i,
              o = e.nodeType;
            if (3 !== o && 8 !== o && 2 !== o)
              return 'undefined' == typeof e.getAttribute
                ? w.prop(e, t, n)
                : ((1 === o && w.isXMLDoc(e)) ||
                    (i =
                      w.attrHooks[t.toLowerCase()] ||
                      (w.expr.match.bool.test(t) ? dt : void 0)),
                  void 0 !== n
                    ? null === n
                      ? void w.removeAttr(e, t)
                      : i && 'set' in i && void 0 !== (r = i.set(e, n, t))
                      ? r
                      : (e.setAttribute(t, n + ''), n)
                    : i && 'get' in i && null !== (r = i.get(e, t))
                    ? r
                    : null == (r = w.find.attr(e, t))
                    ? void 0
                    : r);
          },
          attrHooks: {
            type: {
              set: function(e, t) {
                if (!h.radioValue && 'radio' === t && N(e, 'input')) {
                  var n = e.value;
                  return e.setAttribute('type', t), n && (e.value = n), t;
                }
              },
            },
          },
          removeAttr: function(e, t) {
            var n,
              r = 0,
              i = t && t.match(M);
            if (i && 1 === e.nodeType)
              while ((n = i[r++])) e.removeAttribute(n);
          },
        }),
        (dt = {
          set: function(e, t, n) {
            return !1 === t ? w.removeAttr(e, n) : e.setAttribute(n, n), n;
          },
        }),
        w.each(w.expr.match.bool.source.match(/\w+/g), function(e, t) {
          var n = ht[t] || w.find.attr;

          ht[t] = function(e, t, r) {
            var i,
              o,
              a = t.toLowerCase();
            return (
              r ||
                ((o = ht[a]),
                (ht[a] = i),
                (i = null != n(e, t, r) ? a : null),
                (ht[a] = o)),
              i
            );
          };
        });
      var gt = /^(?:input|select|textarea|button)$/i,
        yt = /^(?:a|area)$/i;
      w.fn.extend({
        prop: function(e, t) {
          return z(this, w.prop, e, t, arguments.length > 1);
        },
        removeProp: function(e) {
          return this.each(function() {
            delete this[w.propFix[e] || e];
          });
        },
      }),
        w.extend({
          prop: function(e, t, n) {
            var r,
              i,
              o = e.nodeType;
            if (3 !== o && 8 !== o && 2 !== o)
              return (
                (1 === o && w.isXMLDoc(e)) ||
                  ((t = w.propFix[t] || t), (i = w.propHooks[t])),
                void 0 !== n
                  ? i && 'set' in i && void 0 !== (r = i.set(e, n, t))
                    ? r
                    : (e[t] = n)
                  : i && 'get' in i && null !== (r = i.get(e, t))
                  ? r
                  : e[t]
              );
          },
          propHooks: {
            tabIndex: {
              get: function(e) {
                var t = w.find.attr(e, 'tabindex');
                return t
                  ? parseInt(t, 10)
                  : gt.test(e.nodeName) || (yt.test(e.nodeName) && e.href)
                  ? 0
                  : -1;
              },
            },
          },
          propFix: {
            for: 'htmlFor',
            class: 'className',
          },
        }),
        h.optSelected ||
          (w.propHooks.selected = {
            get: function(e) {
              var t = e.parentNode;
              return t && t.parentNode && t.parentNode.selectedIndex, null;
            },
            set: function(e) {
              var t = e.parentNode;
              t &&
                (t.selectedIndex, t.parentNode && t.parentNode.selectedIndex);
            },
          }),
        w.each(
          [
            'tabIndex',
            'readOnly',
            'maxLength',
            'cellSpacing',
            'cellPadding',
            'rowSpan',
            'colSpan',
            'useMap',
            'frameBorder',
            'contentEditable',
          ],
          function() {
            w.propFix[this.toLowerCase()] = this;
          }
        );

      function vt(e) {
        return (e.match(M) || []).join(' ');
      }

      function mt(e) {
        return (e.getAttribute && e.getAttribute('class')) || '';
      }

      function xt(e) {
        return Array.isArray(e)
          ? e
          : 'string' == typeof e
          ? e.match(M) || []
          : [];
      }

      w.fn.extend({
        addClass: function(e) {
          var t,
            n,
            r,
            i,
            o,
            a,
            s,
            u = 0;
          if (g(e))
            return this.each(function(t) {
              w(this).addClass(e.call(this, t, mt(this)));
            });
          if ((t = xt(e)).length)
            while ((n = this[u++]))
              if (((i = mt(n)), (r = 1 === n.nodeType && ' ' + vt(i) + ' '))) {
                a = 0;

                while ((o = t[a++]))
                  r.indexOf(' ' + o + ' ') < 0 && (r += o + ' ');

                i !== (s = vt(r)) && n.setAttribute('class', s);
              }
          return this;
        },
        removeClass: function(e) {
          var t,
            n,
            r,
            i,
            o,
            a,
            s,
            u = 0;
          if (g(e))
            return this.each(function(t) {
              w(this).removeClass(e.call(this, t, mt(this)));
            });
          if (!arguments.length) return this.attr('class', '');
          if ((t = xt(e)).length)
            while ((n = this[u++]))
              if (((i = mt(n)), (r = 1 === n.nodeType && ' ' + vt(i) + ' '))) {
                a = 0;

                while ((o = t[a++]))
                  while (r.indexOf(' ' + o + ' ') > -1)
                    r = r.replace(' ' + o + ' ', ' ');

                i !== (s = vt(r)) && n.setAttribute('class', s);
              }
          return this;
        },
        toggleClass: function(e, t) {
          var n = typeof e,
            r = 'string' === n || Array.isArray(e);
          return 'boolean' == typeof t && r
            ? t
              ? this.addClass(e)
              : this.removeClass(e)
            : g(e)
            ? this.each(function(n) {
                w(this).toggleClass(e.call(this, n, mt(this), t), t);
              })
            : this.each(function() {
                var t, i, o, a;

                if (r) {
                  (i = 0), (o = w(this)), (a = xt(e));

                  while ((t = a[i++]))
                    o.hasClass(t) ? o.removeClass(t) : o.addClass(t);
                } else (void 0 !== e && 'boolean' !== n) || ((t = mt(this)) && J.set(this, '__className__', t), this.setAttribute && this.setAttribute('class', t || !1 === e ? '' : J.get(this, '__className__') || ''));
              });
        },
        hasClass: function(e) {
          var t,
            n,
            r = 0;
          t = ' ' + e + ' ';

          while ((n = this[r++]))
            if (1 === n.nodeType && (' ' + vt(mt(n)) + ' ').indexOf(t) > -1)
              return !0;

          return !1;
        },
      });
      var bt = /\r/g;
      w.fn.extend({
        val: function(e) {
          var t,
            n,
            r,
            i = this[0];
          {
            if (arguments.length)
              return (
                (r = g(e)),
                this.each(function(n) {
                  var i;
                  1 === this.nodeType &&
                    (null == (i = r ? e.call(this, n, w(this).val()) : e)
                      ? (i = '')
                      : 'number' == typeof i
                      ? (i += '')
                      : Array.isArray(i) &&
                        (i = w.map(i, function(e) {
                          return null == e ? '' : e + '';
                        })),
                    ((t =
                      w.valHooks[this.type] ||
                      w.valHooks[this.nodeName.toLowerCase()]) &&
                      'set' in t &&
                      void 0 !== t.set(this, i, 'value')) ||
                      (this.value = i));
                })
              );
            if (i)
              return (t =
                w.valHooks[i.type] || w.valHooks[i.nodeName.toLowerCase()]) &&
                'get' in t &&
                void 0 !== (n = t.get(i, 'value'))
                ? n
                : 'string' == typeof (n = i.value)
                ? n.replace(bt, '')
                : null == n
                ? ''
                : n;
          }
        },
      }),
        w.extend({
          valHooks: {
            option: {
              get: function(e) {
                var t = w.find.attr(e, 'value');
                return null != t ? t : vt(w.text(e));
              },
            },
            select: {
              get: function(e) {
                var t,
                  n,
                  r,
                  i = e.options,
                  o = e.selectedIndex,
                  a = 'select-one' === e.type,
                  s = a ? null : [],
                  u = a ? o + 1 : i.length;

                for (r = o < 0 ? u : a ? o : 0; r < u; r++)
                  if (
                    ((n = i[r]).selected || r === o) &&
                    !n.disabled &&
                    (!n.parentNode.disabled || !N(n.parentNode, 'optgroup'))
                  ) {
                    if (((t = w(n).val()), a)) return t;
                    s.push(t);
                  }

                return s;
              },
              set: function(e, t) {
                var n,
                  r,
                  i = e.options,
                  o = w.makeArray(t),
                  a = i.length;

                while (a--)
                  ((r = i[a]).selected =
                    w.inArray(w.valHooks.option.get(r), o) > -1) && (n = !0);

                return n || (e.selectedIndex = -1), o;
              },
            },
          },
        }),
        w.each(['radio', 'checkbox'], function() {
          (w.valHooks[this] = {
            set: function(e, t) {
              if (Array.isArray(t))
                return (e.checked = w.inArray(w(e).val(), t) > -1);
            },
          }),
            h.checkOn ||
              (w.valHooks[this].get = function(e) {
                return null === e.getAttribute('value') ? 'on' : e.value;
              });
        }),
        (h.focusin = 'onfocusin' in e);

      var wt = /^(?:focusinfocus|focusoutblur)$/,
        Tt = function(e) {
          e.stopPropagation();
        };

      w.extend(w.event, {
        trigger: function(t, n, i, o) {
          var a,
            s,
            u,
            l,
            c,
            p,
            d,
            h,
            v = [i || r],
            m = f.call(t, 'type') ? t.type : t,
            x = f.call(t, 'namespace') ? t.namespace.split('.') : [];

          if (
            ((s = h = u = i = i || r),
            3 !== i.nodeType &&
              8 !== i.nodeType &&
              !wt.test(m + w.event.triggered) &&
              (m.indexOf('.') > -1 &&
                ((m = (x = m.split('.')).shift()), x.sort()),
              (c = m.indexOf(':') < 0 && 'on' + m),
              (t = t[w.expando]
                ? t
                : new w.Event(m, 'object' == typeof t && t)),
              (t.isTrigger = o ? 2 : 3),
              (t.namespace = x.join('.')),
              (t.rnamespace = t.namespace
                ? new RegExp('(^|\\.)' + x.join('\\.(?:.*\\.|)') + '(\\.|$)')
                : null),
              (t.result = void 0),
              t.target || (t.target = i),
              (n = null == n ? [t] : w.makeArray(n, [t])),
              (d = w.event.special[m] || {}),
              o || !d.trigger || !1 !== d.trigger.apply(i, n)))
          ) {
            if (!o && !d.noBubble && !y(i)) {
              for (
                l = d.delegateType || m, wt.test(l + m) || (s = s.parentNode);
                s;
                s = s.parentNode
              )
                v.push(s), (u = s);

              u === (i.ownerDocument || r) &&
                v.push(u.defaultView || u.parentWindow || e);
            }

            a = 0;

            while ((s = v[a++]) && !t.isPropagationStopped())
              (h = s),
                (t.type = a > 1 ? l : d.bindType || m),
                (p =
                  (J.get(s, 'events') || {})[t.type] && J.get(s, 'handle')) &&
                  p.apply(s, n),
                (p = c && s[c]) &&
                  p.apply &&
                  Y(s) &&
                  ((t.result = p.apply(s, n)),
                  !1 === t.result && t.preventDefault());

            return (
              (t.type = m),
              o ||
                t.isDefaultPrevented() ||
                (d._default && !1 !== d._default.apply(v.pop(), n)) ||
                !Y(i) ||
                (c &&
                  g(i[m]) &&
                  !y(i) &&
                  ((u = i[c]) && (i[c] = null),
                  (w.event.triggered = m),
                  t.isPropagationStopped() && h.addEventListener(m, Tt),
                  i[m](),
                  t.isPropagationStopped() && h.removeEventListener(m, Tt),
                  (w.event.triggered = void 0),
                  u && (i[c] = u))),
              t.result
            );
          }
        },
        simulate: function(e, t, n) {
          var r = w.extend(new w.Event(), n, {
            type: e,
            isSimulated: !0,
          });
          w.event.trigger(r, null, t);
        },
      }),
        w.fn.extend({
          trigger: function(e, t) {
            return this.each(function() {
              w.event.trigger(e, t, this);
            });
          },
          triggerHandler: function(e, t) {
            var n = this[0];
            if (n) return w.event.trigger(e, t, n, !0);
          },
        }),
        h.focusin ||
          w.each(
            {
              focus: 'focusin',
              blur: 'focusout',
            },
            function(e, t) {
              var n = function(e) {
                w.event.simulate(t, e.target, w.event.fix(e));
              };

              w.event.special[t] = {
                setup: function() {
                  var r = this.ownerDocument || this,
                    i = J.access(r, t);
                  i || r.addEventListener(e, n, !0),
                    J.access(r, t, (i || 0) + 1);
                },
                teardown: function() {
                  var r = this.ownerDocument || this,
                    i = J.access(r, t) - 1;
                  i
                    ? J.access(r, t, i)
                    : (r.removeEventListener(e, n, !0), J.remove(r, t));
                },
              };
            }
          );
      var Ct = e.location,
        Et = Date.now(),
        kt = /\?/;

      w.parseXML = function(t) {
        var n;
        if (!t || 'string' != typeof t) return null;

        try {
          n = new e.DOMParser().parseFromString(t, 'text/xml');
        } catch (e) {
          n = void 0;
        }

        return (
          (n && !n.getElementsByTagName('parsererror').length) ||
            w.error('Invalid XML: ' + t),
          n
        );
      };

      var St = /\[\]$/,
        Dt = /\r?\n/g,
        Nt = /^(?:submit|button|image|reset|file)$/i,
        At = /^(?:input|select|textarea|keygen)/i;

      function jt(e, t, n, r) {
        var i;
        if (Array.isArray(t))
          w.each(t, function(t, i) {
            n || St.test(e)
              ? r(e, i)
              : jt(
                  e + '[' + ('object' == typeof i && null != i ? t : '') + ']',
                  i,
                  n,
                  r
                );
          });
        else if (n || 'object' !== x(t)) r(e, t);
        else for (i in t) jt(e + '[' + i + ']', t[i], n, r);
      }

      (w.param = function(e, t) {
        var n,
          r = [],
          i = function(e, t) {
            var n = g(t) ? t() : t;
            r[r.length] =
              encodeURIComponent(e) +
              '=' +
              encodeURIComponent(null == n ? '' : n);
          };

        if (Array.isArray(e) || (e.jquery && !w.isPlainObject(e)))
          w.each(e, function() {
            i(this.name, this.value);
          });
        else for (n in e) jt(n, e[n], t, i);
        return r.join('&');
      }),
        w.fn.extend({
          serialize: function() {
            return w.param(this.serializeArray());
          },
          serializeArray: function() {
            return this.map(function() {
              var e = w.prop(this, 'elements');
              return e ? w.makeArray(e) : this;
            })
              .filter(function() {
                var e = this.type;
                return (
                  this.name &&
                  !w(this).is(':disabled') &&
                  At.test(this.nodeName) &&
                  !Nt.test(e) &&
                  (this.checked || !pe.test(e))
                );
              })
              .map(function(e, t) {
                var n = w(this).val();
                return null == n
                  ? null
                  : Array.isArray(n)
                  ? w.map(n, function(e) {
                      return {
                        name: t.name,
                        value: e.replace(Dt, '\r\n'),
                      };
                    })
                  : {
                      name: t.name,
                      value: n.replace(Dt, '\r\n'),
                    };
              })
              .get();
          },
        });
      var qt = /%20/g,
        Lt = /#.*$/,
        Ht = /([?&])_=[^&]*/,
        Ot = /^(.*?):[ \t]*([^\r\n]*)$/gm,
        Pt = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
        Mt = /^(?:GET|HEAD)$/,
        Rt = /^\/\//,
        It = {},
        Wt = {},
        $t = '*/'.concat('*'),
        Bt = r.createElement('a');
      Bt.href = Ct.href;

      function Ft(e) {
        return function(t, n) {
          'string' != typeof t && ((n = t), (t = '*'));
          var r,
            i = 0,
            o = t.toLowerCase().match(M) || [];
          if (g(n))
            while ((r = o[i++]))
              '+' === r[0]
                ? ((r = r.slice(1) || '*'), (e[r] = e[r] || []).unshift(n))
                : (e[r] = e[r] || []).push(n);
        };
      }

      function _t(e, t, n, r) {
        var i = {},
          o = e === Wt;

        function a(s) {
          var u;
          return (
            (i[s] = !0),
            w.each(e[s] || [], function(e, s) {
              var l = s(t, n, r);
              return 'string' != typeof l || o || i[l]
                ? o
                  ? !(u = l)
                  : void 0
                : (t.dataTypes.unshift(l), a(l), !1);
            }),
            u
          );
        }

        return a(t.dataTypes[0]) || (!i['*'] && a('*'));
      }

      function zt(e, t) {
        var n,
          r,
          i = w.ajaxSettings.flatOptions || {};

        for (n in t) void 0 !== t[n] && ((i[n] ? e : r || (r = {}))[n] = t[n]);

        return r && w.extend(!0, e, r), e;
      }

      function Xt(e, t, n) {
        var r,
          i,
          o,
          a,
          s = e.contents,
          u = e.dataTypes;

        while ('*' === u[0])
          u.shift(),
            void 0 === r &&
              (r = e.mimeType || t.getResponseHeader('Content-Type'));

        if (r)
          for (i in s)
            if (s[i] && s[i].test(r)) {
              u.unshift(i);
              break;
            }
        if (u[0] in n) o = u[0];
        else {
          for (i in n) {
            if (!u[0] || e.converters[i + ' ' + u[0]]) {
              o = i;
              break;
            }

            a || (a = i);
          }

          o = o || a;
        }
        if (o) return o !== u[0] && u.unshift(o), n[o];
      }

      function Ut(e, t, n, r) {
        var i,
          o,
          a,
          s,
          u,
          l = {},
          c = e.dataTypes.slice();
        if (c[1]) for (a in e.converters) l[a.toLowerCase()] = e.converters[a];
        o = c.shift();

        while (o)
          if (
            (e.responseFields[o] && (n[e.responseFields[o]] = t),
            !u && r && e.dataFilter && (t = e.dataFilter(t, e.dataType)),
            (u = o),
            (o = c.shift()))
          )
            if ('*' === o) o = u;
            else if ('*' !== u && u !== o) {
              if (!(a = l[u + ' ' + o] || l['* ' + o]))
                for (i in l)
                  if (
                    (s = i.split(' '))[1] === o &&
                    (a = l[u + ' ' + s[0]] || l['* ' + s[0]])
                  ) {
                    !0 === a
                      ? (a = l[i])
                      : !0 !== l[i] && ((o = s[0]), c.unshift(s[1]));
                    break;
                  }
              if (!0 !== a)
                if (a && e['throws']) t = a(t);
                else
                  try {
                    t = a(t);
                  } catch (e) {
                    return {
                      state: 'parsererror',
                      error: a ? e : 'No conversion from ' + u + ' to ' + o,
                    };
                  }
            }

        return {
          state: 'success',
          data: t,
        };
      }

      w.extend({
        active: 0,
        lastModified: {},
        etag: {},
        ajaxSettings: {
          url: Ct.href,
          type: 'GET',
          isLocal: Pt.test(Ct.protocol),
          global: !0,
          processData: !0,
          async: !0,
          contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
          accepts: {
            '*': $t,
            text: 'text/plain',
            html: 'text/html',
            xml: 'application/xml, text/xml',
            json: 'application/json, text/javascript',
          },
          contents: {
            xml: /\bxml\b/,
            html: /\bhtml/,
            json: /\bjson\b/,
          },
          responseFields: {
            xml: 'responseXML',
            text: 'responseText',
            json: 'responseJSON',
          },
          converters: {
            '* text': String,
            'text html': !0,
            'text json': JSON.parse,
            'text xml': w.parseXML,
          },
          flatOptions: {
            url: !0,
            context: !0,
          },
        },
        ajaxSetup: function(e, t) {
          return t ? zt(zt(e, w.ajaxSettings), t) : zt(w.ajaxSettings, e);
        },
        ajaxPrefilter: Ft(It),
        ajaxTransport: Ft(Wt),
        ajax: function(t, n) {
          'object' == typeof t && ((n = t), (t = void 0)), (n = n || {});
          var i,
            o,
            a,
            s,
            u,
            l,
            c,
            f,
            p,
            d,
            h = w.ajaxSetup({}, n),
            g = h.context || h,
            y = h.context && (g.nodeType || g.jquery) ? w(g) : w.event,
            v = w.Deferred(),
            m = w.Callbacks('once memory'),
            x = h.statusCode || {},
            b = {},
            T = {},
            C = 'canceled',
            E = {
              readyState: 0,
              getResponseHeader: function(e) {
                var t;

                if (c) {
                  if (!s) {
                    s = {};

                    while ((t = Ot.exec(a))) s[t[1].toLowerCase()] = t[2];
                  }

                  t = s[e.toLowerCase()];
                }

                return null == t ? null : t;
              },
              getAllResponseHeaders: function() {
                return c ? a : null;
              },
              setRequestHeader: function(e, t) {
                return (
                  null == c &&
                    ((e = T[e.toLowerCase()] = T[e.toLowerCase()] || e),
                    (b[e] = t)),
                  this
                );
              },
              overrideMimeType: function(e) {
                return null == c && (h.mimeType = e), this;
              },
              statusCode: function(e) {
                var t;
                if (e)
                  if (c) E.always(e[E.status]);
                  else for (t in e) x[t] = [x[t], e[t]];
                return this;
              },
              abort: function(e) {
                var t = e || C;
                return i && i.abort(t), k(0, t), this;
              },
            };

          if (
            (v.promise(E),
            (h.url = ((t || h.url || Ct.href) + '').replace(
              Rt,
              Ct.protocol + '//'
            )),
            (h.type = n.method || n.type || h.method || h.type),
            (h.dataTypes = (h.dataType || '*').toLowerCase().match(M) || ['']),
            null == h.crossDomain)
          ) {
            l = r.createElement('a');

            try {
              (l.href = h.url),
                (l.href = l.href),
                (h.crossDomain =
                  Bt.protocol + '//' + Bt.host != l.protocol + '//' + l.host);
            } catch (e) {
              h.crossDomain = !0;
            }
          }

          if (
            (h.data &&
              h.processData &&
              'string' != typeof h.data &&
              (h.data = w.param(h.data, h.traditional)),
            _t(It, h, n, E),
            c)
          )
            return E;
          (f = w.event && h.global) &&
            0 == w.active++ &&
            w.event.trigger('ajaxStart'),
            (h.type = h.type.toUpperCase()),
            (h.hasContent = !Mt.test(h.type)),
            (o = h.url.replace(Lt, '')),
            h.hasContent
              ? h.data &&
                h.processData &&
                0 ===
                  (h.contentType || '').indexOf(
                    'application/x-www-form-urlencoded'
                  ) &&
                (h.data = h.data.replace(qt, '+'))
              : ((d = h.url.slice(o.length)),
                h.data &&
                  (h.processData || 'string' == typeof h.data) &&
                  ((o += (kt.test(o) ? '&' : '?') + h.data), delete h.data),
                !1 === h.cache &&
                  ((o = o.replace(Ht, '$1')),
                  (d = (kt.test(o) ? '&' : '?') + '_=' + Et++ + d)),
                (h.url = o + d)),
            h.ifModified &&
              (w.lastModified[o] &&
                E.setRequestHeader('If-Modified-Since', w.lastModified[o]),
              w.etag[o] && E.setRequestHeader('If-None-Match', w.etag[o])),
            ((h.data && h.hasContent && !1 !== h.contentType) ||
              n.contentType) &&
              E.setRequestHeader('Content-Type', h.contentType),
            E.setRequestHeader(
              'Accept',
              h.dataTypes[0] && h.accepts[h.dataTypes[0]]
                ? h.accepts[h.dataTypes[0]] +
                    ('*' !== h.dataTypes[0] ? ', ' + $t + '; q=0.01' : '')
                : h.accepts['*']
            );

          for (p in h.headers) E.setRequestHeader(p, h.headers[p]);

          if (h.beforeSend && (!1 === h.beforeSend.call(g, E, h) || c))
            return E.abort();

          if (
            ((C = 'abort'),
            m.add(h.complete),
            E.done(h.success),
            E.fail(h.error),
            (i = _t(Wt, h, n, E)))
          ) {
            if (((E.readyState = 1), f && y.trigger('ajaxSend', [E, h]), c))
              return E;
            h.async &&
              h.timeout > 0 &&
              (u = e.setTimeout(function() {
                E.abort('timeout');
              }, h.timeout));

            try {
              (c = !1), i.send(b, k);
            } catch (e) {
              if (c) throw e;
              k(-1, e);
            }
          } else k(-1, 'No Transport');

          function k(t, n, r, s) {
            var l,
              p,
              d,
              b,
              T,
              C = n;
            c ||
              ((c = !0),
              u && e.clearTimeout(u),
              (i = void 0),
              (a = s || ''),
              (E.readyState = t > 0 ? 4 : 0),
              (l = (t >= 200 && t < 300) || 304 === t),
              r && (b = Xt(h, E, r)),
              (b = Ut(h, b, E, l)),
              l
                ? (h.ifModified &&
                    ((T = E.getResponseHeader('Last-Modified')) &&
                      (w.lastModified[o] = T),
                    (T = E.getResponseHeader('etag')) && (w.etag[o] = T)),
                  204 === t || 'HEAD' === h.type
                    ? (C = 'nocontent')
                    : 304 === t
                    ? (C = 'notmodified')
                    : ((C = b.state), (p = b.data), (l = !(d = b.error))))
                : ((d = C), (!t && C) || ((C = 'error'), t < 0 && (t = 0))),
              (E.status = t),
              (E.statusText = (n || C) + ''),
              l ? v.resolveWith(g, [p, C, E]) : v.rejectWith(g, [E, C, d]),
              E.statusCode(x),
              (x = void 0),
              f &&
                y.trigger(l ? 'ajaxSuccess' : 'ajaxError', [E, h, l ? p : d]),
              m.fireWith(g, [E, C]),
              f &&
                (y.trigger('ajaxComplete', [E, h]),
                --w.active || w.event.trigger('ajaxStop')));
          }

          return E;
        },
        getJSON: function(e, t, n) {
          return w.get(e, t, n, 'json');
        },
        getScript: function(e, t) {
          return w.get(e, void 0, t, 'script');
        },
      }),
        w.each(['get', 'post'], function(e, t) {
          w[t] = function(e, n, r, i) {
            return (
              g(n) && ((i = i || r), (r = n), (n = void 0)),
              w.ajax(
                w.extend(
                  {
                    url: e,
                    type: t,
                    dataType: i,
                    data: n,
                    success: r,
                  },
                  w.isPlainObject(e) && e
                )
              )
            );
          };
        }),
        (w._evalUrl = function(e) {
          return w.ajax({
            url: e,
            type: 'GET',
            dataType: 'script',
            cache: !0,
            async: !1,
            global: !1,
            throws: !0,
          });
        }),
        w.fn.extend({
          wrapAll: function(e) {
            var t;
            return (
              this[0] &&
                (g(e) && (e = e.call(this[0])),
                (t = w(e, this[0].ownerDocument)
                  .eq(0)
                  .clone(!0)),
                this[0].parentNode && t.insertBefore(this[0]),
                t
                  .map(function() {
                    var e = this;

                    while (e.firstElementChild) e = e.firstElementChild;

                    return e;
                  })
                  .append(this)),
              this
            );
          },
          wrapInner: function(e) {
            return g(e)
              ? this.each(function(t) {
                  w(this).wrapInner(e.call(this, t));
                })
              : this.each(function() {
                  var t = w(this),
                    n = t.contents();
                  n.length ? n.wrapAll(e) : t.append(e);
                });
          },
          wrap: function(e) {
            var t = g(e);
            return this.each(function(n) {
              w(this).wrapAll(t ? e.call(this, n) : e);
            });
          },
          unwrap: function(e) {
            return (
              this.parent(e)
                .not('body')
                .each(function() {
                  w(this).replaceWith(this.childNodes);
                }),
              this
            );
          },
        }),
        (w.expr.pseudos.hidden = function(e) {
          return !w.expr.pseudos.visible(e);
        }),
        (w.expr.pseudos.visible = function(e) {
          return !!(
            e.offsetWidth ||
            e.offsetHeight ||
            e.getClientRects().length
          );
        }),
        (w.ajaxSettings.xhr = function() {
          try {
            return new e.XMLHttpRequest();
          } catch (e) {}
        });
      var Vt = {
          0: 200,
          1223: 204,
        },
        Gt = w.ajaxSettings.xhr();
      (h.cors = !!Gt && 'withCredentials' in Gt),
        (h.ajax = Gt = !!Gt),
        w.ajaxTransport(function(t) {
          var n, r;
          if (h.cors || (Gt && !t.crossDomain))
            return {
              send: function(i, o) {
                var a,
                  s = t.xhr();
                if (
                  (s.open(t.type, t.url, t.async, t.username, t.password),
                  t.xhrFields)
                )
                  for (a in t.xhrFields) s[a] = t.xhrFields[a];
                t.mimeType &&
                  s.overrideMimeType &&
                  s.overrideMimeType(t.mimeType),
                  t.crossDomain ||
                    i['X-Requested-With'] ||
                    (i['X-Requested-With'] = 'XMLHttpRequest');

                for (a in i) s.setRequestHeader(a, i[a]);

                (n = function(e) {
                  return function() {
                    n &&
                      ((n = r = s.onload = s.onerror = s.onabort = s.ontimeout = s.onreadystatechange = null),
                      'abort' === e
                        ? s.abort()
                        : 'error' === e
                        ? 'number' != typeof s.status
                          ? o(0, 'error')
                          : o(s.status, s.statusText)
                        : o(
                            Vt[s.status] || s.status,
                            s.statusText,
                            'text' !== (s.responseType || 'text') ||
                              'string' != typeof s.responseText
                              ? {
                                  binary: s.response,
                                }
                              : {
                                  text: s.responseText,
                                },
                            s.getAllResponseHeaders()
                          ));
                  };
                }),
                  (s.onload = n()),
                  (r = s.onerror = s.ontimeout = n('error')),
                  void 0 !== s.onabort
                    ? (s.onabort = r)
                    : (s.onreadystatechange = function() {
                        4 === s.readyState &&
                          e.setTimeout(function() {
                            n && r();
                          });
                      }),
                  (n = n('abort'));

                try {
                  s.send((t.hasContent && t.data) || null);
                } catch (e) {
                  if (n) throw e;
                }
              },
              abort: function() {
                n && n();
              },
            };
        }),
        w.ajaxPrefilter(function(e) {
          e.crossDomain && (e.contents.script = !1);
        }),
        w.ajaxSetup({
          accepts: {
            script:
              'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript',
          },
          contents: {
            script: /\b(?:java|ecma)script\b/,
          },
          converters: {
            'text script': function(e) {
              return w.globalEval(e), e;
            },
          },
        }),
        w.ajaxPrefilter('script', function(e) {
          void 0 === e.cache && (e.cache = !1),
            e.crossDomain && (e.type = 'GET');
        }),
        w.ajaxTransport('script', function(e) {
          if (e.crossDomain) {
            var t, n;
            return {
              send: function(i, o) {
                (t = w('<script>')
                  .prop({
                    charset: e.scriptCharset,
                    src: e.url,
                  })
                  .on(
                    'load error',
                    (n = function(e) {
                      t.remove(),
                        (n = null),
                        e && o('error' === e.type ? 404 : 200, e.type);
                    })
                  )),
                  r.head.appendChild(t[0]);
              },
              abort: function() {
                n && n();
              },
            };
          }
        });
      var Yt = [],
        Qt = /(=)\?(?=&|$)|\?\?/;
      w.ajaxSetup({
        jsonp: 'callback',
        jsonpCallback: function() {
          var e = Yt.pop() || w.expando + '_' + Et++;
          return (this[e] = !0), e;
        },
      }),
        w.ajaxPrefilter('json jsonp', function(t, n, r) {
          var i,
            o,
            a,
            s =
              !1 !== t.jsonp &&
              (Qt.test(t.url)
                ? 'url'
                : 'string' == typeof t.data &&
                  0 ===
                    (t.contentType || '').indexOf(
                      'application/x-www-form-urlencoded'
                    ) &&
                  Qt.test(t.data) &&
                  'data');
          if (s || 'jsonp' === t.dataTypes[0])
            return (
              (i = t.jsonpCallback = g(t.jsonpCallback)
                ? t.jsonpCallback()
                : t.jsonpCallback),
              s
                ? (t[s] = t[s].replace(Qt, '$1' + i))
                : !1 !== t.jsonp &&
                  (t.url += (kt.test(t.url) ? '&' : '?') + t.jsonp + '=' + i),
              (t.converters['script json'] = function() {
                return a || w.error(i + ' was not called'), a[0];
              }),
              (t.dataTypes[0] = 'json'),
              (o = e[i]),
              (e[i] = function() {
                a = arguments;
              }),
              r.always(function() {
                void 0 === o ? w(e).removeProp(i) : (e[i] = o),
                  t[i] && ((t.jsonpCallback = n.jsonpCallback), Yt.push(i)),
                  a && g(o) && o(a[0]),
                  (a = o = void 0);
              }),
              'script'
            );
        }),
        (h.createHTMLDocument = (function() {
          var e = r.implementation.createHTMLDocument('').body;
          return (
            (e.innerHTML = '<form></form><form></form>'),
            2 === e.childNodes.length
          );
        })()),
        (w.parseHTML = function(e, t, n) {
          if ('string' != typeof e) return [];
          'boolean' == typeof t && ((n = t), (t = !1));
          var i, o, a;
          return (
            t ||
              (h.createHTMLDocument
                ? (((i = (t = r.implementation.createHTMLDocument(
                    ''
                  )).createElement('base')).href = r.location.href),
                  t.head.appendChild(i))
                : (t = r)),
            (o = A.exec(e)),
            (a = !n && []),
            o
              ? [t.createElement(o[1])]
              : ((o = xe([e], t, a)),
                a && a.length && w(a).remove(),
                w.merge([], o.childNodes))
          );
        }),
        (w.fn.load = function(e, t, n) {
          var r,
            i,
            o,
            a = this,
            s = e.indexOf(' ');
          return (
            s > -1 && ((r = vt(e.slice(s))), (e = e.slice(0, s))),
            g(t)
              ? ((n = t), (t = void 0))
              : t && 'object' == typeof t && (i = 'POST'),
            a.length > 0 &&
              w
                .ajax({
                  url: e,
                  type: i || 'GET',
                  dataType: 'html',
                  data: t,
                })
                .done(function(e) {
                  (o = arguments),
                    a.html(
                      r
                        ? w('<div>')
                            .append(w.parseHTML(e))
                            .find(r)
                        : e
                    );
                })
                .always(
                  n &&
                    function(e, t) {
                      a.each(function() {
                        n.apply(this, o || [e.responseText, t, e]);
                      });
                    }
                ),
            this
          );
        }),
        w.each(
          [
            'ajaxStart',
            'ajaxStop',
            'ajaxComplete',
            'ajaxError',
            'ajaxSuccess',
            'ajaxSend',
          ],
          function(e, t) {
            w.fn[t] = function(e) {
              return this.on(t, e);
            };
          }
        ),
        (w.expr.pseudos.animated = function(e) {
          return w.grep(w.timers, function(t) {
            return e === t.elem;
          }).length;
        }),
        (w.offset = {
          setOffset: function(e, t, n) {
            var r,
              i,
              o,
              a,
              s,
              u,
              l,
              c = w.css(e, 'position'),
              f = w(e),
              p = {};
            'static' === c && (e.style.position = 'relative'),
              (s = f.offset()),
              (o = w.css(e, 'top')),
              (u = w.css(e, 'left')),
              (l =
                ('absolute' === c || 'fixed' === c) &&
                (o + u).indexOf('auto') > -1)
                ? ((a = (r = f.position()).top), (i = r.left))
                : ((a = parseFloat(o) || 0), (i = parseFloat(u) || 0)),
              g(t) && (t = t.call(e, n, w.extend({}, s))),
              null != t.top && (p.top = t.top - s.top + a),
              null != t.left && (p.left = t.left - s.left + i),
              'using' in t ? t.using.call(e, p) : f.css(p);
          },
        }),
        w.fn.extend({
          offset: function(e) {
            if (arguments.length)
              return void 0 === e
                ? this
                : this.each(function(t) {
                    w.offset.setOffset(this, e, t);
                  });
            var t,
              n,
              r = this[0];
            if (r)
              return r.getClientRects().length
                ? ((t = r.getBoundingClientRect()),
                  (n = r.ownerDocument.defaultView),
                  {
                    top: t.top + n.pageYOffset,
                    left: t.left + n.pageXOffset,
                  })
                : {
                    top: 0,
                    left: 0,
                  };
          },
          position: function() {
            if (this[0]) {
              var e,
                t,
                n,
                r = this[0],
                i = {
                  top: 0,
                  left: 0,
                };
              if ('fixed' === w.css(r, 'position'))
                t = r.getBoundingClientRect();
              else {
                (t = this.offset()),
                  (n = r.ownerDocument),
                  (e = r.offsetParent || n.documentElement);

                while (
                  e &&
                  (e === n.body || e === n.documentElement) &&
                  'static' === w.css(e, 'position')
                )
                  e = e.parentNode;

                e &&
                  e !== r &&
                  1 === e.nodeType &&
                  (((i = w(e).offset()).top += w.css(e, 'borderTopWidth', !0)),
                  (i.left += w.css(e, 'borderLeftWidth', !0)));
              }
              return {
                top: t.top - i.top - w.css(r, 'marginTop', !0),
                left: t.left - i.left - w.css(r, 'marginLeft', !0),
              };
            }
          },
          offsetParent: function() {
            return this.map(function() {
              var e = this.offsetParent;

              while (e && 'static' === w.css(e, 'position')) e = e.offsetParent;

              return e || be;
            });
          },
        }),
        w.each(
          {
            scrollLeft: 'pageXOffset',
            scrollTop: 'pageYOffset',
          },
          function(e, t) {
            var n = 'pageYOffset' === t;

            w.fn[e] = function(r) {
              return z(
                this,
                function(e, r, i) {
                  var o;
                  if (
                    (y(e) ? (o = e) : 9 === e.nodeType && (o = e.defaultView),
                    void 0 === i)
                  )
                    return o ? o[t] : e[r];
                  o
                    ? o.scrollTo(n ? o.pageXOffset : i, n ? i : o.pageYOffset)
                    : (e[r] = i);
                },
                e,
                r,
                arguments.length
              );
            };
          }
        ),
        w.each(['top', 'left'], function(e, t) {
          w.cssHooks[t] = _e(h.pixelPosition, function(e, n) {
            if (n)
              return (n = Fe(e, t)), We.test(n) ? w(e).position()[t] + 'px' : n;
          });
        }),
        w.each(
          {
            Height: 'height',
            Width: 'width',
          },
          function(e, t) {
            w.each(
              {
                padding: 'inner' + e,
                content: t,
                '': 'outer' + e,
              },
              function(n, r) {
                w.fn[r] = function(i, o) {
                  var a = arguments.length && (n || 'boolean' != typeof i),
                    s = n || (!0 === i || !0 === o ? 'margin' : 'border');
                  return z(
                    this,
                    function(t, n, i) {
                      var o;
                      return y(t)
                        ? 0 === r.indexOf('outer')
                          ? t['inner' + e]
                          : t.document.documentElement['client' + e]
                        : 9 === t.nodeType
                        ? ((o = t.documentElement),
                          Math.max(
                            t.body['scroll' + e],
                            o['scroll' + e],
                            t.body['offset' + e],
                            o['offset' + e],
                            o['client' + e]
                          ))
                        : void 0 === i
                        ? w.css(t, n, s)
                        : w.style(t, n, i, s);
                    },
                    t,
                    a ? i : void 0,
                    a
                  );
                };
              }
            );
          }
        ),
        w.each(
          'blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu'.split(
            ' '
          ),
          function(e, t) {
            w.fn[t] = function(e, n) {
              return arguments.length > 0
                ? this.on(t, null, e, n)
                : this.trigger(t);
            };
          }
        ),
        w.fn.extend({
          hover: function(e, t) {
            return this.mouseenter(e).mouseleave(t || e);
          },
        }),
        w.fn.extend({
          bind: function(e, t, n) {
            return this.on(e, null, t, n);
          },
          unbind: function(e, t) {
            return this.off(e, null, t);
          },
          delegate: function(e, t, n, r) {
            return this.on(t, e, n, r);
          },
          undelegate: function(e, t, n) {
            return 1 === arguments.length
              ? this.off(e, '**')
              : this.off(t, e || '**', n);
          },
        }),
        (w.proxy = function(e, t) {
          var n, r, i;
          if (('string' == typeof t && ((n = e[t]), (t = e), (e = n)), g(e)))
            return (
              (r = o.call(arguments, 2)),
              (i = function() {
                return e.apply(t || this, r.concat(o.call(arguments)));
              }),
              (i.guid = e.guid = e.guid || w.guid++),
              i
            );
        }),
        (w.holdReady = function(e) {
          e ? w.readyWait++ : w.ready(!0);
        }),
        (w.isArray = Array.isArray),
        (w.parseJSON = JSON.parse),
        (w.nodeName = N),
        (w.isFunction = g),
        (w.isWindow = y),
        (w.camelCase = G),
        (w.type = x),
        (w.now = Date.now),
        (w.isNumeric = function(e) {
          var t = w.type(e);
          return (
            ('number' === t || 'string' === t) && !isNaN(e - parseFloat(e))
          );
        }),
        'function' == typeof undefined &&
          undefined.amd &&
          undefined('jquery', [], function() {
            return w;
          });
      var Jt = e.jQuery,
        Kt = e.$;
      return (
        (w.noConflict = function(t) {
          return (
            e.$ === w && (e.$ = Kt), t && e.jQuery === w && (e.jQuery = Jt), w
          );
        }),
        t || (e.jQuery = e.$ = w),
        w
      );
    });
  });

  // This module attempts to square cheerio with jquery
  var PARSER_CLASS = 'mercury-parsing-container';
  var PARSING_NODE;
  jquery_min.noConflict();

  var $ = function $(selector, context, rootjQuery) {
    var contextOverride =
      arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;

    if (contextOverride) {
      if (context && typeof context === 'string') {
        context = PARSING_NODE.find(context);
      } else if (!context) {
        context = PARSING_NODE;
      }
    }

    return new jquery_min.fn.init(selector, context, rootjQuery); // eslint-disable-line new-cap
  }; // eslint-disable-next-line no-multi-assign

  $.fn = $.prototype = jquery_min.fn;
  jquery_min.extend($, jquery_min); // copy's trim, extend etc to $

  var removeUnusedTags = function removeUnusedTags($node) {
    // remove scripts and stylesheets
    $node.find('script, style, link[rel="stylesheet"]').remove();
    return $node;
  };

  $.cloneHtml = function() {
    var html = removeUnusedTags($('html', null, null, false).clone());
    return html
      .children()
      .wrap('<div />')
      .wrap('<div />');
  };

  $.root = function() {
    return $('*').first();
  };

  $.browser = true;

  var isContainer = function isContainer($node) {
    var el = $node.get(0);

    if (el && el.tagName) {
      return el.tagName.toLowerCase() === 'container';
    }

    return false;
  };

  $.html = function($node) {
    if ($node) {
      // we never want to return a parsing container, only its children
      if (isContainer($node) || isContainer($node.children('container'))) {
        return $node.children('container').html() || $node.html();
      }

      return $('<div>')
        .append($node.eq(0).clone())
        .html();
    }

    var $body = removeUnusedTags($('body', null, null, false).clone());
    var $head = removeUnusedTags($('head', null, null, false).clone());

    if (PARSING_NODE && PARSING_NODE.length > 0) {
      return PARSING_NODE.children().html();
    }

    var html = $('<container />')
      .append($('<container>'.concat($head.html(), '</container>')))
      .append($('<container>'.concat($body.html(), '</container>')))
      .wrap('<container />')
      .parent()
      .html();
    return html;
  }; // eslint-disable-next-line no-unused-vars

  $.load = function(html) {
    var returnHtml =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;

    if (!html) {
      html = $.cloneHtml();
    } else {
      html = $('<container />').html(html);
    }

    PARSING_NODE =
      PARSING_NODE ||
      $('<div class="'.concat(PARSER_CLASS, '" style="display:none;" />')); // Strip scripts

    html = removeUnusedTags(html); // Remove comments

    html
      .find('*')
      .contents()
      .each(function() {
        // eslint-disable-next-line no-undef
        if (this.nodeType === Node.COMMENT_NODE) {
          $(this).remove();
        }
      });
    PARSING_NODE.html(html);
    if (returnHtml)
      return {
        $: $,
        html: html.html(),
      };
    return $;
  };

  // this is a shim for the browser build;
  // iconv-lite doubles build size, and we
  // don't need it for already rendered text
  var iconv = {
    encodingExists: function encodingExists() {
      return false;
    },
    decode: function decode(s) {
      return s;
    },
  };

  var NORMALIZE_RE = /\s{2,}/g;
  function normalizeSpaces(text) {
    return text.replace(NORMALIZE_RE, ' ').trim();
  }

  // Given a node type to search for, and a list of regular expressions,
  // look to see if this extraction can be found in the URL. Expects
  // that each expression in r_list will return group(1) as the proper
  // string to be cleaned.
  // Only used for date_published currently.
  function extractFromUrl(url, regexList) {
    var matchRe = regexList.find(function(re) {
      return re.test(url);
    });

    if (matchRe) {
      return matchRe.exec(url)[1];
    }

    return null;
  }

  var _stringWs =
    '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' +
    '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';

  var space = '[' + _stringWs + ']';
  var non = '\u200b\u0085';
  var ltrim = RegExp('^' + space + space + '*');
  var rtrim = RegExp(space + space + '*$');

  var exporter = function(KEY, exec, ALIAS) {
    var exp = {};
    var FORCE = _fails(function() {
      return !!_stringWs[KEY]() || non[KEY]() != non;
    });
    var fn = (exp[KEY] = FORCE ? exec(trim) : _stringWs[KEY]);
    if (ALIAS) exp[ALIAS] = fn;
    _export(_export.P + _export.F * FORCE, 'String', exp);
  }; // 1 -> String#trimLeft
  // 2 -> String#trimRight
  // 3 -> String#trim

  var trim = (exporter.trim = function(string, TYPE) {
    string = String(_defined(string));
    if (TYPE & 1) string = string.replace(ltrim, '');
    if (TYPE & 2) string = string.replace(rtrim, '');
    return string;
  });

  var _stringTrim = exporter;

  var $parseInt = _global.parseInt;

  var $trim = _stringTrim.trim;

  var hex = /^[-+]?0[xX]/;
  var _parseInt =
    $parseInt(_stringWs + '08') !== 8 || $parseInt(_stringWs + '0x16') !== 22
      ? function parseInt(str, radix) {
          var string = $trim(String(str), 3);
          return $parseInt(string, radix >>> 0 || (hex.test(string) ? 16 : 10));
        }
      : $parseInt;

  // 18.2.5 parseInt(string, radix)

  _export(_export.G + _export.F * (parseInt != _parseInt), {
    parseInt: _parseInt,
  });

  var _parseInt$1 = _core.parseInt;

  var _parseInt$2 = _parseInt$1;

  // An expression that looks to try to find the page digit within a URL, if
  // it exists.
  // Matches:
  //  page=1
  //  pg=1
  //  p=1
  //  paging=12
  //  pag=7
  //  pagination/1
  //  paging/88
  //  pa/83
  //  p/11
  //
  // Does not match:
  //  pg=102
  //  page:2
  var PAGE_IN_HREF_RE = new RegExp(
    '(page|paging|(p(a|g|ag)?(e|enum|ewanted|ing|ination)))?(=|/)([0-9]{1,3})',
    'i'
  );
  var HAS_ALPHA_RE = /[a-z]/i;
  var IS_ALPHA_RE = /^[a-z]+$/i;
  var IS_DIGIT_RE = /^[0-9]+$/i;
  var ENCODING_RE = /charset=([\w-]+)\b/;
  var DEFAULT_ENCODING = 'utf-8';

  function pageNumFromUrl(url) {
    var matches = url.match(PAGE_IN_HREF_RE);
    if (!matches) return null;

    var pageNum = _parseInt$2(matches[6], 10); // Return pageNum < 100, otherwise
    // return null

    return pageNum < 100 ? pageNum : null;
  }

  function removeAnchor(url) {
    return url.split('#')[0].replace(/\/$/, '');
  }

  // 22.1.2.2 / 15.4.3.2 Array.isArray(arg)

  _export(_export.S, 'Array', {
    isArray: _isArray,
  });

  var isArray = _core.Array.isArray;

  var isArray$1 = isArray;

  function _arrayWithHoles(arr) {
    if (isArray$1(arr)) return arr;
  }

  var arrayWithHoles = _arrayWithHoles;

  var core_getIterator = (_core.getIterator = function(it) {
    var iterFn = core_getIteratorMethod(it);
    if (typeof iterFn != 'function') throw TypeError(it + ' is not iterable!');
    return _anObject(iterFn.call(it));
  });

  var getIterator = core_getIterator;

  var getIterator$1 = getIterator;

  function _iterableToArrayLimit(arr, i) {
    var _arr = [];
    var _n = true;
    var _d = false;
    var _e = undefined;

    try {
      for (
        var _i = getIterator$1(arr), _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'] != null) _i['return']();
      } finally {
        if (_d) throw _e;
      }
    }

    return _arr;
  }

  var iterableToArrayLimit = _iterableToArrayLimit;

  function _nonIterableRest() {
    throw new TypeError('Invalid attempt to destructure non-iterable instance');
  }

  var nonIterableRest = _nonIterableRest;

  function _slicedToArray(arr, i) {
    return (
      arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || nonIterableRest()
    );
  }

  var slicedToArray = _slicedToArray;

  function isGoodSegment(segment, index, firstSegmentHasLetters) {
    var goodSegment = true; // If this is purely a number, and it's the first or second
    // url_segment, it's probably a page number. Remove it.

    if (index < 2 && IS_DIGIT_RE.test(segment) && segment.length < 3) {
      goodSegment = true;
    } // If this is the first url_segment and it's just "index",
    // remove it

    if (index === 0 && segment.toLowerCase() === 'index') {
      goodSegment = false;
    } // If our first or second url_segment is smaller than 3 characters,
    // and the first url_segment had no alphas, remove it.

    if (index < 2 && segment.length < 3 && !firstSegmentHasLetters) {
      goodSegment = false;
    }

    return goodSegment;
  } // Take a URL, and return the article base of said URL. That is, no
  // pagination data exists in it. Useful for comparing to other links
  // that might have pagination data within them.

  function articleBaseUrl(url$$1, parsed) {
    var parsedUrl = parsed || url.parse(url$$1);
    var protocol = parsedUrl.protocol,
      host = parsedUrl.host,
      path = parsedUrl.path;
    var firstSegmentHasLetters = false;
    var cleanedSegments = path
      .split('/')
      .reverse()
      .reduce(function(acc, rawSegment, index) {
        var segment = rawSegment; // Split off and save anything that looks like a file type.

        if (segment.includes('.')) {
          var _segment$split = segment.split('.'),
            _segment$split2 = slicedToArray(_segment$split, 2),
            possibleSegment = _segment$split2[0],
            fileExt = _segment$split2[1];

          if (IS_ALPHA_RE.test(fileExt)) {
            segment = possibleSegment;
          }
        } // If our first or second segment has anything looking like a page
        // number, remove it.

        if (PAGE_IN_HREF_RE.test(segment) && index < 2) {
          segment = segment.replace(PAGE_IN_HREF_RE, '');
        } // If we're on the first segment, check to see if we have any
        // characters in it. The first segment is actually the last bit of
        // the URL, and this will be helpful to determine if we're on a URL
        // segment that looks like "/2/" for example.

        if (index === 0) {
          firstSegmentHasLetters = HAS_ALPHA_RE.test(segment);
        } // If it's not marked for deletion, push it to cleaned_segments.

        if (isGoodSegment(segment, index, firstSegmentHasLetters)) {
          acc.push(segment);
        }

        return acc;
      }, []);
    return ''
      .concat(protocol, '//')
      .concat(host)
      .concat(cleanedSegments.reverse().join('/'));
  }

  // Given a string, return True if it appears to have an ending sentence
  // within it, false otherwise.
  var SENTENCE_END_RE = new RegExp('.( |$)');
  function hasSentenceEnd(text) {
    return SENTENCE_END_RE.test(text);
  }

  function excerptContent(content) {
    var words =
      arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 10;
    return content
      .trim()
      .split(/\s+/)
      .slice(0, words)
      .join(' ');
  }

  // used in our fetchResource function to
  // ensure correctly encoded responses

  function getEncoding(str) {
    var encoding = DEFAULT_ENCODING;

    if (ENCODING_RE.test(str)) {
      var testEncode = ENCODING_RE.exec(str)[1];

      if (iconv.encodingExists(testEncode)) {
        encoding = testEncode;
      }
    }

    return encoding;
  }

  var nextLine = function(str) {
    var offset = 0;
    str = str.toString();
    return iterator;

    function iterator() {
      var i1 = str.indexOf('\r\n', offset);
      var i2 = str.indexOf('\n', offset);
      var i3 = str.indexOf('\r', offset);
      var indexes = [i1, i2, i3];
      var index = indexes
        .sort(function(a, b) {
          if (a > b) return 1;
          if (a < b) return -1;
          return 0;
        })
        .filter(function(index) {
          return index !== -1;
        })[0];
      if (index !== undefined) return extract(index, index === i1 ? 2 : 1);
      var length = str.length;
      if (length === offset) return null;
      return extract(length, 0);
    }

    function extract(index, skip) {
      var line = str.substr(offset, index - offset);
      offset = index + skip;
      return line;
    }
  };

  // RFC-2068 Start-Line definitions:
  //   Request-Line: Method SP Request-URI SP HTTP-Version CRLF
  //   Status-Line:  HTTP-Version SP Status-Code SP Reason-Phrase CRLF

  var startLine = /^[A-Z_]+(\/\d\.\d)? /;
  var requestLine = /^([A-Z_]+) (.+) [A-Z]+\/(\d)\.(\d)$/;
  var statusLine = /^[A-Z]+\/(\d)\.(\d) (\d{3}) (.*)$/;

  var httpHeaders = function(data, onlyHeaders) {
    return parse$1(normalize(data), onlyHeaders);
  };

  function parse$1(str, onlyHeaders) {
    var line = firstLine(str);
    var match;

    if (onlyHeaders && startLine.test(line)) {
      return parseHeaders(str);
    } else if ((match = line.match(requestLine)) !== null) {
      return {
        method: match[1],
        url: match[2],
        version: {
          major: parseInt(match[3], 10),
          minor: parseInt(match[4], 10),
        },
        headers: parseHeaders(str),
      };
    } else if ((match = line.match(statusLine)) !== null) {
      return {
        version: {
          major: parseInt(match[1], 10),
          minor: parseInt(match[2], 10),
        },
        statusCode: parseInt(match[3], 10),
        statusMessage: match[4],
        headers: parseHeaders(str),
      };
    } else {
      return parseHeaders(str);
    }
  }

  function parseHeaders(str) {
    var headers = {};
    var next = nextLine(str);
    var line = next();
    var index, name, value;
    if (startLine.test(line)) line = next();

    while (line) {
      // subsequent lines in multi-line headers start with whitespace
      if (line[0] === ' ' || line[0] === '\t') {
        value += ' ' + line.trim();
        line = next();
        continue;
      }

      if (name) addHeaderLine(name, value, headers);
      index = line.indexOf(':');
      name = line.substr(0, index);
      value = line.substr(index + 1).trim();
      line = next();
    }

    if (name) addHeaderLine(name, value, headers);
    return headers;
  }

  function normalize(str) {
    if (str && str._header) str = str._header; // extra headers from http.ServerResponse object

    if (!str || typeof str.toString !== 'function') return '';
    return str.toString().trim();
  }

  function firstLine(str) {
    return str.slice(0, str.indexOf('\r\n'));
  } // The following function is lifted from:
  // https://github.com/nodejs/node/blob/f1294f5bfd7f02bce8029818be9c92de59749137/lib/_http_incoming.js#L116-L170
  //
  // Add the given (field, value) pair to the message
  //
  // Per RFC2616, section 4.2 it is acceptable to join multiple instances of the
  // same header with a ', ' if the header in question supports specification of
  // multiple values this way. If not, we declare the first instance the winner
  // and drop the second. Extended header fields (those beginning with 'x-') are
  // always joined.

  function addHeaderLine(field, value, dest) {
    field = field.toLowerCase();

    switch (field) {
      // Array headers:
      case 'set-cookie':
        if (dest[field] !== undefined) {
          dest[field].push(value);
        } else {
          dest[field] = [value];
        }

        break;
      // list is taken from:
      // https://mxr.mozilla.org/mozilla/source/netwerk/protocol/http/src/nsHttpHeaderArray.cpp

      case 'content-type':
      case 'content-length':
      case 'user-agent':
      case 'referer':
      case 'host':
      case 'authorization':
      case 'proxy-authorization':
      case 'if-modified-since':
      case 'if-unmodified-since':
      case 'from':
      case 'location':
      case 'max-forwards':
      case 'retry-after':
      case 'etag':
      case 'last-modified':
      case 'server':
      case 'age':
      case 'expires':
        // drop duplicates
        if (dest[field] === undefined) dest[field] = value;
        break;

      default:
        // make comma-separated list
        if (typeof dest[field] === 'string') {
          dest[field] += ', ' + value;
        } else {
          dest[field] = value;
        }
    }
  }

  // Browser Request
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.

  var XHR = XMLHttpRequest;
  if (!XHR) throw new Error('missing XMLHttpRequest');
  request.log = {
    trace: noop,
    debug: noop,
    info: noop,
    warn: noop,
    error: noop,
  };
  var DEFAULT_TIMEOUT = 3 * 60 * 1000; // 3 minutes
  //
  // request
  //

  function request(options, callback) {
    // The entry-point to the API: prep the options object and pass the real work to run_xhr.
    if (typeof callback !== 'function')
      throw new Error('Bad callback given: ' + callback);
    if (!options) throw new Error('No options given');
    var options_onResponse = options.onResponse; // Save this for later.

    if (typeof options === 'string')
      options = {
        uri: options,
      };
    else options = JSON.parse(JSON.stringify(options)); // Use a duplicate for mutating.

    options.onResponse = options_onResponse; // And put it back.

    if (options.verbose) request.log = getLogger();

    if (options.url) {
      options.uri = options.url;
      delete options.url;
    }

    if (!options.uri && options.uri !== '')
      throw new Error('options.uri is a required argument');
    if (typeof options.uri != 'string')
      throw new Error('options.uri must be a string');
    var unsupported_options = [
      'proxy',
      '_redirectsFollowed',
      'maxRedirects',
      'followRedirect',
    ];

    for (var i = 0; i < unsupported_options.length; i++)
      if (options[unsupported_options[i]])
        throw new Error(
          'options.' + unsupported_options[i] + ' is not supported'
        );

    options.callback = callback;
    options.method = options.method || 'GET';
    options.headers = options.headers || {};
    options.body = options.body || null;
    options.timeout = options.timeout || request.DEFAULT_TIMEOUT;
    if (options.headers.host)
      throw new Error('Options.headers.host is not supported');

    if (options.json) {
      options.headers.accept = options.headers.accept || 'application/json';
      if (options.method !== 'GET')
        options.headers['content-type'] = 'application/json';
      if (typeof options.json !== 'boolean')
        options.body = JSON.stringify(options.json);
      else if (typeof options.body !== 'string')
        options.body = JSON.stringify(options.body);
    } //BEGIN QS Hack

    var serialize = function(obj) {
      var str = [];

      for (var p in obj)
        if (obj.hasOwnProperty(p)) {
          str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
        }

      return str.join('&');
    };

    if (options.qs) {
      var qs =
        typeof options.qs == 'string' ? options.qs : serialize(options.qs);

      if (options.uri.indexOf('?') !== -1) {
        //no get params
        options.uri = options.uri + '&' + qs;
      } else {
        //existing get params
        options.uri = options.uri + '?' + qs;
      }
    } //END QS Hack
    //BEGIN FORM Hack

    var multipart = function(obj) {
      //todo: support file type (useful?)
      var result = {};
      result.boundry =
        '-------------------------------' +
        Math.floor(Math.random() * 1000000000);
      var lines = [];

      for (var p in obj) {
        if (obj.hasOwnProperty(p)) {
          lines.push(
            '--' +
              result.boundry +
              '\n' +
              'Content-Disposition: form-data; name="' +
              p +
              '"' +
              '\n' +
              '\n' +
              obj[p] +
              '\n'
          );
        }
      }

      lines.push('--' + result.boundry + '--');
      result.body = lines.join('');
      result.length = result.body.length;
      result.type = 'multipart/form-data; boundary=' + result.boundry;
      return result;
    };

    if (options.form) {
      if (typeof options.form == 'string') throw 'form name unsupported';

      if (options.method === 'POST') {
        var encoding = (
          options.encoding || 'application/x-www-form-urlencoded'
        ).toLowerCase();
        options.headers['content-type'] = encoding;

        switch (encoding) {
          case 'application/x-www-form-urlencoded':
            options.body = serialize(options.form).replace(/%20/g, '+');
            break;

          case 'multipart/form-data':
            var multi = multipart(options.form); //options.headers['content-length'] = multi.length;

            options.body = multi.body;
            options.headers['content-type'] = multi.type;
            break;

          default:
            throw new Error('unsupported encoding:' + encoding);
        }
      }
    } //END FORM Hack
    // If onResponse is boolean true, call back immediately when the response is known,
    // not when the full request is complete.

    options.onResponse = options.onResponse || noop;

    if (options.onResponse === true) {
      options.onResponse = callback;
      options.callback = noop;
    } // XXX Browsers do not like this.
    //if(options.body)
    //  options.headers['content-length'] = options.body.length;
    // HTTP basic authentication

    if (!options.headers.authorization && options.auth)
      options.headers.authorization =
        'Basic ' + b64_enc(options.auth.username + ':' + options.auth.password);
    return run_xhr(options);
  }

  var req_seq = 0;

  function run_xhr(options) {
    var xhr = new XHR(),
      timed_out = false,
      is_cors = is_crossDomain(options.uri),
      supports_cors = 'withCredentials' in xhr;
    req_seq += 1;
    xhr.seq_id = req_seq;
    xhr.id = req_seq + ': ' + options.method + ' ' + options.uri;
    xhr._id = xhr.id; // I know I will type "_id" from habit all the time.

    if (is_cors && !supports_cors) {
      var cors_err = new Error(
        'Browser does not support cross-origin request: ' + options.uri
      );
      cors_err.cors = 'unsupported';
      return options.callback(cors_err, xhr);
    }

    xhr.timeoutTimer = setTimeout(too_late, options.timeout);

    function too_late() {
      timed_out = true;
      var er = new Error('ETIMEDOUT');
      er.code = 'ETIMEDOUT';
      er.duration = options.timeout;
      request.log.error('Timeout', {
        id: xhr._id,
        milliseconds: options.timeout,
      });
      return options.callback(er, xhr);
    } // Some states can be skipped over, so remember what is still incomplete.

    var did = {
      response: false,
      loading: false,
      end: false,
    };
    xhr.onreadystatechange = on_state_change;
    xhr.open(options.method, options.uri, true); // asynchronous

    if (is_cors) xhr.withCredentials = !!options.withCredentials;
    xhr.send(options.body);
    return xhr;

    function on_state_change(event) {
      if (timed_out)
        return request.log.debug('Ignoring timed out state change', {
          state: xhr.readyState,
          id: xhr.id,
        });
      request.log.debug('State change', {
        state: xhr.readyState,
        id: xhr.id,
        timed_out: timed_out,
      });

      if (xhr.readyState === XHR.OPENED) {
        request.log.debug('Request started', {
          id: xhr.id,
        });

        for (var key in options.headers)
          xhr.setRequestHeader(key, options.headers[key]);
      } else if (xhr.readyState === XHR.HEADERS_RECEIVED) on_response();
      else if (xhr.readyState === XHR.LOADING) {
        on_response();
        on_loading();
      } else if (xhr.readyState === XHR.DONE) {
        on_response();
        on_loading();
        on_end();
      }
    }

    function on_response() {
      if (did.response) return;
      did.response = true;
      request.log.debug('Got response', {
        id: xhr.id,
        status: xhr.status,
      });
      clearTimeout(xhr.timeoutTimer);
      xhr.statusCode = xhr.status; // Node request compatibility
      // Detect failed CORS requests.

      if (is_cors && xhr.statusCode == 0) {
        var cors_err = new Error('CORS request rejected: ' + options.uri);
        cors_err.cors = 'rejected'; // Do not process this request further.

        did.loading = true;
        did.end = true;
        return options.callback(cors_err, xhr);
      }

      options.onResponse(null, xhr);
    }

    function on_loading() {
      if (did.loading) return;
      did.loading = true;
      request.log.debug('Response body loading', {
        id: xhr.id,
      }); // TODO: Maybe simulate "data" events by watching xhr.responseText
    }

    function on_end() {
      if (did.end) return;
      did.end = true;
      request.log.debug('Request done', {
        id: xhr.id,
      });
      xhr.body = xhr.responseText;
      xhr.headers = httpHeaders(xhr.getAllResponseHeaders());

      if (options.json) {
        try {
          xhr.body = JSON.parse(xhr.responseText);
        } catch (er) {
          return options.callback(er, xhr);
        }
      }

      options.callback(null, xhr, xhr.body);
    }
  } // request

  request.withCredentials = false;
  request.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT; //
  // defaults
  //

  request.defaults = function(options, requester) {
    var def = function(method) {
      var d = function(params, callback) {
        if (typeof params === 'string')
          params = {
            uri: params,
          };
        else {
          params = JSON.parse(JSON.stringify(params));
        }

        for (var i in options) {
          if (params[i] === undefined) params[i] = options[i];
        }

        return method(params, callback);
      };

      return d;
    };

    var de = def(request);
    de.get = def(request.get);
    de.post = def(request.post);
    de.put = def(request.put);
    de.head = def(request.head);
    return de;
  }; //
  // HTTP method shortcuts
  //

  var shortcuts = ['get', 'put', 'post', 'head'];
  shortcuts.forEach(function(shortcut) {
    var method = shortcut.toUpperCase();
    var func = shortcut.toLowerCase();

    request[func] = function(opts) {
      if (typeof opts === 'string')
        opts = {
          method: method,
          uri: opts,
        };
      else {
        opts = JSON.parse(JSON.stringify(opts));
        opts.method = method;
      }
      var args = [opts].concat(Array.prototype.slice.apply(arguments, [1]));
      return request.apply(this, args);
    };
  }); //
  // CouchDB shortcut
  //

  request.couch = function(options, callback) {
    if (typeof options === 'string')
      options = {
        uri: options, // Just use the request API to do JSON.
      };
    options.json = true;
    if (options.body) options.json = options.body;
    delete options.body;
    callback = callback || noop;
    var xhr = request(options, couch_handler);
    return xhr;

    function couch_handler(er, resp, body) {
      if (er) return callback(er, resp, body);

      if ((resp.statusCode < 200 || resp.statusCode > 299) && body.error) {
        // The body is a Couch JSON object indicating the error.
        er = new Error(
          'CouchDB error: ' + (body.error.reason || body.error.error)
        );

        for (var key in body) er[key] = body[key];

        return callback(er, resp, body);
      }

      return callback(er, resp, body);
    }
  }; //
  // Utility
  //

  function noop() {}

  function getLogger() {
    var logger = {},
      levels = ['trace', 'debug', 'info', 'warn', 'error'],
      level,
      i;

    for (i = 0; i < levels.length; i++) {
      level = levels[i];
      logger[level] = noop;
      if (typeof console !== 'undefined' && console && console[level])
        logger[level] = formatted(console, level);
    }

    return logger;
  }

  function formatted(obj, method) {
    return formatted_logger;

    function formatted_logger(str, context) {
      if (typeof context === 'object') str += ' ' + JSON.stringify(context);
      return obj[method].call(obj, str);
    }
  } // Return whether a URL is a cross-domain request.

  function is_crossDomain(url) {
    var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/; // jQuery #8138, IE may throw an exception when accessing
    // a field from window.location if document.domain has been set

    var ajaxLocation;

    try {
      ajaxLocation = location.href;
    } catch (e) {
      // Use the href attribute of an A element since IE will modify it given document.location
      ajaxLocation = document.createElement('a');
      ajaxLocation.href = '';
      ajaxLocation = ajaxLocation.href;
    }

    var ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || [],
      parts = rurl.exec(url.toLowerCase());
    var result = !!(
      parts &&
      (parts[1] != ajaxLocParts[1] ||
        parts[2] != ajaxLocParts[2] ||
        (parts[3] || (parts[1] === 'http:' ? 80 : 443)) !=
          (ajaxLocParts[3] || (ajaxLocParts[1] === 'http:' ? 80 : 443)))
    ); //console.debug('is_crossDomain('+url+') -> ' + result)

    return result;
  } // MIT License from http://phpjs.org/functions/base64_encode:358

  function b64_enc(data) {
    // Encodes string using MIME base64 algorithm
    var b64 =
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
    var o1,
      o2,
      o3,
      h1,
      h2,
      h3,
      h4,
      bits,
      i = 0,
      ac = 0,
      enc = '',
      tmp_arr = [];

    if (!data) {
      return data;
    } // assume utf8 data
    // data = this.utf8_encode(data+'');

    do {
      // pack three octets into four hexets
      o1 = data.charCodeAt(i++);
      o2 = data.charCodeAt(i++);
      o3 = data.charCodeAt(i++);
      bits = (o1 << 16) | (o2 << 8) | o3;
      h1 = (bits >> 18) & 0x3f;
      h2 = (bits >> 12) & 0x3f;
      h3 = (bits >> 6) & 0x3f;
      h4 = bits & 0x3f; // use hexets to index into b64, and append result to encoded string

      tmp_arr[ac++] =
        b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
    } while (i < data.length);

    enc = tmp_arr.join('');

    switch (data.length % 3) {
      case 1:
        enc = enc.slice(0, -2) + '==';
        break;

      case 2:
        enc = enc.slice(0, -1) + '=';
        break;
    }

    return enc;
  }

  var browserRequest = request;

  var _marked =
    /*#__PURE__*/
    regenerator.mark(range);

  function range() {
    var start,
      end,
      _args = arguments;
    return regenerator.wrap(
      function range$(_context) {
        while (1) {
          switch ((_context.prev = _context.next)) {
            case 0:
              start = _args.length > 0 && _args[0] !== undefined ? _args[0] : 1;
              end = _args.length > 1 && _args[1] !== undefined ? _args[1] : 1;

            case 2:
              if (!(start <= end)) {
                _context.next = 7;
                break;
              }

              _context.next = 5;
              return (start += 1);

            case 5:
              _context.next = 2;
              break;

            case 7:
            case 'end':
              return _context.stop();
          }
        }
      },
      _marked,
      this
    );
  }

  // extremely simple url validation as a first step
  function validateUrl(_ref) {
    var hostname = _ref.hostname;
    // If this isn't a valid url, return an error message
    return !!hostname;
  }

  var Errors = {
    badUrl: {
      error: true,
      messages:
        'The url parameter passed does not look like a valid URL. Please check your data and try again.',
    },
  };

  var REQUEST_HEADERS = $.browser
    ? {}
    : {
        'User-Agent':
          'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
      }; // The number of milliseconds to attempt to fetch a resource before timing out.

  var FETCH_TIMEOUT = 10000; // Content types that we do not extract content from

  var BAD_CONTENT_TYPES = [
    'audio/mpeg',
    'image/gif',
    'image/jpeg',
    'image/jpg',
  ];
  var BAD_CONTENT_TYPES_RE = new RegExp(
    '^('.concat(BAD_CONTENT_TYPES.join('|'), ')$'),
    'i'
  ); // Use this setting as the maximum size an article can be
  // for us to attempt parsing. Defaults to 5 MB.

  var MAX_CONTENT_LENGTH = 5242880; // Turn the global proxy on or off

  function get(options) {
    return new promise$1(function(resolve$$1, reject) {
      browserRequest(options, function(err, response, body) {
        if (err) {
          reject(err);
        } else {
          resolve$$1({
            body: body,
            response: response,
          });
        }
      });
    });
  } // Evaluate a response to ensure it's something we should be keeping.
  // This does not validate in the sense of a response being 200 level or
  // not. Validation here means that we haven't found reason to bail from
  // further processing of this url.

  function validateResponse(response) {
    var parseNon2xx =
      arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

    // Check if we got a valid status code
    // This isn't great, but I'm requiring a statusMessage to be set
    // before short circuiting b/c nock doesn't set it in tests
    // statusMessage only not set in nock response, in which case
    // I check statusCode, which is currently only 200 for OK responses
    // in tests
    if (
      (response.statusMessage && response.statusMessage !== 'OK') ||
      response.statusCode !== 200
    ) {
      if (!response.statusCode) {
        throw new Error(
          'Unable to fetch content. Original exception was '.concat(
            response.error
          )
        );
      } else if (!parseNon2xx) {
        throw new Error(
          'Resource returned a response status code of '.concat(
            response.statusCode,
            ' and resource was instructed to reject non-2xx level status codes.'
          )
        );
      }
    }

    var _response$headers = response.headers,
      contentType = _response$headers['content-type'],
      contentLength = _response$headers['content-length']; // Check that the content is not in BAD_CONTENT_TYPES

    if (BAD_CONTENT_TYPES_RE.test(contentType)) {
      throw new Error(
        'Content-type for this resource was '.concat(
          contentType,
          ' and is not allowed.'
        )
      );
    } // Check that the content length is below maximum

    if (contentLength > MAX_CONTENT_LENGTH) {
      throw new Error(
        'Content for this resource was too large. Maximum content length is '.concat(
          MAX_CONTENT_LENGTH,
          '.'
        )
      );
    }

    return true;
  } // Grabs the last two pieces of the URL and joins them back together
  // TODO: This should gracefully handle timeouts and raise the
  //       proper exceptions on the many failure cases of HTTP.
  // TODO: Ensure we are not fetching something enormous. Always return
  //       unicode content for HTML, with charset conversion.

  function fetchResource(_x, _x2) {
    return _fetchResource.apply(this, arguments);
  }

  function _fetchResource() {
    _fetchResource = asyncToGenerator(
      /*#__PURE__*/
      regenerator.mark(function _callee(url$$1, parsedUrl) {
        var options, _ref2, response, body;

        return regenerator.wrap(
          function _callee$(_context) {
            while (1) {
              switch ((_context.prev = _context.next)) {
                case 0:
                  parsedUrl = parsedUrl || url.parse(encodeURI(url$$1));
                  options = {
                    url: parsedUrl.href,
                    headers: objectSpread({}, REQUEST_HEADERS),
                    timeout: FETCH_TIMEOUT,
                    // Accept cookies
                    jar: true,
                    // Set to null so the response returns as binary and body as buffer
                    // https://github.com/request/request#requestoptions-callback
                    encoding: null,
                    // Accept and decode gzip
                    gzip: true,
                    // Follow any redirect
                    followAllRedirects: true,
                  };
                  _context.next = 4;
                  return get(options);

                case 4:
                  _ref2 = _context.sent;
                  response = _ref2.response;
                  body = _ref2.body;
                  _context.prev = 7;
                  validateResponse(response);
                  return _context.abrupt('return', {
                    body: body,
                    response: response,
                  });

                case 12:
                  _context.prev = 12;
                  _context.t0 = _context['catch'](7);
                  return _context.abrupt('return', Errors.badUrl);

                case 15:
                case 'end':
                  return _context.stop();
              }
            }
          },
          _callee,
          this,
          [[7, 12]]
        );
      })
    );
    return _fetchResource.apply(this, arguments);
  }

  function convertMetaProp($, from, to) {
    $('meta['.concat(from, ']')).each(function(_, node) {
      var $node = $(node);
      var value = $node.attr(from);
      $node.attr(to, value);
      $node.removeAttr(from);
    });
    return $;
  } // For ease of use in extracting from meta tags,
  // replace the "content" attribute on meta tags with the
  // "value" attribute.
  //
  // In addition, normalize 'property' attributes to 'name' for ease of
  // querying later. See, e.g., og or twitter meta tags.

  function normalizeMetaTags($) {
    $ = convertMetaProp($, 'content', 'value');
    $ = convertMetaProp($, 'property', 'name');
    return $;
  }

  // all object keys, includes non-enumerable and symbols

  var Reflect = _global.Reflect;

  var _ownKeys =
    (Reflect && Reflect.ownKeys) ||
    function ownKeys(it) {
      var keys = _objectGopn.f(_anObject(it));
      var getSymbols = _objectGops.f;
      return getSymbols ? keys.concat(getSymbols(it)) : keys;
    };

  // 26.1.11 Reflect.ownKeys(target)

  _export(_export.S, 'Reflect', {
    ownKeys: _ownKeys,
  });

  var ownKeys = _core.Reflect.ownKeys;

  var ownKeys$1 = ownKeys;

  // Spacer images to be removed
  var SPACER_RE = new RegExp('transparent|spacer|blank', 'i'); // The class we will use to mark elements we want to keep
  // but would normally remove

  var KEEP_CLASS = 'mercury-parser-keep';
  var KEEP_SELECTORS = [
    'iframe[src^="https://www.youtube.com"]',
    'iframe[src^="https://www.youtube-nocookie.com"]',
    'iframe[src^="http://www.youtube.com"]',
    'iframe[src^="https://player.vimeo"]',
    'iframe[src^="http://player.vimeo"]',
  ]; // A list of tags to strip from the output if we encounter them.

  var STRIP_OUTPUT_TAGS = [
    'title',
    'script',
    'noscript',
    'link',
    'style',
    'hr',
    'embed',
    'iframe',
    'object',
  ]; // cleanAttributes
  var WHITELIST_ATTRS = [
    'src',
    'srcset',
    'href',
    'class',
    'id',
    'alt',
    'xlink:href',
    'width',
    'height',
  ];
  var WHITELIST_ATTRS_RE = new RegExp(
    '^('.concat(WHITELIST_ATTRS.join('|'), ')$'),
    'i'
  ); // removeEmpty

  var CLEAN_CONDITIONALLY_TAGS = [
    'ul',
    'ol',
    'table',
    'div',
    'button',
    'form',
  ].join(','); // cleanHeaders

  var HEADER_TAGS = ['h2', 'h3', 'h4', 'h5', 'h6'];
  var HEADER_TAG_LIST = HEADER_TAGS.join(','); // // CONTENT FETCHING CONSTANTS ////
  // A list of strings that can be considered unlikely candidates when
  // extracting content from a resource. These strings are joined together
  // and then tested for existence using re:test, so may contain simple,
  // non-pipe style regular expression queries if necessary.

  var UNLIKELY_CANDIDATES_BLACKLIST = [
    'ad-break',
    'adbox',
    'advert',
    'addthis',
    'agegate',
    'aux',
    'blogger-labels',
    'combx',
    'comment',
    'conversation',
    'disqus',
    'entry-unrelated',
    'extra',
    'foot', // 'form', // This is too generic, has too many false positives
    'header',
    'hidden',
    'loader',
    'login', // Note: This can hit 'blogindex'.
    'menu',
    'meta',
    'nav',
    'outbrain',
    'pager',
    'pagination',
    'predicta', // readwriteweb inline ad box
    'presence_control_external', // lifehacker.com container full of false positives
    'popup',
    'printfriendly',
    'related',
    'remove',
    'remark',
    'rss',
    'share',
    'shoutbox',
    'sidebar',
    'sociable',
    'sponsor',
    'taboola',
    'tools',
  ]; // A list of strings that can be considered LIKELY candidates when
  // extracting content from a resource. Essentially, the inverse of the
  // blacklist above - if something matches both blacklist and whitelist,
  // it is kept. This is useful, for example, if something has a className
  // of "rss-content entry-content". It matched 'rss', so it would normally
  // be removed, however, it's also the entry content, so it should be left
  // alone.
  //
  // These strings are joined together and then tested for existence using
  // re:test, so may contain simple, non-pipe style regular expression queries
  // if necessary.

  var UNLIKELY_CANDIDATES_WHITELIST = [
    'and',
    'article',
    'body',
    'blogindex',
    'column',
    'content',
    'entry-content-asset',
    'format', // misuse of form
    'hfeed',
    'hentry',
    'hatom',
    'main',
    'page',
    'posts',
    'shadow',
  ]; // A list of tags which, if found inside, should cause a <div /> to NOT
  // be turned into a paragraph tag. Shallow div tags without these elements
  // should be turned into <p /> tags.

  var DIV_TO_P_BLOCK_TAGS = [
    'a',
    'blockquote',
    'dl',
    'div',
    'img',
    'p',
    'pre',
    'table',
  ].join(','); // A list of tags that should be ignored when trying to find the top candidate
  // an article container. Checked against className and id.
  //
  // TODO: Perhaps have these scale based on their odds of being quality?

  var POSITIVE_SCORE_HINTS = [
    'article',
    'articlecontent',
    'instapaper_body',
    'blog',
    'body',
    'content',
    'entry-content-asset',
    'entry',
    'hentry',
    'main',
    'Normal',
    'page',
    'pagination',
    'permalink',
    'post',
    'story',
    'text',
    '[-_]copy', // usatoday
    '\\Bcopy',
  ]; // The above list, joined into a matching regular expression

  var POSITIVE_SCORE_RE = new RegExp(POSITIVE_SCORE_HINTS.join('|'), 'i'); // Readability publisher-specific guidelines
  // an article container. Checked against className and id.
  //
  // TODO: Perhaps have these scale based on their odds of being quality?

  var NEGATIVE_SCORE_HINTS = [
    'adbox',
    'advert',
    'author',
    'bio',
    'bookmark',
    'bottom',
    'byline',
    'clear',
    'com-',
    'combx',
    'comment',
    'comment\\B',
    'contact',
    'copy',
    'credit',
    'crumb',
    'date',
    'deck',
    'excerpt',
    'featured', // tnr.com has a featured_content which throws us off
    'foot',
    'footer',
    'footnote',
    'graf',
    'head',
    'info',
    'infotext', // newscientist.com copyright
    'instapaper_ignore',
    'jump',
    'linebreak',
    'link',
    'masthead',
    'media',
    'meta',
    'modal',
    'outbrain', // slate.com junk
    'promo',
    'pr_', // autoblog - press release
    'related',
    'respond',
    'roundcontent', // lifehacker restricted content warning
    'scroll',
    'secondary',
    'share',
    'shopping',
    'shoutbox',
    'side',
    'sidebar',
    'sponsor',
    'stamp',
    'sub',
    'summary',
    'tags',
    'tools',
    'widget',
  ]; // The above list, joined into a matching regular expression

  var NEGATIVE_SCORE_RE = new RegExp(NEGATIVE_SCORE_HINTS.join('|'), 'i'); // XPath to try to determine if a page is wordpress. Not always successful.

  var IS_WP_SELECTOR = 'meta[name=generator][value^=WordPress]'; // Match a digit. Pretty clear.

  var PAGE_RE = new RegExp('pag(e|ing|inat)', 'i'); // Match any link text/classname/id that looks like it could mean the next
  // http://bit.ly/qneNIT

  var BLOCK_LEVEL_TAGS = [
    'article',
    'aside',
    'blockquote',
    'body',
    'br',
    'button',
    'canvas',
    'caption',
    'col',
    'colgroup',
    'dd',
    'div',
    'dl',
    'dt',
    'embed',
    'fieldset',
    'figcaption',
    'figure',
    'footer',
    'form',
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6',
    'header',
    'hgroup',
    'hr',
    'li',
    'map',
    'object',
    'ol',
    'output',
    'p',
    'pre',
    'progress',
    'section',
    'table',
    'tbody',
    'textarea',
    'tfoot',
    'th',
    'thead',
    'tr',
    'ul',
    'video',
  ];
  var BLOCK_LEVEL_TAGS_RE = new RegExp(
    '^('.concat(BLOCK_LEVEL_TAGS.join('|'), ')$'),
    'i'
  ); // The removal is implemented as a blacklist and whitelist, this test finds
  // blacklisted elements that aren't whitelisted. We do this all in one
  // expression-both because it's only one pass, and because this skips the
  // serialization for whitelisted nodes.

  var candidatesBlacklist = UNLIKELY_CANDIDATES_BLACKLIST.join('|');
  var CANDIDATES_BLACKLIST = new RegExp(candidatesBlacklist, 'i');
  var candidatesWhitelist = UNLIKELY_CANDIDATES_WHITELIST.join('|');
  var CANDIDATES_WHITELIST = new RegExp(candidatesWhitelist, 'i');

  function stripUnlikelyCandidates($) {
    //  Loop through the provided document and remove any non-link nodes
    //  that are unlikely candidates for article content.
    //
    //  Links are ignored because there are very often links to content
    //  that are identified as non-body-content, but may be inside
    //  article-like content.
    //
    //  :param $: a cheerio object to strip nodes from
    //  :return $: the cleaned cheerio object
    $('*')
      .not('a')
      .each(function(index, node) {
        var $node = $(node);
        var classes = $node.attr('class');
        var id = $node.attr('id');
        if (!id && !classes) return;
        var classAndId = ''.concat(classes || '', ' ').concat(id || '');

        if (CANDIDATES_WHITELIST.test(classAndId)) {
          return;
        }

        if (CANDIDATES_BLACKLIST.test(classAndId)) {
          $node.remove();
        }
      });
    return $;
  }

  // Another good candidate for refactoring/optimizing.
  // Very imperative code, I don't love it. - AP
  //  Given cheerio object, convert consecutive <br /> tags into
  //  <p /> tags instead.
  //
  //  :param $: A cheerio object

  function brsToPs$$1($) {
    var collapsing = false;
    $('br').each(function(index, element) {
      var $element = $(element);
      var nextElement = $element.next().get(0);

      if (nextElement && nextElement.tagName.toLowerCase() === 'br') {
        collapsing = true;
        $element.remove();
      } else if (collapsing) {
        collapsing = false; // $(element).replaceWith('<p />')

        paragraphize(element, $, true);
      }
    });
    return $;
  }

  // make sure it conforms to the constraints of a P tag (I.E. does
  // not contain any other block tags.)
  //
  // If the node is a <br />, it treats the following inline siblings
  // as if they were its children.
  //
  // :param node: The node to paragraphize; this is a raw node
  // :param $: The cheerio object to handle dom manipulation
  // :param br: Whether or not the passed node is a br

  function paragraphize(node, $) {
    var br =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
    var $node = $(node);

    if (br) {
      var sibling = node.nextSibling;
      var p = $('<p></p>'); // while the next node is text or not a block level element
      // append it to a new p node

      while (
        sibling &&
        !(sibling.tagName && BLOCK_LEVEL_TAGS_RE.test(sibling.tagName))
      ) {
        var _sibling = sibling,
          nextSibling = _sibling.nextSibling;
        $(sibling).appendTo(p);
        sibling = nextSibling;
      }

      $node.replaceWith(p);
      $node.remove();
      return $;
    }

    return $;
  }

  function convertDivs($) {
    $('div').each(function(index, div) {
      var $div = $(div);
      var convertable = $div.children(DIV_TO_P_BLOCK_TAGS).length === 0;

      if (convertable) {
        convertNodeTo$$1($div, $, 'p');
      }
    });
    return $;
  }

  function convertSpans($) {
    $('span').each(function(index, span) {
      var $span = $(span);
      var convertable = $span.parents('p, div').length === 0;

      if (convertable) {
        convertNodeTo$$1($span, $, 'p');
      }
    });
    return $;
  } // Loop through the provided doc, and convert any p-like elements to
  // actual paragraph tags.
  //
  //   Things fitting this criteria:
  //   * Multiple consecutive <br /> tags.
  //   * <div /> tags without block level elements inside of them
  //   * <span /> tags who are not children of <p /> or <div /> tags.
  //
  //   :param $: A cheerio object to search
  //   :return cheerio object with new p elements
  //   (By-reference mutation, though. Returned just for convenience.)

  function convertToParagraphs$$1($) {
    $ = brsToPs$$1($);
    $ = convertDivs($);
    $ = convertSpans($);
    return $;
  }

  function convertNodeTo$$1($node, $) {
    var tag =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'p';
    var node = $node.get(0);

    if (!node) {
      return $;
    }

    var attrs = getAttrs(node) || {}; // console.log(attrs)

    var attribString = ownKeys$1(attrs)
      .map(function(key) {
        return ''.concat(key, '=').concat(attrs[key]);
      })
      .join(' ');

    var html;

    if ($.browser) {
      // In the browser, the contents of noscript tags aren't rendered, therefore
      // transforms on the noscript tag (commonly used for lazy-loading) don't work
      // as expected. This test case handles that
      html =
        node.tagName.toLowerCase() === 'noscript' ? $node.text() : $node.html();
    } else {
      html = $node.contents();
    }

    $node.replaceWith(
      '<'
        .concat(tag, ' ')
        .concat(attribString, '>')
        .concat(html, '</')
        .concat(tag, '>')
    );
    return $;
  }

  function cleanForHeight($img, $) {
    var height = _parseInt$2($img.attr('height'), 10);

    var width = _parseInt$2($img.attr('width'), 10) || 20; // Remove images that explicitly have very small heights or
    // widths, because they are most likely shims or icons,
    // which aren't very useful for reading.

    if ((height || 20) < 10 || width < 10) {
      $img.remove();
    } else if (height) {
      // Don't ever specify a height on images, so that we can
      // scale with respect to width without screwing up the
      // aspect ratio.
      $img.removeAttr('height');
    }

    return $;
  } // Cleans out images where the source string matches transparent/spacer/etc
  // TODO This seems very aggressive - AP

  function removeSpacers($img, $) {
    if (SPACER_RE.test($img.attr('src'))) {
      $img.remove();
    }

    return $;
  }

  function cleanImages($article, $) {
    $article.find('img').each(function(index, img) {
      var $img = $(img);
      cleanForHeight($img, $);
      removeSpacers($img, $);
    });
    return $;
  }

  function _arrayWithoutHoles(arr) {
    if (isArray$1(arr)) {
      for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) {
        arr2[i] = arr[i];
      }

      return arr2;
    }
  }

  var arrayWithoutHoles = _arrayWithoutHoles;

  var _createProperty = function(object, index, value) {
    if (index in object) _objectDp.f(object, index, _propertyDesc(0, value));
    else object[index] = value;
  };

  _export(_export.S + _export.F * !_iterDetect(function(iter) {}), 'Array', {
    // 22.1.2.1 Array.from(arrayLike, mapfn = undefined, thisArg = undefined)
    from: function from(
      arrayLike
      /* , mapfn = undefined, thisArg = undefined */
    ) {
      var O = _toObject(arrayLike);
      var C = typeof this == 'function' ? this : Array;
      var aLen = arguments.length;
      var mapfn = aLen > 1 ? arguments[1] : undefined;
      var mapping = mapfn !== undefined;
      var index = 0;
      var iterFn = core_getIteratorMethod(O);
      var length, result, step, iterator;
      if (mapping) mapfn = _ctx(mapfn, aLen > 2 ? arguments[2] : undefined, 2); // if object isn't iterable or it's array with default iterator - use simple case

      if (iterFn != undefined && !(C == Array && _isArrayIter(iterFn))) {
        for (
          iterator = iterFn.call(O), result = new C();
          !(step = iterator.next()).done;
          index++
        ) {
          _createProperty(
            result,
            index,
            mapping
              ? _iterCall(iterator, mapfn, [step.value, index], true)
              : step.value
          );
        }
      } else {
        length = _toLength(O.length);

        for (result = new C(length); length > index; index++) {
          _createProperty(
            result,
            index,
            mapping ? mapfn(O[index], index) : O[index]
          );
        }
      }

      result.length = index;
      return result;
    },
  });

  var from_1 = _core.Array.from;

  var from_1$1 = from_1;

  var ITERATOR$4 = _wks('iterator');

  var core_isIterable = (_core.isIterable = function(it) {
    var O = Object(it);
    return (
      O[ITERATOR$4] !== undefined ||
      '@@iterator' in O || // eslint-disable-next-line no-prototype-builtins
      _iterators.hasOwnProperty(_classof(O))
    );
  });

  var isIterable = core_isIterable;

  var isIterable$1 = isIterable;

  function _iterableToArray(iter) {
    if (
      isIterable$1(Object(iter)) ||
      Object.prototype.toString.call(iter) === '[object Arguments]'
    )
      return from_1$1(iter);
  }

  var iterableToArray = _iterableToArray;

  function _nonIterableSpread() {
    throw new TypeError('Invalid attempt to spread non-iterable instance');
  }

  var nonIterableSpread = _nonIterableSpread;

  function _toConsumableArray(arr) {
    return (
      arrayWithoutHoles(arr) || iterableToArray(arr) || nonIterableSpread()
    );
  }

  var toConsumableArray = _toConsumableArray;

  function markToKeep(article, $, url$$1) {
    var tags =
      arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];

    if (tags.length === 0) {
      tags = KEEP_SELECTORS;
    }

    if (url$$1) {
      var _URL$parse = url.parse(url$$1),
        protocol = _URL$parse.protocol,
        hostname = _URL$parse.hostname;

      tags = [].concat(toConsumableArray(tags), [
        'iframe[src^="'.concat(protocol, '//').concat(hostname, '"]'),
      ]);
    }

    $(tags.join(','), article).addClass(KEEP_CLASS);
    return $;
  }

  function stripJunkTags(article, $) {
    var tags =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];

    if (tags.length === 0) {
      tags = STRIP_OUTPUT_TAGS;
    } // Remove matching elements, but ignore
    // any element with a class of mercury-parser-keep

    $(tags.join(','), article)
      .not('.'.concat(KEEP_CLASS))
      .remove();
    return $;
  }

  // by the title extractor instead. If there's less than 3 of them (<3),
  // strip them. Otherwise, turn 'em into H2s.

  function cleanHOnes$$1(article, $) {
    var $hOnes = $('h1', article);

    if ($hOnes.length < 3) {
      $hOnes.each(function(index, node) {
        return $(node).remove();
      });
    } else {
      $hOnes.each(function(index, node) {
        convertNodeTo$$1($(node), $, 'h2');
      });
    }

    return $;
  }

  function removeAllButWhitelist($article, $) {
    $article.find('*').each(function(index, node) {
      var attrs = getAttrs(node);
      setAttrs(
        node,
        ownKeys$1(attrs).reduce(function(acc, attr) {
          if (WHITELIST_ATTRS_RE.test(attr)) {
            return objectSpread(
              {},
              acc,
              defineProperty$3({}, attr, attrs[attr])
            );
          }

          return acc;
        }, {})
      );
    }); // Remove the mercury-parser-keep class from result

    $('.'.concat(KEEP_CLASS), $article).removeClass(KEEP_CLASS);
    return $article;
  } // function removeAttrs(article, $) {
  //   REMOVE_ATTRS.forEach((attr) => {
  //     $(`[${attr}]`, article).removeAttr(attr);
  //   });
  // }
  // Remove attributes like style or align

  function cleanAttributes$$1($article, $) {
    // Grabbing the parent because at this point
    // $article will be wrapped in a div which will
    // have a score set on it.
    return removeAllButWhitelist(
      $article.parent().length ? $article.parent() : $article,
      $
    );
  }

  function removeEmpty($article, $) {
    $article.find('p').each(function(index, p) {
      var $p = $(p);
      if ($p.find('iframe, img').length === 0 && $p.text().trim() === '')
        $p.remove();
    });
    return $;
  }

  // // CONTENT FETCHING CONSTANTS ////
  // for a document.

  var NON_TOP_CANDIDATE_TAGS$1 = [
    'br',
    'b',
    'i',
    'label',
    'hr',
    'area',
    'base',
    'basefont',
    'input',
    'img',
    'link',
    'meta',
  ];
  var NON_TOP_CANDIDATE_TAGS_RE$1 = new RegExp(
    '^('.concat(NON_TOP_CANDIDATE_TAGS$1.join('|'), ')$'),
    'i'
  ); // A list of selectors that specify, very clearly, either hNews or other
  // very content-specific style content, like Blogger templates.
  // More examples here: http://microformats.org/wiki/blog-post-formats

  var HNEWS_CONTENT_SELECTORS$1 = [
    ['.hentry', '.entry-content'],
    ['entry', '.entry-content'],
    ['.entry', '.entry_content'],
    ['.post', '.postbody'],
    ['.post', '.post_body'],
    ['.post', '.post-body'],
  ];
  var PHOTO_HINTS$1 = ['figure', 'photo', 'image', 'caption'];
  var PHOTO_HINTS_RE$1 = new RegExp(PHOTO_HINTS$1.join('|'), 'i'); // A list of strings that denote a positive scoring for this content as being
  // an article container. Checked against className and id.
  //
  // TODO: Perhaps have these scale based on their odds of being quality?

  var POSITIVE_SCORE_HINTS$1 = [
    'article',
    'articlecontent',
    'instapaper_body',
    'blog',
    'body',
    'content',
    'entry-content-asset',
    'entry',
    'hentry',
    'main',
    'Normal',
    'page',
    'pagination',
    'permalink',
    'post',
    'story',
    'text',
    '[-_]copy', // usatoday
    '\\Bcopy',
  ]; // The above list, joined into a matching regular expression

  var POSITIVE_SCORE_RE$1 = new RegExp(POSITIVE_SCORE_HINTS$1.join('|'), 'i'); // Readability publisher-specific guidelines

  var READABILITY_ASSET$1 = new RegExp('entry-content-asset', 'i'); // A list of strings that denote a negative scoring for this content as being
  // an article container. Checked against className and id.
  //
  // TODO: Perhaps have these scale based on their odds of being quality?

  var NEGATIVE_SCORE_HINTS$1 = [
    'adbox',
    'advert',
    'author',
    'bio',
    'bookmark',
    'bottom',
    'byline',
    'clear',
    'com-',
    'combx',
    'comment',
    'comment\\B',
    'contact',
    'copy',
    'credit',
    'crumb',
    'date',
    'deck',
    'excerpt',
    'featured', // tnr.com has a featured_content which throws us off
    'foot',
    'footer',
    'footnote',
    'graf',
    'head',
    'info',
    'infotext', // newscientist.com copyright
    'instapaper_ignore',
    'jump',
    'linebreak',
    'link',
    'masthead',
    'media',
    'meta',
    'modal',
    'outbrain', // slate.com junk
    'promo',
    'pr_', // autoblog - press release
    'related',
    'respond',
    'roundcontent', // lifehacker restricted content warning
    'scroll',
    'secondary',
    'share',
    'shopping',
    'shoutbox',
    'side',
    'sidebar',
    'sponsor',
    'stamp',
    'sub',
    'summary',
    'tags',
    'tools',
    'widget',
  ]; // The above list, joined into a matching regular expression

  var NEGATIVE_SCORE_RE$1 = new RegExp(NEGATIVE_SCORE_HINTS$1.join('|'), 'i'); // Match a digit. Pretty clear.
  var PARAGRAPH_SCORE_TAGS$1 = new RegExp('^(p|li|span|pre)$', 'i');
  var CHILD_CONTENT_TAGS$1 = new RegExp('^(td|blockquote|ol|ul|dl)$', 'i');
  var BAD_TAGS$1 = new RegExp('^(address|form)$', 'i');

  function getWeight(node) {
    var classes = node.attr('class');
    var id = node.attr('id');
    var score = 0;

    if (id) {
      // if id exists, try to score on both positive and negative
      if (POSITIVE_SCORE_RE$1.test(id)) {
        score += 25;
      }

      if (NEGATIVE_SCORE_RE$1.test(id)) {
        score -= 25;
      }
    }

    if (classes) {
      if (score === 0) {
        // if classes exist and id did not contribute to score
        // try to score on both positive and negative
        if (POSITIVE_SCORE_RE$1.test(classes)) {
          score += 25;
        }

        if (NEGATIVE_SCORE_RE$1.test(classes)) {
          score -= 25;
        }
      } // even if score has been set by id, add score for
      // possible photo matches
      // "try to keep photos if we can"

      if (PHOTO_HINTS_RE$1.test(classes)) {
        score += 10;
      } // add 25 if class matches entry-content-asset,
      // a class apparently instructed for use in the
      // Readability publisher guidelines
      // https://www.readability.com/developers/guidelines

      if (READABILITY_ASSET$1.test(classes)) {
        score += 25;
      }
    }

    return score;
  }

  var $parseFloat = _global.parseFloat;

  var $trim$1 = _stringTrim.trim;

  var _parseFloat =
    1 / $parseFloat(_stringWs + '-0') !== -Infinity
      ? function parseFloat(str) {
          var string = $trim$1(String(str), 3);
          var result = $parseFloat(string);
          return result === 0 && string.charAt(0) == '-' ? -0 : result;
        }
      : $parseFloat;

  // 18.2.4 parseFloat(string)

  _export(_export.G + _export.F * (parseFloat != _parseFloat), {
    parseFloat: _parseFloat,
  });

  var _parseFloat$1 = _core.parseFloat;

  var _parseFloat$2 = _parseFloat$1;

  // returns the score of a node based on
  // the node's score attribute
  // returns null if no score set
  function getScore($node) {
    return _parseFloat$2($node.attr('score')) || null;
  }

  // return 1 for every comma in text
  function scoreCommas(text) {
    return (text.match(/,/g) || []).length;
  }

  var idkRe = new RegExp('^(p|pre)$', 'i');
  function scoreLength(textLength) {
    var tagName =
      arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'p';
    var chunks = textLength / 50;

    if (chunks > 0) {
      var lengthBonus; // No idea why p or pre are being tamped down here
      // but just following the source for now
      // Not even sure why tagName is included here,
      // since this is only being called from the context
      // of scoreParagraph

      if (idkRe.test(tagName)) {
        lengthBonus = chunks - 2;
      } else {
        lengthBonus = chunks - 1.25;
      }

      return Math.min(Math.max(lengthBonus, 0), 3);
    }

    return 0;
  }

  // commas, etc. Higher is better.

  function scoreParagraph$$1(node) {
    var score = 1;
    var text = node.text().trim();
    var textLength = text.length; // If this paragraph is less than 25 characters, don't count it.

    if (textLength < 25) {
      return 0;
    } // Add points for any commas within this paragraph

    score += scoreCommas(text); // For every 50 characters in this paragraph, add another point. Up
    // to 3 points.

    score += scoreLength(textLength); // Articles can end with short paragraphs when people are being clever
    // but they can also end with short paragraphs setting up lists of junk
    // that we strip. This negative tweaks junk setup paragraphs just below
    // the cutoff threshold.

    if (text.slice(-1) === ':') {
      score -= 1;
    }

    return score;
  }

  function setScore($node, $, score) {
    $node.attr('score', score);
    return $node;
  }

  function addScore$$1($node, $, amount) {
    try {
      var score = getOrInitScore$$1($node, $) + amount;
      setScore($node, $, score);
    } catch (e) {
      // Ignoring; error occurs in scoreNode
    }

    return $node;
  }

  function addToParent$$1(node, $, score) {
    var parent = node.parent();

    if (parent) {
      addScore$$1(parent, $, score * 0.25);
    }

    return node;
  }

  // if not, initializes a score based on
  // the node's tag type

  function getOrInitScore$$1($node, $) {
    var weightNodes =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
    var score = getScore($node);

    if (score) {
      return score;
    }

    score = scoreNode$$1($node);

    if (weightNodes) {
      score += getWeight($node);
    }

    addToParent$$1($node, $, score);
    return score;
  }

  // just scores based on tag.

  function scoreNode$$1($node) {
    var _$node$get = $node.get(0),
      tagName = _$node$get.tagName; // TODO: Consider ordering by most likely.
    // E.g., if divs are a more common tag on a page,
    // Could save doing that regex test on every node – AP

    if (PARAGRAPH_SCORE_TAGS$1.test(tagName)) {
      return scoreParagraph$$1($node);
    }

    if (tagName.toLowerCase() === 'div') {
      return 5;
    }

    if (CHILD_CONTENT_TAGS$1.test(tagName)) {
      return 3;
    }

    if (BAD_TAGS$1.test(tagName)) {
      return -3;
    }

    if (tagName.toLowerCase() === 'th') {
      return -5;
    }

    return 0;
  }

  function convertSpans$1($node, $) {
    if ($node.get(0)) {
      var _$node$get = $node.get(0),
        tagName = _$node$get.tagName;

      if (tagName === 'span') {
        // convert spans to divs
        convertNodeTo$$1($node, $, 'div');
      }
    }
  }

  function addScoreTo($node, $, score) {
    if ($node) {
      convertSpans$1($node, $);
      addScore$$1($node, $, score);
    }
  }

  function scorePs($, weightNodes) {
    $('p, pre')
      .not('[score]')
      .each(function(index, node) {
        // The raw score for this paragraph, before we add any parent/child
        // scores.
        var $node = $(node);
        $node = setScore($node, $, getOrInitScore$$1($node, $, weightNodes));
        var $parent = $node.parent();
        var rawScore = scoreNode$$1($node);
        addScoreTo($parent, $, rawScore, weightNodes);

        if ($parent) {
          // Add half of the individual content score to the
          // grandparent
          addScoreTo($parent.parent(), $, rawScore / 2, weightNodes);
        }
      });
    return $;
  } // score content. Parents get the full value of their children's
  // content score, grandparents half

  function scoreContent$$1($) {
    var weightNodes =
      arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
    // First, look for special hNews based selectors and give them a big
    // boost, if they exist
    HNEWS_CONTENT_SELECTORS$1.forEach(function(_ref) {
      var _ref2 = slicedToArray(_ref, 2),
        parentSelector = _ref2[0],
        childSelector = _ref2[1];

      $(''.concat(parentSelector, ' ').concat(childSelector)).each(function(
        index,
        node
      ) {
        addScore$$1($(node).parent(parentSelector), $, 80);
      });
    }); // Doubling this again
    // Previous solution caused a bug
    // in which parents weren't retaining
    // scores. This is not ideal, and
    // should be fixed.

    scorePs($, weightNodes);
    scorePs($, weightNodes);
    return $;
  }

  // it to see if any of them are decently scored. If they are, they
  // may be split parts of the content (Like two divs, a preamble and
  // a body.) Example:
  // http://articles.latimes.com/2009/oct/14/business/fi-bigtvs14

  function mergeSiblings($candidate, topScore, $) {
    if (!$candidate.parent().length) {
      return $candidate;
    }

    var siblingScoreThreshold = Math.max(10, topScore * 0.25);
    var wrappingDiv = $('<div></div>');
    $candidate
      .parent()
      .children()
      .each(function(index, sibling) {
        var $sibling = $(sibling); // Ignore tags like BR, HR, etc

        if (NON_TOP_CANDIDATE_TAGS_RE$1.test(sibling.tagName)) {
          return null;
        }

        var siblingScore = getScore($sibling);

        if (siblingScore) {
          if ($sibling.get(0) === $candidate.get(0)) {
            wrappingDiv.append($sibling);
          } else {
            var contentBonus = 0;
            var density = linkDensity($sibling); // If sibling has a very low link density,
            // give it a small bonus

            if (density < 0.05) {
              contentBonus += 20;
            } // If sibling has a high link density,
            // give it a penalty

            if (density >= 0.5) {
              contentBonus -= 20;
            } // If sibling node has the same class as
            // candidate, give it a bonus

            if ($sibling.attr('class') === $candidate.attr('class')) {
              contentBonus += topScore * 0.2;
            }

            var newScore = siblingScore + contentBonus;

            if (newScore >= siblingScoreThreshold) {
              return wrappingDiv.append($sibling);
            }

            if (sibling.tagName === 'p') {
              var siblingContent = $sibling.text();
              var siblingContentLength = textLength(siblingContent);

              if (siblingContentLength > 80 && density < 0.25) {
                return wrappingDiv.append($sibling);
              }

              if (
                siblingContentLength <= 80 &&
                density === 0 &&
                hasSentenceEnd(siblingContent)
              ) {
                return wrappingDiv.append($sibling);
              }
            }
          }
        }

        return null;
      });

    if (
      wrappingDiv.children().length === 1 &&
      wrappingDiv
        .children()
        .first()
        .get(0) === $candidate.get(0)
    ) {
      return $candidate;
    }

    return wrappingDiv;
  }

  // candidate nodes we found and find the one with the highest score.

  function findTopCandidate$$1($) {
    var $candidate;
    var topScore = 0;
    $('[score]').each(function(index, node) {
      // Ignore tags like BR, HR, etc
      if (NON_TOP_CANDIDATE_TAGS_RE$1.test(node.tagName)) {
        return;
      }

      var $node = $(node);
      var score = getScore($node);

      if (score > topScore) {
        topScore = score;
        $candidate = $node;
      }
    }); // If we don't have a candidate, return the body
    // or whatever the first element is

    if (!$candidate) {
      return $('body') || $('*').first();
    }

    $candidate = mergeSiblings($candidate, topScore, $);
    return $candidate;
  }

  // Scoring

  function removeUnlessContent($node, $, weight) {
    // Explicitly save entry-content-asset tags, which are
    // noted as valuable in the Publisher guidelines. For now
    // this works everywhere. We may want to consider making
    // this less of a sure-thing later.
    if ($node.hasClass('entry-content-asset')) {
      return;
    }

    var content = normalizeSpaces($node.text());

    if (scoreCommas(content) < 10) {
      var pCount = $('p', $node).length;
      var inputCount = $('input', $node).length; // Looks like a form, too many inputs.

      if (inputCount > pCount / 3) {
        $node.remove();
        return;
      }

      var contentLength = content.length;
      var imgCount = $('img', $node).length; // Content is too short, and there are no images, so
      // this is probably junk content.

      if (contentLength < 25 && imgCount === 0) {
        $node.remove();
        return;
      }

      var density = linkDensity($node); // Too high of link density, is probably a menu or
      // something similar.
      // console.log(weight, density, contentLength)

      if (weight < 25 && density > 0.2 && contentLength > 75) {
        $node.remove();
        return;
      } // Too high of a link density, despite the score being
      // high.

      if (weight >= 25 && density > 0.5) {
        // Don't remove the node if it's a list and the
        // previous sibling starts with a colon though. That
        // means it's probably content.
        var tagName = $node.get(0).tagName.toLowerCase();
        var nodeIsList = tagName === 'ol' || tagName === 'ul';

        if (nodeIsList) {
          var previousNode = $node.prev();

          if (
            previousNode &&
            normalizeSpaces(previousNode.text()).slice(-1) === ':'
          ) {
            return;
          }
        }

        $node.remove();
        return;
      }

      var scriptCount = $('script', $node).length; // Too many script tags, not enough content.

      if (scriptCount > 0 && contentLength < 150) {
        $node.remove();
      }
    }
  } // Given an article, clean it of some superfluous content specified by
  // tags. Things like forms, ads, etc.
  //
  // Tags is an array of tag name's to search through. (like div, form,
  // etc)
  //
  // Return this same doc.

  function cleanTags$$1($article, $) {
    $(CLEAN_CONDITIONALLY_TAGS, $article).each(function(index, node) {
      var $node = $(node); // If marked to keep, skip it

      if (
        $node.hasClass(KEEP_CLASS) ||
        $node.find('.'.concat(KEEP_CLASS)).length > 0
      )
        return;
      var weight = getScore($node);

      if (!weight) {
        weight = getOrInitScore$$1($node, $);
        setScore($node, $, weight);
      } // drop node if its weight is < 0

      if (weight < 0) {
        $node.remove();
      } else {
        // deteremine if node seems like content
        removeUnlessContent($node, $, weight);
      }
    });
    return $;
  }

  function cleanHeaders($article, $) {
    var title =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
    $(HEADER_TAG_LIST, $article).each(function(index, header) {
      var $header = $(header); // Remove any headers that appear before all other p tags in the
      // document. This probably means that it was part of the title, a
      // subtitle or something else extraneous like a datestamp or byline,
      // all of which should be handled by other metadata handling.

      if ($($header, $article).prevAll('p').length === 0) {
        return $header.remove();
      } // Remove any headers that match the title exactly.

      if (normalizeSpaces($(header).text()) === title) {
        return $header.remove();
      } // If this header has a negative weight, it's probably junk.
      // Get rid of it.

      if (getWeight($(header)) < 0) {
        return $header.remove();
      }

      return $header;
    });
    return $;
  }

  // html to avoid later complications with multiple body tags.

  function rewriteTopLevel$$1(article, $) {
    // I'm not using context here because
    // it's problematic when converting the
    // top-level/root node - AP
    $ = convertNodeTo$$1($('html'), $, 'div');
    $ = convertNodeTo$$1($('body'), $, 'div');
    return $;
  }

  function absolutize($, rootUrl, attr, $content) {
    $('['.concat(attr, ']'), $content).each(function(_, node) {
      var attrs = getAttrs(node);
      var url$$1 = attrs[attr];

      if (url$$1) {
        var absoluteUrl = url.resolve(rootUrl, url$$1);
        setAttr(node, attr, absoluteUrl);
      }
    });
  }

  function makeLinksAbsolute$$1($content, $, url$$1) {
    ['href', 'src'].forEach(function(attr) {
      return absolutize($, url$$1, attr, $content);
    });
    return $content;
  }

  function textLength(text) {
    return text.trim().replace(/\s+/g, ' ').length;
  } // Determines what percentage of the text
  // in a node is link text
  // Takes a node, returns a float

  function linkDensity($node) {
    var totalTextLength = textLength($node.text());
    var linkText = $node.find('a').text();
    var linkLength = textLength(linkText);

    if (totalTextLength > 0) {
      return linkLength / totalTextLength;
    }

    if (totalTextLength === 0 && linkLength > 0) {
      return 1;
    }

    return 0;
  }

  var iterator = _wksExt.f('iterator');

  var iterator$1 = iterator;

  _wksDefine('asyncIterator');

  _wksDefine('observable');

  var symbol = _core.Symbol;

  var symbol$1 = symbol;

  var _typeof_1 = createCommonjsModule(function(module) {
    function _typeof2(obj) {
      if (typeof symbol$1 === 'function' && typeof iterator$1 === 'symbol') {
        _typeof2 = function _typeof2(obj) {
          return typeof obj;
        };
      } else {
        _typeof2 = function _typeof2(obj) {
          return obj &&
            typeof symbol$1 === 'function' &&
            obj.constructor === symbol$1 &&
            obj !== symbol$1.prototype
            ? 'symbol'
            : typeof obj;
        };
      }

      return _typeof2(obj);
    }

    function _typeof(obj) {
      if (typeof symbol$1 === 'function' && _typeof2(iterator$1) === 'symbol') {
        module.exports = _typeof = function _typeof(obj) {
          return _typeof2(obj);
        };
      } else {
        module.exports = _typeof = function _typeof(obj) {
          return obj &&
            typeof symbol$1 === 'function' &&
            obj.constructor === symbol$1 &&
            obj !== symbol$1.prototype
            ? 'symbol'
            : _typeof2(obj);
        };
      }

      return _typeof(obj);
    }

    module.exports = _typeof;
  });

  // search for, find a meta tag associated.

  function extractFromMeta$$1($, metaNames, cachedNames) {
    var cleanTags =
      arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
    var foundNames = metaNames.filter(function(name) {
      return cachedNames.indexOf(name) !== -1;
    }); // eslint-disable-next-line no-restricted-syntax

    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      var _loop = function _loop() {
        var name = _step.value;
        var type = 'name';
        var value = 'value';
        var nodes = $('meta['.concat(type, '="').concat(name, '"]')); // Get the unique value of every matching node, in case there
        // are two meta tags with the same name and value.
        // Remove empty values.

        var values = nodes
          .map(function(index, node) {
            return $(node).attr(value);
          })
          .toArray()
          .filter(function(text) {
            return text !== '';
          }); // If we have more than one value for the same name, we have a
        // conflict and can't trust any of them. Skip this name. If we have
        // zero, that means our meta tags had no values. Skip this name
        // also.

        if (values.length === 1) {
          var metaValue; // Meta values that contain HTML should be stripped, as they
          // weren't subject to cleaning previously.

          if (cleanTags) {
            metaValue = stripTags(values[0], $);
          } else {
            var _values = slicedToArray(values, 1);

            metaValue = _values[0];
          }

          return {
            v: metaValue,
          };
        }
      };

      for (
        var _iterator = getIterator$1(foundNames), _step;
        !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
        _iteratorNormalCompletion = true
      ) {
        var _ret = _loop();

        if (_typeof_1(_ret) === 'object') return _ret.v;
      } // If nothing is found, return null
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator.return != null) {
          _iterator.return();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }

    return null;
  }

  function isGoodNode($node, maxChildren) {
    // If it has a number of children, it's more likely a container
    // element. Skip it.
    if ($node.children().length > maxChildren) {
      return false;
    } // If it looks to be within a comment, skip it.

    if (withinComment$$1($node)) {
      return false;
    }

    return true;
  } // Given a a list of selectors find content that may
  // be extractable from the document. This is for flat
  // meta-information, like author, title, date published, etc.

  function extractFromSelectors$$1($, selectors) {
    var maxChildren =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
    var textOnly =
      arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
    // eslint-disable-next-line no-restricted-syntax
    var _iteratorNormalCompletion = true;
    var _didIteratorError = false;
    var _iteratorError = undefined;

    try {
      for (
        var _iterator = getIterator$1(selectors), _step;
        !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
        _iteratorNormalCompletion = true
      ) {
        var selector = _step.value;
        var nodes = $(selector); // If we didn't get exactly one of this selector, this may be
        // a list of articles or comments. Skip it.

        if (nodes.length === 1) {
          var $node = $(nodes[0]);

          if (isGoodNode($node, maxChildren)) {
            var content = void 0;

            if (textOnly) {
              content = $node.text();
            } else {
              content = $node.html();
            }

            if (content) {
              return content;
            }
          }
        }
      }
    } catch (err) {
      _didIteratorError = true;
      _iteratorError = err;
    } finally {
      try {
        if (!_iteratorNormalCompletion && _iterator.return != null) {
          _iterator.return();
        }
      } finally {
        if (_didIteratorError) {
          throw _iteratorError;
        }
      }
    }

    return null;
  }

  // strips all tags from a string of text
  function stripTags(text, $) {
    // Wrapping text in html element prevents errors when text
    // has no html
    var cleanText = $('<span>'.concat(text, '</span>')).text();
    return cleanText === '' ? text : cleanText;
  }

  function withinComment$$1($node) {
    var parents = $node.parents().toArray();
    var commentParent = parents.find(function(parent) {
      var attrs = getAttrs(parent);
      var nodeClass = attrs.class,
        id = attrs.id;
      var classAndId = ''.concat(nodeClass, ' ').concat(id);
      return classAndId.includes('comment');
    });
    return commentParent !== undefined;
  }

  // Given a node, determine if it's article-like enough to return
  // param: node (a cheerio node)
  // return: boolean
  function nodeIsSufficient($node) {
    return $node.text().trim().length >= 100;
  }

  function isWordpress($) {
    return $(IS_WP_SELECTOR).length > 0;
  }

  function getAttrs(node) {
    var attribs = node.attribs,
      attributes = node.attributes;

    if (!attribs && attributes) {
      var attrs = ownKeys$1(attributes).reduce(function(acc, index) {
        var attr = attributes[index];
        if (!attr.name || !attr.value) return acc;
        acc[attr.name] = attr.value;
        return acc;
      }, {});

      return attrs;
    }

    return attribs;
  }

  function setAttr(node, attr, val) {
    if (node.attribs) {
      node.attribs[attr] = val;
    } else if (node.attributes) {
      node.setAttribute(attr, val);
    }

    return node;
  }

  function setAttrs(node, attrs) {
    if (node.attribs) {
      node.attribs = attrs;
    } else if (node.attributes) {
      while (node.attributes.length > 0) {
        node.removeAttribute(node.attributes[0].name);
      }

      ownKeys$1(attrs).forEach(function(key) {
        node.setAttribute(key, attrs[key]);
      });
    }

    return node;
  }

  // DOM manipulation

  var IS_LINK = new RegExp('https?://', 'i');
  var IS_IMAGE = new RegExp('.(png|gif|jpe?g)', 'i');
  var TAGS_TO_REMOVE = ['script', 'style', 'form'].join(',');

  // lazy loaded images into normal images.
  // Many sites will have img tags with no source, or an image tag with a src
  // attribute that a is a placeholer. We need to be able to properly fill in
  // the src attribute so the images are no longer lazy loaded.

  function convertLazyLoadedImages($) {
    $('img').each(function(_, img) {
      var attrs = getAttrs(img);

      ownKeys$1(attrs).forEach(function(attr) {
        var value = attrs[attr];

        if (attr !== 'src' && IS_LINK.test(value) && IS_IMAGE.test(value)) {
          $(img).attr('src', value);
        }
      });
    });
    return $;
  }

  function isComment(index, node) {
    return node.type === 'comment';
  }

  function cleanComments($) {
    $.root()
      .find('*')
      .contents()
      .filter(isComment)
      .remove();
    return $;
  }

  function clean($) {
    $(TAGS_TO_REMOVE).remove();
    $ = cleanComments($);
    return $;
  }

  var Resource = {
    // Create a Resource.
    //
    // :param url: The URL for the document we should retrieve.
    // :param response: If set, use as the response rather than
    //                  attempting to fetch it ourselves. Expects a
    //                  string.
    create: function create(url, preparedResponse, parsedUrl) {
      var _this = this;

      return asyncToGenerator(
        /*#__PURE__*/
        regenerator.mark(function _callee() {
          var result, validResponse;
          return regenerator.wrap(
            function _callee$(_context) {
              while (1) {
                switch ((_context.prev = _context.next)) {
                  case 0:
                    if (!preparedResponse) {
                      _context.next = 5;
                      break;
                    }

                    validResponse = {
                      statusMessage: 'OK',
                      statusCode: 200,
                      headers: {
                        'content-type': 'text/html',
                        'content-length': 500,
                      },
                    };
                    result = {
                      body: preparedResponse,
                      response: validResponse,
                    };
                    _context.next = 8;
                    break;

                  case 5:
                    _context.next = 7;
                    return fetchResource(url, parsedUrl);

                  case 7:
                    result = _context.sent;

                  case 8:
                    if (!result.error) {
                      _context.next = 11;
                      break;
                    }

                    result.failed = true;
                    return _context.abrupt('return', result);

                  case 11:
                    return _context.abrupt('return', _this.generateDoc(result));

                  case 12:
                  case 'end':
                    return _context.stop();
                }
              }
            },
            _callee,
            this
          );
        })
      )();
    },
    generateDoc: function generateDoc(_ref) {
      var content = _ref.body,
        response = _ref.response;
      var contentType = response.headers['content-type']; // TODO: Implement is_text function from
      // https://github.com/ReadabilityHoldings/readability/blob/8dc89613241d04741ebd42fa9fa7df1b1d746303/readability/utils/text.py#L57

      if (!contentType.includes('html') && !contentType.includes('text')) {
        throw new Error('Content does not appear to be text.');
      }

      var $$$1 = this.encodeDoc({
        content: content,
        contentType: contentType,
      });

      if ($$$1.root().children().length === 0) {
        throw new Error('No children, likely a bad parse.');
      }

      $$$1 = normalizeMetaTags($$$1);
      $$$1 = convertLazyLoadedImages($$$1);
      $$$1 = clean($$$1);
      return $$$1;
    },
    encodeDoc: function encodeDoc(_ref2) {
      var content = _ref2.content,
        contentType = _ref2.contentType;
      var encoding = getEncoding(contentType);
      var decodedContent = iconv.decode(content, encoding);
      var $$$1 = $.load(decodedContent); // after first cheerio.load, check to see if encoding matches

      var metaContentType = $$$1('meta[http-equiv=content-type]').attr(
        'content'
      );
      var properEncoding = getEncoding(metaContentType); // if encodings in the header/body dont match, use the one in the body

      if (properEncoding !== encoding) {
        decodedContent = iconv.decode(content, properEncoding);
        $$$1 = $.load(decodedContent);
      }

      return $$$1;
    },
  };

  var merge = function merge(extractor, domains) {
    return domains.reduce(function(acc, domain) {
      acc[domain] = extractor;
      return acc;
    }, {});
  };

  function mergeSupportedDomains(extractor) {
    return extractor.supportedDomains
      ? merge(
          extractor,
          [extractor.domain].concat(
            toConsumableArray(extractor.supportedDomains)
          )
        )
      : merge(extractor, [extractor.domain]);
  }

  var BloggerExtractor = {
    domain: 'blogspot.com',
    content: {
      // Blogger is insane and does not load its content
      // initially in the page, but it's all there
      // in noscript
      selectors: ['.post-content noscript'],
      // Selectors to remove from the extracted content
      clean: [],
      // Convert the noscript tag to a div
      transforms: {
        noscript: 'div',
      },
    },
    author: {
      selectors: ['.post-author-name'],
    },
    title: {
      selectors: ['.post h2.title'],
    },
    date_published: {
      selectors: ['span.publishdate'],
    },
  };

  var NYMagExtractor = {
    domain: 'nymag.com',
    content: {
      // Order by most likely. Extractor will stop on first occurrence
      selectors: ['div.article-content', 'section.body', 'article.article'],
      // Selectors to remove from the extracted content
      clean: ['.ad', '.single-related-story'],
      // Object of tranformations to make on matched elements
      // Each key is the selector, each value is the tag to
      // transform to.
      // If a function is given, it should return a string
      // to convert to or nothing (in which case it will not perform
      // the transformation.
      transforms: {
        // Convert h1s to h2s
        h1: 'h2',
        // Convert lazy-loaded noscript images to figures
        noscript: function noscript($node, $) {
          var $children = $.browser ? $($node.text()) : $node.children();

          if (
            $children.length === 1 &&
            $children.get(0) !== undefined &&
            $children.get(0).tagName.toLowerCase() === 'img'
          ) {
            return 'figure';
          }

          return null;
        },
      },
    },
    title: {
      selectors: ['h1.lede-feature-title', 'h1.headline-primary', 'h1'],
    },
    author: {
      selectors: ['.by-authors', '.lede-feature-author'],
    },
    dek: {
      selectors: ['.lede-feature-teaser'],
    },
    date_published: {
      selectors: [
        ['time.article-timestamp[datetime]', 'datetime'],
        'time.article-timestamp',
      ],
    },
  };

  var WikipediaExtractor = {
    domain: 'wikipedia.org',
    content: {
      selectors: ['#mw-content-text'],
      defaultCleaner: false,
      // transform top infobox to an image with caption
      transforms: {
        '.infobox img': function infoboxImg($node) {
          var $parent = $node.parents('.infobox'); // Only prepend the first image in .infobox

          if ($parent.children('img').length === 0) {
            $parent.prepend($node);
          }
        },
        '.infobox caption': 'figcaption',
        '.infobox': 'figure',
      },
      // Selectors to remove from the extracted content
      clean: [
        '.mw-editsection',
        'figure tr, figure td, figure tbody',
        '#toc',
        '.navbox',
      ],
    },
    author: 'Wikipedia Contributors',
    title: {
      selectors: ['h2.title'],
    },
    date_published: {
      selectors: ['#footer-info-lastmod'],
    },
  };

  var TwitterExtractor = {
    domain: 'twitter.com',
    content: {
      transforms: {
        // We're transforming essentially the whole page here.
        // Twitter doesn't have nice selectors, so our initial
        // selector grabs the whole page, then we're re-writing
        // it to fit our needs before we clean it up.
        '.permalink[role=main]': function permalinkRoleMain($node, $) {
          var tweets = $node.find('.tweet');
          var $tweetContainer = $('<div id="TWEETS_GO_HERE"></div>');
          $tweetContainer.append(tweets);
          $node.replaceWith($tweetContainer);
        },
        // Twitter wraps @ with s, which
        // renders as a strikethrough
        s: 'span',
      },
      selectors: ['.permalink[role=main]'],
      defaultCleaner: false,
      clean: ['.stream-item-footer', 'button', '.tweet-details-fixer'],
    },
    author: {
      selectors: ['.tweet.permalink-tweet .username'],
    },
    date_published: {
      selectors: [
        ['.permalink-tweet ._timestamp[data-time-ms]', 'data-time-ms'],
      ],
    },
  };

  var NYTimesExtractor = {
    domain: 'www.nytimes.com',
    title: {
      selectors: ['h1.g-headline', 'h1[itemprop="headline"]', 'h1.headline'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value'], '.g-byline', '.byline'],
    },
    content: {
      selectors: ['div.g-blocks', 'article#story'],
      transforms: {
        'img.g-lazy': function imgGLazy($node) {
          var src = $node.attr('src'); // const widths = $node.attr('data-widths')
          //                   .slice(1)
          //                   .slice(0, -1)
          //                   .split(',');
          // if (widths.length) {
          //   width = widths.slice(-1);
          // } else {
          //   width = '900';
          // }

          var width = 640;
          src = src.replace('{{size}}', width);
          $node.attr('src', src);
        },
      },
      clean: [
        '.ad',
        'header#story-header',
        '.story-body-1 .lede.video',
        '.visually-hidden',
        '#newsletter-promo',
        '.promo',
        '.comments-button',
        '.hidden',
        '.comments',
        '.supplemental',
        '.nocontent',
        '.story-footer-links',
      ],
    },
    date_published: {
      selectors: [['meta[name="article:published"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: null,
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  var TheAtlanticExtractor = {
    domain: 'www.theatlantic.com',
    title: {
      selectors: ['h1.hed'],
    },
    author: {
      selectors: ['article#article .article-cover-extra .metadata .byline a'],
    },
    content: {
      selectors: [
        ['.article-cover figure.lead-img', '.article-body'],
        '.article-body',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.partner-box', '.callout'],
    },
    date_published: {
      selectors: [['time[itemProp="datePublished"]', 'datetime']],
    },
    lead_image_url: null,
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var NewYorkerExtractor = {
    domain: 'www.newyorker.com',
    title: {
      selectors: ['h1.title'],
    },
    author: {
      selectors: ['.contributors'],
    },
    content: {
      selectors: ['div#articleBody', 'div.articleBody'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
    date_published: {
      selectors: [
        ['meta[name="article:published_time"]', 'value'],
        ['time[itemProp="datePublished"]', 'content'],
      ],
      timezone: 'America/New_York',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: ['.dek', 'h2.dek'],
    },
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var WiredExtractor = {
    domain: 'www.wired.com',
    title: {
      selectors: ['h1.post-title'],
    },
    author: {
      selectors: ['a[rel="author"]'],
    },
    content: {
      selectors: ['article.content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.visually-hidden', 'figcaption img.photo'],
    },
    date_published: {
      selectors: [['meta[itemprop="datePublished"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [],
    },
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var MSNExtractor = {
    domain: 'www.msn.com',
    title: {
      selectors: ['h1'],
    },
    author: {
      selectors: ['span.authorname-txt'],
    },
    content: {
      selectors: ['div.richtext'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['span.caption'],
    },
    date_published: {
      selectors: ['span.time'],
    },
    lead_image_url: {
      selectors: [],
    },
    dek: {
      selectors: [],
    },
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var YahooExtractor = {
    domain: 'www.yahoo.com',
    title: {
      selectors: ['header.canvas-header'],
    },
    author: {
      selectors: ['span.provider-name'],
    },
    content: {
      selectors: [
        // enter content selectors
        '.content-canvas',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.figure-caption'],
    },
    date_published: {
      selectors: [['time.date[datetime]', 'datetime']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [
        // enter dek selectors
      ],
    },
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var BuzzfeedExtractor = {
    domain: 'www.buzzfeed.com',
    title: {
      selectors: ['h1[id="post-title"]'],
    },
    author: {
      selectors: ['a[data-action="user/username"]', 'byline__author'],
    },
    content: {
      selectors: [
        ['.longform_custom_header_media', '#buzz_sub_buzz'],
        '#buzz_sub_buzz',
      ],
      defaultCleaner: false,
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        h2: 'b',
        'div.longform_custom_header_media': function divLongform_custom_header_media(
          $node
        ) {
          if ($node.has('img') && $node.has('.longform_header_image_source')) {
            return 'figure';
          }

          return null;
        },
        'figure.longform_custom_header_media .longform_header_image_source':
          'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [
        '.instapaper_ignore',
        '.suplist_list_hide .buzz_superlist_item .buzz_superlist_number_inline',
        '.share-box',
        '.print',
      ],
    },
    date_published: {
      selectors: ['.buzz-datetime'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [],
    },
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var WikiaExtractor = {
    domain: 'fandom.wikia.com',
    title: {
      selectors: ['h1.entry-title'],
    },
    author: {
      selectors: ['.author vcard', '.fn'],
    },
    content: {
      selectors: ['.grid-content', '.entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [],
    },
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var LittleThingsExtractor = {
    domain: 'www.littlethings.com',
    title: {
      selectors: ['h1.post-title'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    content: {
      selectors: [
        // enter content selectors
        '.mainContentIntro',
        '.content-wrapper',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    next_page_url: null,
    excerpt: null,
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var PoliticoExtractor = {
    domain: 'www.politico.com',
    title: {
      selectors: [
        // enter title selectors
        ['meta[name="og:title"]', 'value'],
      ],
    },
    author: {
      selectors: ['.story-main-content .byline .vcard'],
    },
    content: {
      selectors: [
        // enter content selectors
        '.story-main-content',
        '.content-group',
        '.story-core',
        '.story-text',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: [],
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['figcaption'],
    },
    date_published: {
      selectors: [
        ['.story-main-content .timestamp time[datetime]', 'datetime'],
      ],
    },
    lead_image_url: {
      selectors: [
        // enter lead_image_url selectors
        ['meta[name="og:image"]', 'value'],
      ],
    },
    dek: {
      selectors: [],
    },
    next_page_url: null,
    excerpt: null,
  };

  var DeadspinExtractor = {
    domain: 'deadspin.com',
    supportedDomains: [
      'jezebel.com',
      'lifehacker.com',
      'kotaku.com',
      'gizmodo.com',
      'jalopnik.com',
      'kinja.com',
    ],
    title: {
      selectors: ['h1.headline'],
    },
    author: {
      selectors: ['.author'],
    },
    content: {
      selectors: ['.post-content', '.entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'iframe.lazyload[data-recommend-id^="youtube://"]': function iframeLazyloadDataRecommendIdYoutube(
          $node
        ) {
          var youtubeId = $node.attr('id').split('youtube-')[1];
          $node.attr('src', 'https://www.youtube.com/embed/'.concat(youtubeId));
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.magnifier', '.lightbox'],
    },
    date_published: {
      selectors: [['time.updated[datetime]', 'datetime']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    next_page_url: {
      selectors: [
        // enter selectors
      ],
    },
    excerpt: {
      selectors: [
        // enter selectors
      ],
    },
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var BroadwayWorldExtractor = {
    domain: 'www.broadwayworld.com',
    title: {
      selectors: ['h1.article-title'],
    },
    author: {
      selectors: ['span[itemprop=author]'],
    },
    content: {
      selectors: ['div[itemprop=articlebody]'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
    date_published: {
      selectors: [['meta[itemprop=datePublished]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [],
    },
    next_page_url: {
      selectors: [
        // enter selectors
      ],
    },
    excerpt: {
      selectors: [
        // enter selectors
      ],
    },
  };

  // Rename CustomExtractor
  // to fit your publication
  // (e.g., NYTimesExtractor)
  var ApartmentTherapyExtractor = {
    domain: 'www.apartmenttherapy.com',
    title: {
      selectors: ['h1.headline'],
    },
    author: {
      selectors: ['.PostByline__name'],
    },
    content: {
      selectors: ['div.post__content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'div[data-render-react-id="images/LazyPicture"]': function divDataRenderReactIdImagesLazyPicture(
          $node,
          $
        ) {
          var data = JSON.parse($node.attr('data-props'));
          var src = data.sources[0].src;
          var $img = $('<img />').attr('src', src);
          $node.replaceWith($img);
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
    date_published: {
      selectors: [['.PostByline__timestamp[datetime]', 'datetime']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [],
    },
    next_page_url: {
      selectors: [
        // enter selectors
      ],
    },
    excerpt: {
      selectors: [
        // enter selectors
      ],
    },
  };

  var MediumExtractor = {
    domain: 'medium.com',
    supportedDomains: ['trackchanges.postlight.com'],
    title: {
      selectors: ['h1'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    content: {
      selectors: [
        ['.section-content'],
        '.section-content',
        'article > div > section',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        // Re-write lazy-loaded youtube videos
        iframe: function iframe($node) {
          var ytRe = /https:\/\/i.embed.ly\/.+url=https:\/\/i\.ytimg\.com\/vi\/(\w+)\//;
          var thumb = decodeURIComponent($node.attr('data-thumbnail'));

          if (ytRe.test(thumb)) {
            var _thumb$match = thumb.match(ytRe),
              _thumb$match2 = slicedToArray(_thumb$match, 2),
              _ = _thumb$match2[0],
              youtubeId = _thumb$match2[1]; // eslint-disable-line

            $node.attr(
              'src',
              'https://www.youtube.com/embed/'.concat(youtubeId)
            );
            var $parent = $node.parents('figure');
            var $caption = $parent.find('figcaption');
            $parent.empty().append([$node, $caption]);
          }
        },
        // rewrite figures to pull out image and caption, remove rest
        figure: function figure($node) {
          // ignore if figure has an iframe
          if ($node.find('iframe').length > 0) return;
          var $img = $node.find('img').slice(-1)[0];
          var $caption = $node.find('figcaption');
          $node.empty().append([$img, $caption]);
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
    date_published: {
      selectors: [['time[datetime]', 'datetime']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    next_page_url: {
      selectors: [
        // enter selectors
      ],
    },
    excerpt: {
      selectors: [
        // enter selectors
      ],
    },
  };

  var WwwTmzComExtractor = {
    domain: 'www.tmz.com',
    title: {
      selectors: ['.post-title-breadcrumb', 'h1', '.headline'],
    },
    author: 'TMZ STAFF',
    date_published: {
      selectors: ['.article-posted-date'],
      timezone: 'America/Los_Angeles',
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article-content', '.all-post-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.lightbox-link'],
    },
  };

  var WwwWashingtonpostComExtractor = {
    domain: 'www.washingtonpost.com',
    title: {
      selectors: ['h1', '#topper-headline-wrapper'],
    },
    author: {
      selectors: ['.pb-byline'],
    },
    date_published: {
      selectors: [['.pb-timestamp[itemprop="datePublished"]', 'content']],
    },
    dek: {
      selectors: [],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'div.inline-content': function divInlineContent($node) {
          if ($node.has('img,iframe,video').length > 0) {
            return 'figure';
          }

          $node.remove();
          return null;
        },
        '.pb-caption': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.interstitial-link', '.newsletter-inline-unit'],
    },
  };

  var WwwHuffingtonpostComExtractor = {
    domain: 'www.huffingtonpost.com',
    title: {
      selectors: ['h1.headline__title'],
    },
    author: {
      selectors: ['span.author-card__details__name'],
    },
    date_published: {
      selectors: [
        ['meta[name="article:modified_time"]', 'value'],
        ['meta[name="article:published_time"]', 'value'],
      ],
    },
    dek: {
      selectors: ['h2.headline__subtitle'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.entry__body'],
      defaultCleaner: false,
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        // 'div.top-media': ($node) => {
        //   const $figure = $node.children('figure');
        //   $node.replaceWith($figure);
        // },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [
        '.pull-quote',
        '.tag-cloud',
        '.embed-asset',
        '.below-entry',
        '.entry-corrections',
        '#suggested-story',
      ],
    },
  };

  var NewrepublicComExtractor = {
    domain: 'newrepublic.com',
    title: {
      selectors: ['h1.article-headline', '.minutes-primary h1.minute-title'],
    },
    author: {
      selectors: ['div.author-list', '.minutes-primary h3.minute-byline'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: ['h2.article-subhead'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['.article-cover', 'div.content-body'],
        ['.minute-image', '.minutes-primary div.content-body'],
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['aside'],
    },
  };

  var MoneyCnnComExtractor = {
    domain: 'money.cnn.com',
    title: {
      selectors: ['.article-title'],
    },
    author: {
      selectors: ['.byline a'],
    },
    date_published: {
      selectors: [['meta[name="date"]', 'value']],
      timezone: 'GMT',
    },
    dek: {
      selectors: ['#storytext h2'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['#storytext'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.inStoryHeading'],
    },
  };

  var WwwThevergeComExtractor = {
    domain: 'www.theverge.com',
    supportedDomains: ['www.polygon.com'],
    title: {
      selectors: ['h1'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['h2.p-dek'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        // feature template multi-match
        ['.c-entry-hero .e-image', '.c-entry-intro', '.c-entry-content'], // regular post multi-match
        ['.e-image--hero', '.c-entry-content'], // feature template fallback
        '.l-wrapper .l-feature', // regular post fallback
        'div.c-entry-content',
      ],
      // Transform lazy-loaded images
      transforms: {
        noscript: function noscript($node) {
          var $children = $node.children();

          if ($children.length === 1 && $children.get(0).tagName === 'img') {
            return 'span';
          }

          return null;
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.aside', 'img.c-dynamic-image'],
    },
  };

  var WwwCnnComExtractor = {
    domain: 'www.cnn.com',
    title: {
      selectors: ['h1.pg-headline', 'h1'],
    },
    author: {
      selectors: ['.metadata__byline__author'],
    },
    date_published: {
      selectors: [['meta[name="pubdate"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        // a more specific selector to grab the lead image and the body
        ['.media__video--thumbnail', '.zn-body-text'], // a fallback for the above
        '.zn-body-text',
        'div[itemprop="articleBody"]',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.zn-body__paragraph, .el__leafmedia--sourced-paragraph': function znBody__paragraphEl__leafmediaSourcedParagraph(
          $node
        ) {
          var $text = $node.html();

          if ($text) {
            return 'p';
          }

          return null;
        },
        // this transform cleans the short, all-link sections linking
        // to related content but not marked as such in any way.
        '.zn-body__paragraph': function znBody__paragraph($node) {
          if ($node.has('a')) {
            if (
              $node.text().trim() ===
              $node
                .find('a')
                .text()
                .trim()
            ) {
              $node.remove();
            }
          }
        },
        '.media__video--thumbnail': 'figure',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwAolComExtractor = {
    domain: 'www.aol.com',
    title: {
      selectors: ['h1.p-article__title'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: ['.p-article__byline__date'],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwYoutubeComExtractor = {
    domain: 'www.youtube.com',
    title: {
      selectors: ['.watch-title', 'h1.watch-title-container'],
    },
    author: {
      selectors: ['.yt-user-info'],
    },
    date_published: {
      selectors: [['meta[itemProp="datePublished"]', 'value']],
      timezone: 'GMT',
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      defaultCleaner: false,
      selectors: [['#player-api', '#eow-description']],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '#player-api': function playerApi($node, $) {
          var videoId = $('meta[itemProp="videoId"]').attr('value');
          $node.html(
            '\n          <iframe src="https://www.youtube.com/embed/'.concat(
              videoId,
              '" frameborder="0" allowfullscreen></iframe>'
            )
          );
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwTheguardianComExtractor = {
    domain: 'www.theguardian.com',
    title: {
      selectors: ['.content__headline'],
    },
    author: {
      selectors: ['p.byline'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['.content__standfirst'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.content__article-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.hide-on-mobile', '.inline-icon'],
    },
  };

  var WwwSbnationComExtractor = {
    domain: 'www.sbnation.com',
    title: {
      selectors: ['h1.c-page-title'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['h2.c-entry-summary.p-dek'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.c-entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwBloombergComExtractor = {
    domain: 'www.bloomberg.com',
    title: {
      selectors: [
        // normal articles
        '.lede-headline', // /graphics/ template
        'h1.article-title', // /news/ template
        'h1.lede-text-only__hed',
      ],
    },
    author: {
      selectors: [
        ['meta[name="parsely-author"]', 'value'],
        '.byline-details__link', // /graphics/ template
        '.bydek', // /news/ template
        '.author',
      ],
    },
    date_published: {
      selectors: [
        ['time.published-at', 'datetime'],
        ['time[datetime]', 'datetime'],
        ['meta[name="date"]', 'value'],
        ['meta[name="parsely-pub-date"]', 'value'],
      ],
    },
    dek: {
      selectors: [],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        '.article-body__content', // /graphics/ template
        ['section.copy-block'], // /news/ template
        '.body-copy',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.inline-newsletter', '.page-ad'],
    },
  };

  var WwwBustleComExtractor = {
    domain: 'www.bustle.com',
    title: {
      selectors: ['h1.post-page__title'],
    },
    author: {
      selectors: ['div.content-meta__author'],
    },
    date_published: {
      selectors: [['time.content-meta__published-date[datetime]', 'datetime']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.post-page__body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwNprOrgExtractor = {
    domain: 'www.npr.org',
    title: {
      selectors: ['h1', '.storytitle'],
    },
    author: {
      selectors: ['p.byline__name.byline__name--block'],
    },
    date_published: {
      selectors: [
        ['.dateblock time[datetime]', 'datetime'],
        ['meta[name="date"]', 'value'],
      ],
    },
    lead_image_url: {
      selectors: [
        ['meta[name="og:image"]', 'value'],
        ['meta[name="twitter:image:src"]', 'value'],
      ],
    },
    content: {
      selectors: ['.storytext'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.bucketwrap.image': 'figure',
        '.bucketwrap.image .credit-caption': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['div.enlarge_measure'],
    },
  };

  var WwwRecodeNetExtractor = {
    domain: 'www.recode.net',
    title: {
      selectors: ['h1.c-page-title'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['h2.c-entry-summary.p-dek'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['figure.e-image--hero', '.c-entry-content'],
        '.c-entry-content',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var QzComExtractor = {
    domain: 'qz.com',
    title: {
      selectors: ['header.item-header.content-width-responsive'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: ['.timestamp'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['figure.featured-image', '.item-body'], '.item-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.article-aside', '.progressive-image-thumbnail'],
    },
  };

  var WwwDmagazineComExtractor = {
    domain: 'www.dmagazine.com',
    title: {
      selectors: ['h1.story__title'],
    },
    author: {
      selectors: ['.story__info .story__info__item:first-child'],
    },
    date_published: {
      selectors: [
        // enter selectors
        '.story__info',
      ],
      timezone: 'America/Chicago',
    },
    dek: {
      selectors: ['.story__subhead'],
    },
    lead_image_url: {
      selectors: [['article figure a:first-child', 'href']],
    },
    content: {
      selectors: ['.story__content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwReutersComExtractor = {
    domain: 'www.reuters.com',
    title: {
      selectors: ['h1.article-headline'],
    },
    author: {
      selectors: ['.author'],
    },
    date_published: {
      selectors: [['meta[name="og:article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['#article-text'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.article-subtitle': 'h4',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['#article-byline .author'],
    },
  };

  var MashableComExtractor = {
    domain: 'mashable.com',
    title: {
      selectors: ['h1.title'],
    },
    author: {
      selectors: ['span.author_name a'],
    },
    date_published: {
      selectors: [['meta[name="og:article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['section.article-content.blueprint'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.image-credit': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwChicagotribuneComExtractor = {
    domain: 'www.chicagotribune.com',
    title: {
      selectors: ['h1.trb_ar_hl_t'],
    },
    author: {
      selectors: ['span.trb_ar_by_nm_au'],
    },
    date_published: {
      selectors: [['meta[itemprop="datePublished"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.trb_ar_page'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwVoxComExtractor = {
    domain: 'www.vox.com',
    title: {
      selectors: ['h1.c-page-title'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['.p-dek'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['figure.e-image--hero', '.c-entry-content'],
        '.c-entry-content',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'figure .e-image__image noscript': function figureEImage__imageNoscript(
          $node
        ) {
          var imgHtml = $node.html();
          $node
            .parents('.e-image__image')
            .find('.c-dynamic-image')
            .replaceWith(imgHtml);
        },
        'figure .e-image__meta': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var NewsNationalgeographicComExtractor = {
    domain: 'news.nationalgeographic.com',
    title: {
      selectors: ['h1', 'h1.main-title'],
    },
    author: {
      selectors: ['.byline-component__contributors b span'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
      format: 'ddd MMM DD HH:mm:ss zz YYYY',
      timezone: 'EST',
    },
    dek: {
      selectors: ['.article__deck'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['.parsys.content', '.__image-lead__'], '.content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.parsys.content': function parsysContent($node, $) {
          var $imgSrc = $node
            .find('.image.parbase.section')
            .find('.picturefill')
            .first()
            .data('platform-src');

          if ($imgSrc) {
            $node.prepend(
              $('<img class="__image-lead__" src="'.concat($imgSrc, '"/>'))
            );
          }
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.pull-quote.pull-quote--large'],
    },
  };

  var WwwNationalgeographicComExtractor = {
    domain: 'www.nationalgeographic.com',
    title: {
      selectors: ['h1', 'h1.main-title'],
    },
    author: {
      selectors: ['.byline-component__contributors b span'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['.article__deck'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['.parsys.content', '.__image-lead__'], '.content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.parsys.content': function parsysContent($node, $) {
          var $imageParent = $node.children().first();

          if ($imageParent.hasClass('imageGroup')) {
            var $dataAttrContainer = $imageParent
              .find('.media--medium__container')
              .children()
              .first();
            var imgPath1 = $dataAttrContainer.data('platform-image1-path');
            var imgPath2 = $dataAttrContainer.data('platform-image2-path');

            if (imgPath2 && imgPath1) {
              $node.prepend(
                $(
                  '<div class="__image-lead__">\n                <img src="'
                    .concat(imgPath1, '"/>\n                <img src="')
                    .concat(imgPath2, '"/>\n              </div>')
                )
              );
            }
          } else {
            var $imgSrc = $node
              .find('.image.parbase.section')
              .find('.picturefill')
              .first()
              .data('platform-src');

            if ($imgSrc) {
              $node.prepend(
                $('<img class="__image-lead__" src="'.concat($imgSrc, '"/>'))
              );
            }
          }
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.pull-quote.pull-quote--small'],
    },
  };

  var WwwLatimesComExtractor = {
    domain: 'www.latimes.com',
    title: {
      selectors: ['.trb_ar_hl'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[itemprop="datePublished"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.trb_ar_main'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.trb_ar_la': function trb_ar_la($node) {
          var $figure = $node.find('figure');
          $node.replaceWith($figure);
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.trb_ar_by', '.trb_ar_cr'],
    },
  };

  var PagesixComExtractor = {
    domain: 'pagesix.com',
    supportedDomains: ['nypost.com'],
    title: {
      selectors: ['h1 a'],
    },
    author: {
      selectors: ['.byline'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: [['meta[name="description"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['#featured-image-wrapper', '.entry-content'],
        '.entry-content',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '#featured-image-wrapper': 'figure',
        '.wp-caption-text': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.modal-trigger'],
    },
  };

  var ThefederalistpapersOrgExtractor = {
    domain: 'thefederalistpapers.org',
    title: {
      selectors: ['h1.entry-title'],
    },
    author: {
      selectors: ['main span.entry-author-name'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [['p[style]']],
    },
  };

  var WwwCbssportsComExtractor = {
    domain: 'www.cbssports.com',
    title: {
      selectors: ['.article-headline'],
    },
    author: {
      selectors: ['.author-name'],
    },
    date_published: {
      selectors: [['.date-original-reading-time time', 'datetime']],
      timezone: 'UTC',
    },
    dek: {
      selectors: ['.article-subline'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwMsnbcComExtractor = {
    domain: 'www.msnbc.com',
    title: {
      selectors: ['h1', 'h1.is-title-pane'],
    },
    author: {
      selectors: ['.author'],
    },
    date_published: {
      selectors: [['meta[name="DC.date.issued"]', 'value']],
    },
    dek: {
      selectors: [['meta[name="description"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.pane-node-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.pane-node-body': function paneNodeBody($node, $) {
          var _WwwMsnbcComExtractor = slicedToArray(
              WwwMsnbcComExtractor.lead_image_url.selectors[0],
              2
            ),
            selector = _WwwMsnbcComExtractor[0],
            attr = _WwwMsnbcComExtractor[1];

          var src = $(selector).attr(attr);

          if (src) {
            $node.prepend('<img src="'.concat(src, '" />'));
          }
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwThepoliticalinsiderComExtractor = {
    domain: 'www.thepoliticalinsider.com',
    title: {
      selectors: [['meta[name="sailthru.title"]', 'value']],
    },
    author: {
      selectors: [['meta[name="sailthru.author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="sailthru.date"]', 'value']],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div#article-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwMentalflossComExtractor = {
    domain: 'www.mentalfloss.com',
    title: {
      selectors: ['h1.title', '.title-group', '.inner'],
    },
    author: {
      selectors: ['.field-name-field-enhanced-authors'],
    },
    date_published: {
      selectors: ['.date-display-single'],
      timezone: 'America/New_York',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.field.field-name-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var AbcnewsGoComExtractor = {
    domain: 'abcnews.go.com',
    title: {
      selectors: ['.article-header h1'],
    },
    author: {
      selectors: ['.authors'],
      clean: ['.author-overlay', '.by-text'],
    },
    date_published: {
      selectors: ['.timestamp'],
      timezone: 'America/New_York',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article-copy'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwNydailynewsComExtractor = {
    domain: 'www.nydailynews.com',
    title: {
      selectors: ['h1#ra-headline'],
    },
    author: {
      selectors: [['meta[name="parsely-author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="sailthru.date"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['article#ra-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['dl#ra-tags', '.ra-related', 'a.ra-editor', 'dl#ra-share-bottom'],
    },
  };

  var WwwCnbcComExtractor = {
    domain: 'www.cnbc.com',
    title: {
      selectors: ['h1.title'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div#article_body.content', 'div.story'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwPopsugarComExtractor = {
    domain: 'www.popsugar.com',
    title: {
      selectors: ['h2.post-title', 'title-text'],
    },
    author: {
      selectors: [['meta[name="article:author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['#content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.share-copy-title', '.post-tags', '.reactions'],
    },
  };

  var ObserverComExtractor = {
    domain: 'observer.com',
    title: {
      selectors: ['h1.entry-title'],
    },
    author: {
      selectors: ['.author', '.vcard'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['h2.dek'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var PeopleComExtractor = {
    domain: 'people.com',
    title: {
      selectors: [['meta[name="og:title"]', 'value']],
    },
    author: {
      selectors: ['a.author.url.fn'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.article-body__inner'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwUsmagazineComExtractor = {
    domain: 'www.usmagazine.com',
    title: {
      selectors: ['header h1'],
    },
    author: {
      selectors: ['a.article-byline.tracked-offpage'],
    },
    date_published: {
      timezone: 'America/New_York',
      selectors: ['time.article-published-date'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.article-body-inner'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.module-related'],
    },
  };

  var WwwRollingstoneComExtractor = {
    domain: 'www.rollingstone.com',
    title: {
      selectors: ['h1.content-title'],
    },
    author: {
      selectors: ['a.content-author.tracked-offpage'],
    },
    date_published: {
      selectors: ['time.content-published-date'],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: ['.content-description'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['.lead-container', '.article-content'], '.article-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.module-related'],
    },
  };

  var twofortysevensportsComExtractor = {
    domain: '247sports.com',
    title: {
      selectors: ['title', 'article header h1'],
    },
    author: {
      selectors: ['.author'],
    },
    date_published: {
      selectors: [['time[data-published]', 'data-published']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['section.body.article'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var UproxxComExtractor = {
    domain: 'uproxx.com',
    title: {
      selectors: ['div.post-top h1'],
    },
    author: {
      selectors: ['.post-top .authorname'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.post-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'div.image': 'figure',
        'div.image .wp-media-credit': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwEonlineComExtractor = {
    domain: 'www.eonline.com',
    title: {
      selectors: ['h1.article__title'],
    },
    author: {
      selectors: ['.entry-meta__author a'],
    },
    date_published: {
      selectors: [['meta[itemprop="datePublished"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['.post-content section, .post-content div.post-content__image'],
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'div.post-content__image': 'figure',
        'div.post-content__image .image__credits': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwMiamiheraldComExtractor = {
    domain: 'www.miamiherald.com',
    title: {
      selectors: ['h1.title'],
    },
    date_published: {
      selectors: ['p.published-date'],
      timezone: 'America/New_York',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.dateline-storybody'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwRefinery29ComExtractor = {
    domain: 'www.refinery29.com',
    title: {
      selectors: ['h1.title'],
    },
    author: {
      selectors: ['.contributor'],
    },
    date_published: {
      selectors: [['meta[name="sailthru.date"]', 'value']],
      timezone: 'America/New_York',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['.full-width-opener', '.article-content'],
        '.article-content',
        '.body',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'div.loading noscript': function divLoadingNoscript($node) {
          var imgHtml = $node.html();
          $node.parents('.loading').replaceWith(imgHtml);
        },
        '.section-image': 'figure',
        '.section-image .content-caption': 'figcaption',
        '.section-text': 'p',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.story-share'],
    },
  };

  var WwwMacrumorsComExtractor = {
    domain: 'www.macrumors.com',
    title: {
      selectors: ['h1', 'h1.title'],
    },
    author: {
      selectors: ['.author-url'],
    },
    date_published: {
      selectors: ['.article .byline'],
      // Wednesday January 18, 2017 11:44 am PST
      format: 'dddd MMMM D, YYYY h:mm A zz',
      timezone: 'America/Los_Angeles',
    },
    dek: {
      selectors: [['meta[name="description"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwAndroidcentralComExtractor = {
    domain: 'www.androidcentral.com',
    title: {
      selectors: ['h1', 'h1.main-title'],
    },
    author: {
      selectors: ['.meta-by'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: [['meta[name="og:description"]', 'value']],
    },
    lead_image_url: {
      selectors: [['.image-large', 'src']],
    },
    content: {
      selectors: ['.article-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.intro', 'blockquote'],
    },
  };

  var WwwSiComExtractor = {
    domain: 'www.si.com',
    title: {
      selectors: ['h1', 'h1.headline'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: ['.timestamp'],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: ['.quick-hit ul'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['p', '.marquee_large_2x', '.component.image']],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        noscript: function noscript($node) {
          var $children = $node.children();

          if ($children.length === 1 && $children.get(0).tagName === 'img') {
            return 'figure';
          }

          return null;
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [
        ['.inline-thumb', '.primary-message', '.description', '.instructions'],
      ],
    },
  };

  var WwwRawstoryComExtractor = {
    domain: 'www.rawstory.com',
    title: {
      selectors: ['.blog-title'],
    },
    author: {
      selectors: ['.blog-author a:first-of-type'],
    },
    date_published: {
      selectors: ['.blog-author a:last-of-type'],
      timezone: 'EST',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.blog-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwCnetComExtractor = {
    domain: 'www.cnet.com',
    title: {
      selectors: [['meta[name="og:title"]', 'value']],
    },
    author: {
      selectors: ['a.author'],
    },
    date_published: {
      selectors: ['time'],
      timezone: 'America/Los_Angeles',
    },
    dek: {
      selectors: ['.article-dek'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['img.__image-lead__', '.article-main-body'],
        '.article-main-body',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'figure.image': function figureImage($node) {
          var $img = $node.find('img');
          $img.attr('width', '100%');
          $img.attr('height', '100%');
          $img.addClass('__image-lead__');
          $node.remove('.imgContainer').prepend($img);
        },
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwCinemablendComExtractor = {
    domain: 'www.cinemablend.com',
    title: {
      selectors: ['.story_title'],
    },
    author: {
      selectors: ['.author'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
      timezone: 'EST',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div#wrap_left_content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwTodayComExtractor = {
    domain: 'www.today.com',
    title: {
      selectors: ['h1.entry-headline'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="DC.date.issued"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.entry-container'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.label-comment'],
    },
  };

  var WwwHowtogeekComExtractor = {
    domain: 'www.howtogeek.com',
    title: {
      selectors: ['title'],
    },
    author: {
      selectors: ['#authorinfobox a'],
    },
    date_published: {
      selectors: ['#authorinfobox + div li'],
      timezone: 'GMT',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.thecontent'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwAlComExtractor = {
    domain: 'www.al.com',
    title: {
      selectors: [['meta[name="title"]', 'value']],
    },
    author: {
      selectors: [['meta[name="article_author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article_date_original"]', 'value']],
      timezone: 'EST',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwThepennyhoarderComExtractor = {
    domain: 'www.thepennyhoarder.com',
    title: {
      selectors: [['meta[name="dcterms.title"]', 'value']],
    },
    author: {
      selectors: [['link[rel="author"]', 'title']],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['.post-img', '.post-text'], '.post-text'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwWesternjournalismComExtractor = {
    domain: 'www.westernjournalism.com',
    title: {
      selectors: ['title', 'h1.entry-title'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="DC.date.issued"]', 'value']],
    },
    dek: {
      selectors: ['.subtitle'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.article-sharing.top + div'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.ad-notice-small'],
    },
  };

  var FusionNetExtractor = {
    domain: 'fusion.net',
    title: {
      selectors: ['.post-title', '.single-title', '.headline'],
    },
    author: {
      selectors: ['.show-for-medium .byline'],
    },
    date_published: {
      selectors: [['time.local-time', 'datetime']],
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        ['.post-featured-media', '.article-content'],
        '.article-content',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.fusion-youtube-oembed': 'figure',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwAmericanowComExtractor = {
    domain: 'www.americanow.com',
    title: {
      selectors: ['.title', ['meta[name="title"]', 'value']],
    },
    author: {
      selectors: ['.byline'],
    },
    date_published: {
      selectors: [['meta[name="publish_date"]', 'value']],
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['.article-content', '.image', '.body'], '.body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.article-video-wrapper', '.show-for-small-only'],
    },
  };

  var ScienceflyComExtractor = {
    domain: 'sciencefly.com',
    title: {
      selectors: ['.entry-title', '.cb-entry-title', '.cb-single-title'],
    },
    author: {
      selectors: ['div.cb-author', 'div.cb-author-title'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['div.theiaPostSlider_slides img', 'src']],
    },
    content: {
      selectors: ['div.theiaPostSlider_slides'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var HellogigglesComExtractor = {
    domain: 'hellogiggles.com',
    title: {
      selectors: ['.title'],
    },
    author: {
      selectors: ['.author-link'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var ThoughtcatalogComExtractor = {
    domain: 'thoughtcatalog.com',
    title: {
      selectors: ['h1.title', ['meta[name="og:title"]', 'value']],
    },
    author: {
      selectors: [
        'div.col-xs-12.article_header div.writer-container.writer-container-inline.writer-no-avatar h4.writer-name',
        'h1.writer-name',
      ],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.entry.post'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.tc_mark'],
    },
  };

  var WwwNjComExtractor = {
    domain: 'www.nj.com',
    title: {
      selectors: [['meta[name="title"]', 'value']],
    },
    author: {
      selectors: [['meta[name="article_author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="article_date_original"]', 'value']],
      timezone: 'America/New_York',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.entry-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwInquisitrComExtractor = {
    domain: 'www.inquisitr.com',
    title: {
      selectors: ['h1.entry-title.story--header--title'],
    },
    author: {
      selectors: ['div.story--header--author'],
    },
    date_published: {
      selectors: [['meta[name="datePublished"]', 'value']],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['article.story', '.entry-content.'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [
        '.post-category',
        '.story--header--socials',
        '.story--header--content',
      ],
    },
  };

  var WwwNbcnewsComExtractor = {
    domain: 'www.nbcnews.com',
    title: {
      selectors: ['div.article-hed h1'],
    },
    author: {
      selectors: ['span.byline_author'],
    },
    date_published: {
      selectors: [
        ['.flag_article-wrapper time.timestamp_article[datetime]', 'datetime'],
        '.flag_article-wrapper time',
      ],
      timezone: 'America/New_York',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['div.article-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var FortuneComExtractor = {
    domain: 'fortune.com',
    title: {
      selectors: ['h1'],
    },
    author: {
      selectors: [['meta[name="author"]', 'value']],
    },
    date_published: {
      selectors: ['.MblGHNMJ'],
      timezone: 'UTC',
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['picture', 'article.row'], 'article.row'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var WwwLinkedinComExtractor = {
    domain: 'www.linkedin.com',
    title: {
      selectors: ['.article-title', 'h1'],
    },
    author: {
      selectors: [
        ['meta[name="article:author"]', 'value'],
        '.entity-name a[rel=author]',
      ],
    },
    date_published: {
      selectors: [['time[itemprop="datePublished"]', 'datetime']],
      timezone: 'America/Los_Angeles',
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['header figure', '.prose'], '.prose'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.entity-image'],
    },
  };

  var ObamawhitehouseArchivesGovExtractor = {
    domain: 'obamawhitehouse.archives.gov',
    supportedDomains: ['whitehouse.gov'],
    title: {
      selectors: ['h1', '.pane-node-title'],
    },
    author: {
      selectors: ['.blog-author-link', '.node-person-name-link'],
    },
    date_published: {
      selectors: [['meta[name="article:published_time"]', 'value']],
    },
    dek: {
      selectors: ['.field-name-field-forall-summary'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      defaultCleaner: false,
      selectors: ['div#content-start', '.pane-node-field-forall-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.pane-node-title', '.pane-custom.pane-1'],
    },
  };

  var WwwOpposingviewsComExtractor = {
    domain: 'www.opposingviews.com',
    title: {
      selectors: ['h1.title'],
    },
    author: {
      selectors: ['div.date span span a'],
    },
    date_published: {
      selectors: [['meta[name="publish_date"]', 'value']],
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.show-for-small-only'],
    },
  };

  var WwwProspectmagazineCoUkExtractor = {
    domain: 'www.prospectmagazine.co.uk',
    title: {
      selectors: ['.page-title'],
    },
    author: {
      selectors: ['.aside_author .title'],
    },
    date_published: {
      selectors: ['.post-info'],
      timezone: 'Europe/London',
    },
    dek: {
      selectors: ['.page-subtitle'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [
        // ['article.type-post div.post_content p'],
        'article .post_content',
      ],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var ForwardComExtractor = {
    domain: 'forward.com',
    title: {
      selectors: [['meta[name="og:title"]', 'value']],
    },
    author: {
      selectors: ['.author-name', ['meta[name="sailthru.author"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="date"]', 'value']],
    },
    dek: {
      selectors: [
        // enter selectors
      ],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['.post-item-media-wrap', '.post-item p']],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.donate-box', '.message', '.subtitle'],
    },
  };

  var WwwQdailyComExtractor = {
    domain: 'www.qdaily.com',
    title: {
      selectors: ['h2', 'h2.title'],
    },
    author: {
      selectors: ['.name'],
    },
    date_published: {
      selectors: [['.date.smart-date', 'data-origindate']],
    },
    dek: {
      selectors: ['.excerpt'],
    },
    lead_image_url: {
      selectors: [['.article-detail-hd img', 'src']],
    },
    content: {
      selectors: ['.detail'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['.lazyload', '.lazylad', '.lazylood'],
    },
  };

  var GothamistComExtractor = {
    domain: 'gothamist.com',
    supportedDomains: [
      'chicagoist.com',
      'laist.com',
      'sfist.com',
      'shanghaiist.com',
      'dcist.com',
    ],
    title: {
      selectors: ['h1', '.entry-header h1'],
    },
    author: {
      selectors: ['.author'],
    },
    date_published: {
      selectors: ['abbr', 'abbr.published'],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: [null],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.entry-body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        'div.image-none': 'figure',
        '.image-none i': 'figcaption',
        'div.image-left': 'figure',
        '.image-left i': 'figcaption',
        'div.image-right': 'figure',
        '.image-right i': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [
        '.image-none br',
        '.image-left br',
        '.image-right br',
        '.galleryEase',
      ],
    },
  };

  var WwwFoolComExtractor = {
    domain: 'www.fool.com',
    title: {
      selectors: ['h1'],
    },
    author: {
      selectors: ['.author-inline .author-name'],
    },
    date_published: {
      selectors: [['meta[name="date"]', 'value']],
    },
    dek: {
      selectors: ['header h2'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.article-content'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {
        '.caption img': function captionImg($node) {
          var src = $node.attr('src');
          $node
            .parent()
            .replaceWith('<figure><img src="'.concat(src, '"/></figure>'));
        },
        '.caption': 'figcaption',
      },
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: ['#pitch'],
    },
  };

  var WwwSlateComExtractor = {
    domain: 'www.slate.com',
    title: {
      selectors: ['.hed', 'h1'],
    },
    author: {
      selectors: ['a[rel=author]'],
    },
    date_published: {
      selectors: ['.pub-date'],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: ['.dek'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: ['.body'],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [
        '.about-the-author',
        '.pullquote',
        '.newsletter-signup-component',
        '.top-comment',
      ],
    },
  };

  var IciRadioCanadaCaExtractor = {
    domain: 'ici.radio-canada.ca',
    title: {
      selectors: ['h1'],
    },
    author: {
      selectors: [['meta[name="dc.creator"]', 'value']],
    },
    date_published: {
      selectors: [['meta[name="dc.date.created"]', 'value']],
      timezone: 'America/New_York',
    },
    dek: {
      selectors: ['.bunker-component.lead'],
    },
    lead_image_url: {
      selectors: [['meta[name="og:image"]', 'value']],
    },
    content: {
      selectors: [['.main-multimedia-item', '.news-story-content']],
      // Is there anything in the content you selected that needs transformed
      // before it's consumable content? E.g., unusual lazy loaded images
      transforms: {},
      // Is there anything that is in the result that shouldn't be?
      // The clean selectors will remove anything that matches from
      // the result
      clean: [],
    },
  };

  var CustomExtractors = /*#__PURE__*/ Object.freeze({
    BloggerExtractor: BloggerExtractor,
    NYMagExtractor: NYMagExtractor,
    WikipediaExtractor: WikipediaExtractor,
    TwitterExtractor: TwitterExtractor,
    NYTimesExtractor: NYTimesExtractor,
    TheAtlanticExtractor: TheAtlanticExtractor,
    NewYorkerExtractor: NewYorkerExtractor,
    WiredExtractor: WiredExtractor,
    MSNExtractor: MSNExtractor,
    YahooExtractor: YahooExtractor,
    BuzzfeedExtractor: BuzzfeedExtractor,
    WikiaExtractor: WikiaExtractor,
    LittleThingsExtractor: LittleThingsExtractor,
    PoliticoExtractor: PoliticoExtractor,
    DeadspinExtractor: DeadspinExtractor,
    BroadwayWorldExtractor: BroadwayWorldExtractor,
    ApartmentTherapyExtractor: ApartmentTherapyExtractor,
    MediumExtractor: MediumExtractor,
    WwwTmzComExtractor: WwwTmzComExtractor,
    WwwWashingtonpostComExtractor: WwwWashingtonpostComExtractor,
    WwwHuffingtonpostComExtractor: WwwHuffingtonpostComExtractor,
    NewrepublicComExtractor: NewrepublicComExtractor,
    MoneyCnnComExtractor: MoneyCnnComExtractor,
    WwwThevergeComExtractor: WwwThevergeComExtractor,
    WwwCnnComExtractor: WwwCnnComExtractor,
    WwwAolComExtractor: WwwAolComExtractor,
    WwwYoutubeComExtractor: WwwYoutubeComExtractor,
    WwwTheguardianComExtractor: WwwTheguardianComExtractor,
    WwwSbnationComExtractor: WwwSbnationComExtractor,
    WwwBloombergComExtractor: WwwBloombergComExtractor,
    WwwBustleComExtractor: WwwBustleComExtractor,
    WwwNprOrgExtractor: WwwNprOrgExtractor,
    WwwRecodeNetExtractor: WwwRecodeNetExtractor,
    QzComExtractor: QzComExtractor,
    WwwDmagazineComExtractor: WwwDmagazineComExtractor,
    WwwReutersComExtractor: WwwReutersComExtractor,
    MashableComExtractor: MashableComExtractor,
    WwwChicagotribuneComExtractor: WwwChicagotribuneComExtractor,
    WwwVoxComExtractor: WwwVoxComExtractor,
    NewsNationalgeographicComExtractor: NewsNationalgeographicComExtractor,
    WwwNationalgeographicComExtractor: WwwNationalgeographicComExtractor,
    WwwLatimesComExtractor: WwwLatimesComExtractor,
    PagesixComExtractor: PagesixComExtractor,
    ThefederalistpapersOrgExtractor: ThefederalistpapersOrgExtractor,
    WwwCbssportsComExtractor: WwwCbssportsComExtractor,
    WwwMsnbcComExtractor: WwwMsnbcComExtractor,
    WwwThepoliticalinsiderComExtractor: WwwThepoliticalinsiderComExtractor,
    WwwMentalflossComExtractor: WwwMentalflossComExtractor,
    AbcnewsGoComExtractor: AbcnewsGoComExtractor,
    WwwNydailynewsComExtractor: WwwNydailynewsComExtractor,
    WwwCnbcComExtractor: WwwCnbcComExtractor,
    WwwPopsugarComExtractor: WwwPopsugarComExtractor,
    ObserverComExtractor: ObserverComExtractor,
    PeopleComExtractor: PeopleComExtractor,
    WwwUsmagazineComExtractor: WwwUsmagazineComExtractor,
    WwwRollingstoneComExtractor: WwwRollingstoneComExtractor,
    twofortysevensportsComExtractor: twofortysevensportsComExtractor,
    UproxxComExtractor: UproxxComExtractor,
    WwwEonlineComExtractor: WwwEonlineComExtractor,
    WwwMiamiheraldComExtractor: WwwMiamiheraldComExtractor,
    WwwRefinery29ComExtractor: WwwRefinery29ComExtractor,
    WwwMacrumorsComExtractor: WwwMacrumorsComExtractor,
    WwwAndroidcentralComExtractor: WwwAndroidcentralComExtractor,
    WwwSiComExtractor: WwwSiComExtractor,
    WwwRawstoryComExtractor: WwwRawstoryComExtractor,
    WwwCnetComExtractor: WwwCnetComExtractor,
    WwwCinemablendComExtractor: WwwCinemablendComExtractor,
    WwwTodayComExtractor: WwwTodayComExtractor,
    WwwHowtogeekComExtractor: WwwHowtogeekComExtractor,
    WwwAlComExtractor: WwwAlComExtractor,
    WwwThepennyhoarderComExtractor: WwwThepennyhoarderComExtractor,
    WwwWesternjournalismComExtractor: WwwWesternjournalismComExtractor,
    FusionNetExtractor: FusionNetExtractor,
    WwwAmericanowComExtractor: WwwAmericanowComExtractor,
    ScienceflyComExtractor: ScienceflyComExtractor,
    HellogigglesComExtractor: HellogigglesComExtractor,
    ThoughtcatalogComExtractor: ThoughtcatalogComExtractor,
    WwwNjComExtractor: WwwNjComExtractor,
    WwwInquisitrComExtractor: WwwInquisitrComExtractor,
    WwwNbcnewsComExtractor: WwwNbcnewsComExtractor,
    FortuneComExtractor: FortuneComExtractor,
    WwwLinkedinComExtractor: WwwLinkedinComExtractor,
    ObamawhitehouseArchivesGovExtractor: ObamawhitehouseArchivesGovExtractor,
    WwwOpposingviewsComExtractor: WwwOpposingviewsComExtractor,
    WwwProspectmagazineCoUkExtractor: WwwProspectmagazineCoUkExtractor,
    ForwardComExtractor: ForwardComExtractor,
    WwwQdailyComExtractor: WwwQdailyComExtractor,
    GothamistComExtractor: GothamistComExtractor,
    WwwFoolComExtractor: WwwFoolComExtractor,
    WwwSlateComExtractor: WwwSlateComExtractor,
    IciRadioCanadaCaExtractor: IciRadioCanadaCaExtractor,
  });

  var Extractors = keys$1(CustomExtractors).reduce(function(acc, key) {
    var extractor = CustomExtractors[key];
    return objectSpread({}, acc, mergeSupportedDomains(extractor));
  }, {});

  var stringDirection = createCommonjsModule(function(module, exports) {
    (function() {
      var LTR_MARK = '\u200e',
        RTL_MARK = '\u200f',
        LTR = 'ltr',
        // Left to right direction content
        RTL = 'rtl',
        // Right to left direction content
        BIDI = 'bidi',
        // Both directions - any and all directions will not be ok
        NODI = ''; // No direction - any and all directions are ok

      var rtlSciriptRanges = {
        Hebrew: ['0590', '05FF'],
        Arabic: ['0600', '06FF'],
        NKo: ['07C0', '07FF'],
        Syriac: ['0700', '074F'],
        Thaana: ['0780', '07BF'],
        Tifinagh: ['2D30', '2D7F'],
      };
      /*
       * Gets string direction
       * @param {string} - String to check for direction
       * @returns {string} - 'ltr' if given string is left-to-right,
       * 'rtl' if it's right-to-left and 'bidi' if it has both types of characters
       */

      function getDirection(string) {
        if (typeof string === 'undefined')
          throw new Error('TypeError missing argument');
        if (typeof string !== 'string')
          throw new Error('TypeError getDirection expects strings');
        if (string === '') return NODI;
        if (string.indexOf(LTR_MARK) > -1 && string.indexOf(RTL_MARK) > -1)
          return BIDI;
        if (string.indexOf(LTR_MARK) > -1) return LTR;
        if (string.indexOf(RTL_MARK) > -1) return RTL;
        var hasRtl = hasDirectionCharacters(string, RTL);
        var hasLtr = hasDirectionCharacters(string, LTR);
        if (hasRtl && hasLtr) return BIDI;
        if (hasLtr) return LTR;
        if (hasRtl) return RTL;
        return NODI;
      }
      /**
       * Determine if a string has characters in right-to-left or left-to-right Unicode blocks
       * @param {string} string - String to check for characters
       * @param {string} direction - Direction to check. Either 'ltr' or 'rtl' string
       * @returns {boolean} - True if given string has direction specific characters, False otherwise
       */

      function hasDirectionCharacters(string, direction) {
        var i,
          char,
          range,
          charIsRtl,
          hasRtl = false,
          hasLtr = false,
          hasDigit = false;
        hasDigit = string.search(/[0-9]/) > -1; // Remove white space and non directional characters

        string = string.replace(/[\s\n\0\f\t\v\'\"\-0-9\+\?\!]+/gm, ''); // Loop through each character

        for (i = 0; i < string.length; i++) {
          char = string.charAt(i); // Assume character is not rtl

          charIsRtl = false; // Test each character against all ltr script ranges

          for (range in rtlSciriptRanges) {
            if (rtlSciriptRanges.hasOwnProperty(range)) {
              if (
                isInScriptRange(
                  char,
                  rtlSciriptRanges[range][0],
                  rtlSciriptRanges[range][1]
                )
              ) {
                // If character is rtl, set rtl flag (hasRtl) for string to true
                hasRtl = true; // Set rtl flag for this character to true

                charIsRtl = true;
              }
            }
          } // If this character is *not* rtl then it is ltr and string has
          // ltr characters

          if (charIsRtl === false) {
            hasLtr = true;
          }
        }

        if (direction === RTL) return hasRtl;
        if (direction === LTR) return hasLtr || (!hasRtl && hasDigit);
      }
      /**
       * Checks if a a character is in a Unicode block range
       * @param {string} char - The character to check. An string with only one character
       * @param {string} from - Starting Unicode code of block in hexadecimal. Example: "2D30"
       * @param {string} to - Ending Unicode code of block in hexadecimal. Example: "2F30"
       * @returns {boolean} - true if char is in range.
       */

      function isInScriptRange(char, from, to) {
        var charCode = char.charCodeAt(0),
          fromCode = parseInt(from, 16),
          toCode = parseInt(to, 16);
        return charCode > fromCode && charCode < toCode;
      }
      /**
       * Monkey-patch String global object to expose getDirection method
       */

      function patchStringPrototype() {
        String.prototype.getDirection = function() {
          return getDirection(this.valueOf());
        };
      } // TODO make it AMD friendly

      {
        exports.getDirection = getDirection;
        exports.patch = patchStringPrototype;
      }
    }.call(this));
  });
  var stringDirection_1 = stringDirection.getDirection;
  var stringDirection_2 = stringDirection.patch;

  // CLEAN AUTHOR CONSTANTS
  var CLEAN_AUTHOR_RE = /^\s*(posted |written )?by\s*:?\s*(.*)/i; //     author = re.sub(r'^\s*(posted |written )?by\s*:?\s*(.*)(?i)',
  // CLEAN DEK CONSTANTS

  var TEXT_LINK_RE = new RegExp('http(s)?://', 'i'); // An ordered list of meta tag names that denote likely article deks.

  var MS_DATE_STRING = /^\d{13}$/i;
  var SEC_DATE_STRING = /^\d{10}$/i;
  var CLEAN_DATE_STRING_RE = /^\s*published\s*:?\s*(.*)/i;
  var TIME_MERIDIAN_SPACE_RE = /(.*\d)(am|pm)(.*)/i;
  var TIME_MERIDIAN_DOTS_RE = /\.m\./i;
  var months = [
    'jan',
    'feb',
    'mar',
    'apr',
    'may',
    'jun',
    'jul',
    'aug',
    'sep',
    'oct',
    'nov',
    'dec',
  ];
  var allMonths = months.join('|');
  var timestamp1 = '[0-9]{1,2}:[0-9]{2,2}( ?[ap].?m.?)?';
  var timestamp2 = '[0-9]{1,2}[/-][0-9]{1,2}[/-][0-9]{2,4}';
  var timestamp3 = '-[0-9]{3,4}$';
  var SPLIT_DATE_STRING = new RegExp(
    '('
      .concat(timestamp1, ')|(')
      .concat(timestamp2, ')|(')
      .concat(timestamp3, ')|([0-9]{1,4})|(')
      .concat(allMonths, ')'),
    'ig'
  ); // 2016-11-22T08:57-500
  // Check if datetime string has an offset at the end

  var TIME_WITH_OFFSET_RE = /-\d{3,4}$/; // CLEAN TITLE CONSTANTS
  // A regular expression that will match separating characters on a
  // title, that usually denote breadcrumbs or something similar.

  var TITLE_SPLITTERS_RE = /(: | - | \| )/g;
  var DOMAIN_ENDINGS_RE = new RegExp('.com$|.net$|.org$|.co.uk$', 'g');

  // just the name(s): 'David Smith'.

  function cleanAuthor(author) {
    return normalizeSpaces(author.replace(CLEAN_AUTHOR_RE, '$2').trim());
  }

  var validUrl = createCommonjsModule(function(module) {
    (function(module) {
      module.exports.is_uri = is_iri;
      module.exports.is_http_uri = is_http_iri;
      module.exports.is_https_uri = is_https_iri;
      module.exports.is_web_uri = is_web_iri; // Create aliases

      module.exports.isUri = is_iri;
      module.exports.isHttpUri = is_http_iri;
      module.exports.isHttpsUri = is_https_iri;
      module.exports.isWebUri = is_web_iri; // private function
      // internal URI spitter method - direct from RFC 3986

      var splitUri = function(uri) {
        var splitted = uri.match(
          /(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/
        );
        return splitted;
      };

      function is_iri(value) {
        if (!value) {
          return;
        } // check for illegal characters

        if (
          /[^a-z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\.\-\_\~\%]/i.test(value)
        )
          return; // check for hex escapes that aren't complete

        if (/%[^0-9a-f]/i.test(value)) return;
        if (/%[0-9a-f](:?[^0-9a-f]|$)/i.test(value)) return;
        var splitted = [];
        var scheme = '';
        var authority = '';
        var path = '';
        var query = '';
        var fragment = '';
        var out = ''; // from RFC 3986

        splitted = splitUri(value);
        scheme = splitted[1];
        authority = splitted[2];
        path = splitted[3];
        query = splitted[4];
        fragment = splitted[5]; // scheme and path are required, though the path can be empty

        if (!(scheme && scheme.length && path.length >= 0)) return; // if authority is present, the path must be empty or begin with a /

        if (authority && authority.length) {
          if (!(path.length === 0 || /^\//.test(path))) return;
        } else {
          // if authority is not present, the path must not start with //
          if (/^\/\//.test(path)) return;
        } // scheme must begin with a letter, then consist of letters, digits, +, ., or -

        if (!/^[a-z][a-z0-9\+\-\.]*$/.test(scheme.toLowerCase())) return; // re-assemble the URL per section 5.3 in RFC 3986

        out += scheme + ':';

        if (authority && authority.length) {
          out += '//' + authority;
        }

        out += path;

        if (query && query.length) {
          out += '?' + query;
        }

        if (fragment && fragment.length) {
          out += '#' + fragment;
        }

        return out;
      }

      function is_http_iri(value, allowHttps) {
        if (!is_iri(value)) {
          return;
        }

        var splitted = [];
        var scheme = '';
        var authority = '';
        var path = '';
        var port = '';
        var query = '';
        var fragment = '';
        var out = ''; // from RFC 3986

        splitted = splitUri(value);
        scheme = splitted[1];
        authority = splitted[2];
        path = splitted[3];
        query = splitted[4];
        fragment = splitted[5];
        if (!scheme) return;

        if (allowHttps) {
          if (scheme.toLowerCase() != 'https') return;
        } else {
          if (scheme.toLowerCase() != 'http') return;
        } // fully-qualified URIs must have an authority section that is
        // a valid host

        if (!authority) {
          return;
        } // enable port component

        if (/:(\d+)$/.test(authority)) {
          port = authority.match(/:(\d+)$/)[0];
          authority = authority.replace(/:\d+$/, '');
        }

        out += scheme + ':';
        out += '//' + authority;

        if (port) {
          out += port;
        }

        out += path;

        if (query && query.length) {
          out += '?' + query;
        }

        if (fragment && fragment.length) {
          out += '#' + fragment;
        }

        return out;
      }

      function is_https_iri(value) {
        return is_http_iri(value, true);
      }

      function is_web_iri(value) {
        return is_http_iri(value) || is_https_iri(value);
      }
    })(module);
  });

  function clean$1(leadImageUrl) {
    leadImageUrl = leadImageUrl.trim();

    if (validUrl.isWebUri(leadImageUrl)) {
      return leadImageUrl;
    }

    return null;
  }

  // Return None if the dek wasn't good enough.

  function cleanDek(dek, _ref) {
    var $ = _ref.$,
      excerpt = _ref.excerpt;
    // Sanity check that we didn't get too short or long of a dek.
    if (dek.length > 1000 || dek.length < 5) return null; // Check that dek isn't the same as excerpt

    if (excerpt && excerptContent(excerpt, 10) === excerptContent(dek, 10))
      return null;
    var dekText = stripTags(dek, $); // Plain text links shouldn't exist in the dek. If we have some, it's
    // not a good dek - bail.

    if (TEXT_LINK_RE.test(dekText)) return null;
    return normalizeSpaces(dekText.trim());
  }

  var moment = createCommonjsModule(function(module, exports) {
    (function(global, factory) {
      module.exports = factory();
    })(this, function() {
      var hookCallback;

      function hooks() {
        return hookCallback.apply(null, arguments);
      } // This is done to register the method called with moment()
      // without creating circular dependencies.

      function setHookCallback(callback) {
        hookCallback = callback;
      }

      function isArray(input) {
        return (
          input instanceof Array ||
          Object.prototype.toString.call(input) === '[object Array]'
        );
      }

      function isObject(input) {
        // IE8 will treat undefined and null as object if it wasn't for
        // input != null
        return (
          input != null &&
          Object.prototype.toString.call(input) === '[object Object]'
        );
      }

      function isObjectEmpty(obj) {
        if (Object.getOwnPropertyNames) {
          return Object.getOwnPropertyNames(obj).length === 0;
        } else {
          var k;

          for (k in obj) {
            if (obj.hasOwnProperty(k)) {
              return false;
            }
          }

          return true;
        }
      }

      function isUndefined(input) {
        return input === void 0;
      }

      function isNumber(input) {
        return (
          typeof input === 'number' ||
          Object.prototype.toString.call(input) === '[object Number]'
        );
      }

      function isDate(input) {
        return (
          input instanceof Date ||
          Object.prototype.toString.call(input) === '[object Date]'
        );
      }

      function map(arr, fn) {
        var res = [],
          i;

        for (i = 0; i < arr.length; ++i) {
          res.push(fn(arr[i], i));
        }

        return res;
      }

      function hasOwnProp(a, b) {
        return Object.prototype.hasOwnProperty.call(a, b);
      }

      function extend(a, b) {
        for (var i in b) {
          if (hasOwnProp(b, i)) {
            a[i] = b[i];
          }
        }

        if (hasOwnProp(b, 'toString')) {
          a.toString = b.toString;
        }

        if (hasOwnProp(b, 'valueOf')) {
          a.valueOf = b.valueOf;
        }

        return a;
      }

      function createUTC(input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, true).utc();
      }

      function defaultParsingFlags() {
        // We need to deep clone this object.
        return {
          empty: false,
          unusedTokens: [],
          unusedInput: [],
          overflow: -2,
          charsLeftOver: 0,
          nullInput: false,
          invalidMonth: null,
          invalidFormat: false,
          userInvalidated: false,
          iso: false,
          parsedDateParts: [],
          meridiem: null,
          rfc2822: false,
          weekdayMismatch: false,
        };
      }

      function getParsingFlags(m) {
        if (m._pf == null) {
          m._pf = defaultParsingFlags();
        }

        return m._pf;
      }

      var some;

      if (Array.prototype.some) {
        some = Array.prototype.some;
      } else {
        some = function(fun) {
          var t = Object(this);
          var len = t.length >>> 0;

          for (var i = 0; i < len; i++) {
            if (i in t && fun.call(this, t[i], i, t)) {
              return true;
            }
          }

          return false;
        };
      }

      function isValid(m) {
        if (m._isValid == null) {
          var flags = getParsingFlags(m);
          var parsedParts = some.call(flags.parsedDateParts, function(i) {
            return i != null;
          });
          var isNowValid =
            !isNaN(m._d.getTime()) &&
            flags.overflow < 0 &&
            !flags.empty &&
            !flags.invalidMonth &&
            !flags.invalidWeekday &&
            !flags.weekdayMismatch &&
            !flags.nullInput &&
            !flags.invalidFormat &&
            !flags.userInvalidated &&
            (!flags.meridiem || (flags.meridiem && parsedParts));

          if (m._strict) {
            isNowValid =
              isNowValid &&
              flags.charsLeftOver === 0 &&
              flags.unusedTokens.length === 0 &&
              flags.bigHour === undefined;
          }

          if (Object.isFrozen == null || !Object.isFrozen(m)) {
            m._isValid = isNowValid;
          } else {
            return isNowValid;
          }
        }

        return m._isValid;
      }

      function createInvalid(flags) {
        var m = createUTC(NaN);

        if (flags != null) {
          extend(getParsingFlags(m), flags);
        } else {
          getParsingFlags(m).userInvalidated = true;
        }

        return m;
      } // Plugins that add properties should also add the key here (null value),
      // so we can properly clone ourselves.

      var momentProperties = (hooks.momentProperties = []);

      function copyConfig(to, from) {
        var i, prop, val;

        if (!isUndefined(from._isAMomentObject)) {
          to._isAMomentObject = from._isAMomentObject;
        }

        if (!isUndefined(from._i)) {
          to._i = from._i;
        }

        if (!isUndefined(from._f)) {
          to._f = from._f;
        }

        if (!isUndefined(from._l)) {
          to._l = from._l;
        }

        if (!isUndefined(from._strict)) {
          to._strict = from._strict;
        }

        if (!isUndefined(from._tzm)) {
          to._tzm = from._tzm;
        }

        if (!isUndefined(from._isUTC)) {
          to._isUTC = from._isUTC;
        }

        if (!isUndefined(from._offset)) {
          to._offset = from._offset;
        }

        if (!isUndefined(from._pf)) {
          to._pf = getParsingFlags(from);
        }

        if (!isUndefined(from._locale)) {
          to._locale = from._locale;
        }

        if (momentProperties.length > 0) {
          for (i = 0; i < momentProperties.length; i++) {
            prop = momentProperties[i];
            val = from[prop];

            if (!isUndefined(val)) {
              to[prop] = val;
            }
          }
        }

        return to;
      }

      var updateInProgress = false; // Moment prototype object

      function Moment(config) {
        copyConfig(this, config);
        this._d = new Date(config._d != null ? config._d.getTime() : NaN);

        if (!this.isValid()) {
          this._d = new Date(NaN);
        } // Prevent infinite loop in case updateOffset creates new moment
        // objects.

        if (updateInProgress === false) {
          updateInProgress = true;
          hooks.updateOffset(this);
          updateInProgress = false;
        }
      }

      function isMoment(obj) {
        return (
          obj instanceof Moment || (obj != null && obj._isAMomentObject != null)
        );
      }

      function absFloor(number) {
        if (number < 0) {
          // -0 -> 0
          return Math.ceil(number) || 0;
        } else {
          return Math.floor(number);
        }
      }

      function toInt(argumentForCoercion) {
        var coercedNumber = +argumentForCoercion,
          value = 0;

        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
          value = absFloor(coercedNumber);
        }

        return value;
      } // compare two arrays, return the number of differences

      function compareArrays(array1, array2, dontConvert) {
        var len = Math.min(array1.length, array2.length),
          lengthDiff = Math.abs(array1.length - array2.length),
          diffs = 0,
          i;

        for (i = 0; i < len; i++) {
          if (
            (dontConvert && array1[i] !== array2[i]) ||
            (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))
          ) {
            diffs++;
          }
        }

        return diffs + lengthDiff;
      }

      function warn(msg) {
        if (
          hooks.suppressDeprecationWarnings === false &&
          typeof console !== 'undefined' &&
          console.warn
        ) {
          console.warn('Deprecation warning: ' + msg);
        }
      }

      function deprecate(msg, fn) {
        var firstTime = true;
        return extend(function() {
          if (hooks.deprecationHandler != null) {
            hooks.deprecationHandler(null, msg);
          }

          if (firstTime) {
            var args = [];
            var arg;

            for (var i = 0; i < arguments.length; i++) {
              arg = '';

              if (typeof arguments[i] === 'object') {
                arg += '\n[' + i + '] ';

                for (var key in arguments[0]) {
                  arg += key + ': ' + arguments[0][key] + ', ';
                }

                arg = arg.slice(0, -2); // Remove trailing comma and space
              } else {
                arg = arguments[i];
              }

              args.push(arg);
            }

            warn(
              msg +
                '\nArguments: ' +
                Array.prototype.slice.call(args).join('') +
                '\n' +
                new Error().stack
            );
            firstTime = false;
          }

          return fn.apply(this, arguments);
        }, fn);
      }

      var deprecations = {};

      function deprecateSimple(name, msg) {
        if (hooks.deprecationHandler != null) {
          hooks.deprecationHandler(name, msg);
        }

        if (!deprecations[name]) {
          warn(msg);
          deprecations[name] = true;
        }
      }

      hooks.suppressDeprecationWarnings = false;
      hooks.deprecationHandler = null;

      function isFunction(input) {
        return (
          input instanceof Function ||
          Object.prototype.toString.call(input) === '[object Function]'
        );
      }

      function set(config) {
        var prop, i;

        for (i in config) {
          prop = config[i];

          if (isFunction(prop)) {
            this[i] = prop;
          } else {
            this['_' + i] = prop;
          }
        }

        this._config = config; // Lenient ordinal parsing accepts just a number in addition to
        // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
        // TODO: Remove "ordinalParse" fallback in next major release.

        this._dayOfMonthOrdinalParseLenient = new RegExp(
          (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
            '|' +
            /\d{1,2}/.source
        );
      }

      function mergeConfigs(parentConfig, childConfig) {
        var res = extend({}, parentConfig),
          prop;

        for (prop in childConfig) {
          if (hasOwnProp(childConfig, prop)) {
            if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
              res[prop] = {};
              extend(res[prop], parentConfig[prop]);
              extend(res[prop], childConfig[prop]);
            } else if (childConfig[prop] != null) {
              res[prop] = childConfig[prop];
            } else {
              delete res[prop];
            }
          }
        }

        for (prop in parentConfig) {
          if (
            hasOwnProp(parentConfig, prop) &&
            !hasOwnProp(childConfig, prop) &&
            isObject(parentConfig[prop])
          ) {
            // make sure changes to properties don't modify parent config
            res[prop] = extend({}, res[prop]);
          }
        }

        return res;
      }

      function Locale(config) {
        if (config != null) {
          this.set(config);
        }
      }

      var keys;

      if (Object.keys) {
        keys = Object.keys;
      } else {
        keys = function(obj) {
          var i,
            res = [];

          for (i in obj) {
            if (hasOwnProp(obj, i)) {
              res.push(i);
            }
          }

          return res;
        };
      }

      var defaultCalendar = {
        sameDay: '[Today at] LT',
        nextDay: '[Tomorrow at] LT',
        nextWeek: 'dddd [at] LT',
        lastDay: '[Yesterday at] LT',
        lastWeek: '[Last] dddd [at] LT',
        sameElse: 'L',
      };

      function calendar(key, mom, now) {
        var output = this._calendar[key] || this._calendar['sameElse'];
        return isFunction(output) ? output.call(mom, now) : output;
      }

      var defaultLongDateFormat = {
        LTS: 'h:mm:ss A',
        LT: 'h:mm A',
        L: 'MM/DD/YYYY',
        LL: 'MMMM D, YYYY',
        LLL: 'MMMM D, YYYY h:mm A',
        LLLL: 'dddd, MMMM D, YYYY h:mm A',
      };

      function longDateFormat(key) {
        var format = this._longDateFormat[key],
          formatUpper = this._longDateFormat[key.toUpperCase()];

        if (format || !formatUpper) {
          return format;
        }

        this._longDateFormat[key] = formatUpper.replace(
          /MMMM|MM|DD|dddd/g,
          function(val) {
            return val.slice(1);
          }
        );
        return this._longDateFormat[key];
      }

      var defaultInvalidDate = 'Invalid date';

      function invalidDate() {
        return this._invalidDate;
      }

      var defaultOrdinal = '%d';
      var defaultDayOfMonthOrdinalParse = /\d{1,2}/;

      function ordinal(number) {
        return this._ordinal.replace('%d', number);
      }

      var defaultRelativeTime = {
        future: 'in %s',
        past: '%s ago',
        s: 'a few seconds',
        ss: '%d seconds',
        m: 'a minute',
        mm: '%d minutes',
        h: 'an hour',
        hh: '%d hours',
        d: 'a day',
        dd: '%d days',
        M: 'a month',
        MM: '%d months',
        y: 'a year',
        yy: '%d years',
      };

      function relativeTime(number, withoutSuffix, string, isFuture) {
        var output = this._relativeTime[string];
        return isFunction(output)
          ? output(number, withoutSuffix, string, isFuture)
          : output.replace(/%d/i, number);
      }

      function pastFuture(diff, output) {
        var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
        return isFunction(format)
          ? format(output)
          : format.replace(/%s/i, output);
      }

      var aliases = {};

      function addUnitAlias(unit, shorthand) {
        var lowerCase = unit.toLowerCase();
        aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[
          shorthand
        ] = unit;
      }

      function normalizeUnits(units) {
        return typeof units === 'string'
          ? aliases[units] || aliases[units.toLowerCase()]
          : undefined;
      }

      function normalizeObjectUnits(inputObject) {
        var normalizedInput = {},
          normalizedProp,
          prop;

        for (prop in inputObject) {
          if (hasOwnProp(inputObject, prop)) {
            normalizedProp = normalizeUnits(prop);

            if (normalizedProp) {
              normalizedInput[normalizedProp] = inputObject[prop];
            }
          }
        }

        return normalizedInput;
      }

      var priorities = {};

      function addUnitPriority(unit, priority) {
        priorities[unit] = priority;
      }

      function getPrioritizedUnits(unitsObj) {
        var units = [];

        for (var u in unitsObj) {
          units.push({
            unit: u,
            priority: priorities[u],
          });
        }

        units.sort(function(a, b) {
          return a.priority - b.priority;
        });
        return units;
      }

      function zeroFill(number, targetLength, forceSign) {
        var absNumber = '' + Math.abs(number),
          zerosToFill = targetLength - absNumber.length,
          sign = number >= 0;
        return (
          (sign ? (forceSign ? '+' : '') : '-') +
          Math.pow(10, Math.max(0, zerosToFill))
            .toString()
            .substr(1) +
          absNumber
        );
      }

      var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
      var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
      var formatFunctions = {};
      var formatTokenFunctions = {}; // token:    'M'
      // padded:   ['MM', 2]
      // ordinal:  'Mo'
      // callback: function () { this.month() + 1 }

      function addFormatToken(token, padded, ordinal, callback) {
        var func = callback;

        if (typeof callback === 'string') {
          func = function() {
            return this[callback]();
          };
        }

        if (token) {
          formatTokenFunctions[token] = func;
        }

        if (padded) {
          formatTokenFunctions[padded[0]] = function() {
            return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
          };
        }

        if (ordinal) {
          formatTokenFunctions[ordinal] = function() {
            return this.localeData().ordinal(
              func.apply(this, arguments),
              token
            );
          };
        }
      }

      function removeFormattingTokens(input) {
        if (input.match(/\[[\s\S]/)) {
          return input.replace(/^\[|\]$/g, '');
        }

        return input.replace(/\\/g, '');
      }

      function makeFormatFunction(format) {
        var array = format.match(formattingTokens),
          i,
          length;

        for (i = 0, length = array.length; i < length; i++) {
          if (formatTokenFunctions[array[i]]) {
            array[i] = formatTokenFunctions[array[i]];
          } else {
            array[i] = removeFormattingTokens(array[i]);
          }
        }

        return function(mom) {
          var output = '',
            i;

          for (i = 0; i < length; i++) {
            output += isFunction(array[i])
              ? array[i].call(mom, format)
              : array[i];
          }

          return output;
        };
      } // format date using native date object

      function formatMoment(m, format) {
        if (!m.isValid()) {
          return m.localeData().invalidDate();
        }

        format = expandFormat(format, m.localeData());
        formatFunctions[format] =
          formatFunctions[format] || makeFormatFunction(format);
        return formatFunctions[format](m);
      }

      function expandFormat(format, locale) {
        var i = 5;

        function replaceLongDateFormatTokens(input) {
          return locale.longDateFormat(input) || input;
        }

        localFormattingTokens.lastIndex = 0;

        while (i >= 0 && localFormattingTokens.test(format)) {
          format = format.replace(
            localFormattingTokens,
            replaceLongDateFormatTokens
          );
          localFormattingTokens.lastIndex = 0;
          i -= 1;
        }

        return format;
      }

      var match1 = /\d/; //       0 - 9

      var match2 = /\d\d/; //      00 - 99

      var match3 = /\d{3}/; //     000 - 999

      var match4 = /\d{4}/; //    0000 - 9999

      var match6 = /[+-]?\d{6}/; // -999999 - 999999

      var match1to2 = /\d\d?/; //       0 - 99

      var match3to4 = /\d\d\d\d?/; //     999 - 9999

      var match5to6 = /\d\d\d\d\d\d?/; //   99999 - 999999

      var match1to3 = /\d{1,3}/; //       0 - 999

      var match1to4 = /\d{1,4}/; //       0 - 9999

      var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999

      var matchUnsigned = /\d+/; //       0 - inf

      var matchSigned = /[+-]?\d+/; //    -inf - inf

      var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z

      var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z

      var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
      // any word (or two) characters or numbers including two/three word month in arabic.
      // includes scottish gaelic two word and hyphenated months

      var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;
      var regexes = {};

      function addRegexToken(token, regex, strictRegex) {
        regexes[token] = isFunction(regex)
          ? regex
          : function(isStrict, localeData) {
              return isStrict && strictRegex ? strictRegex : regex;
            };
      }

      function getParseRegexForToken(token, config) {
        if (!hasOwnProp(regexes, token)) {
          return new RegExp(unescapeFormat(token));
        }

        return regexes[token](config._strict, config._locale);
      } // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript

      function unescapeFormat(s) {
        return regexEscape(
          s
            .replace('\\', '')
            .replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function(
              matched,
              p1,
              p2,
              p3,
              p4
            ) {
              return p1 || p2 || p3 || p4;
            })
        );
      }

      function regexEscape(s) {
        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
      }

      var tokens = {};

      function addParseToken(token, callback) {
        var i,
          func = callback;

        if (typeof token === 'string') {
          token = [token];
        }

        if (isNumber(callback)) {
          func = function(input, array) {
            array[callback] = toInt(input);
          };
        }

        for (i = 0; i < token.length; i++) {
          tokens[token[i]] = func;
        }
      }

      function addWeekParseToken(token, callback) {
        addParseToken(token, function(input, array, config, token) {
          config._w = config._w || {};
          callback(input, config._w, config, token);
        });
      }

      function addTimeToArrayFromToken(token, input, config) {
        if (input != null && hasOwnProp(tokens, token)) {
          tokens[token](input, config._a, config, token);
        }
      }

      var YEAR = 0;
      var MONTH = 1;
      var DATE = 2;
      var HOUR = 3;
      var MINUTE = 4;
      var SECOND = 5;
      var MILLISECOND = 6;
      var WEEK = 7;
      var WEEKDAY = 8; // FORMATTING

      addFormatToken('Y', 0, 0, function() {
        var y = this.year();
        return y <= 9999 ? '' + y : '+' + y;
      });
      addFormatToken(0, ['YY', 2], 0, function() {
        return this.year() % 100;
      });
      addFormatToken(0, ['YYYY', 4], 0, 'year');
      addFormatToken(0, ['YYYYY', 5], 0, 'year');
      addFormatToken(0, ['YYYYYY', 6, true], 0, 'year'); // ALIASES

      addUnitAlias('year', 'y'); // PRIORITIES

      addUnitPriority('year', 1); // PARSING

      addRegexToken('Y', matchSigned);
      addRegexToken('YY', match1to2, match2);
      addRegexToken('YYYY', match1to4, match4);
      addRegexToken('YYYYY', match1to6, match6);
      addRegexToken('YYYYYY', match1to6, match6);
      addParseToken(['YYYYY', 'YYYYYY'], YEAR);
      addParseToken('YYYY', function(input, array) {
        array[YEAR] =
          input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
      });
      addParseToken('YY', function(input, array) {
        array[YEAR] = hooks.parseTwoDigitYear(input);
      });
      addParseToken('Y', function(input, array) {
        array[YEAR] = parseInt(input, 10);
      }); // HELPERS

      function daysInYear(year) {
        return isLeapYear(year) ? 366 : 365;
      }

      function isLeapYear(year) {
        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
      } // HOOKS

      hooks.parseTwoDigitYear = function(input) {
        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
      }; // MOMENTS

      var getSetYear = makeGetSet('FullYear', true);

      function getIsLeapYear() {
        return isLeapYear(this.year());
      }

      function makeGetSet(unit, keepTime) {
        return function(value) {
          if (value != null) {
            set$1(this, unit, value);
            hooks.updateOffset(this, keepTime);
            return this;
          } else {
            return get(this, unit);
          }
        };
      }

      function get(mom, unit) {
        return mom.isValid()
          ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]()
          : NaN;
      }

      function set$1(mom, unit, value) {
        if (mom.isValid() && !isNaN(value)) {
          if (
            unit === 'FullYear' &&
            isLeapYear(mom.year()) &&
            mom.month() === 1 &&
            mom.date() === 29
          ) {
            mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](
              value,
              mom.month(),
              daysInMonth(value, mom.month())
            );
          } else {
            mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
          }
        }
      } // MOMENTS

      function stringGet(units) {
        units = normalizeUnits(units);

        if (isFunction(this[units])) {
          return this[units]();
        }

        return this;
      }

      function stringSet(units, value) {
        if (typeof units === 'object') {
          units = normalizeObjectUnits(units);
          var prioritized = getPrioritizedUnits(units);

          for (var i = 0; i < prioritized.length; i++) {
            this[prioritized[i].unit](units[prioritized[i].unit]);
          }
        } else {
          units = normalizeUnits(units);

          if (isFunction(this[units])) {
            return this[units](value);
          }
        }

        return this;
      }

      function mod(n, x) {
        return ((n % x) + x) % x;
      }

      var indexOf;

      if (Array.prototype.indexOf) {
        indexOf = Array.prototype.indexOf;
      } else {
        indexOf = function(o) {
          // I know
          var i;

          for (i = 0; i < this.length; ++i) {
            if (this[i] === o) {
              return i;
            }
          }

          return -1;
        };
      }

      function daysInMonth(year, month) {
        if (isNaN(year) || isNaN(month)) {
          return NaN;
        }

        var modMonth = mod(month, 12);
        year += (month - modMonth) / 12;
        return modMonth === 1
          ? isLeapYear(year)
            ? 29
            : 28
          : 31 - ((modMonth % 7) % 2);
      } // FORMATTING

      addFormatToken('M', ['MM', 2], 'Mo', function() {
        return this.month() + 1;
      });
      addFormatToken('MMM', 0, 0, function(format) {
        return this.localeData().monthsShort(this, format);
      });
      addFormatToken('MMMM', 0, 0, function(format) {
        return this.localeData().months(this, format);
      }); // ALIASES

      addUnitAlias('month', 'M'); // PRIORITY

      addUnitPriority('month', 8); // PARSING

      addRegexToken('M', match1to2);
      addRegexToken('MM', match1to2, match2);
      addRegexToken('MMM', function(isStrict, locale) {
        return locale.monthsShortRegex(isStrict);
      });
      addRegexToken('MMMM', function(isStrict, locale) {
        return locale.monthsRegex(isStrict);
      });
      addParseToken(['M', 'MM'], function(input, array) {
        array[MONTH] = toInt(input) - 1;
      });
      addParseToken(['MMM', 'MMMM'], function(input, array, config, token) {
        var month = config._locale.monthsParse(input, token, config._strict); // if we didn't find a month name, mark the date as invalid.

        if (month != null) {
          array[MONTH] = month;
        } else {
          getParsingFlags(config).invalidMonth = input;
        }
      }); // LOCALES

      var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;
      var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split(
        '_'
      );

      function localeMonths(m, format) {
        if (!m) {
          return isArray(this._months)
            ? this._months
            : this._months['standalone'];
        }

        return isArray(this._months)
          ? this._months[m.month()]
          : this._months[
              (this._months.isFormat || MONTHS_IN_FORMAT).test(format)
                ? 'format'
                : 'standalone'
            ][m.month()];
      }

      var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split(
        '_'
      );

      function localeMonthsShort(m, format) {
        if (!m) {
          return isArray(this._monthsShort)
            ? this._monthsShort
            : this._monthsShort['standalone'];
        }

        return isArray(this._monthsShort)
          ? this._monthsShort[m.month()]
          : this._monthsShort[
              MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'
            ][m.month()];
      }

      function handleStrictParse(monthName, format, strict) {
        var i,
          ii,
          mom,
          llc = monthName.toLocaleLowerCase();

        if (!this._monthsParse) {
          // this is not used
          this._monthsParse = [];
          this._longMonthsParse = [];
          this._shortMonthsParse = [];

          for (i = 0; i < 12; ++i) {
            mom = createUTC([2000, i]);
            this._shortMonthsParse[i] = this.monthsShort(
              mom,
              ''
            ).toLocaleLowerCase();
            this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
          }
        }

        if (strict) {
          if (format === 'MMM') {
            ii = indexOf.call(this._shortMonthsParse, llc);
            return ii !== -1 ? ii : null;
          } else {
            ii = indexOf.call(this._longMonthsParse, llc);
            return ii !== -1 ? ii : null;
          }
        } else {
          if (format === 'MMM') {
            ii = indexOf.call(this._shortMonthsParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._longMonthsParse, llc);
            return ii !== -1 ? ii : null;
          } else {
            ii = indexOf.call(this._longMonthsParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._shortMonthsParse, llc);
            return ii !== -1 ? ii : null;
          }
        }
      }

      function localeMonthsParse(monthName, format, strict) {
        var i, mom, regex;

        if (this._monthsParseExact) {
          return handleStrictParse.call(this, monthName, format, strict);
        }

        if (!this._monthsParse) {
          this._monthsParse = [];
          this._longMonthsParse = [];
          this._shortMonthsParse = [];
        } // TODO: add sorting
        // Sorting makes sure if one month (or abbr) is a prefix of another
        // see sorting in computeMonthsParse

        for (i = 0; i < 12; i++) {
          // make the regex if we don't have it already
          mom = createUTC([2000, i]);

          if (strict && !this._longMonthsParse[i]) {
            this._longMonthsParse[i] = new RegExp(
              '^' + this.months(mom, '').replace('.', '') + '$',
              'i'
            );
            this._shortMonthsParse[i] = new RegExp(
              '^' + this.monthsShort(mom, '').replace('.', '') + '$',
              'i'
            );
          }

          if (!strict && !this._monthsParse[i]) {
            regex =
              '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
            this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
          } // test the regex

          if (
            strict &&
            format === 'MMMM' &&
            this._longMonthsParse[i].test(monthName)
          ) {
            return i;
          } else if (
            strict &&
            format === 'MMM' &&
            this._shortMonthsParse[i].test(monthName)
          ) {
            return i;
          } else if (!strict && this._monthsParse[i].test(monthName)) {
            return i;
          }
        }
      } // MOMENTS

      function setMonth(mom, value) {
        var dayOfMonth;

        if (!mom.isValid()) {
          // No op
          return mom;
        }

        if (typeof value === 'string') {
          if (/^\d+$/.test(value)) {
            value = toInt(value);
          } else {
            value = mom.localeData().monthsParse(value); // TODO: Another silent failure?

            if (!isNumber(value)) {
              return mom;
            }
          }
        }

        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));

        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);

        return mom;
      }

      function getSetMonth(value) {
        if (value != null) {
          setMonth(this, value);
          hooks.updateOffset(this, true);
          return this;
        } else {
          return get(this, 'Month');
        }
      }

      function getDaysInMonth() {
        return daysInMonth(this.year(), this.month());
      }

      var defaultMonthsShortRegex = matchWord;

      function monthsShortRegex(isStrict) {
        if (this._monthsParseExact) {
          if (!hasOwnProp(this, '_monthsRegex')) {
            computeMonthsParse.call(this);
          }

          if (isStrict) {
            return this._monthsShortStrictRegex;
          } else {
            return this._monthsShortRegex;
          }
        } else {
          if (!hasOwnProp(this, '_monthsShortRegex')) {
            this._monthsShortRegex = defaultMonthsShortRegex;
          }

          return this._monthsShortStrictRegex && isStrict
            ? this._monthsShortStrictRegex
            : this._monthsShortRegex;
        }
      }

      var defaultMonthsRegex = matchWord;

      function monthsRegex(isStrict) {
        if (this._monthsParseExact) {
          if (!hasOwnProp(this, '_monthsRegex')) {
            computeMonthsParse.call(this);
          }

          if (isStrict) {
            return this._monthsStrictRegex;
          } else {
            return this._monthsRegex;
          }
        } else {
          if (!hasOwnProp(this, '_monthsRegex')) {
            this._monthsRegex = defaultMonthsRegex;
          }

          return this._monthsStrictRegex && isStrict
            ? this._monthsStrictRegex
            : this._monthsRegex;
        }
      }

      function computeMonthsParse() {
        function cmpLenRev(a, b) {
          return b.length - a.length;
        }

        var shortPieces = [],
          longPieces = [],
          mixedPieces = [],
          i,
          mom;

        for (i = 0; i < 12; i++) {
          // make the regex if we don't have it already
          mom = createUTC([2000, i]);
          shortPieces.push(this.monthsShort(mom, ''));
          longPieces.push(this.months(mom, ''));
          mixedPieces.push(this.months(mom, ''));
          mixedPieces.push(this.monthsShort(mom, ''));
        } // Sorting makes sure if one month (or abbr) is a prefix of another it
        // will match the longer piece.

        shortPieces.sort(cmpLenRev);
        longPieces.sort(cmpLenRev);
        mixedPieces.sort(cmpLenRev);

        for (i = 0; i < 12; i++) {
          shortPieces[i] = regexEscape(shortPieces[i]);
          longPieces[i] = regexEscape(longPieces[i]);
        }

        for (i = 0; i < 24; i++) {
          mixedPieces[i] = regexEscape(mixedPieces[i]);
        }

        this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
        this._monthsShortRegex = this._monthsRegex;
        this._monthsStrictRegex = new RegExp(
          '^(' + longPieces.join('|') + ')',
          'i'
        );
        this._monthsShortStrictRegex = new RegExp(
          '^(' + shortPieces.join('|') + ')',
          'i'
        );
      }

      function createDate(y, m, d, h, M, s, ms) {
        // can't just apply() to create a date:
        // https://stackoverflow.com/q/181348
        var date = new Date(y, m, d, h, M, s, ms); // the date constructor remaps years 0-99 to 1900-1999

        if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
          date.setFullYear(y);
        }

        return date;
      }

      function createUTCDate(y) {
        var date = new Date(Date.UTC.apply(null, arguments)); // the Date.UTC function remaps years 0-99 to 1900-1999

        if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
          date.setUTCFullYear(y);
        }

        return date;
      } // start-of-first-week - start-of-year

      function firstWeekOffset(year, dow, doy) {
        var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
          fwd = 7 + dow - doy,
          // first-week day local weekday -- which local weekday is fwd
          fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
        return -fwdlw + fwd - 1;
      } // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday

      function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
        var localWeekday = (7 + weekday - dow) % 7,
          weekOffset = firstWeekOffset(year, dow, doy),
          dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
          resYear,
          resDayOfYear;

        if (dayOfYear <= 0) {
          resYear = year - 1;
          resDayOfYear = daysInYear(resYear) + dayOfYear;
        } else if (dayOfYear > daysInYear(year)) {
          resYear = year + 1;
          resDayOfYear = dayOfYear - daysInYear(year);
        } else {
          resYear = year;
          resDayOfYear = dayOfYear;
        }

        return {
          year: resYear,
          dayOfYear: resDayOfYear,
        };
      }

      function weekOfYear(mom, dow, doy) {
        var weekOffset = firstWeekOffset(mom.year(), dow, doy),
          week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
          resWeek,
          resYear;

        if (week < 1) {
          resYear = mom.year() - 1;
          resWeek = week + weeksInYear(resYear, dow, doy);
        } else if (week > weeksInYear(mom.year(), dow, doy)) {
          resWeek = week - weeksInYear(mom.year(), dow, doy);
          resYear = mom.year() + 1;
        } else {
          resYear = mom.year();
          resWeek = week;
        }

        return {
          week: resWeek,
          year: resYear,
        };
      }

      function weeksInYear(year, dow, doy) {
        var weekOffset = firstWeekOffset(year, dow, doy),
          weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
        return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
      } // FORMATTING

      addFormatToken('w', ['ww', 2], 'wo', 'week');
      addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek'); // ALIASES

      addUnitAlias('week', 'w');
      addUnitAlias('isoWeek', 'W'); // PRIORITIES

      addUnitPriority('week', 5);
      addUnitPriority('isoWeek', 5); // PARSING

      addRegexToken('w', match1to2);
      addRegexToken('ww', match1to2, match2);
      addRegexToken('W', match1to2);
      addRegexToken('WW', match1to2, match2);
      addWeekParseToken(['w', 'ww', 'W', 'WW'], function(
        input,
        week,
        config,
        token
      ) {
        week[token.substr(0, 1)] = toInt(input);
      }); // HELPERS
      // LOCALES

      function localeWeek(mom) {
        return weekOfYear(mom, this._week.dow, this._week.doy).week;
      }

      var defaultLocaleWeek = {
        dow: 0,
        // Sunday is the first day of the week.
        doy: 6, // The week that contains Jan 6th is the first week of the year.
      };

      function localeFirstDayOfWeek() {
        return this._week.dow;
      }

      function localeFirstDayOfYear() {
        return this._week.doy;
      } // MOMENTS

      function getSetWeek(input) {
        var week = this.localeData().week(this);
        return input == null ? week : this.add((input - week) * 7, 'd');
      }

      function getSetISOWeek(input) {
        var week = weekOfYear(this, 1, 4).week;
        return input == null ? week : this.add((input - week) * 7, 'd');
      } // FORMATTING

      addFormatToken('d', 0, 'do', 'day');
      addFormatToken('dd', 0, 0, function(format) {
        return this.localeData().weekdaysMin(this, format);
      });
      addFormatToken('ddd', 0, 0, function(format) {
        return this.localeData().weekdaysShort(this, format);
      });
      addFormatToken('dddd', 0, 0, function(format) {
        return this.localeData().weekdays(this, format);
      });
      addFormatToken('e', 0, 0, 'weekday');
      addFormatToken('E', 0, 0, 'isoWeekday'); // ALIASES

      addUnitAlias('day', 'd');
      addUnitAlias('weekday', 'e');
      addUnitAlias('isoWeekday', 'E'); // PRIORITY

      addUnitPriority('day', 11);
      addUnitPriority('weekday', 11);
      addUnitPriority('isoWeekday', 11); // PARSING

      addRegexToken('d', match1to2);
      addRegexToken('e', match1to2);
      addRegexToken('E', match1to2);
      addRegexToken('dd', function(isStrict, locale) {
        return locale.weekdaysMinRegex(isStrict);
      });
      addRegexToken('ddd', function(isStrict, locale) {
        return locale.weekdaysShortRegex(isStrict);
      });
      addRegexToken('dddd', function(isStrict, locale) {
        return locale.weekdaysRegex(isStrict);
      });
      addWeekParseToken(['dd', 'ddd', 'dddd'], function(
        input,
        week,
        config,
        token
      ) {
        var weekday = config._locale.weekdaysParse(
          input,
          token,
          config._strict
        ); // if we didn't get a weekday name, mark the date as invalid

        if (weekday != null) {
          week.d = weekday;
        } else {
          getParsingFlags(config).invalidWeekday = input;
        }
      });
      addWeekParseToken(['d', 'e', 'E'], function(input, week, config, token) {
        week[token] = toInt(input);
      }); // HELPERS

      function parseWeekday(input, locale) {
        if (typeof input !== 'string') {
          return input;
        }

        if (!isNaN(input)) {
          return parseInt(input, 10);
        }

        input = locale.weekdaysParse(input);

        if (typeof input === 'number') {
          return input;
        }

        return null;
      }

      function parseIsoWeekday(input, locale) {
        if (typeof input === 'string') {
          return locale.weekdaysParse(input) % 7 || 7;
        }

        return isNaN(input) ? null : input;
      } // LOCALES

      var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split(
        '_'
      );

      function localeWeekdays(m, format) {
        if (!m) {
          return isArray(this._weekdays)
            ? this._weekdays
            : this._weekdays['standalone'];
        }

        return isArray(this._weekdays)
          ? this._weekdays[m.day()]
          : this._weekdays[
              this._weekdays.isFormat.test(format) ? 'format' : 'standalone'
            ][m.day()];
      }

      var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');

      function localeWeekdaysShort(m) {
        return m ? this._weekdaysShort[m.day()] : this._weekdaysShort;
      }

      var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');

      function localeWeekdaysMin(m) {
        return m ? this._weekdaysMin[m.day()] : this._weekdaysMin;
      }

      function handleStrictParse$1(weekdayName, format, strict) {
        var i,
          ii,
          mom,
          llc = weekdayName.toLocaleLowerCase();

        if (!this._weekdaysParse) {
          this._weekdaysParse = [];
          this._shortWeekdaysParse = [];
          this._minWeekdaysParse = [];

          for (i = 0; i < 7; ++i) {
            mom = createUTC([2000, 1]).day(i);
            this._minWeekdaysParse[i] = this.weekdaysMin(
              mom,
              ''
            ).toLocaleLowerCase();
            this._shortWeekdaysParse[i] = this.weekdaysShort(
              mom,
              ''
            ).toLocaleLowerCase();
            this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
          }
        }

        if (strict) {
          if (format === 'dddd') {
            ii = indexOf.call(this._weekdaysParse, llc);
            return ii !== -1 ? ii : null;
          } else if (format === 'ddd') {
            ii = indexOf.call(this._shortWeekdaysParse, llc);
            return ii !== -1 ? ii : null;
          } else {
            ii = indexOf.call(this._minWeekdaysParse, llc);
            return ii !== -1 ? ii : null;
          }
        } else {
          if (format === 'dddd') {
            ii = indexOf.call(this._weekdaysParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._shortWeekdaysParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._minWeekdaysParse, llc);
            return ii !== -1 ? ii : null;
          } else if (format === 'ddd') {
            ii = indexOf.call(this._shortWeekdaysParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._weekdaysParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._minWeekdaysParse, llc);
            return ii !== -1 ? ii : null;
          } else {
            ii = indexOf.call(this._minWeekdaysParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._weekdaysParse, llc);

            if (ii !== -1) {
              return ii;
            }

            ii = indexOf.call(this._shortWeekdaysParse, llc);
            return ii !== -1 ? ii : null;
          }
        }
      }

      function localeWeekdaysParse(weekdayName, format, strict) {
        var i, mom, regex;

        if (this._weekdaysParseExact) {
          return handleStrictParse$1.call(this, weekdayName, format, strict);
        }

        if (!this._weekdaysParse) {
          this._weekdaysParse = [];
          this._minWeekdaysParse = [];
          this._shortWeekdaysParse = [];
          this._fullWeekdaysParse = [];
        }

        for (i = 0; i < 7; i++) {
          // make the regex if we don't have it already
          mom = createUTC([2000, 1]).day(i);

          if (strict && !this._fullWeekdaysParse[i]) {
            this._fullWeekdaysParse[i] = new RegExp(
              '^' + this.weekdays(mom, '').replace('.', '\\.?') + '$',
              'i'
            );
            this._shortWeekdaysParse[i] = new RegExp(
              '^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$',
              'i'
            );
            this._minWeekdaysParse[i] = new RegExp(
              '^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$',
              'i'
            );
          }

          if (!this._weekdaysParse[i]) {
            regex =
              '^' +
              this.weekdays(mom, '') +
              '|^' +
              this.weekdaysShort(mom, '') +
              '|^' +
              this.weekdaysMin(mom, '');
            this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
          } // test the regex

          if (
            strict &&
            format === 'dddd' &&
            this._fullWeekdaysParse[i].test(weekdayName)
          ) {
            return i;
          } else if (
            strict &&
            format === 'ddd' &&
            this._shortWeekdaysParse[i].test(weekdayName)
          ) {
            return i;
          } else if (
            strict &&
            format === 'dd' &&
            this._minWeekdaysParse[i].test(weekdayName)
          ) {
            return i;
          } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
            return i;
          }
        }
      } // MOMENTS

      function getSetDayOfWeek(input) {
        if (!this.isValid()) {
          return input != null ? this : NaN;
        }

        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();

        if (input != null) {
          input = parseWeekday(input, this.localeData());
          return this.add(input - day, 'd');
        } else {
          return day;
        }
      }

      function getSetLocaleDayOfWeek(input) {
        if (!this.isValid()) {
          return input != null ? this : NaN;
        }

        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
        return input == null ? weekday : this.add(input - weekday, 'd');
      }

      function getSetISODayOfWeek(input) {
        if (!this.isValid()) {
          return input != null ? this : NaN;
        } // behaves the same as moment#day except
        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
        // as a setter, sunday should belong to the previous week.

        if (input != null) {
          var weekday = parseIsoWeekday(input, this.localeData());
          return this.day(this.day() % 7 ? weekday : weekday - 7);
        } else {
          return this.day() || 7;
        }
      }

      var defaultWeekdaysRegex = matchWord;

      function weekdaysRegex(isStrict) {
        if (this._weekdaysParseExact) {
          if (!hasOwnProp(this, '_weekdaysRegex')) {
            computeWeekdaysParse.call(this);
          }

          if (isStrict) {
            return this._weekdaysStrictRegex;
          } else {
            return this._weekdaysRegex;
          }
        } else {
          if (!hasOwnProp(this, '_weekdaysRegex')) {
            this._weekdaysRegex = defaultWeekdaysRegex;
          }

          return this._weekdaysStrictRegex && isStrict
            ? this._weekdaysStrictRegex
            : this._weekdaysRegex;
        }
      }

      var defaultWeekdaysShortRegex = matchWord;

      function weekdaysShortRegex(isStrict) {
        if (this._weekdaysParseExact) {
          if (!hasOwnProp(this, '_weekdaysRegex')) {
            computeWeekdaysParse.call(this);
          }

          if (isStrict) {
            return this._weekdaysShortStrictRegex;
          } else {
            return this._weekdaysShortRegex;
          }
        } else {
          if (!hasOwnProp(this, '_weekdaysShortRegex')) {
            this._weekdaysShortRegex = defaultWeekdaysShortRegex;
          }

          return this._weekdaysShortStrictRegex && isStrict
            ? this._weekdaysShortStrictRegex
            : this._weekdaysShortRegex;
        }
      }

      var defaultWeekdaysMinRegex = matchWord;

      function weekdaysMinRegex(isStrict) {
        if (this._weekdaysParseExact) {
          if (!hasOwnProp(this, '_weekdaysRegex')) {
            computeWeekdaysParse.call(this);
          }

          if (isStrict) {
            return this._weekdaysMinStrictRegex;
          } else {
            return this._weekdaysMinRegex;
          }
        } else {
          if (!hasOwnProp(this, '_weekdaysMinRegex')) {
            this._weekdaysMinRegex = defaultWeekdaysMinRegex;
          }

          return this._weekdaysMinStrictRegex && isStrict
            ? this._weekdaysMinStrictRegex
            : this._weekdaysMinRegex;
        }
      }

      function computeWeekdaysParse() {
        function cmpLenRev(a, b) {
          return b.length - a.length;
        }

        var minPieces = [],
          shortPieces = [],
          longPieces = [],
          mixedPieces = [],
          i,
          mom,
          minp,
          shortp,
          longp;

        for (i = 0; i < 7; i++) {
          // make the regex if we don't have it already
          mom = createUTC([2000, 1]).day(i);
          minp = this.weekdaysMin(mom, '');
          shortp = this.weekdaysShort(mom, '');
          longp = this.weekdays(mom, '');
          minPieces.push(minp);
          shortPieces.push(shortp);
          longPieces.push(longp);
          mixedPieces.push(minp);
          mixedPieces.push(shortp);
          mixedPieces.push(longp);
        } // Sorting makes sure if one weekday (or abbr) is a prefix of another it
        // will match the longer piece.

        minPieces.sort(cmpLenRev);
        shortPieces.sort(cmpLenRev);
        longPieces.sort(cmpLenRev);
        mixedPieces.sort(cmpLenRev);

        for (i = 0; i < 7; i++) {
          shortPieces[i] = regexEscape(shortPieces[i]);
          longPieces[i] = regexEscape(longPieces[i]);
          mixedPieces[i] = regexEscape(mixedPieces[i]);
        }

        this._weekdaysRegex = new RegExp(
          '^(' + mixedPieces.join('|') + ')',
          'i'
        );
        this._weekdaysShortRegex = this._weekdaysRegex;
        this._weekdaysMinRegex = this._weekdaysRegex;
        this._weekdaysStrictRegex = new RegExp(
          '^(' + longPieces.join('|') + ')',
          'i'
        );
        this._weekdaysShortStrictRegex = new RegExp(
          '^(' + shortPieces.join('|') + ')',
          'i'
        );
        this._weekdaysMinStrictRegex = new RegExp(
          '^(' + minPieces.join('|') + ')',
          'i'
        );
      } // FORMATTING

      function hFormat() {
        return this.hours() % 12 || 12;
      }

      function kFormat() {
        return this.hours() || 24;
      }

      addFormatToken('H', ['HH', 2], 0, 'hour');
      addFormatToken('h', ['hh', 2], 0, hFormat);
      addFormatToken('k', ['kk', 2], 0, kFormat);
      addFormatToken('hmm', 0, 0, function() {
        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
      });
      addFormatToken('hmmss', 0, 0, function() {
        return (
          '' +
          hFormat.apply(this) +
          zeroFill(this.minutes(), 2) +
          zeroFill(this.seconds(), 2)
        );
      });
      addFormatToken('Hmm', 0, 0, function() {
        return '' + this.hours() + zeroFill(this.minutes(), 2);
      });
      addFormatToken('Hmmss', 0, 0, function() {
        return (
          '' +
          this.hours() +
          zeroFill(this.minutes(), 2) +
          zeroFill(this.seconds(), 2)
        );
      });

      function meridiem(token, lowercase) {
        addFormatToken(token, 0, 0, function() {
          return this.localeData().meridiem(
            this.hours(),
            this.minutes(),
            lowercase
          );
        });
      }

      meridiem('a', true);
      meridiem('A', false); // ALIASES

      addUnitAlias('hour', 'h'); // PRIORITY

      addUnitPriority('hour', 13); // PARSING

      function matchMeridiem(isStrict, locale) {
        return locale._meridiemParse;
      }

      addRegexToken('a', matchMeridiem);
      addRegexToken('A', matchMeridiem);
      addRegexToken('H', match1to2);
      addRegexToken('h', match1to2);
      addRegexToken('k', match1to2);
      addRegexToken('HH', match1to2, match2);
      addRegexToken('hh', match1to2, match2);
      addRegexToken('kk', match1to2, match2);
      addRegexToken('hmm', match3to4);
      addRegexToken('hmmss', match5to6);
      addRegexToken('Hmm', match3to4);
      addRegexToken('Hmmss', match5to6);
      addParseToken(['H', 'HH'], HOUR);
      addParseToken(['k', 'kk'], function(input, array, config) {
        var kInput = toInt(input);
        array[HOUR] = kInput === 24 ? 0 : kInput;
      });
      addParseToken(['a', 'A'], function(input, array, config) {
        config._isPm = config._locale.isPM(input);
        config._meridiem = input;
      });
      addParseToken(['h', 'hh'], function(input, array, config) {
        array[HOUR] = toInt(input);
        getParsingFlags(config).bigHour = true;
      });
      addParseToken('hmm', function(input, array, config) {
        var pos = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos));
        array[MINUTE] = toInt(input.substr(pos));
        getParsingFlags(config).bigHour = true;
      });
      addParseToken('hmmss', function(input, array, config) {
        var pos1 = input.length - 4;
        var pos2 = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos1));
        array[MINUTE] = toInt(input.substr(pos1, 2));
        array[SECOND] = toInt(input.substr(pos2));
        getParsingFlags(config).bigHour = true;
      });
      addParseToken('Hmm', function(input, array, config) {
        var pos = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos));
        array[MINUTE] = toInt(input.substr(pos));
      });
      addParseToken('Hmmss', function(input, array, config) {
        var pos1 = input.length - 4;
        var pos2 = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos1));
        array[MINUTE] = toInt(input.substr(pos1, 2));
        array[SECOND] = toInt(input.substr(pos2));
      }); // LOCALES

      function localeIsPM(input) {
        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
        // Using charAt should be more compatible.
        return (input + '').toLowerCase().charAt(0) === 'p';
      }

      var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;

      function localeMeridiem(hours, minutes, isLower) {
        if (hours > 11) {
          return isLower ? 'pm' : 'PM';
        } else {
          return isLower ? 'am' : 'AM';
        }
      } // MOMENTS
      // Setting the hour should keep the time, because the user explicitly
      // specified which hour they want. So trying to maintain the same hour (in
      // a new timezone) makes sense. Adding/subtracting hours does not follow
      // this rule.

      var getSetHour = makeGetSet('Hours', true);
      var baseConfig = {
        calendar: defaultCalendar,
        longDateFormat: defaultLongDateFormat,
        invalidDate: defaultInvalidDate,
        ordinal: defaultOrdinal,
        dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
        relativeTime: defaultRelativeTime,
        months: defaultLocaleMonths,
        monthsShort: defaultLocaleMonthsShort,
        week: defaultLocaleWeek,
        weekdays: defaultLocaleWeekdays,
        weekdaysMin: defaultLocaleWeekdaysMin,
        weekdaysShort: defaultLocaleWeekdaysShort,
        meridiemParse: defaultLocaleMeridiemParse,
      }; // internal storage for locale config files

      var locales = {};
      var localeFamilies = {};
      var globalLocale;

      function normalizeLocale(key) {
        return key ? key.toLowerCase().replace('_', '-') : key;
      } // pick the locale from the array
      // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
      // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root

      function chooseLocale(names) {
        var i = 0,
          j,
          next,
          locale,
          split;

        while (i < names.length) {
          split = normalizeLocale(names[i]).split('-');
          j = split.length;
          next = normalizeLocale(names[i + 1]);
          next = next ? next.split('-') : null;

          while (j > 0) {
            locale = loadLocale(split.slice(0, j).join('-'));

            if (locale) {
              return locale;
            }

            if (
              next &&
              next.length >= j &&
              compareArrays(split, next, true) >= j - 1
            ) {
              //the next array item is better than a shallower substring of this one
              break;
            }

            j--;
          }

          i++;
        }

        return globalLocale;
      }

      function loadLocale(name) {
        var oldLocale = null; // TODO: Find a better way to register and load all the locales in Node

        if (
          !locales[name] &&
          'object' !== 'undefined' &&
          module &&
          module.exports
        ) {
          try {
            oldLocale = globalLocale._abbr;
            var aliasedRequire = commonjsRequire;
            aliasedRequire('./locale/' + name);
            getSetGlobalLocale(oldLocale);
          } catch (e) {}
        }

        return locales[name];
      } // This function will load locale and then set the global locale.  If
      // no arguments are passed in, it will simply return the current global
      // locale key.

      function getSetGlobalLocale(key, values) {
        var data;

        if (key) {
          if (isUndefined(values)) {
            data = getLocale(key);
          } else {
            data = defineLocale(key, values);
          }

          if (data) {
            // moment.duration._locale = moment._locale = data;
            globalLocale = data;
          } else {
            if (typeof console !== 'undefined' && console.warn) {
              //warn user if arguments are passed but the locale could not be set
              console.warn(
                'Locale ' + key + ' not found. Did you forget to load it?'
              );
            }
          }
        }

        return globalLocale._abbr;
      }

      function defineLocale(name, config) {
        if (config !== null) {
          var locale,
            parentConfig = baseConfig;
          config.abbr = name;

          if (locales[name] != null) {
            deprecateSimple(
              'defineLocaleOverride',
              'use moment.updateLocale(localeName, config) to change ' +
                'an existing locale. moment.defineLocale(localeName, ' +
                'config) should only be used for creating a new locale ' +
                'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.'
            );
            parentConfig = locales[name]._config;
          } else if (config.parentLocale != null) {
            if (locales[config.parentLocale] != null) {
              parentConfig = locales[config.parentLocale]._config;
            } else {
              locale = loadLocale(config.parentLocale);

              if (locale != null) {
                parentConfig = locale._config;
              } else {
                if (!localeFamilies[config.parentLocale]) {
                  localeFamilies[config.parentLocale] = [];
                }

                localeFamilies[config.parentLocale].push({
                  name: name,
                  config: config,
                });
                return null;
              }
            }
          }

          locales[name] = new Locale(mergeConfigs(parentConfig, config));

          if (localeFamilies[name]) {
            localeFamilies[name].forEach(function(x) {
              defineLocale(x.name, x.config);
            });
          } // backwards compat for now: also set the locale
          // make sure we set the locale AFTER all child locales have been
          // created, so we won't end up with the child locale set.

          getSetGlobalLocale(name);
          return locales[name];
        } else {
          // useful for testing
          delete locales[name];
          return null;
        }
      }

      function updateLocale(name, config) {
        if (config != null) {
          var locale,
            tmpLocale,
            parentConfig = baseConfig; // MERGE

          tmpLocale = loadLocale(name);

          if (tmpLocale != null) {
            parentConfig = tmpLocale._config;
          }

          config = mergeConfigs(parentConfig, config);
          locale = new Locale(config);
          locale.parentLocale = locales[name];
          locales[name] = locale; // backwards compat for now: also set the locale

          getSetGlobalLocale(name);
        } else {
          // pass null for config to unupdate, useful for tests
          if (locales[name] != null) {
            if (locales[name].parentLocale != null) {
              locales[name] = locales[name].parentLocale;
            } else if (locales[name] != null) {
              delete locales[name];
            }
          }
        }

        return locales[name];
      } // returns locale data

      function getLocale(key) {
        var locale;

        if (key && key._locale && key._locale._abbr) {
          key = key._locale._abbr;
        }

        if (!key) {
          return globalLocale;
        }

        if (!isArray(key)) {
          //short-circuit everything else
          locale = loadLocale(key);

          if (locale) {
            return locale;
          }

          key = [key];
        }

        return chooseLocale(key);
      }

      function listLocales() {
        return keys(locales);
      }

      function checkOverflow(m) {
        var overflow;
        var a = m._a;

        if (a && getParsingFlags(m).overflow === -2) {
          overflow =
            a[MONTH] < 0 || a[MONTH] > 11
              ? MONTH
              : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH])
              ? DATE
              : a[HOUR] < 0 ||
                a[HOUR] > 24 ||
                (a[HOUR] === 24 &&
                  (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0))
              ? HOUR
              : a[MINUTE] < 0 || a[MINUTE] > 59
              ? MINUTE
              : a[SECOND] < 0 || a[SECOND] > 59
              ? SECOND
              : a[MILLISECOND] < 0 || a[MILLISECOND] > 999
              ? MILLISECOND
              : -1;

          if (
            getParsingFlags(m)._overflowDayOfYear &&
            (overflow < YEAR || overflow > DATE)
          ) {
            overflow = DATE;
          }

          if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
            overflow = WEEK;
          }

          if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
            overflow = WEEKDAY;
          }

          getParsingFlags(m).overflow = overflow;
        }

        return m;
      } // Pick the first defined of two or three arguments.

      function defaults(a, b, c) {
        if (a != null) {
          return a;
        }

        if (b != null) {
          return b;
        }

        return c;
      }

      function currentDateArray(config) {
        // hooks is actually the exported moment object
        var nowValue = new Date(hooks.now());

        if (config._useUTC) {
          return [
            nowValue.getUTCFullYear(),
            nowValue.getUTCMonth(),
            nowValue.getUTCDate(),
          ];
        }

        return [
          nowValue.getFullYear(),
          nowValue.getMonth(),
          nowValue.getDate(),
        ];
      } // convert an array to a date.
      // the array should mirror the parameters below
      // note: all values past the year are optional and will default to the lowest possible value.
      // [year, month, day , hour, minute, second, millisecond]

      function configFromArray(config) {
        var i,
          date,
          input = [],
          currentDate,
          expectedWeekday,
          yearToUse;

        if (config._d) {
          return;
        }

        currentDate = currentDateArray(config); //compute day of the year from weeks and weekdays

        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
          dayOfYearFromWeekInfo(config);
        } //if the day of the year is set, figure out what it is

        if (config._dayOfYear != null) {
          yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);

          if (
            config._dayOfYear > daysInYear(yearToUse) ||
            config._dayOfYear === 0
          ) {
            getParsingFlags(config)._overflowDayOfYear = true;
          }

          date = createUTCDate(yearToUse, 0, config._dayOfYear);
          config._a[MONTH] = date.getUTCMonth();
          config._a[DATE] = date.getUTCDate();
        } // Default to current date.
        // * if no year, month, day of month are given, default to today
        // * if day of month is given, default month and year
        // * if month is given, default only year
        // * if year is given, don't default anything

        for (i = 0; i < 3 && config._a[i] == null; ++i) {
          config._a[i] = input[i] = currentDate[i];
        } // Zero out whatever was not defaulted, including time

        for (; i < 7; i++) {
          config._a[i] = input[i] =
            config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i];
        } // Check for 24:00:00.000

        if (
          config._a[HOUR] === 24 &&
          config._a[MINUTE] === 0 &&
          config._a[SECOND] === 0 &&
          config._a[MILLISECOND] === 0
        ) {
          config._nextDay = true;
          config._a[HOUR] = 0;
        }

        config._d = (config._useUTC ? createUTCDate : createDate).apply(
          null,
          input
        );
        expectedWeekday = config._useUTC
          ? config._d.getUTCDay()
          : config._d.getDay(); // Apply timezone offset from input. The actual utcOffset can be changed
        // with parseZone.

        if (config._tzm != null) {
          config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
        }

        if (config._nextDay) {
          config._a[HOUR] = 24;
        } // check for mismatching day of week

        if (
          config._w &&
          typeof config._w.d !== 'undefined' &&
          config._w.d !== expectedWeekday
        ) {
          getParsingFlags(config).weekdayMismatch = true;
        }
      }

      function dayOfYearFromWeekInfo(config) {
        var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
        w = config._w;

        if (w.GG != null || w.W != null || w.E != null) {
          dow = 1;
          doy = 4; // TODO: We need to take the current isoWeekYear, but that depends on
          // how we interpret now (local, utc, fixed offset). So create
          // a now version of current config (take local/utc/offset flags, and
          // create now).

          weekYear = defaults(
            w.GG,
            config._a[YEAR],
            weekOfYear(createLocal(), 1, 4).year
          );
          week = defaults(w.W, 1);
          weekday = defaults(w.E, 1);

          if (weekday < 1 || weekday > 7) {
            weekdayOverflow = true;
          }
        } else {
          dow = config._locale._week.dow;
          doy = config._locale._week.doy;
          var curWeek = weekOfYear(createLocal(), dow, doy);
          weekYear = defaults(w.gg, config._a[YEAR], curWeek.year); // Default to current week.

          week = defaults(w.w, curWeek.week);

          if (w.d != null) {
            // weekday -- low day numbers are considered next week
            weekday = w.d;

            if (weekday < 0 || weekday > 6) {
              weekdayOverflow = true;
            }
          } else if (w.e != null) {
            // local weekday -- counting starts from beginning of week
            weekday = w.e + dow;

            if (w.e < 0 || w.e > 6) {
              weekdayOverflow = true;
            }
          } else {
            // default to beginning of week
            weekday = dow;
          }
        }

        if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
          getParsingFlags(config)._overflowWeeks = true;
        } else if (weekdayOverflow != null) {
          getParsingFlags(config)._overflowWeekday = true;
        } else {
          temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
          config._a[YEAR] = temp.year;
          config._dayOfYear = temp.dayOfYear;
        }
      } // iso 8601 regex
      // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)

      var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
      var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/;
      var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
      var isoDates = [
        ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
        ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
        ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
        ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
        ['YYYY-DDD', /\d{4}-\d{3}/],
        ['YYYY-MM', /\d{4}-\d\d/, false],
        ['YYYYYYMMDD', /[+-]\d{10}/],
        ['YYYYMMDD', /\d{8}/], // YYYYMM is NOT allowed by the standard
        ['GGGG[W]WWE', /\d{4}W\d{3}/],
        ['GGGG[W]WW', /\d{4}W\d{2}/, false],
        ['YYYYDDD', /\d{7}/],
      ]; // iso time formats and regexes

      var isoTimes = [
        ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
        ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
        ['HH:mm:ss', /\d\d:\d\d:\d\d/],
        ['HH:mm', /\d\d:\d\d/],
        ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
        ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
        ['HHmmss', /\d\d\d\d\d\d/],
        ['HHmm', /\d\d\d\d/],
        ['HH', /\d\d/],
      ];
      var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i; // date from iso format

      function configFromISO(config) {
        var i,
          l,
          string = config._i,
          match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
          allowTime,
          dateFormat,
          timeFormat,
          tzFormat;

        if (match) {
          getParsingFlags(config).iso = true;

          for (i = 0, l = isoDates.length; i < l; i++) {
            if (isoDates[i][1].exec(match[1])) {
              dateFormat = isoDates[i][0];
              allowTime = isoDates[i][2] !== false;
              break;
            }
          }

          if (dateFormat == null) {
            config._isValid = false;
            return;
          }

          if (match[3]) {
            for (i = 0, l = isoTimes.length; i < l; i++) {
              if (isoTimes[i][1].exec(match[3])) {
                // match[2] should be 'T' or space
                timeFormat = (match[2] || ' ') + isoTimes[i][0];
                break;
              }
            }

            if (timeFormat == null) {
              config._isValid = false;
              return;
            }
          }

          if (!allowTime && timeFormat != null) {
            config._isValid = false;
            return;
          }

          if (match[4]) {
            if (tzRegex.exec(match[4])) {
              tzFormat = 'Z';
            } else {
              config._isValid = false;
              return;
            }
          }

          config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
          configFromStringAndFormat(config);
        } else {
          config._isValid = false;
        }
      } // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3

      var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;

      function extractFromRFC2822Strings(
        yearStr,
        monthStr,
        dayStr,
        hourStr,
        minuteStr,
        secondStr
      ) {
        var result = [
          untruncateYear(yearStr),
          defaultLocaleMonthsShort.indexOf(monthStr),
          parseInt(dayStr, 10),
          parseInt(hourStr, 10),
          parseInt(minuteStr, 10),
        ];

        if (secondStr) {
          result.push(parseInt(secondStr, 10));
        }

        return result;
      }

      function untruncateYear(yearStr) {
        var year = parseInt(yearStr, 10);

        if (year <= 49) {
          return 2000 + year;
        } else if (year <= 999) {
          return 1900 + year;
        }

        return year;
      }

      function preprocessRFC2822(s) {
        // Remove comments and folding whitespace and replace multiple-spaces with a single space
        return s
          .replace(/\([^)]*\)|[\n\t]/g, ' ')
          .replace(/(\s\s+)/g, ' ')
          .replace(/^\s\s*/, '')
          .replace(/\s\s*$/, '');
      }

      function checkWeekday(weekdayStr, parsedInput, config) {
        if (weekdayStr) {
          // TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.
          var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
            weekdayActual = new Date(
              parsedInput[0],
              parsedInput[1],
              parsedInput[2]
            ).getDay();

          if (weekdayProvided !== weekdayActual) {
            getParsingFlags(config).weekdayMismatch = true;
            config._isValid = false;
            return false;
          }
        }

        return true;
      }

      var obsOffsets = {
        UT: 0,
        GMT: 0,
        EDT: -4 * 60,
        EST: -5 * 60,
        CDT: -5 * 60,
        CST: -6 * 60,
        MDT: -6 * 60,
        MST: -7 * 60,
        PDT: -7 * 60,
        PST: -8 * 60,
      };

      function calculateOffset(obsOffset, militaryOffset, numOffset) {
        if (obsOffset) {
          return obsOffsets[obsOffset];
        } else if (militaryOffset) {
          // the only allowed military tz is Z
          return 0;
        } else {
          var hm = parseInt(numOffset, 10);
          var m = hm % 100,
            h = (hm - m) / 100;
          return h * 60 + m;
        }
      } // date and time from ref 2822 format

      function configFromRFC2822(config) {
        var match = rfc2822.exec(preprocessRFC2822(config._i));

        if (match) {
          var parsedArray = extractFromRFC2822Strings(
            match[4],
            match[3],
            match[2],
            match[5],
            match[6],
            match[7]
          );

          if (!checkWeekday(match[1], parsedArray, config)) {
            return;
          }

          config._a = parsedArray;
          config._tzm = calculateOffset(match[8], match[9], match[10]);
          config._d = createUTCDate.apply(null, config._a);

          config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);

          getParsingFlags(config).rfc2822 = true;
        } else {
          config._isValid = false;
        }
      } // date from iso format or fallback

      function configFromString(config) {
        var matched = aspNetJsonRegex.exec(config._i);

        if (matched !== null) {
          config._d = new Date(+matched[1]);
          return;
        }

        configFromISO(config);

        if (config._isValid === false) {
          delete config._isValid;
        } else {
          return;
        }

        configFromRFC2822(config);

        if (config._isValid === false) {
          delete config._isValid;
        } else {
          return;
        } // Final attempt, use Input Fallback

        hooks.createFromInputFallback(config);
      }

      hooks.createFromInputFallback = deprecate(
        'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
          'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
          'discouraged and will be removed in an upcoming major release. Please refer to ' +
          'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
        function(config) {
          config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
        }
      ); // constant that refers to the ISO standard

      hooks.ISO_8601 = function() {}; // constant that refers to the RFC 2822 form

      hooks.RFC_2822 = function() {}; // date from string and format string

      function configFromStringAndFormat(config) {
        // TODO: Move this to another part of the creation flow to prevent circular deps
        if (config._f === hooks.ISO_8601) {
          configFromISO(config);
          return;
        }

        if (config._f === hooks.RFC_2822) {
          configFromRFC2822(config);
          return;
        }

        config._a = [];
        getParsingFlags(config).empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC`

        var string = '' + config._i,
          i,
          parsedInput,
          tokens,
          token,
          skipped,
          stringLength = string.length,
          totalParsedInputLength = 0;
        tokens =
          expandFormat(config._f, config._locale).match(formattingTokens) || [];

        for (i = 0; i < tokens.length; i++) {
          token = tokens[i];
          parsedInput = (string.match(getParseRegexForToken(token, config)) ||
            [])[0]; // console.log('token', token, 'parsedInput', parsedInput,
          //         'regex', getParseRegexForToken(token, config));

          if (parsedInput) {
            skipped = string.substr(0, string.indexOf(parsedInput));

            if (skipped.length > 0) {
              getParsingFlags(config).unusedInput.push(skipped);
            }

            string = string.slice(
              string.indexOf(parsedInput) + parsedInput.length
            );
            totalParsedInputLength += parsedInput.length;
          } // don't parse if it's not a known token

          if (formatTokenFunctions[token]) {
            if (parsedInput) {
              getParsingFlags(config).empty = false;
            } else {
              getParsingFlags(config).unusedTokens.push(token);
            }

            addTimeToArrayFromToken(token, parsedInput, config);
          } else if (config._strict && !parsedInput) {
            getParsingFlags(config).unusedTokens.push(token);
          }
        } // add remaining unparsed input length to the string

        getParsingFlags(config).charsLeftOver =
          stringLength - totalParsedInputLength;

        if (string.length > 0) {
          getParsingFlags(config).unusedInput.push(string);
        } // clear _12h flag if hour is <= 12

        if (
          config._a[HOUR] <= 12 &&
          getParsingFlags(config).bigHour === true &&
          config._a[HOUR] > 0
        ) {
          getParsingFlags(config).bigHour = undefined;
        }

        getParsingFlags(config).parsedDateParts = config._a.slice(0);
        getParsingFlags(config).meridiem = config._meridiem; // handle meridiem

        config._a[HOUR] = meridiemFixWrap(
          config._locale,
          config._a[HOUR],
          config._meridiem
        );
        configFromArray(config);
        checkOverflow(config);
      }

      function meridiemFixWrap(locale, hour, meridiem) {
        var isPm;

        if (meridiem == null) {
          // nothing to do
          return hour;
        }

        if (locale.meridiemHour != null) {
          return locale.meridiemHour(hour, meridiem);
        } else if (locale.isPM != null) {
          // Fallback
          isPm = locale.isPM(meridiem);

          if (isPm && hour < 12) {
            hour += 12;
          }

          if (!isPm && hour === 12) {
            hour = 0;
          }

          return hour;
        } else {
          // this is not supposed to happen
          return hour;
        }
      } // date from string and array of format strings

      function configFromStringAndArray(config) {
        var tempConfig, bestMoment, scoreToBeat, i, currentScore;

        if (config._f.length === 0) {
          getParsingFlags(config).invalidFormat = true;
          config._d = new Date(NaN);
          return;
        }

        for (i = 0; i < config._f.length; i++) {
          currentScore = 0;
          tempConfig = copyConfig({}, config);

          if (config._useUTC != null) {
            tempConfig._useUTC = config._useUTC;
          }

          tempConfig._f = config._f[i];
          configFromStringAndFormat(tempConfig);

          if (!isValid(tempConfig)) {
            continue;
          } // if there is any input that was not parsed add a penalty for that format

          currentScore += getParsingFlags(tempConfig).charsLeftOver; //or tokens

          currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
          getParsingFlags(tempConfig).score = currentScore;

          if (scoreToBeat == null || currentScore < scoreToBeat) {
            scoreToBeat = currentScore;
            bestMoment = tempConfig;
          }
        }

        extend(config, bestMoment || tempConfig);
      }

      function configFromObject(config) {
        if (config._d) {
          return;
        }

        var i = normalizeObjectUnits(config._i);
        config._a = map(
          [
            i.year,
            i.month,
            i.day || i.date,
            i.hour,
            i.minute,
            i.second,
            i.millisecond,
          ],
          function(obj) {
            return obj && parseInt(obj, 10);
          }
        );
        configFromArray(config);
      }

      function createFromConfig(config) {
        var res = new Moment(checkOverflow(prepareConfig(config)));

        if (res._nextDay) {
          // Adding is smart enough around DST
          res.add(1, 'd');
          res._nextDay = undefined;
        }

        return res;
      }

      function prepareConfig(config) {
        var input = config._i,
          format = config._f;
        config._locale = config._locale || getLocale(config._l);

        if (input === null || (format === undefined && input === '')) {
          return createInvalid({
            nullInput: true,
          });
        }

        if (typeof input === 'string') {
          config._i = input = config._locale.preparse(input);
        }

        if (isMoment(input)) {
          return new Moment(checkOverflow(input));
        } else if (isDate(input)) {
          config._d = input;
        } else if (isArray(format)) {
          configFromStringAndArray(config);
        } else if (format) {
          configFromStringAndFormat(config);
        } else {
          configFromInput(config);
        }

        if (!isValid(config)) {
          config._d = null;
        }

        return config;
      }

      function configFromInput(config) {
        var input = config._i;

        if (isUndefined(input)) {
          config._d = new Date(hooks.now());
        } else if (isDate(input)) {
          config._d = new Date(input.valueOf());
        } else if (typeof input === 'string') {
          configFromString(config);
        } else if (isArray(input)) {
          config._a = map(input.slice(0), function(obj) {
            return parseInt(obj, 10);
          });
          configFromArray(config);
        } else if (isObject(input)) {
          configFromObject(config);
        } else if (isNumber(input)) {
          // from milliseconds
          config._d = new Date(input);
        } else {
          hooks.createFromInputFallback(config);
        }
      }

      function createLocalOrUTC(input, format, locale, strict, isUTC) {
        var c = {};

        if (locale === true || locale === false) {
          strict = locale;
          locale = undefined;
        }

        if (
          (isObject(input) && isObjectEmpty(input)) ||
          (isArray(input) && input.length === 0)
        ) {
          input = undefined;
        } // object construction must be done this way.
        // https://github.com/moment/moment/issues/1423

        c._isAMomentObject = true;
        c._useUTC = c._isUTC = isUTC;
        c._l = locale;
        c._i = input;
        c._f = format;
        c._strict = strict;
        return createFromConfig(c);
      }

      function createLocal(input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, false);
      }

      var prototypeMin = deprecate(
        'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
        function() {
          var other = createLocal.apply(null, arguments);

          if (this.isValid() && other.isValid()) {
            return other < this ? this : other;
          } else {
            return createInvalid();
          }
        }
      );
      var prototypeMax = deprecate(
        'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
        function() {
          var other = createLocal.apply(null, arguments);

          if (this.isValid() && other.isValid()) {
            return other > this ? this : other;
          } else {
            return createInvalid();
          }
        }
      ); // Pick a moment m from moments so that m[fn](other) is true for all
      // other. This relies on the function fn to be transitive.
      //
      // moments should either be an array of moment objects or an array, whose
      // first element is an array of moment objects.

      function pickBy(fn, moments) {
        var res, i;

        if (moments.length === 1 && isArray(moments[0])) {
          moments = moments[0];
        }

        if (!moments.length) {
          return createLocal();
        }

        res = moments[0];

        for (i = 1; i < moments.length; ++i) {
          if (!moments[i].isValid() || moments[i][fn](res)) {
            res = moments[i];
          }
        }

        return res;
      } // TODO: Use [].sort instead?

      function min() {
        var args = [].slice.call(arguments, 0);
        return pickBy('isBefore', args);
      }

      function max() {
        var args = [].slice.call(arguments, 0);
        return pickBy('isAfter', args);
      }

      var now = function() {
        return Date.now ? Date.now() : +new Date();
      };

      var ordering = [
        'year',
        'quarter',
        'month',
        'week',
        'day',
        'hour',
        'minute',
        'second',
        'millisecond',
      ];

      function isDurationValid(m) {
        for (var key in m) {
          if (
            !(
              indexOf.call(ordering, key) !== -1 &&
              (m[key] == null || !isNaN(m[key]))
            )
          ) {
            return false;
          }
        }

        var unitHasDecimal = false;

        for (var i = 0; i < ordering.length; ++i) {
          if (m[ordering[i]]) {
            if (unitHasDecimal) {
              return false; // only allow non-integers for smallest unit
            }

            if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
              unitHasDecimal = true;
            }
          }
        }

        return true;
      }

      function isValid$1() {
        return this._isValid;
      }

      function createInvalid$1() {
        return createDuration(NaN);
      }

      function Duration(duration) {
        var normalizedInput = normalizeObjectUnits(duration),
          years = normalizedInput.year || 0,
          quarters = normalizedInput.quarter || 0,
          months = normalizedInput.month || 0,
          weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
          days = normalizedInput.day || 0,
          hours = normalizedInput.hour || 0,
          minutes = normalizedInput.minute || 0,
          seconds = normalizedInput.second || 0,
          milliseconds = normalizedInput.millisecond || 0;
        this._isValid = isDurationValid(normalizedInput); // representation for dateAddRemove

        this._milliseconds =
          +milliseconds +
          seconds * 1e3 + // 1000
          minutes * 6e4 + // 1000 * 60
          hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
        // Because of dateAddRemove treats 24 hours as different from a
        // day when working around DST, we need to store them separately

        this._days = +days + weeks * 7; // It is impossible to translate months into days without knowing
        // which months you are are talking about, so we have to store
        // it separately.

        this._months = +months + quarters * 3 + years * 12;
        this._data = {};
        this._locale = getLocale();

        this._bubble();
      }

      function isDuration(obj) {
        return obj instanceof Duration;
      }

      function absRound(number) {
        if (number < 0) {
          return Math.round(-1 * number) * -1;
        } else {
          return Math.round(number);
        }
      } // FORMATTING

      function offset(token, separator) {
        addFormatToken(token, 0, 0, function() {
          var offset = this.utcOffset();
          var sign = '+';

          if (offset < 0) {
            offset = -offset;
            sign = '-';
          }

          return (
            sign +
            zeroFill(~~(offset / 60), 2) +
            separator +
            zeroFill(~~offset % 60, 2)
          );
        });
      }

      offset('Z', ':');
      offset('ZZ', ''); // PARSING

      addRegexToken('Z', matchShortOffset);
      addRegexToken('ZZ', matchShortOffset);
      addParseToken(['Z', 'ZZ'], function(input, array, config) {
        config._useUTC = true;
        config._tzm = offsetFromString(matchShortOffset, input);
      }); // HELPERS
      // timezone chunker
      // '+10:00' > ['10',  '00']
      // '-1530'  > ['-15', '30']

      var chunkOffset = /([\+\-]|\d\d)/gi;

      function offsetFromString(matcher, string) {
        var matches = (string || '').match(matcher);

        if (matches === null) {
          return null;
        }

        var chunk = matches[matches.length - 1] || [];
        var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
        var minutes = +(parts[1] * 60) + toInt(parts[2]);
        return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
      } // Return a moment from input, that is local/utc/zone equivalent to model.

      function cloneWithOffset(input, model) {
        var res, diff;

        if (model._isUTC) {
          res = model.clone();
          diff =
            (isMoment(input) || isDate(input)
              ? input.valueOf()
              : createLocal(input).valueOf()) - res.valueOf(); // Use low-level api, because this fn is low-level api.

          res._d.setTime(res._d.valueOf() + diff);

          hooks.updateOffset(res, false);
          return res;
        } else {
          return createLocal(input).local();
        }
      }

      function getDateOffset(m) {
        // On Firefox.24 Date#getTimezoneOffset returns a floating point.
        // https://github.com/moment/moment/pull/1871
        return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
      } // HOOKS
      // This function will be called whenever a moment is mutated.
      // It is intended to keep the offset in sync with the timezone.

      hooks.updateOffset = function() {}; // MOMENTS
      // keepLocalTime = true means only change the timezone, without
      // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
      // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
      // +0200, so we adjust the time as needed, to be valid.
      //
      // Keeping the time actually adds/subtracts (one hour)
      // from the actual represented time. That is why we call updateOffset
      // a second time. In case it wants us to change the offset again
      // _changeInProgress == true case, then we have to adjust, because
      // there is no such time in the given timezone.

      function getSetOffset(input, keepLocalTime, keepMinutes) {
        var offset = this._offset || 0,
          localAdjust;

        if (!this.isValid()) {
          return input != null ? this : NaN;
        }

        if (input != null) {
          if (typeof input === 'string') {
            input = offsetFromString(matchShortOffset, input);

            if (input === null) {
              return this;
            }
          } else if (Math.abs(input) < 16 && !keepMinutes) {
            input = input * 60;
          }

          if (!this._isUTC && keepLocalTime) {
            localAdjust = getDateOffset(this);
          }

          this._offset = input;
          this._isUTC = true;

          if (localAdjust != null) {
            this.add(localAdjust, 'm');
          }

          if (offset !== input) {
            if (!keepLocalTime || this._changeInProgress) {
              addSubtract(this, createDuration(input - offset, 'm'), 1, false);
            } else if (!this._changeInProgress) {
              this._changeInProgress = true;
              hooks.updateOffset(this, true);
              this._changeInProgress = null;
            }
          }

          return this;
        } else {
          return this._isUTC ? offset : getDateOffset(this);
        }
      }

      function getSetZone(input, keepLocalTime) {
        if (input != null) {
          if (typeof input !== 'string') {
            input = -input;
          }

          this.utcOffset(input, keepLocalTime);
          return this;
        } else {
          return -this.utcOffset();
        }
      }

      function setOffsetToUTC(keepLocalTime) {
        return this.utcOffset(0, keepLocalTime);
      }

      function setOffsetToLocal(keepLocalTime) {
        if (this._isUTC) {
          this.utcOffset(0, keepLocalTime);
          this._isUTC = false;

          if (keepLocalTime) {
            this.subtract(getDateOffset(this), 'm');
          }
        }

        return this;
      }

      function setOffsetToParsedOffset() {
        if (this._tzm != null) {
          this.utcOffset(this._tzm, false, true);
        } else if (typeof this._i === 'string') {
          var tZone = offsetFromString(matchOffset, this._i);

          if (tZone != null) {
            this.utcOffset(tZone);
          } else {
            this.utcOffset(0, true);
          }
        }

        return this;
      }

      function hasAlignedHourOffset(input) {
        if (!this.isValid()) {
          return false;
        }

        input = input ? createLocal(input).utcOffset() : 0;
        return (this.utcOffset() - input) % 60 === 0;
      }

      function isDaylightSavingTime() {
        return (
          this.utcOffset() >
            this.clone()
              .month(0)
              .utcOffset() ||
          this.utcOffset() >
            this.clone()
              .month(5)
              .utcOffset()
        );
      }

      function isDaylightSavingTimeShifted() {
        if (!isUndefined(this._isDSTShifted)) {
          return this._isDSTShifted;
        }

        var c = {};
        copyConfig(c, this);
        c = prepareConfig(c);

        if (c._a) {
          var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
          this._isDSTShifted =
            this.isValid() && compareArrays(c._a, other.toArray()) > 0;
        } else {
          this._isDSTShifted = false;
        }

        return this._isDSTShifted;
      }

      function isLocal() {
        return this.isValid() ? !this._isUTC : false;
      }

      function isUtcOffset() {
        return this.isValid() ? this._isUTC : false;
      }

      function isUtc() {
        return this.isValid() ? this._isUTC && this._offset === 0 : false;
      } // ASP.NET json date format regex

      var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/; // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
      // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
      // and further modified to allow for strings containing both week and day

      var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;

      function createDuration(input, key) {
        var duration = input,
          // matching against regexp is expensive, do it on demand
          match = null,
          sign,
          ret,
          diffRes;

        if (isDuration(input)) {
          duration = {
            ms: input._milliseconds,
            d: input._days,
            M: input._months,
          };
        } else if (isNumber(input)) {
          duration = {};

          if (key) {
            duration[key] = input;
          } else {
            duration.milliseconds = input;
          }
        } else if (!!(match = aspNetRegex.exec(input))) {
          sign = match[1] === '-' ? -1 : 1;
          duration = {
            y: 0,
            d: toInt(match[DATE]) * sign,
            h: toInt(match[HOUR]) * sign,
            m: toInt(match[MINUTE]) * sign,
            s: toInt(match[SECOND]) * sign,
            ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match
          };
        } else if (!!(match = isoRegex.exec(input))) {
          sign = match[1] === '-' ? -1 : 1;
          duration = {
            y: parseIso(match[2], sign),
            M: parseIso(match[3], sign),
            w: parseIso(match[4], sign),
            d: parseIso(match[5], sign),
            h: parseIso(match[6], sign),
            m: parseIso(match[7], sign),
            s: parseIso(match[8], sign),
          };
        } else if (duration == null) {
          // checks for null or undefined
          duration = {};
        } else if (
          typeof duration === 'object' &&
          ('from' in duration || 'to' in duration)
        ) {
          diffRes = momentsDifference(
            createLocal(duration.from),
            createLocal(duration.to)
          );
          duration = {};
          duration.ms = diffRes.milliseconds;
          duration.M = diffRes.months;
        }

        ret = new Duration(duration);

        if (isDuration(input) && hasOwnProp(input, '_locale')) {
          ret._locale = input._locale;
        }

        return ret;
      }

      createDuration.fn = Duration.prototype;
      createDuration.invalid = createInvalid$1;

      function parseIso(inp, sign) {
        // We'd normally use ~~inp for this, but unfortunately it also
        // converts floats to ints.
        // inp may be undefined, so careful calling replace on it.
        var res = inp && parseFloat(inp.replace(',', '.')); // apply sign while we're at it

        return (isNaN(res) ? 0 : res) * sign;
      }

      function positiveMomentsDifference(base, other) {
        var res = {
          milliseconds: 0,
          months: 0,
        };
        res.months =
          other.month() - base.month() + (other.year() - base.year()) * 12;

        if (
          base
            .clone()
            .add(res.months, 'M')
            .isAfter(other)
        ) {
          --res.months;
        }

        res.milliseconds = +other - +base.clone().add(res.months, 'M');
        return res;
      }

      function momentsDifference(base, other) {
        var res;

        if (!(base.isValid() && other.isValid())) {
          return {
            milliseconds: 0,
            months: 0,
          };
        }

        other = cloneWithOffset(other, base);

        if (base.isBefore(other)) {
          res = positiveMomentsDifference(base, other);
        } else {
          res = positiveMomentsDifference(other, base);
          res.milliseconds = -res.milliseconds;
          res.months = -res.months;
        }

        return res;
      } // TODO: remove 'name' arg after deprecation is removed

      function createAdder(direction, name) {
        return function(val, period) {
          var dur, tmp; //invert the arguments, but complain about it

          if (period !== null && !isNaN(+period)) {
            deprecateSimple(
              name,
              'moment().' +
                name +
                '(period, number) is deprecated. Please use moment().' +
                name +
                '(number, period). ' +
                'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.'
            );
            tmp = val;
            val = period;
            period = tmp;
          }

          val = typeof val === 'string' ? +val : val;
          dur = createDuration(val, period);
          addSubtract(this, dur, direction);
          return this;
        };
      }

      function addSubtract(mom, duration, isAdding, updateOffset) {
        var milliseconds = duration._milliseconds,
          days = absRound(duration._days),
          months = absRound(duration._months);

        if (!mom.isValid()) {
          // No op
          return;
        }

        updateOffset = updateOffset == null ? true : updateOffset;

        if (months) {
          setMonth(mom, get(mom, 'Month') + months * isAdding);
        }

        if (days) {
          set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
        }

        if (milliseconds) {
          mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
        }

        if (updateOffset) {
          hooks.updateOffset(mom, days || months);
        }
      }

      var add = createAdder(1, 'add');
      var subtract = createAdder(-1, 'subtract');

      function getCalendarFormat(myMoment, now) {
        var diff = myMoment.diff(now, 'days', true);
        return diff < -6
          ? 'sameElse'
          : diff < -1
          ? 'lastWeek'
          : diff < 0
          ? 'lastDay'
          : diff < 1
          ? 'sameDay'
          : diff < 2
          ? 'nextDay'
          : diff < 7
          ? 'nextWeek'
          : 'sameElse';
      }

      function calendar$1(time, formats) {
        // We want to compare the start of today, vs this.
        // Getting start-of-today depends on whether we're local/utc/offset or not.
        var now = time || createLocal(),
          sod = cloneWithOffset(now, this).startOf('day'),
          format = hooks.calendarFormat(this, sod) || 'sameElse';
        var output =
          formats &&
          (isFunction(formats[format])
            ? formats[format].call(this, now)
            : formats[format]);
        return this.format(
          output || this.localeData().calendar(format, this, createLocal(now))
        );
      }

      function clone() {
        return new Moment(this);
      }

      function isAfter(input, units) {
        var localInput = isMoment(input) ? input : createLocal(input);

        if (!(this.isValid() && localInput.isValid())) {
          return false;
        }

        units = normalizeUnits(units) || 'millisecond';

        if (units === 'millisecond') {
          return this.valueOf() > localInput.valueOf();
        } else {
          return (
            localInput.valueOf() <
            this.clone()
              .startOf(units)
              .valueOf()
          );
        }
      }

      function isBefore(input, units) {
        var localInput = isMoment(input) ? input : createLocal(input);

        if (!(this.isValid() && localInput.isValid())) {
          return false;
        }

        units = normalizeUnits(units) || 'millisecond';

        if (units === 'millisecond') {
          return this.valueOf() < localInput.valueOf();
        } else {
          return (
            this.clone()
              .endOf(units)
              .valueOf() < localInput.valueOf()
          );
        }
      }

      function isBetween(from, to, units, inclusivity) {
        var localFrom = isMoment(from) ? from : createLocal(from),
          localTo = isMoment(to) ? to : createLocal(to);

        if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
          return false;
        }

        inclusivity = inclusivity || '()';
        return (
          (inclusivity[0] === '('
            ? this.isAfter(localFrom, units)
            : !this.isBefore(localFrom, units)) &&
          (inclusivity[1] === ')'
            ? this.isBefore(localTo, units)
            : !this.isAfter(localTo, units))
        );
      }

      function isSame(input, units) {
        var localInput = isMoment(input) ? input : createLocal(input),
          inputMs;

        if (!(this.isValid() && localInput.isValid())) {
          return false;
        }

        units = normalizeUnits(units) || 'millisecond';

        if (units === 'millisecond') {
          return this.valueOf() === localInput.valueOf();
        } else {
          inputMs = localInput.valueOf();
          return (
            this.clone()
              .startOf(units)
              .valueOf() <= inputMs &&
            inputMs <=
              this.clone()
                .endOf(units)
                .valueOf()
          );
        }
      }

      function isSameOrAfter(input, units) {
        return this.isSame(input, units) || this.isAfter(input, units);
      }

      function isSameOrBefore(input, units) {
        return this.isSame(input, units) || this.isBefore(input, units);
      }

      function diff(input, units, asFloat) {
        var that, zoneDelta, output;

        if (!this.isValid()) {
          return NaN;
        }

        that = cloneWithOffset(input, this);

        if (!that.isValid()) {
          return NaN;
        }

        zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
        units = normalizeUnits(units);

        switch (units) {
          case 'year':
            output = monthDiff(this, that) / 12;
            break;

          case 'month':
            output = monthDiff(this, that);
            break;

          case 'quarter':
            output = monthDiff(this, that) / 3;
            break;

          case 'second':
            output = (this - that) / 1e3;
            break;
          // 1000

          case 'minute':
            output = (this - that) / 6e4;
            break;
          // 1000 * 60

          case 'hour':
            output = (this - that) / 36e5;
            break;
          // 1000 * 60 * 60

          case 'day':
            output = (this - that - zoneDelta) / 864e5;
            break;
          // 1000 * 60 * 60 * 24, negate dst

          case 'week':
            output = (this - that - zoneDelta) / 6048e5;
            break;
          // 1000 * 60 * 60 * 24 * 7, negate dst

          default:
            output = this - that;
        }

        return asFloat ? output : absFloor(output);
      }

      function monthDiff(a, b) {
        // difference in months
        var wholeMonthDiff =
            (b.year() - a.year()) * 12 + (b.month() - a.month()),
          // b is in (anchor - 1 month, anchor + 1 month)
          anchor = a.clone().add(wholeMonthDiff, 'months'),
          anchor2,
          adjust;

        if (b - anchor < 0) {
          anchor2 = a.clone().add(wholeMonthDiff - 1, 'months'); // linear across the month

          adjust = (b - anchor) / (anchor - anchor2);
        } else {
          anchor2 = a.clone().add(wholeMonthDiff + 1, 'months'); // linear across the month

          adjust = (b - anchor) / (anchor2 - anchor);
        } //check for negative zero, return zero if negative zero

        return -(wholeMonthDiff + adjust) || 0;
      }

      hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
      hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';

      function toString() {
        return this.clone()
          .locale('en')
          .format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
      }

      function toISOString(keepOffset) {
        if (!this.isValid()) {
          return null;
        }

        var utc = keepOffset !== true;
        var m = utc ? this.clone().utc() : this;

        if (m.year() < 0 || m.year() > 9999) {
          return formatMoment(
            m,
            utc
              ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'
              : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ'
          );
        }

        if (isFunction(Date.prototype.toISOString)) {
          // native implementation is ~50x faster, use it when we can
          if (utc) {
            return this.toDate().toISOString();
          } else {
            return new Date(this.valueOf() + this.utcOffset() * 60 * 1000)
              .toISOString()
              .replace('Z', formatMoment(m, 'Z'));
          }
        }

        return formatMoment(
          m,
          utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ'
        );
      }
      /**
       * Return a human readable representation of a moment that can
       * also be evaluated to get a new moment which is the same
       *
       * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
       */

      function inspect() {
        if (!this.isValid()) {
          return 'moment.invalid(/* ' + this._i + ' */)';
        }

        var func = 'moment';
        var zone = '';

        if (!this.isLocal()) {
          func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
          zone = 'Z';
        }

        var prefix = '[' + func + '("]';
        var year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
        var datetime = '-MM-DD[T]HH:mm:ss.SSS';
        var suffix = zone + '[")]';
        return this.format(prefix + year + datetime + suffix);
      }

      function format(inputString) {
        if (!inputString) {
          inputString = this.isUtc()
            ? hooks.defaultFormatUtc
            : hooks.defaultFormat;
        }

        var output = formatMoment(this, inputString);
        return this.localeData().postformat(output);
      }

      function from(time, withoutSuffix) {
        if (
          this.isValid() &&
          ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
        ) {
          return createDuration({
            to: this,
            from: time,
          })
            .locale(this.locale())
            .humanize(!withoutSuffix);
        } else {
          return this.localeData().invalidDate();
        }
      }

      function fromNow(withoutSuffix) {
        return this.from(createLocal(), withoutSuffix);
      }

      function to(time, withoutSuffix) {
        if (
          this.isValid() &&
          ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
        ) {
          return createDuration({
            from: this,
            to: time,
          })
            .locale(this.locale())
            .humanize(!withoutSuffix);
        } else {
          return this.localeData().invalidDate();
        }
      }

      function toNow(withoutSuffix) {
        return this.to(createLocal(), withoutSuffix);
      } // If passed a locale key, it will set the locale for this
      // instance.  Otherwise, it will return the locale configuration
      // variables for this instance.

      function locale(key) {
        var newLocaleData;

        if (key === undefined) {
          return this._locale._abbr;
        } else {
          newLocaleData = getLocale(key);

          if (newLocaleData != null) {
            this._locale = newLocaleData;
          }

          return this;
        }
      }

      var lang = deprecate(
        'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
        function(key) {
          if (key === undefined) {
            return this.localeData();
          } else {
            return this.locale(key);
          }
        }
      );

      function localeData() {
        return this._locale;
      }

      function startOf(units) {
        units = normalizeUnits(units); // the following switch intentionally omits break keywords
        // to utilize falling through the cases.

        switch (units) {
          case 'year':
            this.month(0);

          /* falls through */

          case 'quarter':
          case 'month':
            this.date(1);

          /* falls through */

          case 'week':
          case 'isoWeek':
          case 'day':
          case 'date':
            this.hours(0);

          /* falls through */

          case 'hour':
            this.minutes(0);

          /* falls through */

          case 'minute':
            this.seconds(0);

          /* falls through */

          case 'second':
            this.milliseconds(0);
        } // weeks are a special case

        if (units === 'week') {
          this.weekday(0);
        }

        if (units === 'isoWeek') {
          this.isoWeekday(1);
        } // quarters are also special

        if (units === 'quarter') {
          this.month(Math.floor(this.month() / 3) * 3);
        }

        return this;
      }

      function endOf(units) {
        units = normalizeUnits(units);

        if (units === undefined || units === 'millisecond') {
          return this;
        } // 'date' is an alias for 'day', so it should be considered as such.

        if (units === 'date') {
          units = 'day';
        }

        return this.startOf(units)
          .add(1, units === 'isoWeek' ? 'week' : units)
          .subtract(1, 'ms');
      }

      function valueOf() {
        return this._d.valueOf() - (this._offset || 0) * 60000;
      }

      function unix() {
        return Math.floor(this.valueOf() / 1000);
      }

      function toDate() {
        return new Date(this.valueOf());
      }

      function toArray() {
        var m = this;
        return [
          m.year(),
          m.month(),
          m.date(),
          m.hour(),
          m.minute(),
          m.second(),
          m.millisecond(),
        ];
      }

      function toObject() {
        var m = this;
        return {
          years: m.year(),
          months: m.month(),
          date: m.date(),
          hours: m.hours(),
          minutes: m.minutes(),
          seconds: m.seconds(),
          milliseconds: m.milliseconds(),
        };
      }

      function toJSON() {
        // new Date(NaN).toJSON() === null
        return this.isValid() ? this.toISOString() : null;
      }

      function isValid$2() {
        return isValid(this);
      }

      function parsingFlags() {
        return extend({}, getParsingFlags(this));
      }

      function invalidAt() {
        return getParsingFlags(this).overflow;
      }

      function creationData() {
        return {
          input: this._i,
          format: this._f,
          locale: this._locale,
          isUTC: this._isUTC,
          strict: this._strict,
        };
      } // FORMATTING

      addFormatToken(0, ['gg', 2], 0, function() {
        return this.weekYear() % 100;
      });
      addFormatToken(0, ['GG', 2], 0, function() {
        return this.isoWeekYear() % 100;
      });

      function addWeekYearFormatToken(token, getter) {
        addFormatToken(0, [token, token.length], 0, getter);
      }

      addWeekYearFormatToken('gggg', 'weekYear');
      addWeekYearFormatToken('ggggg', 'weekYear');
      addWeekYearFormatToken('GGGG', 'isoWeekYear');
      addWeekYearFormatToken('GGGGG', 'isoWeekYear'); // ALIASES

      addUnitAlias('weekYear', 'gg');
      addUnitAlias('isoWeekYear', 'GG'); // PRIORITY

      addUnitPriority('weekYear', 1);
      addUnitPriority('isoWeekYear', 1); // PARSING

      addRegexToken('G', matchSigned);
      addRegexToken('g', matchSigned);
      addRegexToken('GG', match1to2, match2);
      addRegexToken('gg', match1to2, match2);
      addRegexToken('GGGG', match1to4, match4);
      addRegexToken('gggg', match1to4, match4);
      addRegexToken('GGGGG', match1to6, match6);
      addRegexToken('ggggg', match1to6, match6);
      addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function(
        input,
        week,
        config,
        token
      ) {
        week[token.substr(0, 2)] = toInt(input);
      });
      addWeekParseToken(['gg', 'GG'], function(input, week, config, token) {
        week[token] = hooks.parseTwoDigitYear(input);
      }); // MOMENTS

      function getSetWeekYear(input) {
        return getSetWeekYearHelper.call(
          this,
          input,
          this.week(),
          this.weekday(),
          this.localeData()._week.dow,
          this.localeData()._week.doy
        );
      }

      function getSetISOWeekYear(input) {
        return getSetWeekYearHelper.call(
          this,
          input,
          this.isoWeek(),
          this.isoWeekday(),
          1,
          4
        );
      }

      function getISOWeeksInYear() {
        return weeksInYear(this.year(), 1, 4);
      }

      function getWeeksInYear() {
        var weekInfo = this.localeData()._week;

        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
      }

      function getSetWeekYearHelper(input, week, weekday, dow, doy) {
        var weeksTarget;

        if (input == null) {
          return weekOfYear(this, dow, doy).year;
        } else {
          weeksTarget = weeksInYear(input, dow, doy);

          if (week > weeksTarget) {
            week = weeksTarget;
          }

          return setWeekAll.call(this, input, week, weekday, dow, doy);
        }
      }

      function setWeekAll(weekYear, week, weekday, dow, doy) {
        var dayOfYearData = dayOfYearFromWeeks(
            weekYear,
            week,
            weekday,
            dow,
            doy
          ),
          date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
        this.year(date.getUTCFullYear());
        this.month(date.getUTCMonth());
        this.date(date.getUTCDate());
        return this;
      } // FORMATTING

      addFormatToken('Q', 0, 'Qo', 'quarter'); // ALIASES

      addUnitAlias('quarter', 'Q'); // PRIORITY

      addUnitPriority('quarter', 7); // PARSING

      addRegexToken('Q', match1);
      addParseToken('Q', function(input, array) {
        array[MONTH] = (toInt(input) - 1) * 3;
      }); // MOMENTS

      function getSetQuarter(input) {
        return input == null
          ? Math.ceil((this.month() + 1) / 3)
          : this.month((input - 1) * 3 + (this.month() % 3));
      } // FORMATTING

      addFormatToken('D', ['DD', 2], 'Do', 'date'); // ALIASES

      addUnitAlias('date', 'D'); // PRIORITY

      addUnitPriority('date', 9); // PARSING

      addRegexToken('D', match1to2);
      addRegexToken('DD', match1to2, match2);
      addRegexToken('Do', function(isStrict, locale) {
        // TODO: Remove "ordinalParse" fallback in next major release.
        return isStrict
          ? locale._dayOfMonthOrdinalParse || locale._ordinalParse
          : locale._dayOfMonthOrdinalParseLenient;
      });
      addParseToken(['D', 'DD'], DATE);
      addParseToken('Do', function(input, array) {
        array[DATE] = toInt(input.match(match1to2)[0]);
      }); // MOMENTS

      var getSetDayOfMonth = makeGetSet('Date', true); // FORMATTING

      addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear'); // ALIASES

      addUnitAlias('dayOfYear', 'DDD'); // PRIORITY

      addUnitPriority('dayOfYear', 4); // PARSING

      addRegexToken('DDD', match1to3);
      addRegexToken('DDDD', match3);
      addParseToken(['DDD', 'DDDD'], function(input, array, config) {
        config._dayOfYear = toInt(input);
      }); // HELPERS
      // MOMENTS

      function getSetDayOfYear(input) {
        var dayOfYear =
          Math.round(
            (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5
          ) + 1;
        return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
      } // FORMATTING

      addFormatToken('m', ['mm', 2], 0, 'minute'); // ALIASES

      addUnitAlias('minute', 'm'); // PRIORITY

      addUnitPriority('minute', 14); // PARSING

      addRegexToken('m', match1to2);
      addRegexToken('mm', match1to2, match2);
      addParseToken(['m', 'mm'], MINUTE); // MOMENTS

      var getSetMinute = makeGetSet('Minutes', false); // FORMATTING

      addFormatToken('s', ['ss', 2], 0, 'second'); // ALIASES

      addUnitAlias('second', 's'); // PRIORITY

      addUnitPriority('second', 15); // PARSING

      addRegexToken('s', match1to2);
      addRegexToken('ss', match1to2, match2);
      addParseToken(['s', 'ss'], SECOND); // MOMENTS

      var getSetSecond = makeGetSet('Seconds', false); // FORMATTING

      addFormatToken('S', 0, 0, function() {
        return ~~(this.millisecond() / 100);
      });
      addFormatToken(0, ['SS', 2], 0, function() {
        return ~~(this.millisecond() / 10);
      });
      addFormatToken(0, ['SSS', 3], 0, 'millisecond');
      addFormatToken(0, ['SSSS', 4], 0, function() {
        return this.millisecond() * 10;
      });
      addFormatToken(0, ['SSSSS', 5], 0, function() {
        return this.millisecond() * 100;
      });
      addFormatToken(0, ['SSSSSS', 6], 0, function() {
        return this.millisecond() * 1000;
      });
      addFormatToken(0, ['SSSSSSS', 7], 0, function() {
        return this.millisecond() * 10000;
      });
      addFormatToken(0, ['SSSSSSSS', 8], 0, function() {
        return this.millisecond() * 100000;
      });
      addFormatToken(0, ['SSSSSSSSS', 9], 0, function() {
        return this.millisecond() * 1000000;
      }); // ALIASES

      addUnitAlias('millisecond', 'ms'); // PRIORITY

      addUnitPriority('millisecond', 16); // PARSING

      addRegexToken('S', match1to3, match1);
      addRegexToken('SS', match1to3, match2);
      addRegexToken('SSS', match1to3, match3);
      var token;

      for (token = 'SSSS'; token.length <= 9; token += 'S') {
        addRegexToken(token, matchUnsigned);
      }

      function parseMs(input, array) {
        array[MILLISECOND] = toInt(('0.' + input) * 1000);
      }

      for (token = 'S'; token.length <= 9; token += 'S') {
        addParseToken(token, parseMs);
      } // MOMENTS

      var getSetMillisecond = makeGetSet('Milliseconds', false); // FORMATTING

      addFormatToken('z', 0, 0, 'zoneAbbr');
      addFormatToken('zz', 0, 0, 'zoneName'); // MOMENTS

      function getZoneAbbr() {
        return this._isUTC ? 'UTC' : '';
      }

      function getZoneName() {
        return this._isUTC ? 'Coordinated Universal Time' : '';
      }

      var proto = Moment.prototype;
      proto.add = add;
      proto.calendar = calendar$1;
      proto.clone = clone;
      proto.diff = diff;
      proto.endOf = endOf;
      proto.format = format;
      proto.from = from;
      proto.fromNow = fromNow;
      proto.to = to;
      proto.toNow = toNow;
      proto.get = stringGet;
      proto.invalidAt = invalidAt;
      proto.isAfter = isAfter;
      proto.isBefore = isBefore;
      proto.isBetween = isBetween;
      proto.isSame = isSame;
      proto.isSameOrAfter = isSameOrAfter;
      proto.isSameOrBefore = isSameOrBefore;
      proto.isValid = isValid$2;
      proto.lang = lang;
      proto.locale = locale;
      proto.localeData = localeData;
      proto.max = prototypeMax;
      proto.min = prototypeMin;
      proto.parsingFlags = parsingFlags;
      proto.set = stringSet;
      proto.startOf = startOf;
      proto.subtract = subtract;
      proto.toArray = toArray;
      proto.toObject = toObject;
      proto.toDate = toDate;
      proto.toISOString = toISOString;
      proto.inspect = inspect;
      proto.toJSON = toJSON;
      proto.toString = toString;
      proto.unix = unix;
      proto.valueOf = valueOf;
      proto.creationData = creationData;
      proto.year = getSetYear;
      proto.isLeapYear = getIsLeapYear;
      proto.weekYear = getSetWeekYear;
      proto.isoWeekYear = getSetISOWeekYear;
      proto.quarter = proto.quarters = getSetQuarter;
      proto.month = getSetMonth;
      proto.daysInMonth = getDaysInMonth;
      proto.week = proto.weeks = getSetWeek;
      proto.isoWeek = proto.isoWeeks = getSetISOWeek;
      proto.weeksInYear = getWeeksInYear;
      proto.isoWeeksInYear = getISOWeeksInYear;
      proto.date = getSetDayOfMonth;
      proto.day = proto.days = getSetDayOfWeek;
      proto.weekday = getSetLocaleDayOfWeek;
      proto.isoWeekday = getSetISODayOfWeek;
      proto.dayOfYear = getSetDayOfYear;
      proto.hour = proto.hours = getSetHour;
      proto.minute = proto.minutes = getSetMinute;
      proto.second = proto.seconds = getSetSecond;
      proto.millisecond = proto.milliseconds = getSetMillisecond;
      proto.utcOffset = getSetOffset;
      proto.utc = setOffsetToUTC;
      proto.local = setOffsetToLocal;
      proto.parseZone = setOffsetToParsedOffset;
      proto.hasAlignedHourOffset = hasAlignedHourOffset;
      proto.isDST = isDaylightSavingTime;
      proto.isLocal = isLocal;
      proto.isUtcOffset = isUtcOffset;
      proto.isUtc = isUtc;
      proto.isUTC = isUtc;
      proto.zoneAbbr = getZoneAbbr;
      proto.zoneName = getZoneName;
      proto.dates = deprecate(
        'dates accessor is deprecated. Use date instead.',
        getSetDayOfMonth
      );
      proto.months = deprecate(
        'months accessor is deprecated. Use month instead',
        getSetMonth
      );
      proto.years = deprecate(
        'years accessor is deprecated. Use year instead',
        getSetYear
      );
      proto.zone = deprecate(
        'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/',
        getSetZone
      );
      proto.isDSTShifted = deprecate(
        'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information',
        isDaylightSavingTimeShifted
      );

      function createUnix(input) {
        return createLocal(input * 1000);
      }

      function createInZone() {
        return createLocal.apply(null, arguments).parseZone();
      }

      function preParsePostFormat(string) {
        return string;
      }

      var proto$1 = Locale.prototype;
      proto$1.calendar = calendar;
      proto$1.longDateFormat = longDateFormat;
      proto$1.invalidDate = invalidDate;
      proto$1.ordinal = ordinal;
      proto$1.preparse = preParsePostFormat;
      proto$1.postformat = preParsePostFormat;
      proto$1.relativeTime = relativeTime;
      proto$1.pastFuture = pastFuture;
      proto$1.set = set;
      proto$1.months = localeMonths;
      proto$1.monthsShort = localeMonthsShort;
      proto$1.monthsParse = localeMonthsParse;
      proto$1.monthsRegex = monthsRegex;
      proto$1.monthsShortRegex = monthsShortRegex;
      proto$1.week = localeWeek;
      proto$1.firstDayOfYear = localeFirstDayOfYear;
      proto$1.firstDayOfWeek = localeFirstDayOfWeek;
      proto$1.weekdays = localeWeekdays;
      proto$1.weekdaysMin = localeWeekdaysMin;
      proto$1.weekdaysShort = localeWeekdaysShort;
      proto$1.weekdaysParse = localeWeekdaysParse;
      proto$1.weekdaysRegex = weekdaysRegex;
      proto$1.weekdaysShortRegex = weekdaysShortRegex;
      proto$1.weekdaysMinRegex = weekdaysMinRegex;
      proto$1.isPM = localeIsPM;
      proto$1.meridiem = localeMeridiem;

      function get$1(format, index, field, setter) {
        var locale = getLocale();
        var utc = createUTC().set(setter, index);
        return locale[field](utc, format);
      }

      function listMonthsImpl(format, index, field) {
        if (isNumber(format)) {
          index = format;
          format = undefined;
        }

        format = format || '';

        if (index != null) {
          return get$1(format, index, field, 'month');
        }

        var i;
        var out = [];

        for (i = 0; i < 12; i++) {
          out[i] = get$1(format, i, field, 'month');
        }

        return out;
      } // ()
      // (5)
      // (fmt, 5)
      // (fmt)
      // (true)
      // (true, 5)
      // (true, fmt, 5)
      // (true, fmt)

      function listWeekdaysImpl(localeSorted, format, index, field) {
        if (typeof localeSorted === 'boolean') {
          if (isNumber(format)) {
            index = format;
            format = undefined;
          }

          format = format || '';
        } else {
          format = localeSorted;
          index = format;
          localeSorted = false;

          if (isNumber(format)) {
            index = format;
            format = undefined;
          }

          format = format || '';
        }

        var locale = getLocale(),
          shift = localeSorted ? locale._week.dow : 0;

        if (index != null) {
          return get$1(format, (index + shift) % 7, field, 'day');
        }

        var i;
        var out = [];

        for (i = 0; i < 7; i++) {
          out[i] = get$1(format, (i + shift) % 7, field, 'day');
        }

        return out;
      }

      function listMonths(format, index) {
        return listMonthsImpl(format, index, 'months');
      }

      function listMonthsShort(format, index) {
        return listMonthsImpl(format, index, 'monthsShort');
      }

      function listWeekdays(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
      }

      function listWeekdaysShort(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
      }

      function listWeekdaysMin(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
      }

      getSetGlobalLocale('en', {
        dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
        ordinal: function(number) {
          var b = number % 10,
            output =
              toInt((number % 100) / 10) === 1
                ? 'th'
                : b === 1
                ? 'st'
                : b === 2
                ? 'nd'
                : b === 3
                ? 'rd'
                : 'th';
          return number + output;
        },
      }); // Side effect imports

      hooks.lang = deprecate(
        'moment.lang is deprecated. Use moment.locale instead.',
        getSetGlobalLocale
      );
      hooks.langData = deprecate(
        'moment.langData is deprecated. Use moment.localeData instead.',
        getLocale
      );
      var mathAbs = Math.abs;

      function abs() {
        var data = this._data;
        this._milliseconds = mathAbs(this._milliseconds);
        this._days = mathAbs(this._days);
        this._months = mathAbs(this._months);
        data.milliseconds = mathAbs(data.milliseconds);
        data.seconds = mathAbs(data.seconds);
        data.minutes = mathAbs(data.minutes);
        data.hours = mathAbs(data.hours);
        data.months = mathAbs(data.months);
        data.years = mathAbs(data.years);
        return this;
      }

      function addSubtract$1(duration, input, value, direction) {
        var other = createDuration(input, value);
        duration._milliseconds += direction * other._milliseconds;
        duration._days += direction * other._days;
        duration._months += direction * other._months;
        return duration._bubble();
      } // supports only 2.0-style add(1, 's') or add(duration)

      function add$1(input, value) {
        return addSubtract$1(this, input, value, 1);
      } // supports only 2.0-style subtract(1, 's') or subtract(duration)

      function subtract$1(input, value) {
        return addSubtract$1(this, input, value, -1);
      }

      function absCeil(number) {
        if (number < 0) {
          return Math.floor(number);
        } else {
          return Math.ceil(number);
        }
      }

      function bubble() {
        var milliseconds = this._milliseconds;
        var days = this._days;
        var months = this._months;
        var data = this._data;
        var seconds, minutes, hours, years, monthsFromDays; // if we have a mix of positive and negative values, bubble down first
        // check: https://github.com/moment/moment/issues/2166

        if (
          !(
            (milliseconds >= 0 && days >= 0 && months >= 0) ||
            (milliseconds <= 0 && days <= 0 && months <= 0)
          )
        ) {
          milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
          days = 0;
          months = 0;
        } // The following code bubbles up values, see the tests for
        // examples of what that means.

        data.milliseconds = milliseconds % 1000;
        seconds = absFloor(milliseconds / 1000);
        data.seconds = seconds % 60;
        minutes = absFloor(seconds / 60);
        data.minutes = minutes % 60;
        hours = absFloor(minutes / 60);
        data.hours = hours % 24;
        days += absFloor(hours / 24); // convert days to months

        monthsFromDays = absFloor(daysToMonths(days));
        months += monthsFromDays;
        days -= absCeil(monthsToDays(monthsFromDays)); // 12 months -> 1 year

        years = absFloor(months / 12);
        months %= 12;
        data.days = days;
        data.months = months;
        data.years = years;
        return this;
      }

      function daysToMonths(days) {
        // 400 years have 146097 days (taking into account leap year rules)
        // 400 years have 12 months === 4800
        return (days * 4800) / 146097;
      }

      function monthsToDays(months) {
        // the reverse of daysToMonths
        return (months * 146097) / 4800;
      }

      function as(units) {
        if (!this.isValid()) {
          return NaN;
        }

        var days;
        var months;
        var milliseconds = this._milliseconds;
        units = normalizeUnits(units);

        if (units === 'month' || units === 'year') {
          days = this._days + milliseconds / 864e5;
          months = this._months + daysToMonths(days);
          return units === 'month' ? months : months / 12;
        } else {
          // handle milliseconds separately because of floating point math errors (issue #1867)
          days = this._days + Math.round(monthsToDays(this._months));

          switch (units) {
            case 'week':
              return days / 7 + milliseconds / 6048e5;

            case 'day':
              return days + milliseconds / 864e5;

            case 'hour':
              return days * 24 + milliseconds / 36e5;

            case 'minute':
              return days * 1440 + milliseconds / 6e4;

            case 'second':
              return days * 86400 + milliseconds / 1000;
            // Math.floor prevents floating point math errors here

            case 'millisecond':
              return Math.floor(days * 864e5) + milliseconds;

            default:
              throw new Error('Unknown unit ' + units);
          }
        }
      } // TODO: Use this.as('ms')?

      function valueOf$1() {
        if (!this.isValid()) {
          return NaN;
        }

        return (
          this._milliseconds +
          this._days * 864e5 +
          (this._months % 12) * 2592e6 +
          toInt(this._months / 12) * 31536e6
        );
      }

      function makeAs(alias) {
        return function() {
          return this.as(alias);
        };
      }

      var asMilliseconds = makeAs('ms');
      var asSeconds = makeAs('s');
      var asMinutes = makeAs('m');
      var asHours = makeAs('h');
      var asDays = makeAs('d');
      var asWeeks = makeAs('w');
      var asMonths = makeAs('M');
      var asYears = makeAs('y');

      function clone$1() {
        return createDuration(this);
      }

      function get$2(units) {
        units = normalizeUnits(units);
        return this.isValid() ? this[units + 's']() : NaN;
      }

      function makeGetter(name) {
        return function() {
          return this.isValid() ? this._data[name] : NaN;
        };
      }

      var milliseconds = makeGetter('milliseconds');
      var seconds = makeGetter('seconds');
      var minutes = makeGetter('minutes');
      var hours = makeGetter('hours');
      var days = makeGetter('days');
      var months = makeGetter('months');
      var years = makeGetter('years');

      function weeks() {
        return absFloor(this.days() / 7);
      }

      var round = Math.round;
      var thresholds = {
        ss: 44,
        // a few seconds to seconds
        s: 45,
        // seconds to minute
        m: 45,
        // minutes to hour
        h: 22,
        // hours to day
        d: 26,
        // days to month
        M: 11, // months to year
      }; // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize

      function substituteTimeAgo(
        string,
        number,
        withoutSuffix,
        isFuture,
        locale
      ) {
        return locale.relativeTime(
          number || 1,
          !!withoutSuffix,
          string,
          isFuture
        );
      }

      function relativeTime$1(posNegDuration, withoutSuffix, locale) {
        var duration = createDuration(posNegDuration).abs();
        var seconds = round(duration.as('s'));
        var minutes = round(duration.as('m'));
        var hours = round(duration.as('h'));
        var days = round(duration.as('d'));
        var months = round(duration.as('M'));
        var years = round(duration.as('y'));
        var a = (seconds <= thresholds.ss && ['s', seconds]) ||
          (seconds < thresholds.s && ['ss', seconds]) ||
          (minutes <= 1 && ['m']) ||
          (minutes < thresholds.m && ['mm', minutes]) ||
          (hours <= 1 && ['h']) ||
          (hours < thresholds.h && ['hh', hours]) ||
          (days <= 1 && ['d']) ||
          (days < thresholds.d && ['dd', days]) ||
          (months <= 1 && ['M']) ||
          (months < thresholds.M && ['MM', months]) ||
          (years <= 1 && ['y']) || ['yy', years];
        a[2] = withoutSuffix;
        a[3] = +posNegDuration > 0;
        a[4] = locale;
        return substituteTimeAgo.apply(null, a);
      } // This function allows you to set the rounding function for relative time strings

      function getSetRelativeTimeRounding(roundingFunction) {
        if (roundingFunction === undefined) {
          return round;
        }

        if (typeof roundingFunction === 'function') {
          round = roundingFunction;
          return true;
        }

        return false;
      } // This function allows you to set a threshold for relative time strings

      function getSetRelativeTimeThreshold(threshold, limit) {
        if (thresholds[threshold] === undefined) {
          return false;
        }

        if (limit === undefined) {
          return thresholds[threshold];
        }

        thresholds[threshold] = limit;

        if (threshold === 's') {
          thresholds.ss = limit - 1;
        }

        return true;
      }

      function humanize(withSuffix) {
        if (!this.isValid()) {
          return this.localeData().invalidDate();
        }

        var locale = this.localeData();
        var output = relativeTime$1(this, !withSuffix, locale);

        if (withSuffix) {
          output = locale.pastFuture(+this, output);
        }

        return locale.postformat(output);
      }

      var abs$1 = Math.abs;

      function sign(x) {
        return (x > 0) - (x < 0) || +x;
      }

      function toISOString$1() {
        // for ISO strings we do not use the normal bubbling rules:
        //  * milliseconds bubble up until they become hours
        //  * days do not bubble at all
        //  * months bubble up until they become years
        // This is because there is no context-free conversion between hours and days
        // (think of clock changes)
        // and also not between days and months (28-31 days per month)
        if (!this.isValid()) {
          return this.localeData().invalidDate();
        }

        var seconds = abs$1(this._milliseconds) / 1000;
        var days = abs$1(this._days);
        var months = abs$1(this._months);
        var minutes, hours, years; // 3600 seconds -> 60 minutes -> 1 hour

        minutes = absFloor(seconds / 60);
        hours = absFloor(minutes / 60);
        seconds %= 60;
        minutes %= 60; // 12 months -> 1 year

        years = absFloor(months / 12);
        months %= 12; // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js

        var Y = years;
        var M = months;
        var D = days;
        var h = hours;
        var m = minutes;
        var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';
        var total = this.asSeconds();

        if (!total) {
          // this is the same as C#'s (Noda) and python (isodate)...
          // but not other JS (goog.date)
          return 'P0D';
        }

        var totalSign = total < 0 ? '-' : '';
        var ymSign = sign(this._months) !== sign(total) ? '-' : '';
        var daysSign = sign(this._days) !== sign(total) ? '-' : '';
        var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';
        return (
          totalSign +
          'P' +
          (Y ? ymSign + Y + 'Y' : '') +
          (M ? ymSign + M + 'M' : '') +
          (D ? daysSign + D + 'D' : '') +
          (h || m || s ? 'T' : '') +
          (h ? hmsSign + h + 'H' : '') +
          (m ? hmsSign + m + 'M' : '') +
          (s ? hmsSign + s + 'S' : '')
        );
      }

      var proto$2 = Duration.prototype;
      proto$2.isValid = isValid$1;
      proto$2.abs = abs;
      proto$2.add = add$1;
      proto$2.subtract = subtract$1;
      proto$2.as = as;
      proto$2.asMilliseconds = asMilliseconds;
      proto$2.asSeconds = asSeconds;
      proto$2.asMinutes = asMinutes;
      proto$2.asHours = asHours;
      proto$2.asDays = asDays;
      proto$2.asWeeks = asWeeks;
      proto$2.asMonths = asMonths;
      proto$2.asYears = asYears;
      proto$2.valueOf = valueOf$1;
      proto$2._bubble = bubble;
      proto$2.clone = clone$1;
      proto$2.get = get$2;
      proto$2.milliseconds = milliseconds;
      proto$2.seconds = seconds;
      proto$2.minutes = minutes;
      proto$2.hours = hours;
      proto$2.days = days;
      proto$2.weeks = weeks;
      proto$2.months = months;
      proto$2.years = years;
      proto$2.humanize = humanize;
      proto$2.toISOString = toISOString$1;
      proto$2.toString = toISOString$1;
      proto$2.toJSON = toISOString$1;
      proto$2.locale = locale;
      proto$2.localeData = localeData;
      proto$2.toIsoString = deprecate(
        'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)',
        toISOString$1
      );
      proto$2.lang = lang; // Side effect imports
      // FORMATTING

      addFormatToken('X', 0, 0, 'unix');
      addFormatToken('x', 0, 0, 'valueOf'); // PARSING

      addRegexToken('x', matchSigned);
      addRegexToken('X', matchTimestamp);
      addParseToken('X', function(input, array, config) {
        config._d = new Date(parseFloat(input, 10) * 1000);
      });
      addParseToken('x', function(input, array, config) {
        config._d = new Date(toInt(input));
      }); // Side effect imports

      hooks.version = '2.23.0';
      setHookCallback(createLocal);
      hooks.fn = proto;
      hooks.min = min;
      hooks.max = max;
      hooks.now = now;
      hooks.utc = createUTC;
      hooks.unix = createUnix;
      hooks.months = listMonths;
      hooks.isDate = isDate;
      hooks.locale = getSetGlobalLocale;
      hooks.invalid = createInvalid;
      hooks.duration = createDuration;
      hooks.isMoment = isMoment;
      hooks.weekdays = listWeekdays;
      hooks.parseZone = createInZone;
      hooks.localeData = getLocale;
      hooks.isDuration = isDuration;
      hooks.monthsShort = listMonthsShort;
      hooks.weekdaysMin = listWeekdaysMin;
      hooks.defineLocale = defineLocale;
      hooks.updateLocale = updateLocale;
      hooks.locales = listLocales;
      hooks.weekdaysShort = listWeekdaysShort;
      hooks.normalizeUnits = normalizeUnits;
      hooks.relativeTimeRounding = getSetRelativeTimeRounding;
      hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
      hooks.calendarFormat = getCalendarFormat;
      hooks.prototype = proto; // currently HTML5 input type only supports 24-hour formats

      hooks.HTML5_FMT = {
        DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm',
        // <input type="datetime-local" />
        DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss',
        // <input type="datetime-local" step="1" />
        DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS',
        // <input type="datetime-local" step="0.001" />
        DATE: 'YYYY-MM-DD',
        // <input type="date" />
        TIME: 'HH:mm',
        // <input type="time" />
        TIME_SECONDS: 'HH:mm:ss',
        // <input type="time" step="1" />
        TIME_MS: 'HH:mm:ss.SSS',
        // <input type="time" step="0.001" />
        WEEK: 'GGGG-[W]WW',
        // <input type="week" />
        MONTH: 'YYYY-MM', // <input type="month" />
      };
      return hooks;
    });
  });

  var momentTimezoneWithData20122022_min = createCommonjsModule(function(
    module
  ) {
    !(function(a, i) {
      module.exports ? (module.exports = i(moment)) : i(a.moment);
    })(this, function(A) {
      var i,
        c = {},
        n = {},
        s = {},
        u = {};
      (A && 'string' == typeof A.version) ||
        N(
          'Moment Timezone requires Moment.js. See https://momentjs.com/timezone/docs/#/use-it/browser/'
        );
      var a = A.version.split('.'),
        e = +a[0],
        r = +a[1];

      function t(a) {
        return 96 < a ? a - 87 : 64 < a ? a - 29 : a - 48;
      }

      function o(a) {
        var i = 0,
          e = a.split('.'),
          r = e[0],
          o = e[1] || '',
          A = 1,
          c = 0,
          n = 1;

        for (45 === a.charCodeAt(0) && (n = -(i = 1)); i < r.length; i++)
          c = 60 * c + t(r.charCodeAt(i));

        for (i = 0; i < o.length; i++) (A /= 60), (c += t(o.charCodeAt(i)) * A);

        return c * n;
      }

      function m(a) {
        for (var i = 0; i < a.length; i++) a[i] = o(a[i]);
      }

      function f(a, i) {
        var e,
          r = [];

        for (e = 0; e < i.length; e++) r[e] = a[i[e]];

        return r;
      }

      function l(a) {
        var i = a.split('|'),
          e = i[2].split(' '),
          r = i[3].split(''),
          o = i[4].split(' ');
        return (
          m(e),
          m(r),
          m(o),
          (function(a, i) {
            for (var e = 0; e < i; e++)
              a[e] = Math.round((a[e - 1] || 0) + 6e4 * a[e]);

            a[i - 1] = 1 / 0;
          })(o, r.length),
          {
            name: i[0],
            abbrs: f(i[1].split(' '), r),
            offsets: f(e, r),
            untils: o,
            population: 0 | i[5],
          }
        );
      }

      function p(a) {
        a && this._set(l(a));
      }

      function b(a) {
        var i = a.toTimeString(),
          e = i.match(/\([a-z ]+\)/i);
        'GMT' ===
          (e =
            e && e[0]
              ? (e = e[0].match(/[A-Z]/g))
                ? e.join('')
                : void 0
              : (e = i.match(/[A-Z]{3,5}/g))
              ? e[0]
              : void 0) && (e = void 0),
          (this.at = +a),
          (this.abbr = e),
          (this.offset = a.getTimezoneOffset());
      }

      function M(a) {
        (this.zone = a), (this.offsetScore = 0), (this.abbrScore = 0);
      }

      function d(a, i) {
        for (var e, r; (r = 6e4 * (((i.at - a.at) / 12e4) | 0)); )
          (e = new b(new Date(a.at + r))).offset === a.offset
            ? (a = e)
            : (i = e);

        return a;
      }

      function h(a, i) {
        return a.offsetScore !== i.offsetScore
          ? a.offsetScore - i.offsetScore
          : a.abbrScore !== i.abbrScore
          ? a.abbrScore - i.abbrScore
          : i.zone.population - a.zone.population;
      }

      function z(a, i) {
        var e, r;

        for (m(i), e = 0; e < i.length; e++)
          (r = i[e]), (u[r] = u[r] || {}), (u[r][a] = !0);
      }

      function E() {
        try {
          var a = Intl.DateTimeFormat().resolvedOptions().timeZone;

          if (a && 3 < a.length) {
            var i = s[g(a)];
            if (i) return i;
            N(
              'Moment Timezone found ' +
                a +
                ' from the Intl api, but did not have that data loaded.'
            );
          }
        } catch (a) {}

        var e,
          r,
          o,
          A = (function() {
            var a,
              i,
              e,
              r = new Date().getFullYear() - 2,
              o = new b(new Date(r, 0, 1)),
              A = [o];

            for (e = 1; e < 48; e++)
              (i = new b(new Date(r, e, 1))).offset !== o.offset &&
                ((a = d(o, i)), A.push(a), A.push(new b(new Date(a.at + 6e4)))),
                (o = i);

            for (e = 0; e < 4; e++)
              A.push(new b(new Date(r + e, 0, 1))),
                A.push(new b(new Date(r + e, 6, 1)));

            return A;
          })(),
          c = A.length,
          n = (function(a) {
            var i,
              e,
              r,
              o = a.length,
              A = {},
              c = [];

            for (i = 0; i < o; i++)
              for (e in (r = u[a[i].offset] || {}))
                r.hasOwnProperty(e) && (A[e] = !0);

            for (i in A) A.hasOwnProperty(i) && c.push(s[i]);

            return c;
          })(A),
          t = [];

        for (r = 0; r < n.length; r++) {
          for (e = new M(P(n[r]), c), o = 0; o < c; o++) e.scoreOffsetAt(A[o]);

          t.push(e);
        }

        return t.sort(h), 0 < t.length ? t[0].zone.name : void 0;
      }

      function g(a) {
        return (a || '').toLowerCase().replace(/\//g, '_');
      }

      function T(a) {
        var i, e, r, o;

        for ('string' == typeof a && (a = [a]), i = 0; i < a.length; i++)
          (o = g((e = (r = a[i].split('|'))[0]))),
            (c[o] = a[i]),
            (s[o] = e),
            z(o, r[2].split(' '));
      }

      function P(a, i) {
        a = g(a);
        var e,
          r = c[a];
        return r instanceof p
          ? r
          : 'string' == typeof r
          ? ((r = new p(r)), (c[a] = r))
          : n[a] && i !== P && (e = P(n[a], P))
          ? ((r = c[a] = new p())._set(e), (r.name = s[a]), r)
          : null;
      }

      function S(a) {
        var i, e, r, o;

        for ('string' == typeof a && (a = [a]), i = 0; i < a.length; i++)
          (r = g((e = a[i].split('|'))[0])),
            (o = g(e[1])),
            (n[r] = o),
            (s[r] = e[0]),
            (n[o] = r),
            (s[o] = e[1]);
      }

      function _(a) {
        T(a.zones), S(a.links), (C.dataVersion = a.version);
      }

      function k(a) {
        var i = 'X' === a._f || 'x' === a._f;
        return !(!a._a || void 0 !== a._tzm || i);
      }

      function N(a) {
        'undefined' != typeof console &&
          'function' == typeof console.error &&
          console.error(a);
      }

      function C(a) {
        var i = Array.prototype.slice.call(arguments, 0, -1),
          e = arguments[arguments.length - 1],
          r = P(e),
          o = A.utc.apply(null, i);
        return (
          r && !A.isMoment(a) && k(o) && o.add(r.parse(o), 'minutes'),
          o.tz(e),
          o
        );
      }

      (e < 2 || (2 === e && r < 6)) &&
        N(
          'Moment Timezone requires Moment.js >= 2.6.0. You are using Moment.js ' +
            A.version +
            '. See momentjs.com'
        ),
        (p.prototype = {
          _set: function(a) {
            (this.name = a.name),
              (this.abbrs = a.abbrs),
              (this.untils = a.untils),
              (this.offsets = a.offsets),
              (this.population = a.population);
          },
          _index: function(a) {
            var i,
              e = +a,
              r = this.untils;

            for (i = 0; i < r.length; i++) if (e < r[i]) return i;
          },
          parse: function(a) {
            var i,
              e,
              r,
              o,
              A = +a,
              c = this.offsets,
              n = this.untils,
              t = n.length - 1;

            for (o = 0; o < t; o++)
              if (
                ((i = c[o]),
                (e = c[o + 1]),
                (r = c[o ? o - 1 : o]),
                i < e && C.moveAmbiguousForward
                  ? (i = e)
                  : r < i && C.moveInvalidForward && (i = r),
                A < n[o] - 6e4 * i)
              )
                return c[o];

            return c[t];
          },
          abbr: function(a) {
            return this.abbrs[this._index(a)];
          },
          offset: function(a) {
            return (
              N('zone.offset has been deprecated in favor of zone.utcOffset'),
              this.offsets[this._index(a)]
            );
          },
          utcOffset: function(a) {
            return this.offsets[this._index(a)];
          },
        }),
        (M.prototype.scoreOffsetAt = function(a) {
          (this.offsetScore += Math.abs(this.zone.utcOffset(a.at) - a.offset)),
            this.zone.abbr(a.at).replace(/[^A-Z]/g, '') !== a.abbr &&
              this.abbrScore++;
        }),
        (C.version = '0.5.23'),
        (C.dataVersion = ''),
        (C._zones = c),
        (C._links = n),
        (C._names = s),
        (C.add = T),
        (C.link = S),
        (C.load = _),
        (C.zone = P),
        (C.zoneExists = function a(i) {
          return (
            a.didShowError ||
              ((a.didShowError = !0),
              N(
                "moment.tz.zoneExists('" +
                  i +
                  "') has been deprecated in favor of !moment.tz.zone('" +
                  i +
                  "')"
              )),
            !!P(i)
          );
        }),
        (C.guess = function(a) {
          return (i && !a) || (i = E()), i;
        }),
        (C.names = function() {
          var a,
            i = [];

          for (a in s)
            s.hasOwnProperty(a) && (c[a] || c[n[a]]) && s[a] && i.push(s[a]);

          return i.sort();
        }),
        (C.Zone = p),
        (C.unpack = l),
        (C.unpackBase60 = o),
        (C.needsOffset = k),
        (C.moveInvalidForward = !0),
        (C.moveAmbiguousForward = !1);
      var B,
        O = A.fn;

      function G(a) {
        return function() {
          return this._z ? this._z.abbr(this) : a.call(this);
        };
      }

      (A.tz = C),
        (A.defaultZone = null),
        (A.updateOffset = function(a, i) {
          var e,
            r = A.defaultZone;
          void 0 === a._z &&
            (r &&
              k(a) &&
              !a._isUTC &&
              ((a._d = A.utc(a._a)._d), a.utc().add(r.parse(a), 'minutes')),
            (a._z = r)),
            a._z &&
              ((e = a._z.utcOffset(a)),
              Math.abs(e) < 16 && (e /= 60),
              void 0 !== a.utcOffset ? a.utcOffset(-e, i) : a.zone(e, i));
        }),
        (O.tz = function(a, i) {
          if (a) {
            if ('string' != typeof a)
              throw new Error(
                'Time zone name must be a string, got ' +
                  a +
                  ' [' +
                  typeof a +
                  ']'
              );
            return (
              (this._z = P(a)),
              this._z
                ? A.updateOffset(this, i)
                : N(
                    'Moment Timezone has no data for ' +
                      a +
                      '. See http://momentjs.com/timezone/docs/#/data-loading/.'
                  ),
              this
            );
          }

          if (this._z) return this._z.name;
        }),
        (O.zoneName = G(O.zoneName)),
        (O.zoneAbbr = G(O.zoneAbbr)),
        (O.utc = ((B = O.utc),
        function() {
          return (this._z = null), B.apply(this, arguments);
        })),
        (A.tz.setDefault = function(a) {
          return (
            (e < 2 || (2 === e && r < 9)) &&
              N(
                'Moment Timezone setDefault() requires Moment.js >= 2.9.0. You are using Moment.js ' +
                  A.version +
                  '.'
              ),
            (A.defaultZone = a ? P(a) : null),
            A
          );
        });
      var D = A.momentProperties;
      return (
        '[object Array]' === Object.prototype.toString.call(D)
          ? (D.push('_z'), D.push('_a'))
          : D && (D._z = null),
        _({
          version: '2018g',
          zones: [
            'Africa/Abidjan|GMT|0|0||48e5',
            'Africa/Nairobi|EAT|-30|0||47e5',
            'Africa/Algiers|CET|-10|0||26e5',
            'Africa/Lagos|WAT|-10|0||17e6',
            'Africa/Maputo|CAT|-20|0||26e5',
            'Africa/Cairo|EET EEST|-20 -30|01010|1M2m0 gL0 e10 mn0|15e6',
            'Africa/Casablanca|+00 +01|0 -10|0101010101010101010101010101|1H3C0 wM0 co0 go0 1o00 s00 dA0 vc0 11A0 A00 e00 y00 11A0 uM0 e00 Dc0 11A0 s00 e00 IM0 WM0 mo0 gM0 LA0 WM0 jA0 e00|32e5',
            'Europe/Paris|CET CEST|-10 -20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|11e6',
            'Africa/Johannesburg|SAST|-20|0||84e5',
            'Africa/Khartoum|EAT CAT|-30 -20|01|1Usl0|51e5',
            'Africa/Sao_Tome|GMT WAT|0 -10|01|1UQN0',
            'Africa/Tripoli|EET CET CEST|-20 -10 -20|0120|1IlA0 TA0 1o00|11e5',
            'Africa/Windhoek|CAT WAT|-20 -10|0101010101010|1GQo0 11B0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0|32e4',
            'America/Adak|HST HDT|a0 90|01010101010101010101010|1GIc0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|326',
            'America/Anchorage|AKST AKDT|90 80|01010101010101010101010|1GIb0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|30e4',
            'America/Santo_Domingo|AST|40|0||29e5',
            'America/Araguaina|-03 -02|30 20|010|1IdD0 Lz0|14e4',
            'America/Fortaleza|-03|30|0||34e5',
            'America/Asuncion|-03 -04|30 40|01010101010101010101010|1GTf0 1cN0 17b0 1ip0 17b0 1ip0 17b0 1ip0 19X0 1fB0 19X0 1fB0 19X0 1ip0 17b0 1ip0 17b0 1ip0 19X0 1fB0 19X0 1fB0|28e5',
            'America/Panama|EST|50|0||15e5',
            'America/Mexico_City|CST CDT|60 50|01010101010101010101010|1GQw0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0|20e6',
            'America/Bahia|-02 -03|20 30|01|1GCq0|27e5',
            'America/Managua|CST|60|0||22e5',
            'America/La_Paz|-04|40|0||19e5',
            'America/Lima|-05|50|0||11e6',
            'America/Denver|MST MDT|70 60|01010101010101010101010|1GI90 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|26e5',
            'America/Campo_Grande|-03 -04|30 40|01010101010101010101010|1GCr0 1zd0 Lz0 1C10 Lz0 1C10 On0 1zd0 On0 1zd0 On0 1zd0 On0 1HB0 FX0 1HB0 FX0 1HB0 IL0 1HB0 FX0 1HB0|77e4',
            'America/Cancun|CST CDT EST|60 50 50|01010102|1GQw0 1nX0 14p0 1lb0 14p0 1lb0 Dd0|63e4',
            'America/Caracas|-0430 -04|4u 40|01|1QMT0|29e5',
            'America/Chicago|CST CDT|60 50|01010101010101010101010|1GI80 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|92e5',
            'America/Chihuahua|MST MDT|70 60|01010101010101010101010|1GQx0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0|81e4',
            'America/Phoenix|MST|70|0||42e5',
            'America/Los_Angeles|PST PDT|80 70|01010101010101010101010|1GIa0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|15e6',
            'America/New_York|EST EDT|50 40|01010101010101010101010|1GI70 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|21e6',
            'America/Rio_Branco|-04 -05|40 50|01|1KLE0|31e4',
            'America/Fort_Nelson|PST PDT MST|80 70 70|01010102|1GIa0 1zb0 Op0 1zb0 Op0 1zb0 Op0|39e2',
            'America/Halifax|AST ADT|40 30|01010101010101010101010|1GI60 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|39e4',
            'America/Godthab|-03 -02|30 20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|17e3',
            'America/Grand_Turk|EST EDT AST|50 40 40|0101010121010101010|1GI70 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 5Ip0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|37e2',
            'America/Havana|CST CDT|50 40|01010101010101010101010|1GQt0 1qM0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0|21e5',
            'America/Metlakatla|PST AKST AKDT|80 90 80|0121212121212121|1PAa0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|14e2',
            'America/Miquelon|-03 -02|30 20|01010101010101010101010|1GI50 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|61e2',
            'America/Montevideo|-02 -03|20 30|01010101|1GI40 1o10 11z0 1o10 11z0 1o10 11z0|17e5',
            'America/Noronha|-02|20|0||30e2',
            'America/Port-au-Prince|EST EDT|50 40|010101010101010101010|1GI70 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 3iN0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|23e5',
            'Antarctica/Palmer|-03 -04|30 40|010101010|1H3D0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0|40',
            'America/Santiago|-03 -04|30 40|010101010101010101010|1H3D0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1zb0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0|62e5',
            'America/Sao_Paulo|-02 -03|20 30|01010101010101010101010|1GCq0 1zd0 Lz0 1C10 Lz0 1C10 On0 1zd0 On0 1zd0 On0 1zd0 On0 1HB0 FX0 1HB0 FX0 1HB0 IL0 1HB0 FX0 1HB0|20e6',
            'Atlantic/Azores|-01 +00|10 0|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|25e4',
            'America/St_Johns|NST NDT|3u 2u|01010101010101010101010|1GI5u 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0|11e4',
            'Antarctica/Casey|+11 +08|-b0 -80|0101|1GAF0 blz0 3m10|10',
            'Antarctica/Davis|+05 +07|-50 -70|01|1GAI0|70',
            'Pacific/Port_Moresby|+10|-a0|0||25e4',
            'Pacific/Guadalcanal|+11|-b0|0||11e4',
            'Asia/Tashkent|+05|-50|0||23e5',
            'Pacific/Auckland|NZDT NZST|-d0 -c0|01010101010101010101010|1GQe0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00|14e5',
            'Asia/Baghdad|+03|-30|0||66e5',
            'Antarctica/Troll|+00 +02|0 -20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|40',
            'Asia/Dhaka|+06|-60|0||16e6',
            'Asia/Amman|EET EEST|-20 -30|010101010101010101010|1GPy0 4bX0 Dd0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 11A0 1o00|25e5',
            'Asia/Kamchatka|+12|-c0|0||18e4',
            'Asia/Baku|+04 +05|-40 -50|010101010|1GNA0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00|27e5',
            'Asia/Bangkok|+07|-70|0||15e6',
            'Asia/Barnaul|+07 +06|-70 -60|010|1N7v0 3rd0',
            'Asia/Beirut|EET EEST|-20 -30|01010101010101010101010|1GNy0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0|22e5',
            'Asia/Kuala_Lumpur|+08|-80|0||71e5',
            'Asia/Kolkata|IST|-5u|0||15e6',
            'Asia/Chita|+10 +08 +09|-a0 -80 -90|012|1N7s0 3re0|33e4',
            'Asia/Ulaanbaatar|+08 +09|-80 -90|01010|1O8G0 1cJ0 1cP0 1cJ0|12e5',
            'Asia/Shanghai|CST|-80|0||23e6',
            'Asia/Colombo|+0530|-5u|0||22e5',
            'Asia/Damascus|EET EEST|-20 -30|01010101010101010101010|1GPy0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0|26e5',
            'Asia/Dili|+09|-90|0||19e4',
            'Asia/Dubai|+04|-40|0||39e5',
            'Asia/Famagusta|EET EEST +03|-20 -30 -30|0101010101201010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 15U0 2Ks0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0',
            'Asia/Gaza|EET EEST|-20 -30|01010101010101010101010|1GPy0 1a00 1fA0 1cL0 1cN0 1nX0 1210 1nz0 1220 1qL0 WN0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1qL0 WN0 1qL0 WN0 1qL0|18e5',
            'Asia/Hong_Kong|HKT|-80|0||73e5',
            'Asia/Hovd|+07 +08|-70 -80|01010|1O8H0 1cJ0 1cP0 1cJ0|81e3',
            'Asia/Irkutsk|+09 +08|-90 -80|01|1N7t0|60e4',
            'Europe/Istanbul|EET EEST +03|-20 -30 -30|01010101012|1GNB0 1qM0 11A0 1o00 1200 1nA0 11A0 1tA0 U00 15w0|13e6',
            'Asia/Jakarta|WIB|-70|0||31e6',
            'Asia/Jayapura|WIT|-90|0||26e4',
            'Asia/Jerusalem|IST IDT|-20 -30|01010101010101010101010|1GPA0 1aL0 1eN0 1oL0 10N0 1oL0 10N0 1oL0 10N0 1rz0 W10 1rz0 W10 1rz0 10N0 1oL0 10N0 1oL0 10N0 1rz0 W10 1rz0|81e4',
            'Asia/Kabul|+0430|-4u|0||46e5',
            'Asia/Karachi|PKT|-50|0||24e6',
            'Asia/Kathmandu|+0545|-5J|0||12e5',
            'Asia/Yakutsk|+10 +09|-a0 -90|01|1N7s0|28e4',
            'Asia/Krasnoyarsk|+08 +07|-80 -70|01|1N7u0|10e5',
            'Asia/Magadan|+12 +10 +11|-c0 -a0 -b0|012|1N7q0 3Cq0|95e3',
            'Asia/Makassar|WITA|-80|0||15e5',
            'Asia/Manila|PST|-80|0||24e6',
            'Europe/Athens|EET EEST|-20 -30|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|35e5',
            'Asia/Novosibirsk|+07 +06|-70 -60|010|1N7v0 4eN0|15e5',
            'Asia/Omsk|+07 +06|-70 -60|01|1N7v0|12e5',
            'Asia/Pyongyang|KST KST|-90 -8u|010|1P4D0 6BA0|29e5',
            'Asia/Rangoon|+0630|-6u|0||48e5',
            'Asia/Sakhalin|+11 +10|-b0 -a0|010|1N7r0 3rd0|58e4',
            'Asia/Seoul|KST|-90|0||23e6',
            'Asia/Srednekolymsk|+12 +11|-c0 -b0|01|1N7q0|35e2',
            'Asia/Tehran|+0330 +0430|-3u -4u|01010101010101010101010|1GLUu 1dz0 1cN0 1dz0 1cp0 1dz0 1cp0 1dz0 1cp0 1dz0 1cN0 1dz0 1cp0 1dz0 1cp0 1dz0 1cp0 1dz0 1cN0 1dz0 1cp0 1dz0|14e6',
            'Asia/Tokyo|JST|-90|0||38e6',
            'Asia/Tomsk|+07 +06|-70 -60|010|1N7v0 3Qp0|10e5',
            'Asia/Vladivostok|+11 +10|-b0 -a0|01|1N7r0|60e4',
            'Asia/Yekaterinburg|+06 +05|-60 -50|01|1N7w0|14e5',
            'Europe/Lisbon|WET WEST|0 -10|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|27e5',
            'Atlantic/Cape_Verde|-01|10|0||50e4',
            'Australia/Sydney|AEDT AEST|-b0 -a0|01010101010101010101010|1GQg0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0|40e5',
            'Australia/Adelaide|ACDT ACST|-au -9u|01010101010101010101010|1GQgu 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0|11e5',
            'Australia/Brisbane|AEST|-a0|0||20e5',
            'Australia/Darwin|ACST|-9u|0||12e4',
            'Australia/Eucla|+0845|-8J|0||368',
            'Australia/Lord_Howe|+11 +1030|-b0 -au|01010101010101010101010|1GQf0 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu|347',
            'Australia/Perth|AWST|-80|0||18e5',
            'Pacific/Easter|-05 -06|50 60|010101010101010101010|1H3D0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1zb0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0|30e2',
            'Europe/Dublin|GMT IST|0 -10|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|12e5',
            'Etc/GMT-1|+01|-10|0|',
            'Pacific/Fakaofo|+13|-d0|0||483',
            'Pacific/Kiritimati|+14|-e0|0||51e2',
            'Etc/GMT-2|+02|-20|0|',
            'Pacific/Tahiti|-10|a0|0||18e4',
            'Pacific/Niue|-11|b0|0||12e2',
            'Etc/GMT+12|-12|c0|0|',
            'Pacific/Galapagos|-06|60|0||25e3',
            'Etc/GMT+7|-07|70|0|',
            'Pacific/Pitcairn|-08|80|0||56',
            'Pacific/Gambier|-09|90|0||125',
            'Etc/UCT|UCT|0|0|',
            'Etc/UTC|UTC|0|0|',
            'Europe/Ulyanovsk|+04 +03|-40 -30|010|1N7y0 3rd0|13e5',
            'Europe/London|GMT BST|0 -10|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|10e6',
            'Europe/Chisinau|EET EEST|-20 -30|01010101010101010101010|1GNA0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0|67e4',
            'Europe/Kaliningrad|+03 EET|-30 -20|01|1N7z0|44e4',
            'Europe/Kirov|+04 +03|-40 -30|01|1N7y0|48e4',
            'Europe/Moscow|MSK MSK|-40 -30|01|1N7y0|16e6',
            'Europe/Saratov|+04 +03|-40 -30|010|1N7y0 5810',
            'Europe/Simferopol|EET EEST MSK MSK|-20 -30 -40 -30|0101023|1GNB0 1qM0 11A0 1o00 11z0 1nW0|33e4',
            'Europe/Volgograd|+04 +03|-40 -30|010|1N7y0 9Jd0|10e5',
            'Pacific/Honolulu|HST|a0|0||37e4',
            'MET|MET MEST|-10 -20|01010101010101010101010|1GNB0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0',
            'Pacific/Chatham|+1345 +1245|-dJ -cJ|01010101010101010101010|1GQe0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00|600',
            'Pacific/Apia|+14 +13|-e0 -d0|01010101010101010101010|1GQe0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00|37e3',
            'Pacific/Bougainville|+10 +11|-a0 -b0|01|1NwE0|18e4',
            'Pacific/Fiji|+13 +12|-d0 -c0|01010101010101010101010|1Goe0 1Nc0 Ao0 1Q00 xz0 1SN0 uM0 1SM0 uM0 1VA0 s00 1VA0 s00 1VA0 s00 1VA0 uM0 1SM0 uM0 1VA0 s00 1VA0|88e4',
            'Pacific/Guam|ChST|-a0|0||17e4',
            'Pacific/Marquesas|-0930|9u|0||86e2',
            'Pacific/Pago_Pago|SST|b0|0||37e2',
            'Pacific/Norfolk|+1130 +11|-bu -b0|01|1PoCu|25e4',
            'Pacific/Tongatapu|+13 +14|-d0 -e0|010|1S4d0 s00|75e3',
          ],
          links: [
            'Africa/Abidjan|Africa/Accra',
            'Africa/Abidjan|Africa/Bamako',
            'Africa/Abidjan|Africa/Banjul',
            'Africa/Abidjan|Africa/Bissau',
            'Africa/Abidjan|Africa/Conakry',
            'Africa/Abidjan|Africa/Dakar',
            'Africa/Abidjan|Africa/Freetown',
            'Africa/Abidjan|Africa/Lome',
            'Africa/Abidjan|Africa/Monrovia',
            'Africa/Abidjan|Africa/Nouakchott',
            'Africa/Abidjan|Africa/Ouagadougou',
            'Africa/Abidjan|Africa/Timbuktu',
            'Africa/Abidjan|America/Danmarkshavn',
            'Africa/Abidjan|Atlantic/Reykjavik',
            'Africa/Abidjan|Atlantic/St_Helena',
            'Africa/Abidjan|Etc/GMT',
            'Africa/Abidjan|Etc/GMT+0',
            'Africa/Abidjan|Etc/GMT-0',
            'Africa/Abidjan|Etc/GMT0',
            'Africa/Abidjan|Etc/Greenwich',
            'Africa/Abidjan|GMT',
            'Africa/Abidjan|GMT+0',
            'Africa/Abidjan|GMT-0',
            'Africa/Abidjan|GMT0',
            'Africa/Abidjan|Greenwich',
            'Africa/Abidjan|Iceland',
            'Africa/Algiers|Africa/Tunis',
            'Africa/Cairo|Egypt',
            'Africa/Casablanca|Africa/El_Aaiun',
            'Africa/Johannesburg|Africa/Maseru',
            'Africa/Johannesburg|Africa/Mbabane',
            'Africa/Lagos|Africa/Bangui',
            'Africa/Lagos|Africa/Brazzaville',
            'Africa/Lagos|Africa/Douala',
            'Africa/Lagos|Africa/Kinshasa',
            'Africa/Lagos|Africa/Libreville',
            'Africa/Lagos|Africa/Luanda',
            'Africa/Lagos|Africa/Malabo',
            'Africa/Lagos|Africa/Ndjamena',
            'Africa/Lagos|Africa/Niamey',
            'Africa/Lagos|Africa/Porto-Novo',
            'Africa/Maputo|Africa/Blantyre',
            'Africa/Maputo|Africa/Bujumbura',
            'Africa/Maputo|Africa/Gaborone',
            'Africa/Maputo|Africa/Harare',
            'Africa/Maputo|Africa/Kigali',
            'Africa/Maputo|Africa/Lubumbashi',
            'Africa/Maputo|Africa/Lusaka',
            'Africa/Nairobi|Africa/Addis_Ababa',
            'Africa/Nairobi|Africa/Asmara',
            'Africa/Nairobi|Africa/Asmera',
            'Africa/Nairobi|Africa/Dar_es_Salaam',
            'Africa/Nairobi|Africa/Djibouti',
            'Africa/Nairobi|Africa/Juba',
            'Africa/Nairobi|Africa/Kampala',
            'Africa/Nairobi|Africa/Mogadishu',
            'Africa/Nairobi|Indian/Antananarivo',
            'Africa/Nairobi|Indian/Comoro',
            'Africa/Nairobi|Indian/Mayotte',
            'Africa/Tripoli|Libya',
            'America/Adak|America/Atka',
            'America/Adak|US/Aleutian',
            'America/Anchorage|America/Juneau',
            'America/Anchorage|America/Nome',
            'America/Anchorage|America/Sitka',
            'America/Anchorage|America/Yakutat',
            'America/Anchorage|US/Alaska',
            'America/Campo_Grande|America/Cuiaba',
            'America/Chicago|America/Indiana/Knox',
            'America/Chicago|America/Indiana/Tell_City',
            'America/Chicago|America/Knox_IN',
            'America/Chicago|America/Matamoros',
            'America/Chicago|America/Menominee',
            'America/Chicago|America/North_Dakota/Beulah',
            'America/Chicago|America/North_Dakota/Center',
            'America/Chicago|America/North_Dakota/New_Salem',
            'America/Chicago|America/Rainy_River',
            'America/Chicago|America/Rankin_Inlet',
            'America/Chicago|America/Resolute',
            'America/Chicago|America/Winnipeg',
            'America/Chicago|CST6CDT',
            'America/Chicago|Canada/Central',
            'America/Chicago|US/Central',
            'America/Chicago|US/Indiana-Starke',
            'America/Chihuahua|America/Mazatlan',
            'America/Chihuahua|Mexico/BajaSur',
            'America/Denver|America/Boise',
            'America/Denver|America/Cambridge_Bay',
            'America/Denver|America/Edmonton',
            'America/Denver|America/Inuvik',
            'America/Denver|America/Ojinaga',
            'America/Denver|America/Shiprock',
            'America/Denver|America/Yellowknife',
            'America/Denver|Canada/Mountain',
            'America/Denver|MST7MDT',
            'America/Denver|Navajo',
            'America/Denver|US/Mountain',
            'America/Fortaleza|America/Argentina/Buenos_Aires',
            'America/Fortaleza|America/Argentina/Catamarca',
            'America/Fortaleza|America/Argentina/ComodRivadavia',
            'America/Fortaleza|America/Argentina/Cordoba',
            'America/Fortaleza|America/Argentina/Jujuy',
            'America/Fortaleza|America/Argentina/La_Rioja',
            'America/Fortaleza|America/Argentina/Mendoza',
            'America/Fortaleza|America/Argentina/Rio_Gallegos',
            'America/Fortaleza|America/Argentina/Salta',
            'America/Fortaleza|America/Argentina/San_Juan',
            'America/Fortaleza|America/Argentina/San_Luis',
            'America/Fortaleza|America/Argentina/Tucuman',
            'America/Fortaleza|America/Argentina/Ushuaia',
            'America/Fortaleza|America/Belem',
            'America/Fortaleza|America/Buenos_Aires',
            'America/Fortaleza|America/Catamarca',
            'America/Fortaleza|America/Cayenne',
            'America/Fortaleza|America/Cordoba',
            'America/Fortaleza|America/Jujuy',
            'America/Fortaleza|America/Maceio',
            'America/Fortaleza|America/Mendoza',
            'America/Fortaleza|America/Paramaribo',
            'America/Fortaleza|America/Recife',
            'America/Fortaleza|America/Rosario',
            'America/Fortaleza|America/Santarem',
            'America/Fortaleza|Antarctica/Rothera',
            'America/Fortaleza|Atlantic/Stanley',
            'America/Fortaleza|Etc/GMT+3',
            'America/Halifax|America/Glace_Bay',
            'America/Halifax|America/Goose_Bay',
            'America/Halifax|America/Moncton',
            'America/Halifax|America/Thule',
            'America/Halifax|Atlantic/Bermuda',
            'America/Halifax|Canada/Atlantic',
            'America/Havana|Cuba',
            'America/La_Paz|America/Boa_Vista',
            'America/La_Paz|America/Guyana',
            'America/La_Paz|America/Manaus',
            'America/La_Paz|America/Porto_Velho',
            'America/La_Paz|Brazil/West',
            'America/La_Paz|Etc/GMT+4',
            'America/Lima|America/Bogota',
            'America/Lima|America/Guayaquil',
            'America/Lima|Etc/GMT+5',
            'America/Los_Angeles|America/Dawson',
            'America/Los_Angeles|America/Ensenada',
            'America/Los_Angeles|America/Santa_Isabel',
            'America/Los_Angeles|America/Tijuana',
            'America/Los_Angeles|America/Vancouver',
            'America/Los_Angeles|America/Whitehorse',
            'America/Los_Angeles|Canada/Pacific',
            'America/Los_Angeles|Canada/Yukon',
            'America/Los_Angeles|Mexico/BajaNorte',
            'America/Los_Angeles|PST8PDT',
            'America/Los_Angeles|US/Pacific',
            'America/Los_Angeles|US/Pacific-New',
            'America/Managua|America/Belize',
            'America/Managua|America/Costa_Rica',
            'America/Managua|America/El_Salvador',
            'America/Managua|America/Guatemala',
            'America/Managua|America/Regina',
            'America/Managua|America/Swift_Current',
            'America/Managua|America/Tegucigalpa',
            'America/Managua|Canada/Saskatchewan',
            'America/Mexico_City|America/Bahia_Banderas',
            'America/Mexico_City|America/Merida',
            'America/Mexico_City|America/Monterrey',
            'America/Mexico_City|Mexico/General',
            'America/New_York|America/Detroit',
            'America/New_York|America/Fort_Wayne',
            'America/New_York|America/Indiana/Indianapolis',
            'America/New_York|America/Indiana/Marengo',
            'America/New_York|America/Indiana/Petersburg',
            'America/New_York|America/Indiana/Vevay',
            'America/New_York|America/Indiana/Vincennes',
            'America/New_York|America/Indiana/Winamac',
            'America/New_York|America/Indianapolis',
            'America/New_York|America/Iqaluit',
            'America/New_York|America/Kentucky/Louisville',
            'America/New_York|America/Kentucky/Monticello',
            'America/New_York|America/Louisville',
            'America/New_York|America/Montreal',
            'America/New_York|America/Nassau',
            'America/New_York|America/Nipigon',
            'America/New_York|America/Pangnirtung',
            'America/New_York|America/Thunder_Bay',
            'America/New_York|America/Toronto',
            'America/New_York|Canada/Eastern',
            'America/New_York|EST5EDT',
            'America/New_York|US/East-Indiana',
            'America/New_York|US/Eastern',
            'America/New_York|US/Michigan',
            'America/Noronha|Atlantic/South_Georgia',
            'America/Noronha|Brazil/DeNoronha',
            'America/Noronha|Etc/GMT+2',
            'America/Panama|America/Atikokan',
            'America/Panama|America/Cayman',
            'America/Panama|America/Coral_Harbour',
            'America/Panama|America/Jamaica',
            'America/Panama|EST',
            'America/Panama|Jamaica',
            'America/Phoenix|America/Creston',
            'America/Phoenix|America/Dawson_Creek',
            'America/Phoenix|America/Hermosillo',
            'America/Phoenix|MST',
            'America/Phoenix|US/Arizona',
            'America/Rio_Branco|America/Eirunepe',
            'America/Rio_Branco|America/Porto_Acre',
            'America/Rio_Branco|Brazil/Acre',
            'America/Santiago|Chile/Continental',
            'America/Santo_Domingo|America/Anguilla',
            'America/Santo_Domingo|America/Antigua',
            'America/Santo_Domingo|America/Aruba',
            'America/Santo_Domingo|America/Barbados',
            'America/Santo_Domingo|America/Blanc-Sablon',
            'America/Santo_Domingo|America/Curacao',
            'America/Santo_Domingo|America/Dominica',
            'America/Santo_Domingo|America/Grenada',
            'America/Santo_Domingo|America/Guadeloupe',
            'America/Santo_Domingo|America/Kralendijk',
            'America/Santo_Domingo|America/Lower_Princes',
            'America/Santo_Domingo|America/Marigot',
            'America/Santo_Domingo|America/Martinique',
            'America/Santo_Domingo|America/Montserrat',
            'America/Santo_Domingo|America/Port_of_Spain',
            'America/Santo_Domingo|America/Puerto_Rico',
            'America/Santo_Domingo|America/St_Barthelemy',
            'America/Santo_Domingo|America/St_Kitts',
            'America/Santo_Domingo|America/St_Lucia',
            'America/Santo_Domingo|America/St_Thomas',
            'America/Santo_Domingo|America/St_Vincent',
            'America/Santo_Domingo|America/Tortola',
            'America/Santo_Domingo|America/Virgin',
            'America/Sao_Paulo|Brazil/East',
            'America/St_Johns|Canada/Newfoundland',
            'Antarctica/Palmer|America/Punta_Arenas',
            'Asia/Baghdad|Antarctica/Syowa',
            'Asia/Baghdad|Asia/Aden',
            'Asia/Baghdad|Asia/Bahrain',
            'Asia/Baghdad|Asia/Kuwait',
            'Asia/Baghdad|Asia/Qatar',
            'Asia/Baghdad|Asia/Riyadh',
            'Asia/Baghdad|Etc/GMT-3',
            'Asia/Baghdad|Europe/Minsk',
            'Asia/Bangkok|Asia/Ho_Chi_Minh',
            'Asia/Bangkok|Asia/Novokuznetsk',
            'Asia/Bangkok|Asia/Phnom_Penh',
            'Asia/Bangkok|Asia/Saigon',
            'Asia/Bangkok|Asia/Vientiane',
            'Asia/Bangkok|Etc/GMT-7',
            'Asia/Bangkok|Indian/Christmas',
            'Asia/Dhaka|Antarctica/Vostok',
            'Asia/Dhaka|Asia/Almaty',
            'Asia/Dhaka|Asia/Bishkek',
            'Asia/Dhaka|Asia/Dacca',
            'Asia/Dhaka|Asia/Kashgar',
            'Asia/Dhaka|Asia/Qyzylorda',
            'Asia/Dhaka|Asia/Thimbu',
            'Asia/Dhaka|Asia/Thimphu',
            'Asia/Dhaka|Asia/Urumqi',
            'Asia/Dhaka|Etc/GMT-6',
            'Asia/Dhaka|Indian/Chagos',
            'Asia/Dili|Etc/GMT-9',
            'Asia/Dili|Pacific/Palau',
            'Asia/Dubai|Asia/Muscat',
            'Asia/Dubai|Asia/Tbilisi',
            'Asia/Dubai|Asia/Yerevan',
            'Asia/Dubai|Etc/GMT-4',
            'Asia/Dubai|Europe/Samara',
            'Asia/Dubai|Indian/Mahe',
            'Asia/Dubai|Indian/Mauritius',
            'Asia/Dubai|Indian/Reunion',
            'Asia/Gaza|Asia/Hebron',
            'Asia/Hong_Kong|Hongkong',
            'Asia/Jakarta|Asia/Pontianak',
            'Asia/Jerusalem|Asia/Tel_Aviv',
            'Asia/Jerusalem|Israel',
            'Asia/Kamchatka|Asia/Anadyr',
            'Asia/Kamchatka|Etc/GMT-12',
            'Asia/Kamchatka|Kwajalein',
            'Asia/Kamchatka|Pacific/Funafuti',
            'Asia/Kamchatka|Pacific/Kwajalein',
            'Asia/Kamchatka|Pacific/Majuro',
            'Asia/Kamchatka|Pacific/Nauru',
            'Asia/Kamchatka|Pacific/Tarawa',
            'Asia/Kamchatka|Pacific/Wake',
            'Asia/Kamchatka|Pacific/Wallis',
            'Asia/Kathmandu|Asia/Katmandu',
            'Asia/Kolkata|Asia/Calcutta',
            'Asia/Kuala_Lumpur|Asia/Brunei',
            'Asia/Kuala_Lumpur|Asia/Kuching',
            'Asia/Kuala_Lumpur|Asia/Singapore',
            'Asia/Kuala_Lumpur|Etc/GMT-8',
            'Asia/Kuala_Lumpur|Singapore',
            'Asia/Makassar|Asia/Ujung_Pandang',
            'Asia/Rangoon|Asia/Yangon',
            'Asia/Rangoon|Indian/Cocos',
            'Asia/Seoul|ROK',
            'Asia/Shanghai|Asia/Chongqing',
            'Asia/Shanghai|Asia/Chungking',
            'Asia/Shanghai|Asia/Harbin',
            'Asia/Shanghai|Asia/Macao',
            'Asia/Shanghai|Asia/Macau',
            'Asia/Shanghai|Asia/Taipei',
            'Asia/Shanghai|PRC',
            'Asia/Shanghai|ROC',
            'Asia/Tashkent|Antarctica/Mawson',
            'Asia/Tashkent|Asia/Aqtau',
            'Asia/Tashkent|Asia/Aqtobe',
            'Asia/Tashkent|Asia/Ashgabat',
            'Asia/Tashkent|Asia/Ashkhabad',
            'Asia/Tashkent|Asia/Atyrau',
            'Asia/Tashkent|Asia/Dushanbe',
            'Asia/Tashkent|Asia/Oral',
            'Asia/Tashkent|Asia/Samarkand',
            'Asia/Tashkent|Etc/GMT-5',
            'Asia/Tashkent|Indian/Kerguelen',
            'Asia/Tashkent|Indian/Maldives',
            'Asia/Tehran|Iran',
            'Asia/Tokyo|Japan',
            'Asia/Ulaanbaatar|Asia/Choibalsan',
            'Asia/Ulaanbaatar|Asia/Ulan_Bator',
            'Asia/Vladivostok|Asia/Ust-Nera',
            'Asia/Yakutsk|Asia/Khandyga',
            'Atlantic/Azores|America/Scoresbysund',
            'Atlantic/Cape_Verde|Etc/GMT+1',
            'Australia/Adelaide|Australia/Broken_Hill',
            'Australia/Adelaide|Australia/South',
            'Australia/Adelaide|Australia/Yancowinna',
            'Australia/Brisbane|Australia/Lindeman',
            'Australia/Brisbane|Australia/Queensland',
            'Australia/Darwin|Australia/North',
            'Australia/Lord_Howe|Australia/LHI',
            'Australia/Perth|Australia/West',
            'Australia/Sydney|Australia/ACT',
            'Australia/Sydney|Australia/Canberra',
            'Australia/Sydney|Australia/Currie',
            'Australia/Sydney|Australia/Hobart',
            'Australia/Sydney|Australia/Melbourne',
            'Australia/Sydney|Australia/NSW',
            'Australia/Sydney|Australia/Tasmania',
            'Australia/Sydney|Australia/Victoria',
            'Etc/UCT|UCT',
            'Etc/UTC|Etc/Universal',
            'Etc/UTC|Etc/Zulu',
            'Etc/UTC|UTC',
            'Etc/UTC|Universal',
            'Etc/UTC|Zulu',
            'Europe/Athens|Asia/Nicosia',
            'Europe/Athens|EET',
            'Europe/Athens|Europe/Bucharest',
            'Europe/Athens|Europe/Helsinki',
            'Europe/Athens|Europe/Kiev',
            'Europe/Athens|Europe/Mariehamn',
            'Europe/Athens|Europe/Nicosia',
            'Europe/Athens|Europe/Riga',
            'Europe/Athens|Europe/Sofia',
            'Europe/Athens|Europe/Tallinn',
            'Europe/Athens|Europe/Uzhgorod',
            'Europe/Athens|Europe/Vilnius',
            'Europe/Athens|Europe/Zaporozhye',
            'Europe/Chisinau|Europe/Tiraspol',
            'Europe/Dublin|Eire',
            'Europe/Istanbul|Asia/Istanbul',
            'Europe/Istanbul|Turkey',
            'Europe/Lisbon|Atlantic/Canary',
            'Europe/Lisbon|Atlantic/Faeroe',
            'Europe/Lisbon|Atlantic/Faroe',
            'Europe/Lisbon|Atlantic/Madeira',
            'Europe/Lisbon|Portugal',
            'Europe/Lisbon|WET',
            'Europe/London|Europe/Belfast',
            'Europe/London|Europe/Guernsey',
            'Europe/London|Europe/Isle_of_Man',
            'Europe/London|Europe/Jersey',
            'Europe/London|GB',
            'Europe/London|GB-Eire',
            'Europe/Moscow|W-SU',
            'Europe/Paris|Africa/Ceuta',
            'Europe/Paris|Arctic/Longyearbyen',
            'Europe/Paris|Atlantic/Jan_Mayen',
            'Europe/Paris|CET',
            'Europe/Paris|Europe/Amsterdam',
            'Europe/Paris|Europe/Andorra',
            'Europe/Paris|Europe/Belgrade',
            'Europe/Paris|Europe/Berlin',
            'Europe/Paris|Europe/Bratislava',
            'Europe/Paris|Europe/Brussels',
            'Europe/Paris|Europe/Budapest',
            'Europe/Paris|Europe/Busingen',
            'Europe/Paris|Europe/Copenhagen',
            'Europe/Paris|Europe/Gibraltar',
            'Europe/Paris|Europe/Ljubljana',
            'Europe/Paris|Europe/Luxembourg',
            'Europe/Paris|Europe/Madrid',
            'Europe/Paris|Europe/Malta',
            'Europe/Paris|Europe/Monaco',
            'Europe/Paris|Europe/Oslo',
            'Europe/Paris|Europe/Podgorica',
            'Europe/Paris|Europe/Prague',
            'Europe/Paris|Europe/Rome',
            'Europe/Paris|Europe/San_Marino',
            'Europe/Paris|Europe/Sarajevo',
            'Europe/Paris|Europe/Skopje',
            'Europe/Paris|Europe/Stockholm',
            'Europe/Paris|Europe/Tirane',
            'Europe/Paris|Europe/Vaduz',
            'Europe/Paris|Europe/Vatican',
            'Europe/Paris|Europe/Vienna',
            'Europe/Paris|Europe/Warsaw',
            'Europe/Paris|Europe/Zagreb',
            'Europe/Paris|Europe/Zurich',
            'Europe/Paris|Poland',
            'Europe/Ulyanovsk|Europe/Astrakhan',
            'Pacific/Auckland|Antarctica/McMurdo',
            'Pacific/Auckland|Antarctica/South_Pole',
            'Pacific/Auckland|NZ',
            'Pacific/Chatham|NZ-CHAT',
            'Pacific/Easter|Chile/EasterIsland',
            'Pacific/Fakaofo|Etc/GMT-13',
            'Pacific/Fakaofo|Pacific/Enderbury',
            'Pacific/Galapagos|Etc/GMT+6',
            'Pacific/Gambier|Etc/GMT+9',
            'Pacific/Guadalcanal|Antarctica/Macquarie',
            'Pacific/Guadalcanal|Etc/GMT-11',
            'Pacific/Guadalcanal|Pacific/Efate',
            'Pacific/Guadalcanal|Pacific/Kosrae',
            'Pacific/Guadalcanal|Pacific/Noumea',
            'Pacific/Guadalcanal|Pacific/Pohnpei',
            'Pacific/Guadalcanal|Pacific/Ponape',
            'Pacific/Guam|Pacific/Saipan',
            'Pacific/Honolulu|HST',
            'Pacific/Honolulu|Pacific/Johnston',
            'Pacific/Honolulu|US/Hawaii',
            'Pacific/Kiritimati|Etc/GMT-14',
            'Pacific/Niue|Etc/GMT+11',
            'Pacific/Pago_Pago|Pacific/Midway',
            'Pacific/Pago_Pago|Pacific/Samoa',
            'Pacific/Pago_Pago|US/Samoa',
            'Pacific/Pitcairn|Etc/GMT+8',
            'Pacific/Port_Moresby|Antarctica/DumontDUrville',
            'Pacific/Port_Moresby|Etc/GMT-10',
            'Pacific/Port_Moresby|Pacific/Chuuk',
            'Pacific/Port_Moresby|Pacific/Truk',
            'Pacific/Port_Moresby|Pacific/Yap',
            'Pacific/Tahiti|Etc/GMT+10',
            'Pacific/Tahiti|Pacific/Rarotonga',
          ],
        }),
        A
      );
    });
  });

  var parseformat = parseFormat;
  var dayNames = [
    'Sunday',
    'Monday',
    'Tuesday',
    'Wednesday',
    'Thursday',
    'Friday',
    'Saturday',
  ];
  var abbreviatedDayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
  var shortestDayNames = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
  var monthNames = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
  ];
  var abbreviatedMonthNames = [
    'Jan',
    'Feb',
    'Mar',
    'Apr',
    'May',
    'Jun',
    'Jul',
    'Aug',
    'Sep',
    'Oct',
    'Nov',
    'Dec',
  ];
  var regexDayNames = new RegExp(dayNames.join('|'), 'i');
  var regexAbbreviatedDayNames = new RegExp(abbreviatedDayNames.join('|'), 'i');
  var regexShortestDayNames = new RegExp(
    '\\b(' + shortestDayNames.join('|') + ')\\b',
    'i'
  );
  var regexMonthNames = new RegExp(monthNames.join('|'), 'i');
  var regexAbbreviatedMonthNames = new RegExp(
    abbreviatedMonthNames.join('|'),
    'i'
  );
  var regexFirstSecondThirdFourth = /(\d+)(st|nd|rd|th)\b/i;
  var regexEndian = /(\d{1,4})([/.-])(\d{1,2})[/.-](\d{1,4})/;
  var regexTimezone = /((\+|-)\d\d:?\d\d)$/;
  var amOrPm = '(' + ['AM?', 'PM?'].join('|') + ')';
  var regexHoursWithLeadingZeroDigitMinutesSecondsAmPm = new RegExp(
    '0\\d\\:\\d{1,2}\\:\\d{1,2}(\\s*)' + amOrPm,
    'i'
  );
  var regexHoursWithLeadingZeroDigitMinutesAmPm = new RegExp(
    '0\\d\\:\\d{1,2}(\\s*)' + amOrPm,
    'i'
  );
  var regexHoursWithLeadingZeroDigitAmPm = new RegExp(
    '0\\d(\\s*)' + amOrPm,
    'i'
  );
  var regexHoursMinutesSecondsAmPm = new RegExp(
    '\\d{1,2}\\:\\d{1,2}\\:\\d{1,2}(\\s*)' + amOrPm,
    'i'
  );
  var regexHoursMinutesAmPm = new RegExp(
    '\\d{1,2}\\:\\d{1,2}(\\s*)' + amOrPm,
    'i'
  );
  var regexHoursAmPm = new RegExp('\\d{1,2}(\\s*)' + amOrPm, 'i');
  var regexISO8601HoursWithLeadingZeroMinutesSecondsMilliseconds = /\d{2}:\d{2}:\d{2}\.\d{3}/;
  var regexISO8601HoursWithLeadingZeroMinutesSecondsCentiSeconds = /\d{2}:\d{2}:\d{2}\.\d{2}/;
  var regexISO8601HoursWithLeadingZeroMinutesSecondsDeciSeconds = /\d{2}:\d{2}:\d{2}\.\d{1}/;
  var regexHoursWithLeadingZeroMinutesSeconds = /0\d:\d{2}:\d{2}/;
  var regexHoursWithLeadingZeroMinutes = /0\d:\d{2}/;
  var regexHoursMinutesSeconds = /\d{1,2}:\d{2}:\d{2}/;
  var regexHoursMinutesSecondsMilliseconds = /\d{1,2}:\d{2}:\d{2}\.\d{3}/;
  var regexHoursMinutesSecondsCentiSeconds = /\d{1,2}:\d{2}:\d{2}\.\d{2}/;
  var regexHoursMinutesSecondsDeciSeconds = /\d{1,2}:\d{2}:\d{2}\.\d{1}/;
  var regexHoursMinutes = /\d{1,2}:\d{2}/;
  var regexYearLong = /\d{4}/;
  var regexDayLeadingZero = /0\d/;
  var regexDay = /\d{1,2}/;
  var regexYearShort = /\d{2}/;
  var regexDayShortMonthShort = /^([1-9])\/([1-9]|0[1-9])$/;
  var regexDayShortMonth = /^([1-9])\/(1[012])$/;
  var regexDayMonthShort = /^(0[1-9]|[12][0-9]|3[01])\/([1-9])$/;
  var regexDayMonth = /^(0[1-9]|[12][0-9]|3[01])\/(1[012]|0[1-9])$/;
  var regexMonthShortYearShort = /^([1-9])\/([1-9][0-9])$/;
  var regexMonthYearShort = /^(0[1-9]|1[012])\/([1-9][0-9])$/;
  var formatIncludesMonth = /([/][M]|[M][/]|[MM]|[MMMM])/;
  var regexFillingWords = /\b(at)\b/i;
  var regexUnixMillisecondTimestamp = /\d{13}/;
  var regexUnixTimestamp = /\d{10}/; // option defaults

  var defaultOrder = {
    '/': 'MDY',
    '.': 'DMY',
    '-': 'YMD',
  };

  function parseFormat(dateString, options) {
    var format = dateString.toString(); // default options

    options = options || {};
    options.preferredOrder = options.preferredOrder || defaultOrder; // Unix Millisecond Timestamp ☛ x

    format = format.replace(regexUnixMillisecondTimestamp, 'x'); // Unix Timestamp ☛ X

    format = format.replace(regexUnixTimestamp, 'X'); // escape filling words

    format = format.replace(regexFillingWords, '[$1]'); //  DAYS
    // Monday ☛ dddd

    format = format.replace(regexDayNames, 'dddd'); // Mon ☛ ddd

    format = format.replace(regexAbbreviatedDayNames, 'ddd'); // Mo ☛ dd

    format = format.replace(regexShortestDayNames, 'dd'); // 1st, 2nd, 23rd ☛ do

    format = format.replace(regexFirstSecondThirdFourth, 'Do'); // MONTHS
    // January ☛ MMMM

    format = format.replace(regexMonthNames, 'MMMM'); // Jan ☛ MMM

    format = format.replace(regexAbbreviatedMonthNames, 'MMM'); // replace endians, like 8/20/2010, 20.8.2010 or 2010-8-20

    format = format.replace(regexEndian, replaceEndian.bind(null, options)); // TIME
    // timezone +02:00 ☛ Z

    format = format.replace(regexTimezone, 'Z'); // 23:39:43.331 ☛ 'HH:mm:ss.SSS'

    format = format.replace(
      regexISO8601HoursWithLeadingZeroMinutesSecondsMilliseconds,
      'HH:mm:ss.SSS'
    ); // 23:39:43.33 ☛ 'HH:mm:ss.SS'

    format = format.replace(
      regexISO8601HoursWithLeadingZeroMinutesSecondsCentiSeconds,
      'HH:mm:ss.SS'
    ); // 23:39:43.3 ☛ 'HH:mm:ss.S'

    format = format.replace(
      regexISO8601HoursWithLeadingZeroMinutesSecondsDeciSeconds,
      'HH:mm:ss.S'
    );

    function replaceWithAmPm(timeFormat) {
      return function(match, whitespace, amPm) {
        return (
          timeFormat +
          whitespace +
          (amPm[0].toUpperCase() === amPm[0] ? 'A' : 'a')
        );
      };
    } // 05:30:20pm ☛ hh:mm:ssa

    format = format.replace(
      regexHoursWithLeadingZeroDigitMinutesSecondsAmPm,
      replaceWithAmPm('hh:mm:ss')
    ); // 10:30:20pm ☛ h:mm:ssa

    format = format.replace(
      regexHoursMinutesSecondsAmPm,
      replaceWithAmPm('h:mm:ss')
    ); // 05:30pm ☛ hh:mma

    format = format.replace(
      regexHoursWithLeadingZeroDigitMinutesAmPm,
      replaceWithAmPm('hh:mm')
    ); // 10:30pm ☛ h:mma

    format = format.replace(regexHoursMinutesAmPm, replaceWithAmPm('h:mm')); // 05pm ☛ hha

    format = format.replace(
      regexHoursWithLeadingZeroDigitAmPm,
      replaceWithAmPm('hh')
    ); // 10pm ☛ ha

    format = format.replace(regexHoursAmPm, replaceWithAmPm('h')); // 05:30:20 ☛ HH:mm:ss

    format = format.replace(
      regexHoursWithLeadingZeroMinutesSeconds,
      'HH:mm:ss'
    ); // 5:30:20.222 ☛ H:mm:ss.SSS

    format = format.replace(
      regexHoursMinutesSecondsMilliseconds,
      'H:mm:ss.SSS'
    ); // 5:30:20.22 ☛ H:mm:ss.SS

    format = format.replace(regexHoursMinutesSecondsCentiSeconds, 'H:mm:ss.SS'); // 5:30:20.2 ☛ H:mm:ss.S

    format = format.replace(regexHoursMinutesSecondsDeciSeconds, 'H:mm:ss.S'); // 10:30:20 ☛ H:mm:ss

    format = format.replace(regexHoursMinutesSeconds, 'H:mm:ss'); // 05:30 ☛ H:mm

    format = format.replace(regexHoursWithLeadingZeroMinutes, 'HH:mm'); // 10:30 ☛ HH:mm

    format = format.replace(regexHoursMinutes, 'H:mm'); // do we still have numbers left?
    // Lets check for 4 digits first, these are years for sure

    format = format.replace(regexYearLong, 'YYYY'); // check if both numbers are < 13, then it must be D/M

    format = format.replace(regexDayShortMonthShort, 'D/M'); // check if first number is < 10 && last < 13, then it must be D/MM

    format = format.replace(regexDayShortMonth, 'D/MM'); // check if last number is < 32 && last < 10, then it must be DD/M

    format = format.replace(regexDayMonthShort, 'DD/M'); // check if both numbers are > 10, but first < 32 && last < 13, then it must be DD/MM

    format = format.replace(regexDayMonth, 'DD/MM'); // check if first < 10 && last > 12, then it must be M/YY

    format = format.replace(regexMonthShortYearShort, 'M/YY'); // check if first < 13 && last > 12, then it must be MM/YY

    format = format.replace(regexMonthYearShort, 'MM/YY'); // to prevent 9.20 gets formated to D.Y, we format the complete date first, then go for the time

    if (format.match(formatIncludesMonth)) {
      var regexHoursDotWithLeadingZeroOrDoubleDigitMinutes = /0\d.\d{2}|\d{2}.\d{2}/;
      var regexHoursDotMinutes = /\d{1}.\d{2}/;
      format = format.replace(
        regexHoursDotWithLeadingZeroOrDoubleDigitMinutes,
        'H.mm'
      );
      format = format.replace(regexHoursDotMinutes, 'h.mm');
    } // now, the next number, if existing, must be a day

    format = format.replace(regexDayLeadingZero, 'DD');
    format = format.replace(regexDay, 'D'); // last but not least, there could still be a year left

    format = format.replace(regexYearShort, 'YY');

    if (format.length < 1) {
      format = undefined;
    }

    return format;
  } // if we can't find an endian based on the separator, but
  // there still is a short date with day, month & year,
  // we try to make a smart decision to identify the order

  function replaceEndian(
    options,
    matchedPart,
    first,
    separator,
    second,
    third
  ) {
    var parts;
    var hasSingleDigit =
      Math.min(first.length, second.length, third.length) === 1;
    var hasQuadDigit =
      Math.max(first.length, second.length, third.length) === 4;
    var preferredOrder =
      typeof options.preferredOrder === 'string'
        ? options.preferredOrder
        : options.preferredOrder[separator];
    first = parseInt(first, 10);
    second = parseInt(second, 10);
    third = parseInt(third, 10);
    parts = [first, second, third];
    preferredOrder = preferredOrder.toUpperCase(); // If first is a year, order will always be Year-Month-Day

    if (first > 31) {
      parts[0] = hasQuadDigit ? 'YYYY' : 'YY';
      parts[1] = hasSingleDigit ? 'M' : 'MM';
      parts[2] = hasSingleDigit ? 'D' : 'DD';
      return parts.join(separator);
    } // Second will never be the year. And if it is a day,
    // the order will always be Month-Day-Year

    if (second > 12) {
      parts[0] = hasSingleDigit ? 'M' : 'MM';
      parts[1] = hasSingleDigit ? 'D' : 'DD';
      parts[2] = hasQuadDigit ? 'YYYY' : 'YY';
      return parts.join(separator);
    } // if third is a year ...

    if (third > 31) {
      parts[2] = hasQuadDigit ? 'YYYY' : 'YY'; // ... try to find day in first and second.
      // If found, the remaining part is the month.

      if (preferredOrder[0] === 'M' && first < 13) {
        parts[0] = hasSingleDigit ? 'M' : 'MM';
        parts[1] = hasSingleDigit ? 'D' : 'DD';
        return parts.join(separator);
      }

      parts[0] = hasSingleDigit ? 'D' : 'DD';
      parts[1] = hasSingleDigit ? 'M' : 'MM';
      return parts.join(separator);
    } // if we had no luck until here, we use the preferred order

    parts[preferredOrder.indexOf('D')] = hasSingleDigit ? 'D' : 'DD';
    parts[preferredOrder.indexOf('M')] = hasSingleDigit ? 'M' : 'MM';
    parts[preferredOrder.indexOf('Y')] = hasQuadDigit ? 'YYYY' : 'YY';
    return parts.join(separator);
  }

  var momentParseformat = parseformat;
  /* istanbul ignore next */

  if (typeof window !== 'undefined' && window.moment) {
    window.moment.parseFormat = parseformat;
  }

  function cleanDateString(dateString) {
    return (dateString.match(SPLIT_DATE_STRING) || [])
      .join(' ')
      .replace(TIME_MERIDIAN_DOTS_RE, 'm')
      .replace(TIME_MERIDIAN_SPACE_RE, '$1 $2 $3')
      .replace(CLEAN_DATE_STRING_RE, '$1')
      .trim();
  }
  function createDate(dateString, timezone, format) {
    if (TIME_WITH_OFFSET_RE.test(dateString)) {
      return momentTimezoneWithData20122022_min(new Date(dateString));
    }

    return timezone
      ? momentTimezoneWithData20122022_min.tz(
          dateString,
          format || momentParseformat(dateString),
          timezone
        )
      : momentTimezoneWithData20122022_min(
          dateString,
          format || momentParseformat(dateString)
        );
  } // Take a date published string, and hopefully return a date out of
  // it. Return none if we fail.

  function cleanDatePublished(dateString) {
    var _ref =
        arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
      timezone = _ref.timezone,
      format = _ref.format;

    // If string is in milliseconds or seconds, convert to int and return
    if (MS_DATE_STRING.test(dateString) || SEC_DATE_STRING.test(dateString)) {
      return new Date(_parseInt$2(dateString, 10)).toISOString();
    }

    var date = createDate(dateString, timezone, format);

    if (!date.isValid()) {
      dateString = cleanDateString(dateString);
      date = createDate(dateString, timezone, format);
    }

    return date.isValid() ? date.toISOString() : null;
  }

  function extractCleanNode(article, _ref) {
    var $ = _ref.$,
      _ref$cleanConditional = _ref.cleanConditionally,
      cleanConditionally =
        _ref$cleanConditional === void 0 ? true : _ref$cleanConditional,
      _ref$title = _ref.title,
      title = _ref$title === void 0 ? '' : _ref$title,
      _ref$url = _ref.url,
      url = _ref$url === void 0 ? '' : _ref$url,
      _ref$defaultCleaner = _ref.defaultCleaner,
      defaultCleaner =
        _ref$defaultCleaner === void 0 ? true : _ref$defaultCleaner;
    // Rewrite the tag name to div if it's a top level node like body or
    // html to avoid later complications with multiple body tags.
    rewriteTopLevel$$1(article, $); // Drop small images and spacer images
    // Only do this is defaultCleaner is set to true;
    // this can sometimes be too aggressive.

    if (defaultCleaner) cleanImages(article, $); // Make links absolute

    makeLinksAbsolute$$1(article, $, url); // Mark elements to keep that would normally be removed.
    // E.g., stripJunkTags will remove iframes, so we're going to mark
    // YouTube/Vimeo videos as elements we want to keep.

    markToKeep(article, $, url); // Drop certain tags like <title>, etc
    // This is -mostly- for cleanliness, not security.

    stripJunkTags(article, $); // H1 tags are typically the article title, which should be extracted
    // by the title extractor instead. If there's less than 3 of them (<3),
    // strip them. Otherwise, turn 'em into H2s.

    cleanHOnes$$1(article, $); // Clean headers

    cleanHeaders(article, $, title); // We used to clean UL's and OL's here, but it was leading to
    // too many in-article lists being removed. Consider a better
    // way to detect menus particularly and remove them.
    // Also optionally running, since it can be overly aggressive.

    if (defaultCleaner) cleanTags$$1(article, $, cleanConditionally); // Remove empty paragraph nodes

    removeEmpty(article, $); // Remove unnecessary attributes

    cleanAttributes$$1(article, $);
    return article;
  }

  function cleanTitle$$1(title, _ref) {
    var url = _ref.url,
      $ = _ref.$;

    // If title has |, :, or - in it, see if
    // we can clean it up.
    if (TITLE_SPLITTERS_RE.test(title)) {
      title = resolveSplitTitle(title, url);
    } // Final sanity check that we didn't get a crazy title.
    // if (title.length > 150 || title.length < 15) {

    if (title.length > 150) {
      // If we did, return h1 from the document if it exists
      var h1 = $('h1');

      if (h1.length === 1) {
        title = h1.text();
      }
    } // strip any html tags in the title text

    return normalizeSpaces(stripTags(title, $).trim());
  }

  var global$1 =
    typeof global !== 'undefined'
      ? global
      : typeof self !== 'undefined'
      ? self
      : typeof window !== 'undefined'
      ? window
      : {};

  var lodash = createCommonjsModule(function(module, exports) {
    (function() {
      /** Used as a safe reference for `undefined` in pre ES5 environments */
      var undefined;
      /** Used to pool arrays and objects used internally */

      var arrayPool = [],
        objectPool = [];
      /** Used to generate unique IDs */

      var idCounter = 0;
      /** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */

      var keyPrefix = +new Date() + '';
      /** Used as the size when optimizations are enabled for large arrays */

      var largeArraySize = 75;
      /** Used as the max size of the `arrayPool` and `objectPool` */

      var maxPoolSize = 40;
      /** Used to detect and test whitespace */

      var whitespace = // whitespace
        ' \t\x0B\f\xA0\ufeff' + // line terminators
        '\n\r\u2028\u2029' + // unicode category "Zs" space separators
        '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000';
      /** Used to match empty string literals in compiled template source */

      var reEmptyStringLeading = /\b__p \+= '';/g,
        reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
        reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
      /**
       * Used to match ES6 template delimiters
       * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals
       */

      var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
      /** Used to match regexp flags from their coerced string values */

      var reFlags = /\w*$/;
      /** Used to detected named functions */

      var reFuncName = /^\s*function[ \n\r\t]+\w/;
      /** Used to match "interpolate" template delimiters */

      var reInterpolate = /<%=([\s\S]+?)%>/g;
      /** Used to match leading whitespace and zeros to be removed */

      var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
      /** Used to ensure capturing order of template delimiters */

      var reNoMatch = /($^)/;
      /** Used to detect functions containing a `this` reference */

      var reThis = /\bthis\b/;
      /** Used to match unescaped characters in compiled string literals */

      var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
      /** Used to assign default `context` object properties */

      var contextProps = [
        'Array',
        'Boolean',
        'Date',
        'Function',
        'Math',
        'Number',
        'Object',
        'RegExp',
        'String',
        '_',
        'attachEvent',
        'clearTimeout',
        'isFinite',
        'isNaN',
        'parseInt',
        'setTimeout',
      ];
      /** Used to make template sourceURLs easier to identify */

      var templateCounter = 0;
      /** `Object#toString` result shortcuts */

      var argsClass = '[object Arguments]',
        arrayClass = '[object Array]',
        boolClass = '[object Boolean]',
        dateClass = '[object Date]',
        funcClass = '[object Function]',
        numberClass = '[object Number]',
        objectClass = '[object Object]',
        regexpClass = '[object RegExp]',
        stringClass = '[object String]';
      /** Used to identify object classifications that `_.clone` supports */

      var cloneableClasses = {};
      cloneableClasses[funcClass] = false;
      cloneableClasses[argsClass] = cloneableClasses[
        arrayClass
      ] = cloneableClasses[boolClass] = cloneableClasses[
        dateClass
      ] = cloneableClasses[numberClass] = cloneableClasses[
        objectClass
      ] = cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
      /** Used as an internal `_.debounce` options object */

      var debounceOptions = {
        leading: false,
        maxWait: 0,
        trailing: false,
      };
      /** Used as the property descriptor for `__bindData__` */

      var descriptor = {
        configurable: false,
        enumerable: false,
        value: null,
        writable: false,
      };
      /** Used to determine if values are of the language type Object */

      var objectTypes = {
        boolean: false,
        function: true,
        object: true,
        number: false,
        string: false,
        undefined: false,
      };
      /** Used to escape characters for inclusion in compiled string literals */

      var stringEscapes = {
        '\\': '\\',
        "'": "'",
        '\n': 'n',
        '\r': 'r',
        '\t': 't',
        '\u2028': 'u2028',
        '\u2029': 'u2029',
      };
      /** Used as a reference to the global object */

      var root = (objectTypes[typeof window] && window) || this;
      /** Detect free variable `exports` */

      var freeExports = exports && !exports.nodeType && exports;
      /** Detect free variable `module` */

      var freeModule = module && !module.nodeType && module;
      /** Detect the popular CommonJS extension `module.exports` */

      var moduleExports =
        freeModule && freeModule.exports === freeExports && freeExports;
      /** Detect free variable `global` from Node.js or Browserified code and use it as `root` */

      var freeGlobal = objectTypes[typeof global$1] && global$1;

      if (
        freeGlobal &&
        (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)
      ) {
        root = freeGlobal;
      }
      /*--------------------------------------------------------------------------*/

      /**
       * The base implementation of `_.indexOf` without support for binary searches
       * or `fromIndex` constraints.
       *
       * @private
       * @param {Array} array The array to search.
       * @param {*} value The value to search for.
       * @param {number} [fromIndex=0] The index to search from.
       * @returns {number} Returns the index of the matched value or `-1`.
       */

      function baseIndexOf(array, value, fromIndex) {
        var index = (fromIndex || 0) - 1,
          length = array ? array.length : 0;

        while (++index < length) {
          if (array[index] === value) {
            return index;
          }
        }

        return -1;
      }
      /**
       * An implementation of `_.contains` for cache objects that mimics the return
       * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
       *
       * @private
       * @param {Object} cache The cache object to inspect.
       * @param {*} value The value to search for.
       * @returns {number} Returns `0` if `value` is found, else `-1`.
       */

      function cacheIndexOf(cache, value) {
        var type = typeof value;
        cache = cache.cache;

        if (type == 'boolean' || value == null) {
          return cache[value] ? 0 : -1;
        }

        if (type != 'number' && type != 'string') {
          type = 'object';
        }

        var key = type == 'number' ? value : keyPrefix + value;
        cache = (cache = cache[type]) && cache[key];
        return type == 'object'
          ? cache && baseIndexOf(cache, value) > -1
            ? 0
            : -1
          : cache
          ? 0
          : -1;
      }
      /**
       * Adds a given value to the corresponding cache object.
       *
       * @private
       * @param {*} value The value to add to the cache.
       */

      function cachePush(value) {
        var cache = this.cache,
          type = typeof value;

        if (type == 'boolean' || value == null) {
          cache[value] = true;
        } else {
          if (type != 'number' && type != 'string') {
            type = 'object';
          }

          var key = type == 'number' ? value : keyPrefix + value,
            typeCache = cache[type] || (cache[type] = {});

          if (type == 'object') {
            (typeCache[key] || (typeCache[key] = [])).push(value);
          } else {
            typeCache[key] = true;
          }
        }
      }
      /**
       * Used by `_.max` and `_.min` as the default callback when a given
       * collection is a string value.
       *
       * @private
       * @param {string} value The character to inspect.
       * @returns {number} Returns the code unit of given character.
       */

      function charAtCallback(value) {
        return value.charCodeAt(0);
      }
      /**
       * Used by `sortBy` to compare transformed `collection` elements, stable sorting
       * them in ascending order.
       *
       * @private
       * @param {Object} a The object to compare to `b`.
       * @param {Object} b The object to compare to `a`.
       * @returns {number} Returns the sort order indicator of `1` or `-1`.
       */

      function compareAscending(a, b) {
        var ac = a.criteria,
          bc = b.criteria,
          index = -1,
          length = ac.length;

        while (++index < length) {
          var value = ac[index],
            other = bc[index];

          if (value !== other) {
            if (value > other || typeof value == 'undefined') {
              return 1;
            }

            if (value < other || typeof other == 'undefined') {
              return -1;
            }
          }
        } // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
        // that causes it, under certain circumstances, to return the same value for
        // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247
        //
        // This also ensures a stable sort in V8 and other engines.
        // See http://code.google.com/p/v8/issues/detail?id=90

        return a.index - b.index;
      }
      /**
       * Creates a cache object to optimize linear searches of large arrays.
       *
       * @private
       * @param {Array} [array=[]] The array to search.
       * @returns {null|Object} Returns the cache object or `null` if caching should not be used.
       */

      function createCache(array) {
        var index = -1,
          length = array.length,
          first = array[0],
          mid = array[(length / 2) | 0],
          last = array[length - 1];

        if (
          first &&
          typeof first == 'object' &&
          mid &&
          typeof mid == 'object' &&
          last &&
          typeof last == 'object'
        ) {
          return false;
        }

        var cache = getObject();
        cache['false'] = cache['null'] = cache['true'] = cache[
          'undefined'
        ] = false;
        var result = getObject();
        result.array = array;
        result.cache = cache;
        result.push = cachePush;

        while (++index < length) {
          result.push(array[index]);
        }

        return result;
      }
      /**
       * Used by `template` to escape characters for inclusion in compiled
       * string literals.
       *
       * @private
       * @param {string} match The matched character to escape.
       * @returns {string} Returns the escaped character.
       */

      function escapeStringChar(match) {
        return '\\' + stringEscapes[match];
      }
      /**
       * Gets an array from the array pool or creates a new one if the pool is empty.
       *
       * @private
       * @returns {Array} The array from the pool.
       */

      function getArray() {
        return arrayPool.pop() || [];
      }
      /**
       * Gets an object from the object pool or creates a new one if the pool is empty.
       *
       * @private
       * @returns {Object} The object from the pool.
       */

      function getObject() {
        return (
          objectPool.pop() || {
            array: null,
            cache: null,
            criteria: null,
            false: false,
            index: 0,
            null: false,
            number: null,
            object: null,
            push: null,
            string: null,
            true: false,
            undefined: false,
            value: null,
          }
        );
      }
      /**
       * Releases the given array back to the array pool.
       *
       * @private
       * @param {Array} [array] The array to release.
       */

      function releaseArray(array) {
        array.length = 0;

        if (arrayPool.length < maxPoolSize) {
          arrayPool.push(array);
        }
      }
      /**
       * Releases the given object back to the object pool.
       *
       * @private
       * @param {Object} [object] The object to release.
       */

      function releaseObject(object) {
        var cache = object.cache;

        if (cache) {
          releaseObject(cache);
        }

        object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;

        if (objectPool.length < maxPoolSize) {
          objectPool.push(object);
        }
      }
      /**
       * Slices the `collection` from the `start` index up to, but not including,
       * the `end` index.
       *
       * Note: This function is used instead of `Array#slice` to support node lists
       * in IE < 9 and to ensure dense arrays are returned.
       *
       * @private
       * @param {Array|Object|string} collection The collection to slice.
       * @param {number} start The start index.
       * @param {number} end The end index.
       * @returns {Array} Returns the new array.
       */

      function slice(array, start, end) {
        start || (start = 0);

        if (typeof end == 'undefined') {
          end = array ? array.length : 0;
        }

        var index = -1,
          length = end - start || 0,
          result = Array(length < 0 ? 0 : length);

        while (++index < length) {
          result[index] = array[start + index];
        }

        return result;
      }
      /*--------------------------------------------------------------------------*/

      /**
       * Create a new `lodash` function using the given context object.
       *
       * @static
       * @memberOf _
       * @category Utilities
       * @param {Object} [context=root] The context object.
       * @returns {Function} Returns the `lodash` function.
       */

      function runInContext(context) {
        // Avoid issues with some ES3 environments that attempt to use values, named
        // after built-in constructors like `Object`, for the creation of literals.
        // ES5 clears this up by stating that literals must use built-in constructors.
        // See http://es5.github.io/#x11.1.5.
        context = context
          ? _.defaults(root.Object(), context, _.pick(root, contextProps))
          : root;
        /** Native constructor references */

        var Array = context.Array,
          Boolean = context.Boolean,
          Date = context.Date,
          Function = context.Function,
          Math = context.Math,
          Number = context.Number,
          Object = context.Object,
          RegExp = context.RegExp,
          String = context.String,
          TypeError = context.TypeError;
        /**
         * Used for `Array` method references.
         *
         * Normally `Array.prototype` would suffice, however, using an array literal
         * avoids issues in Narwhal.
         */

        var arrayRef = [];
        /** Used for native method references */

        var objectProto = Object.prototype;
        /** Used to restore the original `_` reference in `noConflict` */

        var oldDash = context._;
        /** Used to resolve the internal [[Class]] of values */

        var toString = objectProto.toString;
        /** Used to detect if a method is native */

        var reNative = RegExp(
          '^' +
            String(toString)
              .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
              .replace(/toString| for [^\]]+/g, '.*?') +
            '$'
        );
        /** Native method shortcuts */

        var ceil = Math.ceil,
          clearTimeout = context.clearTimeout,
          floor = Math.floor,
          fnToString = Function.prototype.toString,
          getPrototypeOf =
            isNative((getPrototypeOf = Object.getPrototypeOf)) &&
            getPrototypeOf,
          hasOwnProperty = objectProto.hasOwnProperty,
          push = arrayRef.push,
          setTimeout = context.setTimeout,
          splice = arrayRef.splice,
          unshift = arrayRef.unshift;
        /** Used to set meta data on functions */

        var defineProperty = (function() {
          // IE 8 only accepts DOM elements
          try {
            var o = {},
              func = isNative((func = Object.defineProperty)) && func,
              result = func(o, o, o) && func;
          } catch (e) {}

          return result;
        })();
        /* Native method shortcuts for methods with the same name as other `lodash` methods */

        var nativeCreate =
            isNative((nativeCreate = Object.create)) && nativeCreate,
          nativeIsArray =
            isNative((nativeIsArray = Array.isArray)) && nativeIsArray,
          nativeIsFinite = context.isFinite,
          nativeIsNaN = context.isNaN,
          nativeKeys = isNative((nativeKeys = Object.keys)) && nativeKeys,
          nativeMax = Math.max,
          nativeMin = Math.min,
          nativeParseInt = context.parseInt,
          nativeRandom = Math.random;
        /** Used to lookup a built-in constructor by [[Class]] */

        var ctorByClass = {};
        ctorByClass[arrayClass] = Array;
        ctorByClass[boolClass] = Boolean;
        ctorByClass[dateClass] = Date;
        ctorByClass[funcClass] = Function;
        ctorByClass[objectClass] = Object;
        ctorByClass[numberClass] = Number;
        ctorByClass[regexpClass] = RegExp;
        ctorByClass[stringClass] = String;
        /*--------------------------------------------------------------------------*/

        /**
         * Creates a `lodash` object which wraps the given value to enable intuitive
         * method chaining.
         *
         * In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
         * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
         * and `unshift`
         *
         * Chaining is supported in custom builds as long as the `value` method is
         * implicitly or explicitly included in the build.
         *
         * The chainable wrapper functions are:
         * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
         * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`,
         * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`,
         * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
         * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
         * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
         * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`,
         * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
         * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`,
         * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`,
         * and `zip`
         *
         * The non-chainable wrapper functions are:
         * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`,
         * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `has`, `identity`,
         * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
         * `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`,
         * `isObject`, `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`,
         * `lastIndexOf`, `mixin`, `noConflict`, `parseInt`, `pop`, `random`, `reduce`,
         * `reduceRight`, `result`, `shift`, `size`, `some`, `sortedIndex`, `runInContext`,
         * `template`, `unescape`, `uniqueId`, and `value`
         *
         * The wrapper functions `first` and `last` return wrapped values when `n` is
         * provided, otherwise they return unwrapped values.
         *
         * Explicit chaining can be enabled by using the `_.chain` method.
         *
         * @name _
         * @constructor
         * @category Chaining
         * @param {*} value The value to wrap in a `lodash` instance.
         * @returns {Object} Returns a `lodash` instance.
         * @example
         *
         * var wrapped = _([1, 2, 3]);
         *
         * // returns an unwrapped value
         * wrapped.reduce(function(sum, num) {
         *   return sum + num;
         * });
         * // => 6
         *
         * // returns a wrapped value
         * var squares = wrapped.map(function(num) {
         *   return num * num;
         * });
         *
         * _.isArray(squares);
         * // => false
         *
         * _.isArray(squares.value());
         * // => true
         */

        function lodash(value) {
          // don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
          return value &&
            typeof value == 'object' &&
            !isArray(value) &&
            hasOwnProperty.call(value, '__wrapped__')
            ? value
            : new lodashWrapper(value);
        }
        /**
         * A fast path for creating `lodash` wrapper objects.
         *
         * @private
         * @param {*} value The value to wrap in a `lodash` instance.
         * @param {boolean} chainAll A flag to enable chaining for all methods
         * @returns {Object} Returns a `lodash` instance.
         */

        function lodashWrapper(value, chainAll) {
          this.__chain__ = !!chainAll;
          this.__wrapped__ = value;
        } // ensure `new lodashWrapper` is an instance of `lodash`

        lodashWrapper.prototype = lodash.prototype;
        /**
         * An object used to flag environments features.
         *
         * @static
         * @memberOf _
         * @type Object
         */

        var support = (lodash.support = {});
        /**
         * Detect if functions can be decompiled by `Function#toString`
         * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps).
         *
         * @memberOf _.support
         * @type boolean
         */

        support.funcDecomp =
          !isNative(context.WinRTError) && reThis.test(runInContext);
        /**
         * Detect if `Function#name` is supported (all but IE).
         *
         * @memberOf _.support
         * @type boolean
         */

        support.funcNames = typeof Function.name == 'string';
        /**
         * By default, the template delimiters used by Lo-Dash are similar to those in
         * embedded Ruby (ERB). Change the following template settings to use alternative
         * delimiters.
         *
         * @static
         * @memberOf _
         * @type Object
         */

        lodash.templateSettings = {
          /**
           * Used to detect `data` property values to be HTML-escaped.
           *
           * @memberOf _.templateSettings
           * @type RegExp
           */
          escape: /<%-([\s\S]+?)%>/g,

          /**
           * Used to detect code to be evaluated.
           *
           * @memberOf _.templateSettings
           * @type RegExp
           */
          evaluate: /<%([\s\S]+?)%>/g,

          /**
           * Used to detect `data` property values to inject.
           *
           * @memberOf _.templateSettings
           * @type RegExp
           */
          interpolate: reInterpolate,

          /**
           * Used to reference the data object in the template text.
           *
           * @memberOf _.templateSettings
           * @type string
           */
          variable: '',

          /**
           * Used to import variables into the compiled template.
           *
           * @memberOf _.templateSettings
           * @type Object
           */
          imports: {
            /**
             * A reference to the `lodash` function.
             *
             * @memberOf _.templateSettings.imports
             * @type Function
             */
            _: lodash,
          },
        };
        /*--------------------------------------------------------------------------*/

        /**
         * The base implementation of `_.bind` that creates the bound function and
         * sets its meta data.
         *
         * @private
         * @param {Array} bindData The bind data array.
         * @returns {Function} Returns the new bound function.
         */

        function baseBind(bindData) {
          var func = bindData[0],
            partialArgs = bindData[2],
            thisArg = bindData[4];

          function bound() {
            // `Function#bind` spec
            // http://es5.github.io/#x15.3.4.5
            if (partialArgs) {
              // avoid `arguments` object deoptimizations by using `slice` instead
              // of `Array.prototype.slice.call` and not assigning `arguments` to a
              // variable as a ternary expression
              var args = slice(partialArgs);
              push.apply(args, arguments);
            } // mimic the constructor's `return` behavior
            // http://es5.github.io/#x13.2.2

            if (this instanceof bound) {
              // ensure `new bound` is an instance of `func`
              var thisBinding = baseCreate(func.prototype),
                result = func.apply(thisBinding, args || arguments);
              return isObject(result) ? result : thisBinding;
            }

            return func.apply(thisArg, args || arguments);
          }

          setBindData(bound, bindData);
          return bound;
        }
        /**
         * The base implementation of `_.clone` without argument juggling or support
         * for `thisArg` binding.
         *
         * @private
         * @param {*} value The value to clone.
         * @param {boolean} [isDeep=false] Specify a deep clone.
         * @param {Function} [callback] The function to customize cloning values.
         * @param {Array} [stackA=[]] Tracks traversed source objects.
         * @param {Array} [stackB=[]] Associates clones with source counterparts.
         * @returns {*} Returns the cloned value.
         */

        function baseClone(value, isDeep, callback, stackA, stackB) {
          if (callback) {
            var result = callback(value);

            if (typeof result != 'undefined') {
              return result;
            }
          } // inspect [[Class]]

          var isObj = isObject(value);

          if (isObj) {
            var className = toString.call(value);

            if (!cloneableClasses[className]) {
              return value;
            }

            var ctor = ctorByClass[className];

            switch (className) {
              case boolClass:
              case dateClass:
                return new ctor(+value);

              case numberClass:
              case stringClass:
                return new ctor(value);

              case regexpClass:
                result = ctor(value.source, reFlags.exec(value));
                result.lastIndex = value.lastIndex;
                return result;
            }
          } else {
            return value;
          }

          var isArr = isArray(value);

          if (isDeep) {
            // check for circular references and return corresponding clone
            var initedStack = !stackA;
            stackA || (stackA = getArray());
            stackB || (stackB = getArray());
            var length = stackA.length;

            while (length--) {
              if (stackA[length] == value) {
                return stackB[length];
              }
            }

            result = isArr ? ctor(value.length) : {};
          } else {
            result = isArr ? slice(value) : assign({}, value);
          } // add array properties assigned by `RegExp#exec`

          if (isArr) {
            if (hasOwnProperty.call(value, 'index')) {
              result.index = value.index;
            }

            if (hasOwnProperty.call(value, 'input')) {
              result.input = value.input;
            }
          } // exit for shallow clone

          if (!isDeep) {
            return result;
          } // add the source value to the stack of traversed objects
          // and associate it with its clone

          stackA.push(value);
          stackB.push(result); // recursively populate clone (susceptible to call stack limits)

          (isArr ? forEach : forOwn)(value, function(objValue, key) {
            result[key] = baseClone(objValue, isDeep, callback, stackA, stackB);
          });

          if (initedStack) {
            releaseArray(stackA);
            releaseArray(stackB);
          }

          return result;
        }
        /**
         * The base implementation of `_.create` without support for assigning
         * properties to the created object.
         *
         * @private
         * @param {Object} prototype The object to inherit from.
         * @returns {Object} Returns the new object.
         */

        function baseCreate(prototype, properties) {
          return isObject(prototype) ? nativeCreate(prototype) : {};
        } // fallback for browsers without `Object.create`

        if (!nativeCreate) {
          baseCreate = (function() {
            function Object() {}

            return function(prototype) {
              if (isObject(prototype)) {
                Object.prototype = prototype;
                var result = new Object();
                Object.prototype = null;
              }

              return result || context.Object();
            };
          })();
        }
        /**
         * The base implementation of `_.createCallback` without support for creating
         * "_.pluck" or "_.where" style callbacks.
         *
         * @private
         * @param {*} [func=identity] The value to convert to a callback.
         * @param {*} [thisArg] The `this` binding of the created callback.
         * @param {number} [argCount] The number of arguments the callback accepts.
         * @returns {Function} Returns a callback function.
         */

        function baseCreateCallback(func, thisArg, argCount) {
          if (typeof func != 'function') {
            return identity;
          } // exit early for no `thisArg` or already bound by `Function#bind`

          if (typeof thisArg == 'undefined' || !('prototype' in func)) {
            return func;
          }

          var bindData = func.__bindData__;

          if (typeof bindData == 'undefined') {
            if (support.funcNames) {
              bindData = !func.name;
            }

            bindData = bindData || !support.funcDecomp;

            if (!bindData) {
              var source = fnToString.call(func);

              if (!support.funcNames) {
                bindData = !reFuncName.test(source);
              }

              if (!bindData) {
                // checks if `func` references the `this` keyword and stores the result
                bindData = reThis.test(source);
                setBindData(func, bindData);
              }
            }
          } // exit early if there are no `this` references or `func` is bound

          if (bindData === false || (bindData !== true && bindData[1] & 1)) {
            return func;
          }

          switch (argCount) {
            case 1:
              return function(value) {
                return func.call(thisArg, value);
              };

            case 2:
              return function(a, b) {
                return func.call(thisArg, a, b);
              };

            case 3:
              return function(value, index, collection) {
                return func.call(thisArg, value, index, collection);
              };

            case 4:
              return function(accumulator, value, index, collection) {
                return func.call(
                  thisArg,
                  accumulator,
                  value,
                  index,
                  collection
                );
              };
          }

          return bind(func, thisArg);
        }
        /**
         * The base implementation of `createWrapper` that creates the wrapper and
         * sets its meta data.
         *
         * @private
         * @param {Array} bindData The bind data array.
         * @returns {Function} Returns the new function.
         */

        function baseCreateWrapper(bindData) {
          var func = bindData[0],
            bitmask = bindData[1],
            partialArgs = bindData[2],
            partialRightArgs = bindData[3],
            thisArg = bindData[4],
            arity = bindData[5];
          var isBind = bitmask & 1,
            isBindKey = bitmask & 2,
            isCurry = bitmask & 4,
            isCurryBound = bitmask & 8,
            key = func;

          function bound() {
            var thisBinding = isBind ? thisArg : this;

            if (partialArgs) {
              var args = slice(partialArgs);
              push.apply(args, arguments);
            }

            if (partialRightArgs || isCurry) {
              args || (args = slice(arguments));

              if (partialRightArgs) {
                push.apply(args, partialRightArgs);
              }

              if (isCurry && args.length < arity) {
                bitmask |= 16 & ~32;
                return baseCreateWrapper([
                  func,
                  isCurryBound ? bitmask : bitmask & ~3,
                  args,
                  null,
                  thisArg,
                  arity,
                ]);
              }
            }

            args || (args = arguments);

            if (isBindKey) {
              func = thisBinding[key];
            }

            if (this instanceof bound) {
              thisBinding = baseCreate(func.prototype);
              var result = func.apply(thisBinding, args);
              return isObject(result) ? result : thisBinding;
            }

            return func.apply(thisBinding, args);
          }

          setBindData(bound, bindData);
          return bound;
        }
        /**
         * The base implementation of `_.difference` that accepts a single array
         * of values to exclude.
         *
         * @private
         * @param {Array} array The array to process.
         * @param {Array} [values] The array of values to exclude.
         * @returns {Array} Returns a new array of filtered values.
         */

        function baseDifference(array, values) {
          var index = -1,
            indexOf = getIndexOf(),
            length = array ? array.length : 0,
            isLarge = length >= largeArraySize && indexOf === baseIndexOf,
            result = [];

          if (isLarge) {
            var cache = createCache(values);

            if (cache) {
              indexOf = cacheIndexOf;
              values = cache;
            } else {
              isLarge = false;
            }
          }

          while (++index < length) {
            var value = array[index];

            if (indexOf(values, value) < 0) {
              result.push(value);
            }
          }

          if (isLarge) {
            releaseObject(values);
          }

          return result;
        }
        /**
         * The base implementation of `_.flatten` without support for callback
         * shorthands or `thisArg` binding.
         *
         * @private
         * @param {Array} array The array to flatten.
         * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
         * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects.
         * @param {number} [fromIndex=0] The index to start from.
         * @returns {Array} Returns a new flattened array.
         */

        function baseFlatten(array, isShallow, isStrict, fromIndex) {
          var index = (fromIndex || 0) - 1,
            length = array ? array.length : 0,
            result = [];

          while (++index < length) {
            var value = array[index];

            if (
              value &&
              typeof value == 'object' &&
              typeof value.length == 'number' &&
              (isArray(value) || isArguments(value))
            ) {
              // recursively flatten arrays (susceptible to call stack limits)
              if (!isShallow) {
                value = baseFlatten(value, isShallow, isStrict);
              }

              var valIndex = -1,
                valLength = value.length,
                resIndex = result.length;
              result.length += valLength;

              while (++valIndex < valLength) {
                result[resIndex++] = value[valIndex];
              }
            } else if (!isStrict) {
              result.push(value);
            }
          }

          return result;
        }
        /**
         * The base implementation of `_.isEqual`, without support for `thisArg` binding,
         * that allows partial "_.where" style comparisons.
         *
         * @private
         * @param {*} a The value to compare.
         * @param {*} b The other value to compare.
         * @param {Function} [callback] The function to customize comparing values.
         * @param {Function} [isWhere=false] A flag to indicate performing partial comparisons.
         * @param {Array} [stackA=[]] Tracks traversed `a` objects.
         * @param {Array} [stackB=[]] Tracks traversed `b` objects.
         * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
         */

        function baseIsEqual(a, b, callback, isWhere, stackA, stackB) {
          // used to indicate that when comparing objects, `a` has at least the properties of `b`
          if (callback) {
            var result = callback(a, b);

            if (typeof result != 'undefined') {
              return !!result;
            }
          } // exit early for identical values

          if (a === b) {
            // treat `+0` vs. `-0` as not equal
            return a !== 0 || 1 / a == 1 / b;
          }

          var type = typeof a,
            otherType = typeof b; // exit early for unlike primitive values

          if (
            a === a &&
            !(a && objectTypes[type]) &&
            !(b && objectTypes[otherType])
          ) {
            return false;
          } // exit early for `null` and `undefined` avoiding ES3's Function#call behavior
          // http://es5.github.io/#x15.3.4.4

          if (a == null || b == null) {
            return a === b;
          } // compare [[Class]] names

          var className = toString.call(a),
            otherClass = toString.call(b);

          if (className == argsClass) {
            className = objectClass;
          }

          if (otherClass == argsClass) {
            otherClass = objectClass;
          }

          if (className != otherClass) {
            return false;
          }

          switch (className) {
            case boolClass:
            case dateClass:
              // coerce dates and booleans to numbers, dates to milliseconds and booleans
              // to `1` or `0` treating invalid dates coerced to `NaN` as not equal
              return +a == +b;

            case numberClass:
              // treat `NaN` vs. `NaN` as equal
              return a != +a
                ? b != +b // but treat `+0` vs. `-0` as not equal
                : a == 0
                ? 1 / a == 1 / b
                : a == +b;

            case regexpClass:
            case stringClass:
              // coerce regexes to strings (http://es5.github.io/#x15.10.6.4)
              // treat string primitives and their corresponding object instances as equal
              return a == String(b);
          }

          var isArr = className == arrayClass;

          if (!isArr) {
            // unwrap any `lodash` wrapped values
            var aWrapped = hasOwnProperty.call(a, '__wrapped__'),
              bWrapped = hasOwnProperty.call(b, '__wrapped__');

            if (aWrapped || bWrapped) {
              return baseIsEqual(
                aWrapped ? a.__wrapped__ : a,
                bWrapped ? b.__wrapped__ : b,
                callback,
                isWhere,
                stackA,
                stackB
              );
            } // exit for functions and DOM nodes

            if (className != objectClass) {
              return false;
            } // in older versions of Opera, `arguments` objects have `Array` constructors

            var ctorA = a.constructor,
              ctorB = b.constructor; // non `Object` object instances with different constructors are not equal

            if (
              ctorA != ctorB &&
              !(
                isFunction(ctorA) &&
                ctorA instanceof ctorA &&
                isFunction(ctorB) &&
                ctorB instanceof ctorB
              ) &&
              'constructor' in a &&
              'constructor' in b
            ) {
              return false;
            }
          } // assume cyclic structures are equal
          // the algorithm for detecting cyclic structures is adapted from ES 5.1
          // section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)

          var initedStack = !stackA;
          stackA || (stackA = getArray());
          stackB || (stackB = getArray());
          var length = stackA.length;

          while (length--) {
            if (stackA[length] == a) {
              return stackB[length] == b;
            }
          }

          var size = 0;
          result = true; // add `a` and `b` to the stack of traversed objects

          stackA.push(a);
          stackB.push(b); // recursively compare objects and arrays (susceptible to call stack limits)

          if (isArr) {
            // compare lengths to determine if a deep comparison is necessary
            length = a.length;
            size = b.length;
            result = size == length;

            if (result || isWhere) {
              // deep compare the contents, ignoring non-numeric properties
              while (size--) {
                var index = length,
                  value = b[size];

                if (isWhere) {
                  while (index--) {
                    if (
                      (result = baseIsEqual(
                        a[index],
                        value,
                        callback,
                        isWhere,
                        stackA,
                        stackB
                      ))
                    ) {
                      break;
                    }
                  }
                } else if (
                  !(result = baseIsEqual(
                    a[size],
                    value,
                    callback,
                    isWhere,
                    stackA,
                    stackB
                  ))
                ) {
                  break;
                }
              }
            }
          } else {
            // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
            // which, in this case, is more costly
            forIn(b, function(value, key, b) {
              if (hasOwnProperty.call(b, key)) {
                // count the number of properties.
                size++; // deep compare each property value.

                return (result =
                  hasOwnProperty.call(a, key) &&
                  baseIsEqual(
                    a[key],
                    value,
                    callback,
                    isWhere,
                    stackA,
                    stackB
                  ));
              }
            });

            if (result && !isWhere) {
              // ensure both objects have the same number of properties
              forIn(a, function(value, key, a) {
                if (hasOwnProperty.call(a, key)) {
                  // `size` will be `-1` if `a` has more properties than `b`
                  return (result = --size > -1);
                }
              });
            }
          }

          stackA.pop();
          stackB.pop();

          if (initedStack) {
            releaseArray(stackA);
            releaseArray(stackB);
          }

          return result;
        }
        /**
         * The base implementation of `_.merge` without argument juggling or support
         * for `thisArg` binding.
         *
         * @private
         * @param {Object} object The destination object.
         * @param {Object} source The source object.
         * @param {Function} [callback] The function to customize merging properties.
         * @param {Array} [stackA=[]] Tracks traversed source objects.
         * @param {Array} [stackB=[]] Associates values with source counterparts.
         */

        function baseMerge(object, source, callback, stackA, stackB) {
          (isArray(source) ? forEach : forOwn)(source, function(source, key) {
            var found,
              isArr,
              result = source,
              value = object[key];

            if (
              source &&
              ((isArr = isArray(source)) || isPlainObject(source))
            ) {
              // avoid merging previously merged cyclic sources
              var stackLength = stackA.length;

              while (stackLength--) {
                if ((found = stackA[stackLength] == source)) {
                  value = stackB[stackLength];
                  break;
                }
              }

              if (!found) {
                var isShallow;

                if (callback) {
                  result = callback(value, source);

                  if ((isShallow = typeof result != 'undefined')) {
                    value = result;
                  }
                }

                if (!isShallow) {
                  value = isArr
                    ? isArray(value)
                      ? value
                      : []
                    : isPlainObject(value)
                    ? value
                    : {};
                } // add `source` and associated `value` to the stack of traversed objects

                stackA.push(source);
                stackB.push(value); // recursively merge objects and arrays (susceptible to call stack limits)

                if (!isShallow) {
                  baseMerge(value, source, callback, stackA, stackB);
                }
              }
            } else {
              if (callback) {
                result = callback(value, source);

                if (typeof result == 'undefined') {
                  result = source;
                }
              }

              if (typeof result != 'undefined') {
                value = result;
              }
            }

            object[key] = value;
          });
        }
        /**
         * The base implementation of `_.random` without argument juggling or support
         * for returning floating-point numbers.
         *
         * @private
         * @param {number} min The minimum possible value.
         * @param {number} max The maximum possible value.
         * @returns {number} Returns a random number.
         */

        function baseRandom(min, max) {
          return min + floor(nativeRandom() * (max - min + 1));
        }
        /**
         * The base implementation of `_.uniq` without support for callback shorthands
         * or `thisArg` binding.
         *
         * @private
         * @param {Array} array The array to process.
         * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
         * @param {Function} [callback] The function called per iteration.
         * @returns {Array} Returns a duplicate-value-free array.
         */

        function baseUniq(array, isSorted, callback) {
          var index = -1,
            indexOf = getIndexOf(),
            length = array ? array.length : 0,
            result = [];
          var isLarge =
              !isSorted && length >= largeArraySize && indexOf === baseIndexOf,
            seen = callback || isLarge ? getArray() : result;

          if (isLarge) {
            var cache = createCache(seen);
            indexOf = cacheIndexOf;
            seen = cache;
          }

          while (++index < length) {
            var value = array[index],
              computed = callback ? callback(value, index, array) : value;

            if (
              isSorted
                ? !index || seen[seen.length - 1] !== computed
                : indexOf(seen, computed) < 0
            ) {
              if (callback || isLarge) {
                seen.push(computed);
              }

              result.push(value);
            }
          }

          if (isLarge) {
            releaseArray(seen.array);
            releaseObject(seen);
          } else if (callback) {
            releaseArray(seen);
          }

          return result;
        }
        /**
         * Creates a function that aggregates a collection, creating an object composed
         * of keys generated from the results of running each element of the collection
         * through a callback. The given `setter` function sets the keys and values
         * of the composed object.
         *
         * @private
         * @param {Function} setter The setter function.
         * @returns {Function} Returns the new aggregator function.
         */

        function createAggregator(setter) {
          return function(collection, callback, thisArg) {
            var result = {};
            callback = lodash.createCallback(callback, thisArg, 3);
            var index = -1,
              length = collection ? collection.length : 0;

            if (typeof length == 'number') {
              while (++index < length) {
                var value = collection[index];
                setter(
                  result,
                  value,
                  callback(value, index, collection),
                  collection
                );
              }
            } else {
              forOwn(collection, function(value, key, collection) {
                setter(
                  result,
                  value,
                  callback(value, key, collection),
                  collection
                );
              });
            }

            return result;
          };
        }
        /**
         * Creates a function that, when called, either curries or invokes `func`
         * with an optional `this` binding and partially applied arguments.
         *
         * @private
         * @param {Function|string} func The function or method name to reference.
         * @param {number} bitmask The bitmask of method flags to compose.
         *  The bitmask may be composed of the following flags:
         *  1 - `_.bind`
         *  2 - `_.bindKey`
         *  4 - `_.curry`
         *  8 - `_.curry` (bound)
         *  16 - `_.partial`
         *  32 - `_.partialRight`
         * @param {Array} [partialArgs] An array of arguments to prepend to those
         *  provided to the new function.
         * @param {Array} [partialRightArgs] An array of arguments to append to those
         *  provided to the new function.
         * @param {*} [thisArg] The `this` binding of `func`.
         * @param {number} [arity] The arity of `func`.
         * @returns {Function} Returns the new function.
         */

        function createWrapper(
          func,
          bitmask,
          partialArgs,
          partialRightArgs,
          thisArg,
          arity
        ) {
          var isBind = bitmask & 1,
            isBindKey = bitmask & 2,
            isCurry = bitmask & 4,
            isPartial = bitmask & 16,
            isPartialRight = bitmask & 32;

          if (!isBindKey && !isFunction(func)) {
            throw new TypeError();
          }

          if (isPartial && !partialArgs.length) {
            bitmask &= ~16;
            isPartial = partialArgs = false;
          }

          if (isPartialRight && !partialRightArgs.length) {
            bitmask &= ~32;
            isPartialRight = partialRightArgs = false;
          }

          var bindData = func && func.__bindData__;

          if (bindData && bindData !== true) {
            // clone `bindData`
            bindData = slice(bindData);

            if (bindData[2]) {
              bindData[2] = slice(bindData[2]);
            }

            if (bindData[3]) {
              bindData[3] = slice(bindData[3]);
            } // set `thisBinding` is not previously bound

            if (isBind && !(bindData[1] & 1)) {
              bindData[4] = thisArg;
            } // set if previously bound but not currently (subsequent curried functions)

            if (!isBind && bindData[1] & 1) {
              bitmask |= 8;
            } // set curried arity if not yet set

            if (isCurry && !(bindData[1] & 4)) {
              bindData[5] = arity;
            } // append partial left arguments

            if (isPartial) {
              push.apply(bindData[2] || (bindData[2] = []), partialArgs);
            } // append partial right arguments

            if (isPartialRight) {
              unshift.apply(
                bindData[3] || (bindData[3] = []),
                partialRightArgs
              );
            } // merge flags

            bindData[1] |= bitmask;
            return createWrapper.apply(null, bindData);
          } // fast path for `_.bind`

          var creater =
            bitmask == 1 || bitmask === 17 ? baseBind : baseCreateWrapper;
          return creater([
            func,
            bitmask,
            partialArgs,
            partialRightArgs,
            thisArg,
            arity,
          ]);
        }
        /**
         * Used by `escape` to convert characters to HTML entities.
         *
         * @private
         * @param {string} match The matched character to escape.
         * @returns {string} Returns the escaped character.
         */

        function escapeHtmlChar(match) {
          return htmlEscapes[match];
        }
        /**
         * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
         * customized, this method returns the custom method, otherwise it returns
         * the `baseIndexOf` function.
         *
         * @private
         * @returns {Function} Returns the "indexOf" function.
         */

        function getIndexOf() {
          var result =
            (result = lodash.indexOf) === indexOf ? baseIndexOf : result;
          return result;
        }
        /**
         * Checks if `value` is a native function.
         *
         * @private
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
         */

        function isNative(value) {
          return typeof value == 'function' && reNative.test(value);
        }
        /**
         * Sets `this` binding data on a given function.
         *
         * @private
         * @param {Function} func The function to set data on.
         * @param {Array} value The data array to set.
         */

        var setBindData = !defineProperty
          ? noop
          : function(func, value) {
              descriptor.value = value;
              defineProperty(func, '__bindData__', descriptor);
              descriptor.value = null;
            };
        /**
         * A fallback implementation of `isPlainObject` which checks if a given value
         * is an object created by the `Object` constructor, assuming objects created
         * by the `Object` constructor have no inherited enumerable properties and that
         * there are no `Object.prototype` extensions.
         *
         * @private
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
         */

        function shimIsPlainObject(value) {
          var ctor, result; // avoid non Object objects, `arguments` objects, and DOM elements

          if (
            !(value && toString.call(value) == objectClass) ||
            ((ctor = value.constructor),
            isFunction(ctor) && !(ctor instanceof ctor))
          ) {
            return false;
          } // In most environments an object's own properties are iterated before
          // its inherited properties. If the last iterated property is an object's
          // own property then there are no inherited enumerable properties.

          forIn(value, function(value, key) {
            result = key;
          });
          return (
            typeof result == 'undefined' || hasOwnProperty.call(value, result)
          );
        }
        /**
         * Used by `unescape` to convert HTML entities to characters.
         *
         * @private
         * @param {string} match The matched character to unescape.
         * @returns {string} Returns the unescaped character.
         */

        function unescapeHtmlChar(match) {
          return htmlUnescapes[match];
        }
        /*--------------------------------------------------------------------------*/

        /**
         * Checks if `value` is an `arguments` object.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is an `arguments` object, else `false`.
         * @example
         *
         * (function() { return _.isArguments(arguments); })(1, 2, 3);
         * // => true
         *
         * _.isArguments([1, 2, 3]);
         * // => false
         */

        function isArguments(value) {
          return (
            (value &&
              typeof value == 'object' &&
              typeof value.length == 'number' &&
              toString.call(value) == argsClass) ||
            false
          );
        }
        /**
         * Checks if `value` is an array.
         *
         * @static
         * @memberOf _
         * @type Function
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is an array, else `false`.
         * @example
         *
         * (function() { return _.isArray(arguments); })();
         * // => false
         *
         * _.isArray([1, 2, 3]);
         * // => true
         */

        var isArray =
          nativeIsArray ||
          function(value) {
            return (
              (value &&
                typeof value == 'object' &&
                typeof value.length == 'number' &&
                toString.call(value) == arrayClass) ||
              false
            );
          };
        /**
         * A fallback implementation of `Object.keys` which produces an array of the
         * given object's own enumerable property names.
         *
         * @private
         * @type Function
         * @param {Object} object The object to inspect.
         * @returns {Array} Returns an array of property names.
         */

        var shimKeys = function(object) {
          var index,
            iterable = object,
            result = [];
          if (!iterable) return result;
          if (!objectTypes[typeof object]) return result;

          for (index in iterable) {
            if (hasOwnProperty.call(iterable, index)) {
              result.push(index);
            }
          }

          return result;
        };
        /**
         * Creates an array composed of the own enumerable property names of an object.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to inspect.
         * @returns {Array} Returns an array of property names.
         * @example
         *
         * _.keys({ 'one': 1, 'two': 2, 'three': 3 });
         * // => ['one', 'two', 'three'] (property order is not guaranteed across environments)
         */

        var keys = !nativeKeys
          ? shimKeys
          : function(object) {
              if (!isObject(object)) {
                return [];
              }

              return nativeKeys(object);
            };
        /**
         * Used to convert characters to HTML entities:
         *
         * Though the `>` character is escaped for symmetry, characters like `>` and `/`
         * don't require escaping in HTML and have no special meaning unless they're part
         * of a tag or an unquoted attribute value.
         * http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
         */

        var htmlEscapes = {
          '&': '&amp;',
          '<': '&lt;',
          '>': '&gt;',
          '"': '&quot;',
          "'": '&#39;',
        };
        /** Used to convert HTML entities to characters */

        var htmlUnescapes = invert(htmlEscapes);
        /** Used to match HTML entities and HTML characters */

        var reEscapedHtml = RegExp(
            '(' + keys(htmlUnescapes).join('|') + ')',
            'g'
          ),
          reUnescapedHtml = RegExp('[' + keys(htmlEscapes).join('') + ']', 'g');
        /*--------------------------------------------------------------------------*/

        /**
         * Assigns own enumerable properties of source object(s) to the destination
         * object. Subsequent sources will overwrite property assignments of previous
         * sources. If a callback is provided it will be executed to produce the
         * assigned values. The callback is bound to `thisArg` and invoked with two
         * arguments; (objectValue, sourceValue).
         *
         * @static
         * @memberOf _
         * @type Function
         * @alias extend
         * @category Objects
         * @param {Object} object The destination object.
         * @param {...Object} [source] The source objects.
         * @param {Function} [callback] The function to customize assigning values.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns the destination object.
         * @example
         *
         * _.assign({ 'name': 'fred' }, { 'employer': 'slate' });
         * // => { 'name': 'fred', 'employer': 'slate' }
         *
         * var defaults = _.partialRight(_.assign, function(a, b) {
         *   return typeof a == 'undefined' ? b : a;
         * });
         *
         * var object = { 'name': 'barney' };
         * defaults(object, { 'name': 'fred', 'employer': 'slate' });
         * // => { 'name': 'barney', 'employer': 'slate' }
         */

        var assign = function(object, source, guard) {
          var index,
            iterable = object,
            result = iterable;
          if (!iterable) return result;
          var args = arguments,
            argsIndex = 0,
            argsLength = typeof guard == 'number' ? 2 : args.length;

          if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
            var callback = baseCreateCallback(
              args[--argsLength - 1],
              args[argsLength--],
              2
            );
          } else if (
            argsLength > 2 &&
            typeof args[argsLength - 1] == 'function'
          ) {
            callback = args[--argsLength];
          }

          while (++argsIndex < argsLength) {
            iterable = args[argsIndex];

            if (iterable && objectTypes[typeof iterable]) {
              var ownIndex = -1,
                ownProps = objectTypes[typeof iterable] && keys(iterable),
                length = ownProps ? ownProps.length : 0;

              while (++ownIndex < length) {
                index = ownProps[ownIndex];
                result[index] = callback
                  ? callback(result[index], iterable[index])
                  : iterable[index];
              }
            }
          }

          return result;
        };
        /**
         * Creates a clone of `value`. If `isDeep` is `true` nested objects will also
         * be cloned, otherwise they will be assigned by reference. If a callback
         * is provided it will be executed to produce the cloned values. If the
         * callback returns `undefined` cloning will be handled by the method instead.
         * The callback is bound to `thisArg` and invoked with one argument; (value).
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to clone.
         * @param {boolean} [isDeep=false] Specify a deep clone.
         * @param {Function} [callback] The function to customize cloning values.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the cloned value.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * var shallow = _.clone(characters);
         * shallow[0] === characters[0];
         * // => true
         *
         * var deep = _.clone(characters, true);
         * deep[0] === characters[0];
         * // => false
         *
         * _.mixin({
         *   'clone': _.partialRight(_.clone, function(value) {
         *     return _.isElement(value) ? value.cloneNode(false) : undefined;
         *   })
         * });
         *
         * var clone = _.clone(document.body);
         * clone.childNodes.length;
         * // => 0
         */

        function clone(value, isDeep, callback, thisArg) {
          // allows working with "Collections" methods without using their `index`
          // and `collection` arguments for `isDeep` and `callback`
          if (typeof isDeep != 'boolean' && isDeep != null) {
            thisArg = callback;
            callback = isDeep;
            isDeep = false;
          }

          return baseClone(
            value,
            isDeep,
            typeof callback == 'function' &&
              baseCreateCallback(callback, thisArg, 1)
          );
        }
        /**
         * Creates a deep clone of `value`. If a callback is provided it will be
         * executed to produce the cloned values. If the callback returns `undefined`
         * cloning will be handled by the method instead. The callback is bound to
         * `thisArg` and invoked with one argument; (value).
         *
         * Note: This method is loosely based on the structured clone algorithm. Functions
         * and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
         * objects created by constructors other than `Object` are cloned to plain `Object` objects.
         * See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to deep clone.
         * @param {Function} [callback] The function to customize cloning values.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the deep cloned value.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * var deep = _.cloneDeep(characters);
         * deep[0] === characters[0];
         * // => false
         *
         * var view = {
         *   'label': 'docs',
         *   'node': element
         * };
         *
         * var clone = _.cloneDeep(view, function(value) {
         *   return _.isElement(value) ? value.cloneNode(true) : undefined;
         * });
         *
         * clone.node == view.node;
         * // => false
         */

        function cloneDeep(value, callback, thisArg) {
          return baseClone(
            value,
            true,
            typeof callback == 'function' &&
              baseCreateCallback(callback, thisArg, 1)
          );
        }
        /**
         * Creates an object that inherits from the given `prototype` object. If a
         * `properties` object is provided its own enumerable properties are assigned
         * to the created object.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} prototype The object to inherit from.
         * @param {Object} [properties] The properties to assign to the object.
         * @returns {Object} Returns the new object.
         * @example
         *
         * function Shape() {
         *   this.x = 0;
         *   this.y = 0;
         * }
         *
         * function Circle() {
         *   Shape.call(this);
         * }
         *
         * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle });
         *
         * var circle = new Circle;
         * circle instanceof Circle;
         * // => true
         *
         * circle instanceof Shape;
         * // => true
         */

        function create(prototype, properties) {
          var result = baseCreate(prototype);
          return properties ? assign(result, properties) : result;
        }
        /**
         * Assigns own enumerable properties of source object(s) to the destination
         * object for all destination properties that resolve to `undefined`. Once a
         * property is set, additional defaults of the same property will be ignored.
         *
         * @static
         * @memberOf _
         * @type Function
         * @category Objects
         * @param {Object} object The destination object.
         * @param {...Object} [source] The source objects.
         * @param- {Object} [guard] Allows working with `_.reduce` without using its
         *  `key` and `object` arguments as sources.
         * @returns {Object} Returns the destination object.
         * @example
         *
         * var object = { 'name': 'barney' };
         * _.defaults(object, { 'name': 'fred', 'employer': 'slate' });
         * // => { 'name': 'barney', 'employer': 'slate' }
         */

        var defaults = function(object, source, guard) {
          var index,
            iterable = object,
            result = iterable;
          if (!iterable) return result;
          var args = arguments,
            argsIndex = 0,
            argsLength = typeof guard == 'number' ? 2 : args.length;

          while (++argsIndex < argsLength) {
            iterable = args[argsIndex];

            if (iterable && objectTypes[typeof iterable]) {
              var ownIndex = -1,
                ownProps = objectTypes[typeof iterable] && keys(iterable),
                length = ownProps ? ownProps.length : 0;

              while (++ownIndex < length) {
                index = ownProps[ownIndex];
                if (typeof result[index] == 'undefined')
                  result[index] = iterable[index];
              }
            }
          }

          return result;
        };
        /**
         * This method is like `_.findIndex` except that it returns the key of the
         * first element that passes the callback check, instead of the element itself.
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to search.
         * @param {Function|Object|string} [callback=identity] The function called per
         *  iteration. If a property name or object is provided it will be used to
         *  create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {string|undefined} Returns the key of the found element, else `undefined`.
         * @example
         *
         * var characters = {
         *   'barney': {  'age': 36, 'blocked': false },
         *   'fred': {    'age': 40, 'blocked': true },
         *   'pebbles': { 'age': 1,  'blocked': false }
         * };
         *
         * _.findKey(characters, function(chr) {
         *   return chr.age < 40;
         * });
         * // => 'barney' (property order is not guaranteed across environments)
         *
         * // using "_.where" callback shorthand
         * _.findKey(characters, { 'age': 1 });
         * // => 'pebbles'
         *
         * // using "_.pluck" callback shorthand
         * _.findKey(characters, 'blocked');
         * // => 'fred'
         */

        function findKey(object, callback, thisArg) {
          var result;
          callback = lodash.createCallback(callback, thisArg, 3);
          forOwn(object, function(value, key, object) {
            if (callback(value, key, object)) {
              result = key;
              return false;
            }
          });
          return result;
        }
        /**
         * This method is like `_.findKey` except that it iterates over elements
         * of a `collection` in the opposite order.
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to search.
         * @param {Function|Object|string} [callback=identity] The function called per
         *  iteration. If a property name or object is provided it will be used to
         *  create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {string|undefined} Returns the key of the found element, else `undefined`.
         * @example
         *
         * var characters = {
         *   'barney': {  'age': 36, 'blocked': true },
         *   'fred': {    'age': 40, 'blocked': false },
         *   'pebbles': { 'age': 1,  'blocked': true }
         * };
         *
         * _.findLastKey(characters, function(chr) {
         *   return chr.age < 40;
         * });
         * // => returns `pebbles`, assuming `_.findKey` returns `barney`
         *
         * // using "_.where" callback shorthand
         * _.findLastKey(characters, { 'age': 40 });
         * // => 'fred'
         *
         * // using "_.pluck" callback shorthand
         * _.findLastKey(characters, 'blocked');
         * // => 'pebbles'
         */

        function findLastKey(object, callback, thisArg) {
          var result;
          callback = lodash.createCallback(callback, thisArg, 3);
          forOwnRight(object, function(value, key, object) {
            if (callback(value, key, object)) {
              result = key;
              return false;
            }
          });
          return result;
        }
        /**
         * Iterates over own and inherited enumerable properties of an object,
         * executing the callback for each property. The callback is bound to `thisArg`
         * and invoked with three arguments; (value, key, object). Callbacks may exit
         * iteration early by explicitly returning `false`.
         *
         * @static
         * @memberOf _
         * @type Function
         * @category Objects
         * @param {Object} object The object to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns `object`.
         * @example
         *
         * function Shape() {
         *   this.x = 0;
         *   this.y = 0;
         * }
         *
         * Shape.prototype.move = function(x, y) {
         *   this.x += x;
         *   this.y += y;
         * };
         *
         * _.forIn(new Shape, function(value, key) {
         *   console.log(key);
         * });
         * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments)
         */

        var forIn = function(collection, callback, thisArg) {
          var index,
            iterable = collection,
            result = iterable;
          if (!iterable) return result;
          if (!objectTypes[typeof iterable]) return result;
          callback =
            callback && typeof thisArg == 'undefined'
              ? callback
              : baseCreateCallback(callback, thisArg, 3);

          for (index in iterable) {
            if (callback(iterable[index], index, collection) === false)
              return result;
          }

          return result;
        };
        /**
         * This method is like `_.forIn` except that it iterates over elements
         * of a `collection` in the opposite order.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns `object`.
         * @example
         *
         * function Shape() {
         *   this.x = 0;
         *   this.y = 0;
         * }
         *
         * Shape.prototype.move = function(x, y) {
         *   this.x += x;
         *   this.y += y;
         * };
         *
         * _.forInRight(new Shape, function(value, key) {
         *   console.log(key);
         * });
         * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move'
         */

        function forInRight(object, callback, thisArg) {
          var pairs = [];
          forIn(object, function(value, key) {
            pairs.push(key, value);
          });
          var length = pairs.length;
          callback = baseCreateCallback(callback, thisArg, 3);

          while (length--) {
            if (callback(pairs[length--], pairs[length], object) === false) {
              break;
            }
          }

          return object;
        }
        /**
         * Iterates over own enumerable properties of an object, executing the callback
         * for each property. The callback is bound to `thisArg` and invoked with three
         * arguments; (value, key, object). Callbacks may exit iteration early by
         * explicitly returning `false`.
         *
         * @static
         * @memberOf _
         * @type Function
         * @category Objects
         * @param {Object} object The object to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns `object`.
         * @example
         *
         * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
         *   console.log(key);
         * });
         * // => logs '0', '1', and 'length' (property order is not guaranteed across environments)
         */

        var forOwn = function(collection, callback, thisArg) {
          var index,
            iterable = collection,
            result = iterable;
          if (!iterable) return result;
          if (!objectTypes[typeof iterable]) return result;
          callback =
            callback && typeof thisArg == 'undefined'
              ? callback
              : baseCreateCallback(callback, thisArg, 3);
          var ownIndex = -1,
            ownProps = objectTypes[typeof iterable] && keys(iterable),
            length = ownProps ? ownProps.length : 0;

          while (++ownIndex < length) {
            index = ownProps[ownIndex];
            if (callback(iterable[index], index, collection) === false)
              return result;
          }

          return result;
        };
        /**
         * This method is like `_.forOwn` except that it iterates over elements
         * of a `collection` in the opposite order.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns `object`.
         * @example
         *
         * _.forOwnRight({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
         *   console.log(key);
         * });
         * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
         */

        function forOwnRight(object, callback, thisArg) {
          var props = keys(object),
            length = props.length;
          callback = baseCreateCallback(callback, thisArg, 3);

          while (length--) {
            var key = props[length];

            if (callback(object[key], key, object) === false) {
              break;
            }
          }

          return object;
        }
        /**
         * Creates a sorted array of property names of all enumerable properties,
         * own and inherited, of `object` that have function values.
         *
         * @static
         * @memberOf _
         * @alias methods
         * @category Objects
         * @param {Object} object The object to inspect.
         * @returns {Array} Returns an array of property names that have function values.
         * @example
         *
         * _.functions(_);
         * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
         */

        function functions(object) {
          var result = [];
          forIn(object, function(value, key) {
            if (isFunction(value)) {
              result.push(key);
            }
          });
          return result.sort();
        }
        /**
         * Checks if the specified property name exists as a direct property of `object`,
         * instead of an inherited property.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to inspect.
         * @param {string} key The name of the property to check.
         * @returns {boolean} Returns `true` if key is a direct property, else `false`.
         * @example
         *
         * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
         * // => true
         */

        function has(object, key) {
          return object ? hasOwnProperty.call(object, key) : false;
        }
        /**
         * Creates an object composed of the inverted keys and values of the given object.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to invert.
         * @returns {Object} Returns the created inverted object.
         * @example
         *
         * _.invert({ 'first': 'fred', 'second': 'barney' });
         * // => { 'fred': 'first', 'barney': 'second' }
         */

        function invert(object) {
          var index = -1,
            props = keys(object),
            length = props.length,
            result = {};

          while (++index < length) {
            var key = props[index];
            result[object[key]] = key;
          }

          return result;
        }
        /**
         * Checks if `value` is a boolean value.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a boolean value, else `false`.
         * @example
         *
         * _.isBoolean(null);
         * // => false
         */

        function isBoolean(value) {
          return (
            value === true ||
            value === false ||
            (value &&
              typeof value == 'object' &&
              toString.call(value) == boolClass) ||
            false
          );
        }
        /**
         * Checks if `value` is a date.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a date, else `false`.
         * @example
         *
         * _.isDate(new Date);
         * // => true
         */

        function isDate(value) {
          return (
            (value &&
              typeof value == 'object' &&
              toString.call(value) == dateClass) ||
            false
          );
        }
        /**
         * Checks if `value` is a DOM element.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a DOM element, else `false`.
         * @example
         *
         * _.isElement(document.body);
         * // => true
         */

        function isElement(value) {
          return (value && value.nodeType === 1) || false;
        }
        /**
         * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
         * length of `0` and objects with no own enumerable properties are considered
         * "empty".
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Array|Object|string} value The value to inspect.
         * @returns {boolean} Returns `true` if the `value` is empty, else `false`.
         * @example
         *
         * _.isEmpty([1, 2, 3]);
         * // => false
         *
         * _.isEmpty({});
         * // => true
         *
         * _.isEmpty('');
         * // => true
         */

        function isEmpty(value) {
          var result = true;

          if (!value) {
            return result;
          }

          var className = toString.call(value),
            length = value.length;

          if (
            className == arrayClass ||
            className == stringClass ||
            className == argsClass ||
            (className == objectClass &&
              typeof length == 'number' &&
              isFunction(value.splice))
          ) {
            return !length;
          }

          forOwn(value, function() {
            return (result = false);
          });
          return result;
        }
        /**
         * Performs a deep comparison between two values to determine if they are
         * equivalent to each other. If a callback is provided it will be executed
         * to compare values. If the callback returns `undefined` comparisons will
         * be handled by the method instead. The callback is bound to `thisArg` and
         * invoked with two arguments; (a, b).
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} a The value to compare.
         * @param {*} b The other value to compare.
         * @param {Function} [callback] The function to customize comparing values.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
         * @example
         *
         * var object = { 'name': 'fred' };
         * var copy = { 'name': 'fred' };
         *
         * object == copy;
         * // => false
         *
         * _.isEqual(object, copy);
         * // => true
         *
         * var words = ['hello', 'goodbye'];
         * var otherWords = ['hi', 'goodbye'];
         *
         * _.isEqual(words, otherWords, function(a, b) {
         *   var reGreet = /^(?:hello|hi)$/i,
         *       aGreet = _.isString(a) && reGreet.test(a),
         *       bGreet = _.isString(b) && reGreet.test(b);
         *
         *   return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
         * });
         * // => true
         */

        function isEqual(a, b, callback, thisArg) {
          return baseIsEqual(
            a,
            b,
            typeof callback == 'function' &&
              baseCreateCallback(callback, thisArg, 2)
          );
        }
        /**
         * Checks if `value` is, or can be coerced to, a finite number.
         *
         * Note: This is not the same as native `isFinite` which will return true for
         * booleans and empty strings. See http://es5.github.io/#x15.1.2.5.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is finite, else `false`.
         * @example
         *
         * _.isFinite(-101);
         * // => true
         *
         * _.isFinite('10');
         * // => true
         *
         * _.isFinite(true);
         * // => false
         *
         * _.isFinite('');
         * // => false
         *
         * _.isFinite(Infinity);
         * // => false
         */

        function isFinite(value) {
          return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
        }
        /**
         * Checks if `value` is a function.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a function, else `false`.
         * @example
         *
         * _.isFunction(_);
         * // => true
         */

        function isFunction(value) {
          return typeof value == 'function';
        }
        /**
         * Checks if `value` is the language type of Object.
         * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is an object, else `false`.
         * @example
         *
         * _.isObject({});
         * // => true
         *
         * _.isObject([1, 2, 3]);
         * // => true
         *
         * _.isObject(1);
         * // => false
         */

        function isObject(value) {
          // check if the value is the ECMAScript language type of Object
          // http://es5.github.io/#x8
          // and avoid a V8 bug
          // http://code.google.com/p/v8/issues/detail?id=2291
          return !!(value && objectTypes[typeof value]);
        }
        /**
         * Checks if `value` is `NaN`.
         *
         * Note: This is not the same as native `isNaN` which will return `true` for
         * `undefined` and other non-numeric values. See http://es5.github.io/#x15.1.2.4.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is `NaN`, else `false`.
         * @example
         *
         * _.isNaN(NaN);
         * // => true
         *
         * _.isNaN(new Number(NaN));
         * // => true
         *
         * isNaN(undefined);
         * // => true
         *
         * _.isNaN(undefined);
         * // => false
         */

        function isNaN(value) {
          // `NaN` as a primitive is the only value that is not equal to itself
          // (perform the [[Class]] check first to avoid errors with some host objects in IE)
          return isNumber(value) && value != +value;
        }
        /**
         * Checks if `value` is `null`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is `null`, else `false`.
         * @example
         *
         * _.isNull(null);
         * // => true
         *
         * _.isNull(undefined);
         * // => false
         */

        function isNull(value) {
          return value === null;
        }
        /**
         * Checks if `value` is a number.
         *
         * Note: `NaN` is considered a number. See http://es5.github.io/#x8.5.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a number, else `false`.
         * @example
         *
         * _.isNumber(8.4 * 5);
         * // => true
         */

        function isNumber(value) {
          return (
            typeof value == 'number' ||
            (value &&
              typeof value == 'object' &&
              toString.call(value) == numberClass) ||
            false
          );
        }
        /**
         * Checks if `value` is an object created by the `Object` constructor.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
         * @example
         *
         * function Shape() {
         *   this.x = 0;
         *   this.y = 0;
         * }
         *
         * _.isPlainObject(new Shape);
         * // => false
         *
         * _.isPlainObject([1, 2, 3]);
         * // => false
         *
         * _.isPlainObject({ 'x': 0, 'y': 0 });
         * // => true
         */

        var isPlainObject = !getPrototypeOf
          ? shimIsPlainObject
          : function(value) {
              if (!(value && toString.call(value) == objectClass)) {
                return false;
              }

              var valueOf = value.valueOf,
                objProto =
                  isNative(valueOf) &&
                  (objProto = getPrototypeOf(valueOf)) &&
                  getPrototypeOf(objProto);
              return objProto
                ? value == objProto || getPrototypeOf(value) == objProto
                : shimIsPlainObject(value);
            };
        /**
         * Checks if `value` is a regular expression.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`.
         * @example
         *
         * _.isRegExp(/fred/);
         * // => true
         */

        function isRegExp(value) {
          return (
            (value &&
              typeof value == 'object' &&
              toString.call(value) == regexpClass) ||
            false
          );
        }
        /**
         * Checks if `value` is a string.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is a string, else `false`.
         * @example
         *
         * _.isString('fred');
         * // => true
         */

        function isString(value) {
          return (
            typeof value == 'string' ||
            (value &&
              typeof value == 'object' &&
              toString.call(value) == stringClass) ||
            false
          );
        }
        /**
         * Checks if `value` is `undefined`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {*} value The value to check.
         * @returns {boolean} Returns `true` if the `value` is `undefined`, else `false`.
         * @example
         *
         * _.isUndefined(void 0);
         * // => true
         */

        function isUndefined(value) {
          return typeof value == 'undefined';
        }
        /**
         * Creates an object with the same keys as `object` and values generated by
         * running each own enumerable property of `object` through the callback.
         * The callback is bound to `thisArg` and invoked with three arguments;
         * (value, key, object).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a new object with values of the results of each `callback` execution.
         * @example
         *
         * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
         * // => { 'a': 3, 'b': 6, 'c': 9 }
         *
         * var characters = {
         *   'fred': { 'name': 'fred', 'age': 40 },
         *   'pebbles': { 'name': 'pebbles', 'age': 1 }
         * };
         *
         * // using "_.pluck" callback shorthand
         * _.mapValues(characters, 'age');
         * // => { 'fred': 40, 'pebbles': 1 }
         */

        function mapValues(object, callback, thisArg) {
          var result = {};
          callback = lodash.createCallback(callback, thisArg, 3);
          forOwn(object, function(value, key, object) {
            result[key] = callback(value, key, object);
          });
          return result;
        }
        /**
         * Recursively merges own enumerable properties of the source object(s), that
         * don't resolve to `undefined` into the destination object. Subsequent sources
         * will overwrite property assignments of previous sources. If a callback is
         * provided it will be executed to produce the merged values of the destination
         * and source properties. If the callback returns `undefined` merging will
         * be handled by the method instead. The callback is bound to `thisArg` and
         * invoked with two arguments; (objectValue, sourceValue).
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The destination object.
         * @param {...Object} [source] The source objects.
         * @param {Function} [callback] The function to customize merging properties.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns the destination object.
         * @example
         *
         * var names = {
         *   'characters': [
         *     { 'name': 'barney' },
         *     { 'name': 'fred' }
         *   ]
         * };
         *
         * var ages = {
         *   'characters': [
         *     { 'age': 36 },
         *     { 'age': 40 }
         *   ]
         * };
         *
         * _.merge(names, ages);
         * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
         *
         * var food = {
         *   'fruits': ['apple'],
         *   'vegetables': ['beet']
         * };
         *
         * var otherFood = {
         *   'fruits': ['banana'],
         *   'vegetables': ['carrot']
         * };
         *
         * _.merge(food, otherFood, function(a, b) {
         *   return _.isArray(a) ? a.concat(b) : undefined;
         * });
         * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
         */

        function merge(object) {
          var args = arguments,
            length = 2;

          if (!isObject(object)) {
            return object;
          } // allows working with `_.reduce` and `_.reduceRight` without using
          // their `index` and `collection` arguments

          if (typeof args[2] != 'number') {
            length = args.length;
          }

          if (length > 3 && typeof args[length - 2] == 'function') {
            var callback = baseCreateCallback(
              args[--length - 1],
              args[length--],
              2
            );
          } else if (length > 2 && typeof args[length - 1] == 'function') {
            callback = args[--length];
          }

          var sources = slice(arguments, 1, length),
            index = -1,
            stackA = getArray(),
            stackB = getArray();

          while (++index < length) {
            baseMerge(object, sources[index], callback, stackA, stackB);
          }

          releaseArray(stackA);
          releaseArray(stackB);
          return object;
        }
        /**
         * Creates a shallow clone of `object` excluding the specified properties.
         * Property names may be specified as individual arguments or as arrays of
         * property names. If a callback is provided it will be executed for each
         * property of `object` omitting the properties the callback returns truey
         * for. The callback is bound to `thisArg` and invoked with three arguments;
         * (value, key, object).
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The source object.
         * @param {Function|...string|string[]} [callback] The properties to omit or the
         *  function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns an object without the omitted properties.
         * @example
         *
         * _.omit({ 'name': 'fred', 'age': 40 }, 'age');
         * // => { 'name': 'fred' }
         *
         * _.omit({ 'name': 'fred', 'age': 40 }, function(value) {
         *   return typeof value == 'number';
         * });
         * // => { 'name': 'fred' }
         */

        function omit(object, callback, thisArg) {
          var result = {};

          if (typeof callback != 'function') {
            var props = [];
            forIn(object, function(value, key) {
              props.push(key);
            });
            props = baseDifference(
              props,
              baseFlatten(arguments, true, false, 1)
            );
            var index = -1,
              length = props.length;

            while (++index < length) {
              var key = props[index];
              result[key] = object[key];
            }
          } else {
            callback = lodash.createCallback(callback, thisArg, 3);
            forIn(object, function(value, key, object) {
              if (!callback(value, key, object)) {
                result[key] = value;
              }
            });
          }

          return result;
        }
        /**
         * Creates a two dimensional array of an object's key-value pairs,
         * i.e. `[[key1, value1], [key2, value2]]`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to inspect.
         * @returns {Array} Returns new array of key-value pairs.
         * @example
         *
         * _.pairs({ 'barney': 36, 'fred': 40 });
         * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments)
         */

        function pairs(object) {
          var index = -1,
            props = keys(object),
            length = props.length,
            result = Array(length);

          while (++index < length) {
            var key = props[index];
            result[index] = [key, object[key]];
          }

          return result;
        }
        /**
         * Creates a shallow clone of `object` composed of the specified properties.
         * Property names may be specified as individual arguments or as arrays of
         * property names. If a callback is provided it will be executed for each
         * property of `object` picking the properties the callback returns truey
         * for. The callback is bound to `thisArg` and invoked with three arguments;
         * (value, key, object).
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The source object.
         * @param {Function|...string|string[]} [callback] The function called per
         *  iteration or property names to pick, specified as individual property
         *  names or arrays of property names.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns an object composed of the picked properties.
         * @example
         *
         * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name');
         * // => { 'name': 'fred' }
         *
         * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) {
         *   return key.charAt(0) != '_';
         * });
         * // => { 'name': 'fred' }
         */

        function pick(object, callback, thisArg) {
          var result = {};

          if (typeof callback != 'function') {
            var index = -1,
              props = baseFlatten(arguments, true, false, 1),
              length = isObject(object) ? props.length : 0;

            while (++index < length) {
              var key = props[index];

              if (key in object) {
                result[key] = object[key];
              }
            }
          } else {
            callback = lodash.createCallback(callback, thisArg, 3);
            forIn(object, function(value, key, object) {
              if (callback(value, key, object)) {
                result[key] = value;
              }
            });
          }

          return result;
        }
        /**
         * An alternative to `_.reduce` this method transforms `object` to a new
         * `accumulator` object which is the result of running each of its own
         * enumerable properties through a callback, with each callback execution
         * potentially mutating the `accumulator` object. The callback is bound to
         * `thisArg` and invoked with four arguments; (accumulator, value, key, object).
         * Callbacks may exit iteration early by explicitly returning `false`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Array|Object} object The object to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [accumulator] The custom accumulator value.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the accumulated value.
         * @example
         *
         * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
         *   num *= num;
         *   if (num % 2) {
         *     return result.push(num) < 3;
         *   }
         * });
         * // => [1, 9, 25]
         *
         * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
         *   result[key] = num * 3;
         * });
         * // => { 'a': 3, 'b': 6, 'c': 9 }
         */

        function transform(object, callback, accumulator, thisArg) {
          var isArr = isArray(object);

          if (accumulator == null) {
            if (isArr) {
              accumulator = [];
            } else {
              var ctor = object && object.constructor,
                proto = ctor && ctor.prototype;
              accumulator = baseCreate(proto);
            }
          }

          if (callback) {
            callback = lodash.createCallback(callback, thisArg, 4);
            (isArr ? forEach : forOwn)(object, function(value, index, object) {
              return callback(accumulator, value, index, object);
            });
          }

          return accumulator;
        }
        /**
         * Creates an array composed of the own enumerable property values of `object`.
         *
         * @static
         * @memberOf _
         * @category Objects
         * @param {Object} object The object to inspect.
         * @returns {Array} Returns an array of property values.
         * @example
         *
         * _.values({ 'one': 1, 'two': 2, 'three': 3 });
         * // => [1, 2, 3] (property order is not guaranteed across environments)
         */

        function values(object) {
          var index = -1,
            props = keys(object),
            length = props.length,
            result = Array(length);

          while (++index < length) {
            result[index] = object[props[index]];
          }

          return result;
        }
        /*--------------------------------------------------------------------------*/

        /**
         * Creates an array of elements from the specified indexes, or keys, of the
         * `collection`. Indexes may be specified as individual arguments or as arrays
         * of indexes.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {...(number|number[]|string|string[])} [index] The indexes of `collection`
         *   to retrieve, specified as individual indexes or arrays of indexes.
         * @returns {Array} Returns a new array of elements corresponding to the
         *  provided indexes.
         * @example
         *
         * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
         * // => ['a', 'c', 'e']
         *
         * _.at(['fred', 'barney', 'pebbles'], 0, 2);
         * // => ['fred', 'pebbles']
         */

        function at(collection) {
          var args = arguments,
            index = -1,
            props = baseFlatten(args, true, false, 1),
            length =
              args[2] && args[2][args[1]] === collection ? 1 : props.length,
            result = Array(length);

          while (++index < length) {
            result[index] = collection[props[index]];
          }

          return result;
        }
        /**
         * Checks if a given value is present in a collection using strict equality
         * for comparisons, i.e. `===`. If `fromIndex` is negative, it is used as the
         * offset from the end of the collection.
         *
         * @static
         * @memberOf _
         * @alias include
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {*} target The value to check for.
         * @param {number} [fromIndex=0] The index to search from.
         * @returns {boolean} Returns `true` if the `target` element is found, else `false`.
         * @example
         *
         * _.contains([1, 2, 3], 1);
         * // => true
         *
         * _.contains([1, 2, 3], 1, 2);
         * // => false
         *
         * _.contains({ 'name': 'fred', 'age': 40 }, 'fred');
         * // => true
         *
         * _.contains('pebbles', 'eb');
         * // => true
         */

        function contains(collection, target, fromIndex) {
          var index = -1,
            indexOf = getIndexOf(),
            length = collection ? collection.length : 0,
            result = false;
          fromIndex =
            (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;

          if (isArray(collection)) {
            result = indexOf(collection, target, fromIndex) > -1;
          } else if (typeof length == 'number') {
            result =
              (isString(collection)
                ? collection.indexOf(target, fromIndex)
                : indexOf(collection, target, fromIndex)) > -1;
          } else {
            forOwn(collection, function(value) {
              if (++index >= fromIndex) {
                return !(result = value === target);
              }
            });
          }

          return result;
        }
        /**
         * Creates an object composed of keys generated from the results of running
         * each element of `collection` through the callback. The corresponding value
         * of each key is the number of times the key was returned by the callback.
         * The callback is bound to `thisArg` and invoked with three arguments;
         * (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns the composed aggregate object.
         * @example
         *
         * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
         * // => { '4': 1, '6': 2 }
         *
         * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
         * // => { '4': 1, '6': 2 }
         *
         * _.countBy(['one', 'two', 'three'], 'length');
         * // => { '3': 2, '5': 1 }
         */

        var countBy = createAggregator(function(result, value, key) {
          hasOwnProperty.call(result, key) ? result[key]++ : (result[key] = 1);
        });
        /**
         * Checks if the given callback returns truey value for **all** elements of
         * a collection. The callback is bound to `thisArg` and invoked with three
         * arguments; (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias all
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {boolean} Returns `true` if all elements passed the callback check,
         *  else `false`.
         * @example
         *
         * _.every([true, 1, null, 'yes']);
         * // => false
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.every(characters, 'age');
         * // => true
         *
         * // using "_.where" callback shorthand
         * _.every(characters, { 'age': 36 });
         * // => false
         */

        function every(collection, callback, thisArg) {
          var result = true;
          callback = lodash.createCallback(callback, thisArg, 3);
          var index = -1,
            length = collection ? collection.length : 0;

          if (typeof length == 'number') {
            while (++index < length) {
              if (
                !(result = !!callback(collection[index], index, collection))
              ) {
                break;
              }
            }
          } else {
            forOwn(collection, function(value, index, collection) {
              return (result = !!callback(value, index, collection));
            });
          }

          return result;
        }
        /**
         * Iterates over elements of a collection, returning an array of all elements
         * the callback returns truey for. The callback is bound to `thisArg` and
         * invoked with three arguments; (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias select
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a new array of elements that passed the callback check.
         * @example
         *
         * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
         * // => [2, 4, 6]
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36, 'blocked': false },
         *   { 'name': 'fred',   'age': 40, 'blocked': true }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.filter(characters, 'blocked');
         * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
         *
         * // using "_.where" callback shorthand
         * _.filter(characters, { 'age': 36 });
         * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
         */

        function filter(collection, callback, thisArg) {
          var result = [];
          callback = lodash.createCallback(callback, thisArg, 3);
          var index = -1,
            length = collection ? collection.length : 0;

          if (typeof length == 'number') {
            while (++index < length) {
              var value = collection[index];

              if (callback(value, index, collection)) {
                result.push(value);
              }
            }
          } else {
            forOwn(collection, function(value, index, collection) {
              if (callback(value, index, collection)) {
                result.push(value);
              }
            });
          }

          return result;
        }
        /**
         * Iterates over elements of a collection, returning the first element that
         * the callback returns truey for. The callback is bound to `thisArg` and
         * invoked with three arguments; (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias detect, findWhere
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the found element, else `undefined`.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney',  'age': 36, 'blocked': false },
         *   { 'name': 'fred',    'age': 40, 'blocked': true },
         *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
         * ];
         *
         * _.find(characters, function(chr) {
         *   return chr.age < 40;
         * });
         * // => { 'name': 'barney', 'age': 36, 'blocked': false }
         *
         * // using "_.where" callback shorthand
         * _.find(characters, { 'age': 1 });
         * // =>  { 'name': 'pebbles', 'age': 1, 'blocked': false }
         *
         * // using "_.pluck" callback shorthand
         * _.find(characters, 'blocked');
         * // => { 'name': 'fred', 'age': 40, 'blocked': true }
         */

        function find(collection, callback, thisArg) {
          callback = lodash.createCallback(callback, thisArg, 3);
          var index = -1,
            length = collection ? collection.length : 0;

          if (typeof length == 'number') {
            while (++index < length) {
              var value = collection[index];

              if (callback(value, index, collection)) {
                return value;
              }
            }
          } else {
            var result;
            forOwn(collection, function(value, index, collection) {
              if (callback(value, index, collection)) {
                result = value;
                return false;
              }
            });
            return result;
          }
        }
        /**
         * This method is like `_.find` except that it iterates over elements
         * of a `collection` from right to left.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the found element, else `undefined`.
         * @example
         *
         * _.findLast([1, 2, 3, 4], function(num) {
         *   return num % 2 == 1;
         * });
         * // => 3
         */

        function findLast(collection, callback, thisArg) {
          var result;
          callback = lodash.createCallback(callback, thisArg, 3);
          forEachRight(collection, function(value, index, collection) {
            if (callback(value, index, collection)) {
              result = value;
              return false;
            }
          });
          return result;
        }
        /**
         * Iterates over elements of a collection, executing the callback for each
         * element. The callback is bound to `thisArg` and invoked with three arguments;
         * (value, index|key, collection). Callbacks may exit iteration early by
         * explicitly returning `false`.
         *
         * Note: As with other "Collections" methods, objects with a `length` property
         * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn`
         * may be used for object iteration.
         *
         * @static
         * @memberOf _
         * @alias each
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array|Object|string} Returns `collection`.
         * @example
         *
         * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(',');
         * // => logs each number and returns '1,2,3'
         *
         * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); });
         * // => logs each number and returns the object (property order is not guaranteed across environments)
         */

        function forEach(collection, callback, thisArg) {
          var index = -1,
            length = collection ? collection.length : 0;
          callback =
            callback && typeof thisArg == 'undefined'
              ? callback
              : baseCreateCallback(callback, thisArg, 3);

          if (typeof length == 'number') {
            while (++index < length) {
              if (callback(collection[index], index, collection) === false) {
                break;
              }
            }
          } else {
            forOwn(collection, callback);
          }

          return collection;
        }
        /**
         * This method is like `_.forEach` except that it iterates over elements
         * of a `collection` from right to left.
         *
         * @static
         * @memberOf _
         * @alias eachRight
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array|Object|string} Returns `collection`.
         * @example
         *
         * _([1, 2, 3]).forEachRight(function(num) { console.log(num); }).join(',');
         * // => logs each number from right to left and returns '3,2,1'
         */

        function forEachRight(collection, callback, thisArg) {
          var length = collection ? collection.length : 0;
          callback =
            callback && typeof thisArg == 'undefined'
              ? callback
              : baseCreateCallback(callback, thisArg, 3);

          if (typeof length == 'number') {
            while (length--) {
              if (callback(collection[length], length, collection) === false) {
                break;
              }
            }
          } else {
            var props = keys(collection);
            length = props.length;
            forOwn(collection, function(value, key, collection) {
              key = props ? props[--length] : --length;
              return callback(collection[key], key, collection);
            });
          }

          return collection;
        }
        /**
         * Creates an object composed of keys generated from the results of running
         * each element of a collection through the callback. The corresponding value
         * of each key is an array of the elements responsible for generating the key.
         * The callback is bound to `thisArg` and invoked with three arguments;
         * (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns the composed aggregate object.
         * @example
         *
         * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
         * // => { '4': [4.2], '6': [6.1, 6.4] }
         *
         * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
         * // => { '4': [4.2], '6': [6.1, 6.4] }
         *
         * // using "_.pluck" callback shorthand
         * _.groupBy(['one', 'two', 'three'], 'length');
         * // => { '3': ['one', 'two'], '5': ['three'] }
         */

        var groupBy = createAggregator(function(result, value, key) {
          (hasOwnProperty.call(result, key)
            ? result[key]
            : (result[key] = [])
          ).push(value);
        });
        /**
         * Creates an object composed of keys generated from the results of running
         * each element of the collection through the given callback. The corresponding
         * value of each key is the last element responsible for generating the key.
         * The callback is bound to `thisArg` and invoked with three arguments;
         * (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Object} Returns the composed aggregate object.
         * @example
         *
         * var keys = [
         *   { 'dir': 'left', 'code': 97 },
         *   { 'dir': 'right', 'code': 100 }
         * ];
         *
         * _.indexBy(keys, 'dir');
         * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
         *
         * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); });
         * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
         *
         * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String);
         * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
         */

        var indexBy = createAggregator(function(result, value, key) {
          result[key] = value;
        });
        /**
         * Invokes the method named by `methodName` on each element in the `collection`
         * returning an array of the results of each invoked method. Additional arguments
         * will be provided to each invoked method. If `methodName` is a function it
         * will be invoked for, and `this` bound to, each element in the `collection`.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|string} methodName The name of the method to invoke or
         *  the function invoked per iteration.
         * @param {...*} [arg] Arguments to invoke the method with.
         * @returns {Array} Returns a new array of the results of each invoked method.
         * @example
         *
         * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
         * // => [[1, 5, 7], [1, 2, 3]]
         *
         * _.invoke([123, 456], String.prototype.split, '');
         * // => [['1', '2', '3'], ['4', '5', '6']]
         */

        function invoke(collection, methodName) {
          var args = slice(arguments, 2),
            index = -1,
            isFunc = typeof methodName == 'function',
            length = collection ? collection.length : 0,
            result = Array(typeof length == 'number' ? length : 0);
          forEach(collection, function(value) {
            result[++index] = (isFunc ? methodName : value[methodName]).apply(
              value,
              args
            );
          });
          return result;
        }
        /**
         * Creates an array of values by running each element in the collection
         * through the callback. The callback is bound to `thisArg` and invoked with
         * three arguments; (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias collect
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a new array of the results of each `callback` execution.
         * @example
         *
         * _.map([1, 2, 3], function(num) { return num * 3; });
         * // => [3, 6, 9]
         *
         * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
         * // => [3, 6, 9] (property order is not guaranteed across environments)
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.map(characters, 'name');
         * // => ['barney', 'fred']
         */

        function map(collection, callback, thisArg) {
          var index = -1,
            length = collection ? collection.length : 0;
          callback = lodash.createCallback(callback, thisArg, 3);

          if (typeof length == 'number') {
            var result = Array(length);

            while (++index < length) {
              result[index] = callback(collection[index], index, collection);
            }
          } else {
            result = [];
            forOwn(collection, function(value, key, collection) {
              result[++index] = callback(value, key, collection);
            });
          }

          return result;
        }
        /**
         * Retrieves the maximum value of a collection. If the collection is empty or
         * falsey `-Infinity` is returned. If a callback is provided it will be executed
         * for each value in the collection to generate the criterion by which the value
         * is ranked. The callback is bound to `thisArg` and invoked with three
         * arguments; (value, index, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the maximum value.
         * @example
         *
         * _.max([4, 2, 8, 6]);
         * // => 8
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * _.max(characters, function(chr) { return chr.age; });
         * // => { 'name': 'fred', 'age': 40 };
         *
         * // using "_.pluck" callback shorthand
         * _.max(characters, 'age');
         * // => { 'name': 'fred', 'age': 40 };
         */

        function max(collection, callback, thisArg) {
          var computed = -Infinity,
            result = computed; // allows working with functions like `_.map` without using
          // their `index` argument as a callback

          if (
            typeof callback != 'function' &&
            thisArg &&
            thisArg[callback] === collection
          ) {
            callback = null;
          }

          if (callback == null && isArray(collection)) {
            var index = -1,
              length = collection.length;

            while (++index < length) {
              var value = collection[index];

              if (value > result) {
                result = value;
              }
            }
          } else {
            callback =
              callback == null && isString(collection)
                ? charAtCallback
                : lodash.createCallback(callback, thisArg, 3);
            forEach(collection, function(value, index, collection) {
              var current = callback(value, index, collection);

              if (current > computed) {
                computed = current;
                result = value;
              }
            });
          }

          return result;
        }
        /**
         * Retrieves the minimum value of a collection. If the collection is empty or
         * falsey `Infinity` is returned. If a callback is provided it will be executed
         * for each value in the collection to generate the criterion by which the value
         * is ranked. The callback is bound to `thisArg` and invoked with three
         * arguments; (value, index, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the minimum value.
         * @example
         *
         * _.min([4, 2, 8, 6]);
         * // => 2
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * _.min(characters, function(chr) { return chr.age; });
         * // => { 'name': 'barney', 'age': 36 };
         *
         * // using "_.pluck" callback shorthand
         * _.min(characters, 'age');
         * // => { 'name': 'barney', 'age': 36 };
         */

        function min(collection, callback, thisArg) {
          var computed = Infinity,
            result = computed; // allows working with functions like `_.map` without using
          // their `index` argument as a callback

          if (
            typeof callback != 'function' &&
            thisArg &&
            thisArg[callback] === collection
          ) {
            callback = null;
          }

          if (callback == null && isArray(collection)) {
            var index = -1,
              length = collection.length;

            while (++index < length) {
              var value = collection[index];

              if (value < result) {
                result = value;
              }
            }
          } else {
            callback =
              callback == null && isString(collection)
                ? charAtCallback
                : lodash.createCallback(callback, thisArg, 3);
            forEach(collection, function(value, index, collection) {
              var current = callback(value, index, collection);

              if (current < computed) {
                computed = current;
                result = value;
              }
            });
          }

          return result;
        }
        /**
         * Retrieves the value of a specified property from all elements in the collection.
         *
         * @static
         * @memberOf _
         * @type Function
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {string} property The name of the property to pluck.
         * @returns {Array} Returns a new array of property values.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * _.pluck(characters, 'name');
         * // => ['barney', 'fred']
         */

        var pluck = map;
        /**
         * Reduces a collection to a value which is the accumulated result of running
         * each element in the collection through the callback, where each successive
         * callback execution consumes the return value of the previous execution. If
         * `accumulator` is not provided the first element of the collection will be
         * used as the initial `accumulator` value. The callback is bound to `thisArg`
         * and invoked with four arguments; (accumulator, value, index|key, collection).
         *
         * @static
         * @memberOf _
         * @alias foldl, inject
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [accumulator] Initial value of the accumulator.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the accumulated value.
         * @example
         *
         * var sum = _.reduce([1, 2, 3], function(sum, num) {
         *   return sum + num;
         * });
         * // => 6
         *
         * var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
         *   result[key] = num * 3;
         *   return result;
         * }, {});
         * // => { 'a': 3, 'b': 6, 'c': 9 }
         */

        function reduce(collection, callback, accumulator, thisArg) {
          if (!collection) return accumulator;
          var noaccum = arguments.length < 3;
          callback = lodash.createCallback(callback, thisArg, 4);
          var index = -1,
            length = collection.length;

          if (typeof length == 'number') {
            if (noaccum) {
              accumulator = collection[++index];
            }

            while (++index < length) {
              accumulator = callback(
                accumulator,
                collection[index],
                index,
                collection
              );
            }
          } else {
            forOwn(collection, function(value, index, collection) {
              accumulator = noaccum
                ? ((noaccum = false), value)
                : callback(accumulator, value, index, collection);
            });
          }

          return accumulator;
        }
        /**
         * This method is like `_.reduce` except that it iterates over elements
         * of a `collection` from right to left.
         *
         * @static
         * @memberOf _
         * @alias foldr
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function} [callback=identity] The function called per iteration.
         * @param {*} [accumulator] Initial value of the accumulator.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the accumulated value.
         * @example
         *
         * var list = [[0, 1], [2, 3], [4, 5]];
         * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
         * // => [4, 5, 2, 3, 0, 1]
         */

        function reduceRight(collection, callback, accumulator, thisArg) {
          var noaccum = arguments.length < 3;
          callback = lodash.createCallback(callback, thisArg, 4);
          forEachRight(collection, function(value, index, collection) {
            accumulator = noaccum
              ? ((noaccum = false), value)
              : callback(accumulator, value, index, collection);
          });
          return accumulator;
        }
        /**
         * The opposite of `_.filter` this method returns the elements of a
         * collection that the callback does **not** return truey for.
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a new array of elements that failed the callback check.
         * @example
         *
         * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
         * // => [1, 3, 5]
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36, 'blocked': false },
         *   { 'name': 'fred',   'age': 40, 'blocked': true }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.reject(characters, 'blocked');
         * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }]
         *
         * // using "_.where" callback shorthand
         * _.reject(characters, { 'age': 36 });
         * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }]
         */

        function reject(collection, callback, thisArg) {
          callback = lodash.createCallback(callback, thisArg, 3);
          return filter(collection, function(value, index, collection) {
            return !callback(value, index, collection);
          });
        }
        /**
         * Retrieves a random element or `n` random elements from a collection.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to sample.
         * @param {number} [n] The number of elements to sample.
         * @param- {Object} [guard] Allows working with functions like `_.map`
         *  without using their `index` arguments as `n`.
         * @returns {Array} Returns the random sample(s) of `collection`.
         * @example
         *
         * _.sample([1, 2, 3, 4]);
         * // => 2
         *
         * _.sample([1, 2, 3, 4], 2);
         * // => [3, 1]
         */

        function sample(collection, n, guard) {
          if (collection && typeof collection.length != 'number') {
            collection = values(collection);
          }

          if (n == null || guard) {
            return collection
              ? collection[baseRandom(0, collection.length - 1)]
              : undefined;
          }

          var result = shuffle(collection);
          result.length = nativeMin(nativeMax(0, n), result.length);
          return result;
        }
        /**
         * Creates an array of shuffled values, using a version of the Fisher-Yates
         * shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to shuffle.
         * @returns {Array} Returns a new shuffled collection.
         * @example
         *
         * _.shuffle([1, 2, 3, 4, 5, 6]);
         * // => [4, 1, 6, 3, 5, 2]
         */

        function shuffle(collection) {
          var index = -1,
            length = collection ? collection.length : 0,
            result = Array(typeof length == 'number' ? length : 0);
          forEach(collection, function(value) {
            var rand = baseRandom(0, ++index);
            result[index] = result[rand];
            result[rand] = value;
          });
          return result;
        }
        /**
         * Gets the size of the `collection` by returning `collection.length` for arrays
         * and array-like objects or the number of own enumerable properties for objects.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to inspect.
         * @returns {number} Returns `collection.length` or number of own enumerable properties.
         * @example
         *
         * _.size([1, 2]);
         * // => 2
         *
         * _.size({ 'one': 1, 'two': 2, 'three': 3 });
         * // => 3
         *
         * _.size('pebbles');
         * // => 7
         */

        function size(collection) {
          var length = collection ? collection.length : 0;
          return typeof length == 'number' ? length : keys(collection).length;
        }
        /**
         * Checks if the callback returns a truey value for **any** element of a
         * collection. The function returns as soon as it finds a passing value and
         * does not iterate over the entire collection. The callback is bound to
         * `thisArg` and invoked with three arguments; (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias any
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {boolean} Returns `true` if any element passed the callback check,
         *  else `false`.
         * @example
         *
         * _.some([null, 0, 'yes', false], Boolean);
         * // => true
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36, 'blocked': false },
         *   { 'name': 'fred',   'age': 40, 'blocked': true }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.some(characters, 'blocked');
         * // => true
         *
         * // using "_.where" callback shorthand
         * _.some(characters, { 'age': 1 });
         * // => false
         */

        function some(collection, callback, thisArg) {
          var result;
          callback = lodash.createCallback(callback, thisArg, 3);
          var index = -1,
            length = collection ? collection.length : 0;

          if (typeof length == 'number') {
            while (++index < length) {
              if ((result = callback(collection[index], index, collection))) {
                break;
              }
            }
          } else {
            forOwn(collection, function(value, index, collection) {
              return !(result = callback(value, index, collection));
            });
          }

          return !!result;
        }
        /**
         * Creates an array of elements, sorted in ascending order by the results of
         * running each element in a collection through the callback. This method
         * performs a stable sort, that is, it will preserve the original sort order
         * of equal elements. The callback is bound to `thisArg` and invoked with
         * three arguments; (value, index|key, collection).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an array of property names is provided for `callback` the collection
         * will be sorted by each property value.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Array|Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a new array of sorted elements.
         * @example
         *
         * _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
         * // => [3, 1, 2]
         *
         * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
         * // => [3, 1, 2]
         *
         * var characters = [
         *   { 'name': 'barney',  'age': 36 },
         *   { 'name': 'fred',    'age': 40 },
         *   { 'name': 'barney',  'age': 26 },
         *   { 'name': 'fred',    'age': 30 }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.map(_.sortBy(characters, 'age'), _.values);
         * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]]
         *
         * // sorting by multiple properties
         * _.map(_.sortBy(characters, ['name', 'age']), _.values);
         * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]]
         */

        function sortBy(collection, callback, thisArg) {
          var index = -1,
            isArr = isArray(callback),
            length = collection ? collection.length : 0,
            result = Array(typeof length == 'number' ? length : 0);

          if (!isArr) {
            callback = lodash.createCallback(callback, thisArg, 3);
          }

          forEach(collection, function(value, key, collection) {
            var object = (result[++index] = getObject());

            if (isArr) {
              object.criteria = map(callback, function(key) {
                return value[key];
              });
            } else {
              (object.criteria = getArray())[0] = callback(
                value,
                key,
                collection
              );
            }

            object.index = index;
            object.value = value;
          });
          length = result.length;
          result.sort(compareAscending);

          while (length--) {
            var object = result[length];
            result[length] = object.value;

            if (!isArr) {
              releaseArray(object.criteria);
            }

            releaseObject(object);
          }

          return result;
        }
        /**
         * Converts the `collection` to an array.
         *
         * @static
         * @memberOf _
         * @category Collections
         * @param {Array|Object|string} collection The collection to convert.
         * @returns {Array} Returns the new converted array.
         * @example
         *
         * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
         * // => [2, 3, 4]
         */

        function toArray(collection) {
          if (collection && typeof collection.length == 'number') {
            return slice(collection);
          }

          return values(collection);
        }
        /**
         * Performs a deep comparison of each element in a `collection` to the given
         * `properties` object, returning an array of all elements that have equivalent
         * property values.
         *
         * @static
         * @memberOf _
         * @type Function
         * @category Collections
         * @param {Array|Object|string} collection The collection to iterate over.
         * @param {Object} props The object of property values to filter by.
         * @returns {Array} Returns a new array of elements that have the given properties.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] },
         *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
         * ];
         *
         * _.where(characters, { 'age': 36 });
         * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }]
         *
         * _.where(characters, { 'pets': ['dino'] });
         * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }]
         */

        var where = filter;
        /*--------------------------------------------------------------------------*/

        /**
         * Creates an array with all falsey values removed. The values `false`, `null`,
         * `0`, `""`, `undefined`, and `NaN` are all falsey.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to compact.
         * @returns {Array} Returns a new array of filtered values.
         * @example
         *
         * _.compact([0, 1, false, 2, '', 3]);
         * // => [1, 2, 3]
         */

        function compact(array) {
          var index = -1,
            length = array ? array.length : 0,
            result = [];

          while (++index < length) {
            var value = array[index];

            if (value) {
              result.push(value);
            }
          }

          return result;
        }
        /**
         * Creates an array excluding all values of the provided arrays using strict
         * equality for comparisons, i.e. `===`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to process.
         * @param {...Array} [values] The arrays of values to exclude.
         * @returns {Array} Returns a new array of filtered values.
         * @example
         *
         * _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
         * // => [1, 3, 4]
         */

        function difference(array) {
          return baseDifference(array, baseFlatten(arguments, true, true, 1));
        }
        /**
         * This method is like `_.find` except that it returns the index of the first
         * element that passes the callback check, instead of the element itself.
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to search.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {number} Returns the index of the found element, else `-1`.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney',  'age': 36, 'blocked': false },
         *   { 'name': 'fred',    'age': 40, 'blocked': true },
         *   { 'name': 'pebbles', 'age': 1,  'blocked': false }
         * ];
         *
         * _.findIndex(characters, function(chr) {
         *   return chr.age < 20;
         * });
         * // => 2
         *
         * // using "_.where" callback shorthand
         * _.findIndex(characters, { 'age': 36 });
         * // => 0
         *
         * // using "_.pluck" callback shorthand
         * _.findIndex(characters, 'blocked');
         * // => 1
         */

        function findIndex(array, callback, thisArg) {
          var index = -1,
            length = array ? array.length : 0;
          callback = lodash.createCallback(callback, thisArg, 3);

          while (++index < length) {
            if (callback(array[index], index, array)) {
              return index;
            }
          }

          return -1;
        }
        /**
         * This method is like `_.findIndex` except that it iterates over elements
         * of a `collection` from right to left.
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to search.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {number} Returns the index of the found element, else `-1`.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney',  'age': 36, 'blocked': true },
         *   { 'name': 'fred',    'age': 40, 'blocked': false },
         *   { 'name': 'pebbles', 'age': 1,  'blocked': true }
         * ];
         *
         * _.findLastIndex(characters, function(chr) {
         *   return chr.age > 30;
         * });
         * // => 1
         *
         * // using "_.where" callback shorthand
         * _.findLastIndex(characters, { 'age': 36 });
         * // => 0
         *
         * // using "_.pluck" callback shorthand
         * _.findLastIndex(characters, 'blocked');
         * // => 2
         */

        function findLastIndex(array, callback, thisArg) {
          var length = array ? array.length : 0;
          callback = lodash.createCallback(callback, thisArg, 3);

          while (length--) {
            if (callback(array[length], length, array)) {
              return length;
            }
          }

          return -1;
        }
        /**
         * Gets the first element or first `n` elements of an array. If a callback
         * is provided elements at the beginning of the array are returned as long
         * as the callback returns truey. The callback is bound to `thisArg` and
         * invoked with three arguments; (value, index, array).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias head, take
         * @category Arrays
         * @param {Array} array The array to query.
         * @param {Function|Object|number|string} [callback] The function called
         *  per element or the number of elements to return. If a property name or
         *  object is provided it will be used to create a "_.pluck" or "_.where"
         *  style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the first element(s) of `array`.
         * @example
         *
         * _.first([1, 2, 3]);
         * // => 1
         *
         * _.first([1, 2, 3], 2);
         * // => [1, 2]
         *
         * _.first([1, 2, 3], function(num) {
         *   return num < 3;
         * });
         * // => [1, 2]
         *
         * var characters = [
         *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
         *   { 'name': 'fred',    'blocked': false, 'employer': 'slate' },
         *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.first(characters, 'blocked');
         * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }]
         *
         * // using "_.where" callback shorthand
         * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name');
         * // => ['barney', 'fred']
         */

        function first(array, callback, thisArg) {
          var n = 0,
            length = array ? array.length : 0;

          if (typeof callback != 'number' && callback != null) {
            var index = -1;
            callback = lodash.createCallback(callback, thisArg, 3);

            while (++index < length && callback(array[index], index, array)) {
              n++;
            }
          } else {
            n = callback;

            if (n == null || thisArg) {
              return array ? array[0] : undefined;
            }
          }

          return slice(array, 0, nativeMin(nativeMax(0, n), length));
        }
        /**
         * Flattens a nested array (the nesting can be to any depth). If `isShallow`
         * is truey, the array will only be flattened a single level. If a callback
         * is provided each element of the array is passed through the callback before
         * flattening. The callback is bound to `thisArg` and invoked with three
         * arguments; (value, index, array).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to flatten.
         * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a new flattened array.
         * @example
         *
         * _.flatten([1, [2], [3, [[4]]]]);
         * // => [1, 2, 3, 4];
         *
         * _.flatten([1, [2], [3, [[4]]]], true);
         * // => [1, 2, 3, [[4]]];
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] },
         *   { 'name': 'fred',   'age': 40, 'pets': ['baby puss', 'dino'] }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.flatten(characters, 'pets');
         * // => ['hoppy', 'baby puss', 'dino']
         */

        function flatten(array, isShallow, callback, thisArg) {
          // juggle arguments
          if (typeof isShallow != 'boolean' && isShallow != null) {
            thisArg = callback;
            callback =
              typeof isShallow != 'function' &&
              thisArg &&
              thisArg[isShallow] === array
                ? null
                : isShallow;
            isShallow = false;
          }

          if (callback != null) {
            array = map(array, callback, thisArg);
          }

          return baseFlatten(array, isShallow);
        }
        /**
         * Gets the index at which the first occurrence of `value` is found using
         * strict equality for comparisons, i.e. `===`. If the array is already sorted
         * providing `true` for `fromIndex` will run a faster binary search.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to search.
         * @param {*} value The value to search for.
         * @param {boolean|number} [fromIndex=0] The index to search from or `true`
         *  to perform a binary search on a sorted array.
         * @returns {number} Returns the index of the matched value or `-1`.
         * @example
         *
         * _.indexOf([1, 2, 3, 1, 2, 3], 2);
         * // => 1
         *
         * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
         * // => 4
         *
         * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
         * // => 2
         */

        function indexOf(array, value, fromIndex) {
          if (typeof fromIndex == 'number') {
            var length = array ? array.length : 0;
            fromIndex =
              fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0;
          } else if (fromIndex) {
            var index = sortedIndex(array, value);
            return array[index] === value ? index : -1;
          }

          return baseIndexOf(array, value, fromIndex);
        }
        /**
         * Gets all but the last element or last `n` elements of an array. If a
         * callback is provided elements at the end of the array are excluded from
         * the result as long as the callback returns truey. The callback is bound
         * to `thisArg` and invoked with three arguments; (value, index, array).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to query.
         * @param {Function|Object|number|string} [callback=1] The function called
         *  per element or the number of elements to exclude. If a property name or
         *  object is provided it will be used to create a "_.pluck" or "_.where"
         *  style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a slice of `array`.
         * @example
         *
         * _.initial([1, 2, 3]);
         * // => [1, 2]
         *
         * _.initial([1, 2, 3], 2);
         * // => [1]
         *
         * _.initial([1, 2, 3], function(num) {
         *   return num > 1;
         * });
         * // => [1]
         *
         * var characters = [
         *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
         *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
         *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.initial(characters, 'blocked');
         * // => [{ 'name': 'barney',  'blocked': false, 'employer': 'slate' }]
         *
         * // using "_.where" callback shorthand
         * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name');
         * // => ['barney', 'fred']
         */

        function initial(array, callback, thisArg) {
          var n = 0,
            length = array ? array.length : 0;

          if (typeof callback != 'number' && callback != null) {
            var index = length;
            callback = lodash.createCallback(callback, thisArg, 3);

            while (index-- && callback(array[index], index, array)) {
              n++;
            }
          } else {
            n = callback == null || thisArg ? 1 : callback || n;
          }

          return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
        }
        /**
         * Creates an array of unique values present in all provided arrays using
         * strict equality for comparisons, i.e. `===`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {...Array} [array] The arrays to inspect.
         * @returns {Array} Returns an array of shared values.
         * @example
         *
         * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]);
         * // => [1, 2]
         */

        function intersection() {
          var args = [],
            argsIndex = -1,
            argsLength = arguments.length,
            caches = getArray(),
            indexOf = getIndexOf(),
            trustIndexOf = indexOf === baseIndexOf,
            seen = getArray();

          while (++argsIndex < argsLength) {
            var value = arguments[argsIndex];

            if (isArray(value) || isArguments(value)) {
              args.push(value);
              caches.push(
                trustIndexOf &&
                  value.length >= largeArraySize &&
                  createCache(argsIndex ? args[argsIndex] : seen)
              );
            }
          }

          var array = args[0],
            index = -1,
            length = array ? array.length : 0,
            result = [];

          outer: while (++index < length) {
            var cache = caches[0];
            value = array[index];

            if (
              (cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0
            ) {
              argsIndex = argsLength;
              (cache || seen).push(value);

              while (--argsIndex) {
                cache = caches[argsIndex];

                if (
                  (cache
                    ? cacheIndexOf(cache, value)
                    : indexOf(args[argsIndex], value)) < 0
                ) {
                  continue outer;
                }
              }

              result.push(value);
            }
          }

          while (argsLength--) {
            cache = caches[argsLength];

            if (cache) {
              releaseObject(cache);
            }
          }

          releaseArray(caches);
          releaseArray(seen);
          return result;
        }
        /**
         * Gets the last element or last `n` elements of an array. If a callback is
         * provided elements at the end of the array are returned as long as the
         * callback returns truey. The callback is bound to `thisArg` and invoked
         * with three arguments; (value, index, array).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to query.
         * @param {Function|Object|number|string} [callback] The function called
         *  per element or the number of elements to return. If a property name or
         *  object is provided it will be used to create a "_.pluck" or "_.where"
         *  style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {*} Returns the last element(s) of `array`.
         * @example
         *
         * _.last([1, 2, 3]);
         * // => 3
         *
         * _.last([1, 2, 3], 2);
         * // => [2, 3]
         *
         * _.last([1, 2, 3], function(num) {
         *   return num > 1;
         * });
         * // => [2, 3]
         *
         * var characters = [
         *   { 'name': 'barney',  'blocked': false, 'employer': 'slate' },
         *   { 'name': 'fred',    'blocked': true,  'employer': 'slate' },
         *   { 'name': 'pebbles', 'blocked': true,  'employer': 'na' }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.pluck(_.last(characters, 'blocked'), 'name');
         * // => ['fred', 'pebbles']
         *
         * // using "_.where" callback shorthand
         * _.last(characters, { 'employer': 'na' });
         * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
         */

        function last(array, callback, thisArg) {
          var n = 0,
            length = array ? array.length : 0;

          if (typeof callback != 'number' && callback != null) {
            var index = length;
            callback = lodash.createCallback(callback, thisArg, 3);

            while (index-- && callback(array[index], index, array)) {
              n++;
            }
          } else {
            n = callback;

            if (n == null || thisArg) {
              return array ? array[length - 1] : undefined;
            }
          }

          return slice(array, nativeMax(0, length - n));
        }
        /**
         * Gets the index at which the last occurrence of `value` is found using strict
         * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
         * as the offset from the end of the collection.
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to search.
         * @param {*} value The value to search for.
         * @param {number} [fromIndex=array.length-1] The index to search from.
         * @returns {number} Returns the index of the matched value or `-1`.
         * @example
         *
         * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
         * // => 4
         *
         * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
         * // => 1
         */

        function lastIndexOf(array, value, fromIndex) {
          var index = array ? array.length : 0;

          if (typeof fromIndex == 'number') {
            index =
              (fromIndex < 0
                ? nativeMax(0, index + fromIndex)
                : nativeMin(fromIndex, index - 1)) + 1;
          }

          while (index--) {
            if (array[index] === value) {
              return index;
            }
          }

          return -1;
        }
        /**
         * Removes all provided values from the given array using strict equality for
         * comparisons, i.e. `===`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to modify.
         * @param {...*} [value] The values to remove.
         * @returns {Array} Returns `array`.
         * @example
         *
         * var array = [1, 2, 3, 1, 2, 3];
         * _.pull(array, 2, 3);
         * console.log(array);
         * // => [1, 1]
         */

        function pull(array) {
          var args = arguments,
            argsIndex = 0,
            argsLength = args.length,
            length = array ? array.length : 0;

          while (++argsIndex < argsLength) {
            var index = -1,
              value = args[argsIndex];

            while (++index < length) {
              if (array[index] === value) {
                splice.call(array, index--, 1);
                length--;
              }
            }
          }

          return array;
        }
        /**
         * Creates an array of numbers (positive and/or negative) progressing from
         * `start` up to but not including `end`. If `start` is less than `stop` a
         * zero-length range is created unless a negative `step` is specified.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {number} [start=0] The start of the range.
         * @param {number} end The end of the range.
         * @param {number} [step=1] The value to increment or decrement by.
         * @returns {Array} Returns a new range array.
         * @example
         *
         * _.range(4);
         * // => [0, 1, 2, 3]
         *
         * _.range(1, 5);
         * // => [1, 2, 3, 4]
         *
         * _.range(0, 20, 5);
         * // => [0, 5, 10, 15]
         *
         * _.range(0, -4, -1);
         * // => [0, -1, -2, -3]
         *
         * _.range(1, 4, 0);
         * // => [1, 1, 1]
         *
         * _.range(0);
         * // => []
         */

        function range(start, end, step) {
          start = +start || 0;
          step = typeof step == 'number' ? step : +step || 1;

          if (end == null) {
            end = start;
            start = 0;
          } // use `Array(length)` so engines like Chakra and V8 avoid slower modes
          // http://youtu.be/XAqIpGU8ZZk#t=17m25s

          var index = -1,
            length = nativeMax(0, ceil((end - start) / (step || 1))),
            result = Array(length);

          while (++index < length) {
            result[index] = start;
            start += step;
          }

          return result;
        }
        /**
         * Removes all elements from an array that the callback returns truey for
         * and returns an array of removed elements. The callback is bound to `thisArg`
         * and invoked with three arguments; (value, index, array).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to modify.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a new array of removed elements.
         * @example
         *
         * var array = [1, 2, 3, 4, 5, 6];
         * var evens = _.remove(array, function(num) { return num % 2 == 0; });
         *
         * console.log(array);
         * // => [1, 3, 5]
         *
         * console.log(evens);
         * // => [2, 4, 6]
         */

        function remove(array, callback, thisArg) {
          var index = -1,
            length = array ? array.length : 0,
            result = [];
          callback = lodash.createCallback(callback, thisArg, 3);

          while (++index < length) {
            var value = array[index];

            if (callback(value, index, array)) {
              result.push(value);
              splice.call(array, index--, 1);
              length--;
            }
          }

          return result;
        }
        /**
         * The opposite of `_.initial` this method gets all but the first element or
         * first `n` elements of an array. If a callback function is provided elements
         * at the beginning of the array are excluded from the result as long as the
         * callback returns truey. The callback is bound to `thisArg` and invoked
         * with three arguments; (value, index, array).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias drop, tail
         * @category Arrays
         * @param {Array} array The array to query.
         * @param {Function|Object|number|string} [callback=1] The function called
         *  per element or the number of elements to exclude. If a property name or
         *  object is provided it will be used to create a "_.pluck" or "_.where"
         *  style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a slice of `array`.
         * @example
         *
         * _.rest([1, 2, 3]);
         * // => [2, 3]
         *
         * _.rest([1, 2, 3], 2);
         * // => [3]
         *
         * _.rest([1, 2, 3], function(num) {
         *   return num < 3;
         * });
         * // => [3]
         *
         * var characters = [
         *   { 'name': 'barney',  'blocked': true,  'employer': 'slate' },
         *   { 'name': 'fred',    'blocked': false,  'employer': 'slate' },
         *   { 'name': 'pebbles', 'blocked': true, 'employer': 'na' }
         * ];
         *
         * // using "_.pluck" callback shorthand
         * _.pluck(_.rest(characters, 'blocked'), 'name');
         * // => ['fred', 'pebbles']
         *
         * // using "_.where" callback shorthand
         * _.rest(characters, { 'employer': 'slate' });
         * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }]
         */

        function rest(array, callback, thisArg) {
          if (typeof callback != 'number' && callback != null) {
            var n = 0,
              index = -1,
              length = array ? array.length : 0;
            callback = lodash.createCallback(callback, thisArg, 3);

            while (++index < length && callback(array[index], index, array)) {
              n++;
            }
          } else {
            n = callback == null || thisArg ? 1 : nativeMax(0, callback);
          }

          return slice(array, n);
        }
        /**
         * Uses a binary search to determine the smallest index at which a value
         * should be inserted into a given sorted array in order to maintain the sort
         * order of the array. If a callback is provided it will be executed for
         * `value` and each element of `array` to compute their sort ranking. The
         * callback is bound to `thisArg` and invoked with one argument; (value).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to inspect.
         * @param {*} value The value to evaluate.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {number} Returns the index at which `value` should be inserted
         *  into `array`.
         * @example
         *
         * _.sortedIndex([20, 30, 50], 40);
         * // => 2
         *
         * // using "_.pluck" callback shorthand
         * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
         * // => 2
         *
         * var dict = {
         *   'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
         * };
         *
         * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
         *   return dict.wordToNumber[word];
         * });
         * // => 2
         *
         * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
         *   return this.wordToNumber[word];
         * }, dict);
         * // => 2
         */

        function sortedIndex(array, value, callback, thisArg) {
          var low = 0,
            high = array ? array.length : low; // explicitly reference `identity` for better inlining in Firefox

          callback = callback
            ? lodash.createCallback(callback, thisArg, 1)
            : identity;
          value = callback(value);

          while (low < high) {
            var mid = (low + high) >>> 1;
            callback(array[mid]) < value ? (low = mid + 1) : (high = mid);
          }

          return low;
        }
        /**
         * Creates an array of unique values, in order, of the provided arrays using
         * strict equality for comparisons, i.e. `===`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {...Array} [array] The arrays to inspect.
         * @returns {Array} Returns an array of combined values.
         * @example
         *
         * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]);
         * // => [1, 2, 3, 5, 4]
         */

        function union() {
          return baseUniq(baseFlatten(arguments, true, true));
        }
        /**
         * Creates a duplicate-value-free version of an array using strict equality
         * for comparisons, i.e. `===`. If the array is sorted, providing
         * `true` for `isSorted` will use a faster algorithm. If a callback is provided
         * each element of `array` is passed through the callback before uniqueness
         * is computed. The callback is bound to `thisArg` and invoked with three
         * arguments; (value, index, array).
         *
         * If a property name is provided for `callback` the created "_.pluck" style
         * callback will return the property value of the given element.
         *
         * If an object is provided for `callback` the created "_.where" style callback
         * will return `true` for elements that have the properties of the given object,
         * else `false`.
         *
         * @static
         * @memberOf _
         * @alias unique
         * @category Arrays
         * @param {Array} array The array to process.
         * @param {boolean} [isSorted=false] A flag to indicate that `array` is sorted.
         * @param {Function|Object|string} [callback=identity] The function called
         *  per iteration. If a property name or object is provided it will be used
         *  to create a "_.pluck" or "_.where" style callback, respectively.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns a duplicate-value-free array.
         * @example
         *
         * _.uniq([1, 2, 1, 3, 1]);
         * // => [1, 2, 3]
         *
         * _.uniq([1, 1, 2, 2, 3], true);
         * // => [1, 2, 3]
         *
         * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
         * // => ['A', 'b', 'C']
         *
         * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
         * // => [1, 2.5, 3]
         *
         * // using "_.pluck" callback shorthand
         * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
         * // => [{ 'x': 1 }, { 'x': 2 }]
         */

        function uniq(array, isSorted, callback, thisArg) {
          // juggle arguments
          if (typeof isSorted != 'boolean' && isSorted != null) {
            thisArg = callback;
            callback =
              typeof isSorted != 'function' &&
              thisArg &&
              thisArg[isSorted] === array
                ? null
                : isSorted;
            isSorted = false;
          }

          if (callback != null) {
            callback = lodash.createCallback(callback, thisArg, 3);
          }

          return baseUniq(array, isSorted, callback);
        }
        /**
         * Creates an array excluding all provided values using strict equality for
         * comparisons, i.e. `===`.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {Array} array The array to filter.
         * @param {...*} [value] The values to exclude.
         * @returns {Array} Returns a new array of filtered values.
         * @example
         *
         * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
         * // => [2, 3, 4]
         */

        function without(array) {
          return baseDifference(array, slice(arguments, 1));
        }
        /**
         * Creates an array that is the symmetric difference of the provided arrays.
         * See http://en.wikipedia.org/wiki/Symmetric_difference.
         *
         * @static
         * @memberOf _
         * @category Arrays
         * @param {...Array} [array] The arrays to inspect.
         * @returns {Array} Returns an array of values.
         * @example
         *
         * _.xor([1, 2, 3], [5, 2, 1, 4]);
         * // => [3, 5, 4]
         *
         * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]);
         * // => [1, 4, 5]
         */

        function xor() {
          var index = -1,
            length = arguments.length;

          while (++index < length) {
            var array = arguments[index];

            if (isArray(array) || isArguments(array)) {
              var result = result
                ? baseUniq(
                    baseDifference(result, array).concat(
                      baseDifference(array, result)
                    )
                  )
                : array;
            }
          }

          return result || [];
        }
        /**
         * Creates an array of grouped elements, the first of which contains the first
         * elements of the given arrays, the second of which contains the second
         * elements of the given arrays, and so on.
         *
         * @static
         * @memberOf _
         * @alias unzip
         * @category Arrays
         * @param {...Array} [array] Arrays to process.
         * @returns {Array} Returns a new array of grouped elements.
         * @example
         *
         * _.zip(['fred', 'barney'], [30, 40], [true, false]);
         * // => [['fred', 30, true], ['barney', 40, false]]
         */

        function zip() {
          var array = arguments.length > 1 ? arguments : arguments[0],
            index = -1,
            length = array ? max(pluck(array, 'length')) : 0,
            result = Array(length < 0 ? 0 : length);

          while (++index < length) {
            result[index] = pluck(array, index);
          }

          return result;
        }
        /**
         * Creates an object composed from arrays of `keys` and `values`. Provide
         * either a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`
         * or two arrays, one of `keys` and one of corresponding `values`.
         *
         * @static
         * @memberOf _
         * @alias object
         * @category Arrays
         * @param {Array} keys The array of keys.
         * @param {Array} [values=[]] The array of values.
         * @returns {Object} Returns an object composed of the given keys and
         *  corresponding values.
         * @example
         *
         * _.zipObject(['fred', 'barney'], [30, 40]);
         * // => { 'fred': 30, 'barney': 40 }
         */

        function zipObject(keys, values) {
          var index = -1,
            length = keys ? keys.length : 0,
            result = {};

          if (!values && length && !isArray(keys[0])) {
            values = [];
          }

          while (++index < length) {
            var key = keys[index];

            if (values) {
              result[key] = values[index];
            } else if (key) {
              result[key[0]] = key[1];
            }
          }

          return result;
        }
        /*--------------------------------------------------------------------------*/

        /**
         * Creates a function that executes `func`, with  the `this` binding and
         * arguments of the created function, only after being called `n` times.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {number} n The number of times the function must be called before
         *  `func` is executed.
         * @param {Function} func The function to restrict.
         * @returns {Function} Returns the new restricted function.
         * @example
         *
         * var saves = ['profile', 'settings'];
         *
         * var done = _.after(saves.length, function() {
         *   console.log('Done saving!');
         * });
         *
         * _.forEach(saves, function(type) {
         *   asyncSave({ 'type': type, 'complete': done });
         * });
         * // => logs 'Done saving!', after all saves have completed
         */

        function after(n, func) {
          if (!isFunction(func)) {
            throw new TypeError();
          }

          return function() {
            if (--n < 1) {
              return func.apply(this, arguments);
            }
          };
        }
        /**
         * Creates a function that, when called, invokes `func` with the `this`
         * binding of `thisArg` and prepends any additional `bind` arguments to those
         * provided to the bound function.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to bind.
         * @param {*} [thisArg] The `this` binding of `func`.
         * @param {...*} [arg] Arguments to be partially applied.
         * @returns {Function} Returns the new bound function.
         * @example
         *
         * var func = function(greeting) {
         *   return greeting + ' ' + this.name;
         * };
         *
         * func = _.bind(func, { 'name': 'fred' }, 'hi');
         * func();
         * // => 'hi fred'
         */

        function bind(func, thisArg) {
          return arguments.length > 2
            ? createWrapper(func, 17, slice(arguments, 2), null, thisArg)
            : createWrapper(func, 1, null, null, thisArg);
        }
        /**
         * Binds methods of an object to the object itself, overwriting the existing
         * method. Method names may be specified as individual arguments or as arrays
         * of method names. If no method names are provided all the function properties
         * of `object` will be bound.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Object} object The object to bind and assign the bound methods to.
         * @param {...string} [methodName] The object method names to
         *  bind, specified as individual method names or arrays of method names.
         * @returns {Object} Returns `object`.
         * @example
         *
         * var view = {
         *   'label': 'docs',
         *   'onClick': function() { console.log('clicked ' + this.label); }
         * };
         *
         * _.bindAll(view);
         * jQuery('#docs').on('click', view.onClick);
         * // => logs 'clicked docs', when the button is clicked
         */

        function bindAll(object) {
          var funcs =
              arguments.length > 1
                ? baseFlatten(arguments, true, false, 1)
                : functions(object),
            index = -1,
            length = funcs.length;

          while (++index < length) {
            var key = funcs[index];
            object[key] = createWrapper(object[key], 1, null, null, object);
          }

          return object;
        }
        /**
         * Creates a function that, when called, invokes the method at `object[key]`
         * and prepends any additional `bindKey` arguments to those provided to the bound
         * function. This method differs from `_.bind` by allowing bound functions to
         * reference methods that will be redefined or don't yet exist.
         * See http://michaux.ca/articles/lazy-function-definition-pattern.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Object} object The object the method belongs to.
         * @param {string} key The key of the method.
         * @param {...*} [arg] Arguments to be partially applied.
         * @returns {Function} Returns the new bound function.
         * @example
         *
         * var object = {
         *   'name': 'fred',
         *   'greet': function(greeting) {
         *     return greeting + ' ' + this.name;
         *   }
         * };
         *
         * var func = _.bindKey(object, 'greet', 'hi');
         * func();
         * // => 'hi fred'
         *
         * object.greet = function(greeting) {
         *   return greeting + 'ya ' + this.name + '!';
         * };
         *
         * func();
         * // => 'hiya fred!'
         */

        function bindKey(object, key) {
          return arguments.length > 2
            ? createWrapper(key, 19, slice(arguments, 2), null, object)
            : createWrapper(key, 3, null, null, object);
        }
        /**
         * Creates a function that is the composition of the provided functions,
         * where each function consumes the return value of the function that follows.
         * For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
         * Each function is executed with the `this` binding of the composed function.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {...Function} [func] Functions to compose.
         * @returns {Function} Returns the new composed function.
         * @example
         *
         * var realNameMap = {
         *   'pebbles': 'penelope'
         * };
         *
         * var format = function(name) {
         *   name = realNameMap[name.toLowerCase()] || name;
         *   return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
         * };
         *
         * var greet = function(formatted) {
         *   return 'Hiya ' + formatted + '!';
         * };
         *
         * var welcome = _.compose(greet, format);
         * welcome('pebbles');
         * // => 'Hiya Penelope!'
         */

        function compose() {
          var funcs = arguments,
            length = funcs.length;

          while (length--) {
            if (!isFunction(funcs[length])) {
              throw new TypeError();
            }
          }

          return function() {
            var args = arguments,
              length = funcs.length;

            while (length--) {
              args = [funcs[length].apply(this, args)];
            }

            return args[0];
          };
        }
        /**
         * Creates a function which accepts one or more arguments of `func` that when
         * invoked either executes `func` returning its result, if all `func` arguments
         * have been provided, or returns a function that accepts one or more of the
         * remaining `func` arguments, and so on. The arity of `func` can be specified
         * if `func.length` is not sufficient.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to curry.
         * @param {number} [arity=func.length] The arity of `func`.
         * @returns {Function} Returns the new curried function.
         * @example
         *
         * var curried = _.curry(function(a, b, c) {
         *   console.log(a + b + c);
         * });
         *
         * curried(1)(2)(3);
         * // => 6
         *
         * curried(1, 2)(3);
         * // => 6
         *
         * curried(1, 2, 3);
         * // => 6
         */

        function curry(func, arity) {
          arity = typeof arity == 'number' ? arity : +arity || func.length;
          return createWrapper(func, 4, null, null, null, arity);
        }
        /**
         * Creates a function that will delay the execution of `func` until after
         * `wait` milliseconds have elapsed since the last time it was invoked.
         * Provide an options object to indicate that `func` should be invoked on
         * the leading and/or trailing edge of the `wait` timeout. Subsequent calls
         * to the debounced function will return the result of the last `func` call.
         *
         * Note: If `leading` and `trailing` options are `true` `func` will be called
         * on the trailing edge of the timeout only if the the debounced function is
         * invoked more than once during the `wait` timeout.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to debounce.
         * @param {number} wait The number of milliseconds to delay.
         * @param {Object} [options] The options object.
         * @param {boolean} [options.leading=false] Specify execution on the leading edge of the timeout.
         * @param {number} [options.maxWait] The maximum time `func` is allowed to be delayed before it's called.
         * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
         * @returns {Function} Returns the new debounced function.
         * @example
         *
         * // avoid costly calculations while the window size is in flux
         * var lazyLayout = _.debounce(calculateLayout, 150);
         * jQuery(window).on('resize', lazyLayout);
         *
         * // execute `sendMail` when the click event is fired, debouncing subsequent calls
         * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
         *   'leading': true,
         *   'trailing': false
         * });
         *
         * // ensure `batchLog` is executed once after 1 second of debounced calls
         * var source = new EventSource('/stream');
         * source.addEventListener('message', _.debounce(batchLog, 250, {
         *   'maxWait': 1000
         * }, false);
         */

        function debounce(func, wait, options) {
          var args,
            maxTimeoutId,
            result,
            stamp,
            thisArg,
            timeoutId,
            trailingCall,
            lastCalled = 0,
            maxWait = false,
            trailing = true;

          if (!isFunction(func)) {
            throw new TypeError();
          }

          wait = nativeMax(0, wait) || 0;

          if (options === true) {
            var leading = true;
            trailing = false;
          } else if (isObject(options)) {
            leading = options.leading;
            maxWait =
              'maxWait' in options && (nativeMax(wait, options.maxWait) || 0);
            trailing = 'trailing' in options ? options.trailing : trailing;
          }

          var delayed = function() {
            var remaining = wait - (now() - stamp);

            if (remaining <= 0) {
              if (maxTimeoutId) {
                clearTimeout(maxTimeoutId);
              }

              var isCalled = trailingCall;
              maxTimeoutId = timeoutId = trailingCall = undefined;

              if (isCalled) {
                lastCalled = now();
                result = func.apply(thisArg, args);

                if (!timeoutId && !maxTimeoutId) {
                  args = thisArg = null;
                }
              }
            } else {
              timeoutId = setTimeout(delayed, remaining);
            }
          };

          var maxDelayed = function() {
            if (timeoutId) {
              clearTimeout(timeoutId);
            }

            maxTimeoutId = timeoutId = trailingCall = undefined;

            if (trailing || maxWait !== wait) {
              lastCalled = now();
              result = func.apply(thisArg, args);

              if (!timeoutId && !maxTimeoutId) {
                args = thisArg = null;
              }
            }
          };

          return function() {
            args = arguments;
            stamp = now();
            thisArg = this;
            trailingCall = trailing && (timeoutId || !leading);

            if (maxWait === false) {
              var leadingCall = leading && !timeoutId;
            } else {
              if (!maxTimeoutId && !leading) {
                lastCalled = stamp;
              }

              var remaining = maxWait - (stamp - lastCalled),
                isCalled = remaining <= 0;

              if (isCalled) {
                if (maxTimeoutId) {
                  maxTimeoutId = clearTimeout(maxTimeoutId);
                }

                lastCalled = stamp;
                result = func.apply(thisArg, args);
              } else if (!maxTimeoutId) {
                maxTimeoutId = setTimeout(maxDelayed, remaining);
              }
            }

            if (isCalled && timeoutId) {
              timeoutId = clearTimeout(timeoutId);
            } else if (!timeoutId && wait !== maxWait) {
              timeoutId = setTimeout(delayed, wait);
            }

            if (leadingCall) {
              isCalled = true;
              result = func.apply(thisArg, args);
            }

            if (isCalled && !timeoutId && !maxTimeoutId) {
              args = thisArg = null;
            }

            return result;
          };
        }
        /**
         * Defers executing the `func` function until the current call stack has cleared.
         * Additional arguments will be provided to `func` when it is invoked.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to defer.
         * @param {...*} [arg] Arguments to invoke the function with.
         * @returns {number} Returns the timer id.
         * @example
         *
         * _.defer(function(text) { console.log(text); }, 'deferred');
         * // logs 'deferred' after one or more milliseconds
         */

        function defer(func) {
          if (!isFunction(func)) {
            throw new TypeError();
          }

          var args = slice(arguments, 1);
          return setTimeout(function() {
            func.apply(undefined, args);
          }, 1);
        }
        /**
         * Executes the `func` function after `wait` milliseconds. Additional arguments
         * will be provided to `func` when it is invoked.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to delay.
         * @param {number} wait The number of milliseconds to delay execution.
         * @param {...*} [arg] Arguments to invoke the function with.
         * @returns {number} Returns the timer id.
         * @example
         *
         * _.delay(function(text) { console.log(text); }, 1000, 'later');
         * // => logs 'later' after one second
         */

        function delay(func, wait) {
          if (!isFunction(func)) {
            throw new TypeError();
          }

          var args = slice(arguments, 2);
          return setTimeout(function() {
            func.apply(undefined, args);
          }, wait);
        }
        /**
         * Creates a function that memoizes the result of `func`. If `resolver` is
         * provided it will be used to determine the cache key for storing the result
         * based on the arguments provided to the memoized function. By default, the
         * first argument provided to the memoized function is used as the cache key.
         * The `func` is executed with the `this` binding of the memoized function.
         * The result cache is exposed as the `cache` property on the memoized function.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to have its output memoized.
         * @param {Function} [resolver] A function used to resolve the cache key.
         * @returns {Function} Returns the new memoizing function.
         * @example
         *
         * var fibonacci = _.memoize(function(n) {
         *   return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
         * });
         *
         * fibonacci(9)
         * // => 34
         *
         * var data = {
         *   'fred': { 'name': 'fred', 'age': 40 },
         *   'pebbles': { 'name': 'pebbles', 'age': 1 }
         * };
         *
         * // modifying the result cache
         * var get = _.memoize(function(name) { return data[name]; }, _.identity);
         * get('pebbles');
         * // => { 'name': 'pebbles', 'age': 1 }
         *
         * get.cache.pebbles.name = 'penelope';
         * get('pebbles');
         * // => { 'name': 'penelope', 'age': 1 }
         */

        function memoize(func, resolver) {
          if (!isFunction(func)) {
            throw new TypeError();
          }

          var memoized = function() {
            var cache = memoized.cache,
              key = resolver
                ? resolver.apply(this, arguments)
                : keyPrefix + arguments[0];
            return hasOwnProperty.call(cache, key)
              ? cache[key]
              : (cache[key] = func.apply(this, arguments));
          };

          memoized.cache = {};
          return memoized;
        }
        /**
         * Creates a function that is restricted to execute `func` once. Repeat calls to
         * the function will return the value of the first call. The `func` is executed
         * with the `this` binding of the created function.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to restrict.
         * @returns {Function} Returns the new restricted function.
         * @example
         *
         * var initialize = _.once(createApplication);
         * initialize();
         * initialize();
         * // `initialize` executes `createApplication` once
         */

        function once(func) {
          var ran, result;

          if (!isFunction(func)) {
            throw new TypeError();
          }

          return function() {
            if (ran) {
              return result;
            }

            ran = true;
            result = func.apply(this, arguments); // clear the `func` variable so the function may be garbage collected

            func = null;
            return result;
          };
        }
        /**
         * Creates a function that, when called, invokes `func` with any additional
         * `partial` arguments prepended to those provided to the new function. This
         * method is similar to `_.bind` except it does **not** alter the `this` binding.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to partially apply arguments to.
         * @param {...*} [arg] Arguments to be partially applied.
         * @returns {Function} Returns the new partially applied function.
         * @example
         *
         * var greet = function(greeting, name) { return greeting + ' ' + name; };
         * var hi = _.partial(greet, 'hi');
         * hi('fred');
         * // => 'hi fred'
         */

        function partial(func) {
          return createWrapper(func, 16, slice(arguments, 1));
        }
        /**
         * This method is like `_.partial` except that `partial` arguments are
         * appended to those provided to the new function.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to partially apply arguments to.
         * @param {...*} [arg] Arguments to be partially applied.
         * @returns {Function} Returns the new partially applied function.
         * @example
         *
         * var defaultsDeep = _.partialRight(_.merge, _.defaults);
         *
         * var options = {
         *   'variable': 'data',
         *   'imports': { 'jq': $ }
         * };
         *
         * defaultsDeep(options, _.templateSettings);
         *
         * options.variable
         * // => 'data'
         *
         * options.imports
         * // => { '_': _, 'jq': $ }
         */

        function partialRight(func) {
          return createWrapper(func, 32, null, slice(arguments, 1));
        }
        /**
         * Creates a function that, when executed, will only call the `func` function
         * at most once per every `wait` milliseconds. Provide an options object to
         * indicate that `func` should be invoked on the leading and/or trailing edge
         * of the `wait` timeout. Subsequent calls to the throttled function will
         * return the result of the last `func` call.
         *
         * Note: If `leading` and `trailing` options are `true` `func` will be called
         * on the trailing edge of the timeout only if the the throttled function is
         * invoked more than once during the `wait` timeout.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {Function} func The function to throttle.
         * @param {number} wait The number of milliseconds to throttle executions to.
         * @param {Object} [options] The options object.
         * @param {boolean} [options.leading=true] Specify execution on the leading edge of the timeout.
         * @param {boolean} [options.trailing=true] Specify execution on the trailing edge of the timeout.
         * @returns {Function} Returns the new throttled function.
         * @example
         *
         * // avoid excessively updating the position while scrolling
         * var throttled = _.throttle(updatePosition, 100);
         * jQuery(window).on('scroll', throttled);
         *
         * // execute `renewToken` when the click event is fired, but not more than once every 5 minutes
         * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
         *   'trailing': false
         * }));
         */

        function throttle(func, wait, options) {
          var leading = true,
            trailing = true;

          if (!isFunction(func)) {
            throw new TypeError();
          }

          if (options === false) {
            leading = false;
          } else if (isObject(options)) {
            leading = 'leading' in options ? options.leading : leading;
            trailing = 'trailing' in options ? options.trailing : trailing;
          }

          debounceOptions.leading = leading;
          debounceOptions.maxWait = wait;
          debounceOptions.trailing = trailing;
          return debounce(func, wait, debounceOptions);
        }
        /**
         * Creates a function that provides `value` to the wrapper function as its
         * first argument. Additional arguments provided to the function are appended
         * to those provided to the wrapper function. The wrapper is executed with
         * the `this` binding of the created function.
         *
         * @static
         * @memberOf _
         * @category Functions
         * @param {*} value The value to wrap.
         * @param {Function} wrapper The wrapper function.
         * @returns {Function} Returns the new function.
         * @example
         *
         * var p = _.wrap(_.escape, function(func, text) {
         *   return '<p>' + func(text) + '</p>';
         * });
         *
         * p('Fred, Wilma, & Pebbles');
         * // => '<p>Fred, Wilma, &amp; Pebbles</p>'
         */

        function wrap(value, wrapper) {
          return createWrapper(wrapper, 16, [value]);
        }
        /*--------------------------------------------------------------------------*/

        /**
         * Creates a function that returns `value`.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {*} value The value to return from the new function.
         * @returns {Function} Returns the new function.
         * @example
         *
         * var object = { 'name': 'fred' };
         * var getter = _.constant(object);
         * getter() === object;
         * // => true
         */

        function constant(value) {
          return function() {
            return value;
          };
        }
        /**
         * Produces a callback bound to an optional `thisArg`. If `func` is a property
         * name the created callback will return the property value for a given element.
         * If `func` is an object the created callback will return `true` for elements
         * that contain the equivalent object properties, otherwise it will return `false`.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {*} [func=identity] The value to convert to a callback.
         * @param {*} [thisArg] The `this` binding of the created callback.
         * @param {number} [argCount] The number of arguments the callback accepts.
         * @returns {Function} Returns a callback function.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * // wrap to create custom callback shorthands
         * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
         *   var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
         *   return !match ? func(callback, thisArg) : function(object) {
         *     return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
         *   };
         * });
         *
         * _.filter(characters, 'age__gt38');
         * // => [{ 'name': 'fred', 'age': 40 }]
         */

        function createCallback(func, thisArg, argCount) {
          var type = typeof func;

          if (func == null || type == 'function') {
            return baseCreateCallback(func, thisArg, argCount);
          } // handle "_.pluck" style callback shorthands

          if (type != 'object') {
            return property(func);
          }

          var props = keys(func),
            key = props[0],
            a = func[key]; // handle "_.where" style callback shorthands

          if (props.length == 1 && a === a && !isObject(a)) {
            // fast path the common case of providing an object with a single
            // property containing a primitive value
            return function(object) {
              var b = object[key];
              return a === b && (a !== 0 || 1 / a == 1 / b);
            };
          }

          return function(object) {
            var length = props.length,
              result = false;

            while (length--) {
              if (
                !(result = baseIsEqual(
                  object[props[length]],
                  func[props[length]],
                  null,
                  true
                ))
              ) {
                break;
              }
            }

            return result;
          };
        }
        /**
         * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
         * corresponding HTML entities.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {string} string The string to escape.
         * @returns {string} Returns the escaped string.
         * @example
         *
         * _.escape('Fred, Wilma, & Pebbles');
         * // => 'Fred, Wilma, &amp; Pebbles'
         */

        function escape(string) {
          return string == null
            ? ''
            : String(string).replace(reUnescapedHtml, escapeHtmlChar);
        }
        /**
         * This method returns the first argument provided to it.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {*} value Any value.
         * @returns {*} Returns `value`.
         * @example
         *
         * var object = { 'name': 'fred' };
         * _.identity(object) === object;
         * // => true
         */

        function identity(value) {
          return value;
        }
        /**
         * Adds function properties of a source object to the destination object.
         * If `object` is a function methods will be added to its prototype as well.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {Function|Object} [object=lodash] object The destination object.
         * @param {Object} source The object of functions to add.
         * @param {Object} [options] The options object.
         * @param {boolean} [options.chain=true] Specify whether the functions added are chainable.
         * @example
         *
         * function capitalize(string) {
         *   return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
         * }
         *
         * _.mixin({ 'capitalize': capitalize });
         * _.capitalize('fred');
         * // => 'Fred'
         *
         * _('fred').capitalize().value();
         * // => 'Fred'
         *
         * _.mixin({ 'capitalize': capitalize }, { 'chain': false });
         * _('fred').capitalize();
         * // => 'Fred'
         */

        function mixin(object, source, options) {
          var chain = true,
            methodNames = source && functions(source);

          if (!source || (!options && !methodNames.length)) {
            if (options == null) {
              options = source;
            }

            ctor = lodashWrapper;
            source = object;
            object = lodash;
            methodNames = functions(source);
          }

          if (options === false) {
            chain = false;
          } else if (isObject(options) && 'chain' in options) {
            chain = options.chain;
          }

          var ctor = object,
            isFunc = isFunction(ctor);
          forEach(methodNames, function(methodName) {
            var func = (object[methodName] = source[methodName]);

            if (isFunc) {
              ctor.prototype[methodName] = function() {
                var chainAll = this.__chain__,
                  value = this.__wrapped__,
                  args = [value];
                push.apply(args, arguments);
                var result = func.apply(object, args);

                if (chain || chainAll) {
                  if (value === result && isObject(result)) {
                    return this;
                  }

                  result = new ctor(result);
                  result.__chain__ = chainAll;
                }

                return result;
              };
            }
          });
        }
        /**
         * Reverts the '_' variable to its previous value and returns a reference to
         * the `lodash` function.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @returns {Function} Returns the `lodash` function.
         * @example
         *
         * var lodash = _.noConflict();
         */

        function noConflict() {
          context._ = oldDash;
          return this;
        }
        /**
         * A no-operation function.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @example
         *
         * var object = { 'name': 'fred' };
         * _.noop(object) === undefined;
         * // => true
         */

        function noop() {} // no operation performed

        /**
         * Gets the number of milliseconds that have elapsed since the Unix epoch
         * (1 January 1970 00:00:00 UTC).
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @example
         *
         * var stamp = _.now();
         * _.defer(function() { console.log(_.now() - stamp); });
         * // => logs the number of milliseconds it took for the deferred function to be called
         */

        var now =
          (isNative((now = Date.now)) && now) ||
          function() {
            return new Date().getTime();
          };
        /**
         * Converts the given value into an integer of the specified radix.
         * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the
         * `value` is a hexadecimal, in which case a `radix` of `16` is used.
         *
         * Note: This method avoids differences in native ES3 and ES5 `parseInt`
         * implementations. See http://es5.github.io/#E.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {string} value The value to parse.
         * @param {number} [radix] The radix used to interpret the value to parse.
         * @returns {number} Returns the new integer value.
         * @example
         *
         * _.parseInt('08');
         * // => 8
         */

        var parseInt =
          nativeParseInt(whitespace + '08') == 8
            ? nativeParseInt
            : function(value, radix) {
                // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt`
                return nativeParseInt(
                  isString(value)
                    ? value.replace(reLeadingSpacesAndZeros, '')
                    : value,
                  radix || 0
                );
              };
        /**
         * Creates a "_.pluck" style function, which returns the `key` value of a
         * given object.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {string} key The name of the property to retrieve.
         * @returns {Function} Returns the new function.
         * @example
         *
         * var characters = [
         *   { 'name': 'fred',   'age': 40 },
         *   { 'name': 'barney', 'age': 36 }
         * ];
         *
         * var getName = _.property('name');
         *
         * _.map(characters, getName);
         * // => ['barney', 'fred']
         *
         * _.sortBy(characters, getName);
         * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred',   'age': 40 }]
         */

        function property(key) {
          return function(object) {
            return object[key];
          };
        }
        /**
         * Produces a random number between `min` and `max` (inclusive). If only one
         * argument is provided a number between `0` and the given number will be
         * returned. If `floating` is truey or either `min` or `max` are floats a
         * floating-point number will be returned instead of an integer.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {number} [min=0] The minimum possible value.
         * @param {number} [max=1] The maximum possible value.
         * @param {boolean} [floating=false] Specify returning a floating-point number.
         * @returns {number} Returns a random number.
         * @example
         *
         * _.random(0, 5);
         * // => an integer between 0 and 5
         *
         * _.random(5);
         * // => also an integer between 0 and 5
         *
         * _.random(5, true);
         * // => a floating-point number between 0 and 5
         *
         * _.random(1.2, 5.2);
         * // => a floating-point number between 1.2 and 5.2
         */

        function random(min, max, floating) {
          var noMin = min == null,
            noMax = max == null;

          if (floating == null) {
            if (typeof min == 'boolean' && noMax) {
              floating = min;
              min = 1;
            } else if (!noMax && typeof max == 'boolean') {
              floating = max;
              noMax = true;
            }
          }

          if (noMin && noMax) {
            max = 1;
          }

          min = +min || 0;

          if (noMax) {
            max = min;
            min = 0;
          } else {
            max = +max || 0;
          }

          if (floating || min % 1 || max % 1) {
            var rand = nativeRandom();
            return nativeMin(
              min +
                rand *
                  (max - min + parseFloat('1e-' + ((rand + '').length - 1))),
              max
            );
          }

          return baseRandom(min, max);
        }
        /**
         * Resolves the value of property `key` on `object`. If `key` is a function
         * it will be invoked with the `this` binding of `object` and its result returned,
         * else the property value is returned. If `object` is falsey then `undefined`
         * is returned.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {Object} object The object to inspect.
         * @param {string} key The name of the property to resolve.
         * @returns {*} Returns the resolved value.
         * @example
         *
         * var object = {
         *   'cheese': 'crumpets',
         *   'stuff': function() {
         *     return 'nonsense';
         *   }
         * };
         *
         * _.result(object, 'cheese');
         * // => 'crumpets'
         *
         * _.result(object, 'stuff');
         * // => 'nonsense'
         */

        function result(object, key) {
          if (object) {
            var value = object[key];
            return isFunction(value) ? object[key]() : value;
          }
        }
        /**
         * A micro-templating method that handles arbitrary delimiters, preserves
         * whitespace, and correctly escapes quotes within interpolated code.
         *
         * Note: In the development build, `_.template` utilizes sourceURLs for easier
         * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
         *
         * For more information on precompiling templates see:
         * https://lodash.com/custom-builds
         *
         * For more information on Chrome extension sandboxes see:
         * http://developer.chrome.com/stable/extensions/sandboxingEval.html
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {string} text The template text.
         * @param {Object} data The data object used to populate the text.
         * @param {Object} [options] The options object.
         * @param {RegExp} [options.escape] The "escape" delimiter.
         * @param {RegExp} [options.evaluate] The "evaluate" delimiter.
         * @param {Object} [options.imports] An object to import into the template as local variables.
         * @param {RegExp} [options.interpolate] The "interpolate" delimiter.
         * @param {string} [sourceURL] The sourceURL of the template's compiled source.
         * @param {string} [variable] The data object variable name.
         * @returns {Function|string} Returns a compiled function when no `data` object
         *  is given, else it returns the interpolated text.
         * @example
         *
         * // using the "interpolate" delimiter to create a compiled template
         * var compiled = _.template('hello <%= name %>');
         * compiled({ 'name': 'fred' });
         * // => 'hello fred'
         *
         * // using the "escape" delimiter to escape HTML in data property values
         * _.template('<b><%- value %></b>', { 'value': '<script>' });
         * // => '<b>&lt;script&gt;</b>'
         *
         * // using the "evaluate" delimiter to generate HTML
         * var list = '<% _.forEach(people, function(name) { %><li><%- name %></li><% }); %>';
         * _.template(list, { 'people': ['fred', 'barney'] });
         * // => '<li>fred</li><li>barney</li>'
         *
         * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
         * _.template('hello ${ name }', { 'name': 'pebbles' });
         * // => 'hello pebbles'
         *
         * // using the internal `print` function in "evaluate" delimiters
         * _.template('<% print("hello " + name); %>!', { 'name': 'barney' });
         * // => 'hello barney!'
         *
         * // using a custom template delimiters
         * _.templateSettings = {
         *   'interpolate': /{{([\s\S]+?)}}/g
         * };
         *
         * _.template('hello {{ name }}!', { 'name': 'mustache' });
         * // => 'hello mustache!'
         *
         * // using the `imports` option to import jQuery
         * var list = '<% jq.each(people, function(name) { %><li><%- name %></li><% }); %>';
         * _.template(list, { 'people': ['fred', 'barney'] }, { 'imports': { 'jq': jQuery } });
         * // => '<li>fred</li><li>barney</li>'
         *
         * // using the `sourceURL` option to specify a custom sourceURL for the template
         * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
         * compiled(data);
         * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
         *
         * // using the `variable` option to ensure a with-statement isn't used in the compiled template
         * var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
         * compiled.source;
         * // => function(data) {
         *   var __t, __p = '', __e = _.escape;
         *   __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
         *   return __p;
         * }
         *
         * // using the `source` property to inline compiled templates for meaningful
         * // line numbers in error messages and a stack trace
         * fs.writeFileSync(path.join(cwd, 'jst.js'), '\
         *   var JST = {\
         *     "main": ' + _.template(mainText).source + '\
         *   };\
         * ');
         */

        function template(text, data, options) {
          // based on John Resig's `tmpl` implementation
          // http://ejohn.org/blog/javascript-micro-templating/
          // and Laura Doktorova's doT.js
          // https://github.com/olado/doT
          var settings = lodash.templateSettings;
          text = String(text || ''); // avoid missing dependencies when `iteratorTemplate` is not defined

          options = defaults({}, options, settings);
          var imports = defaults({}, options.imports, settings.imports),
            importsKeys = keys(imports),
            importsValues = values(imports);
          var isEvaluating,
            index = 0,
            interpolate = options.interpolate || reNoMatch,
            source = "__p += '"; // compile the regexp to match each delimiter

          var reDelimiters = RegExp(
            (options.escape || reNoMatch).source +
              '|' +
              interpolate.source +
              '|' +
              (interpolate === reInterpolate ? reEsTemplate : reNoMatch)
                .source +
              '|' +
              (options.evaluate || reNoMatch).source +
              '|$',
            'g'
          );
          text.replace(reDelimiters, function(
            match,
            escapeValue,
            interpolateValue,
            esTemplateValue,
            evaluateValue,
            offset
          ) {
            interpolateValue || (interpolateValue = esTemplateValue); // escape characters that cannot be included in string literals

            source += text
              .slice(index, offset)
              .replace(reUnescapedString, escapeStringChar); // replace delimiters with snippets

            if (escapeValue) {
              source += "' +\n__e(" + escapeValue + ") +\n'";
            }

            if (evaluateValue) {
              isEvaluating = true;
              source += "';\n" + evaluateValue + ";\n__p += '";
            }

            if (interpolateValue) {
              source +=
                "' +\n((__t = (" +
                interpolateValue +
                ")) == null ? '' : __t) +\n'";
            }

            index = offset + match.length; // the JS engine embedded in Adobe products requires returning the `match`
            // string in order to produce the correct `offset` value

            return match;
          });
          source += "';\n"; // if `variable` is not specified, wrap a with-statement around the generated
          // code to add the data object to the top of the scope chain

          var variable = options.variable,
            hasVariable = variable;

          if (!hasVariable) {
            variable = 'obj';
            source = 'with (' + variable + ') {\n' + source + '\n}\n';
          } // cleanup code by stripping empty strings

          source = (isEvaluating
            ? source.replace(reEmptyStringLeading, '')
            : source
          )
            .replace(reEmptyStringMiddle, '$1')
            .replace(reEmptyStringTrailing, '$1;'); // frame code as the function body

          source =
            'function(' +
            variable +
            ') {\n' +
            (hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
            "var __t, __p = '', __e = _.escape" +
            (isEvaluating
              ? ', __j = Array.prototype.join;\n' +
                "function print() { __p += __j.call(arguments, '') }\n"
              : ';\n') +
            source +
            'return __p\n}'; // Use a sourceURL for easier debugging.
          // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl

          var sourceURL =
            '\n/*\n//# sourceURL=' +
            (options.sourceURL ||
              '/lodash/template/source[' + templateCounter++ + ']') +
            '\n*/';

          try {
            var result = Function(
              importsKeys,
              'return ' + source + sourceURL
            ).apply(undefined, importsValues);
          } catch (e) {
            e.source = source;
            throw e;
          }

          if (data) {
            return result(data);
          } // provide the compiled function's source by its `toString` method, in
          // supported environments, or the `source` property as a convenience for
          // inlining compiled templates during the build process

          result.source = source;
          return result;
        }
        /**
         * Executes the callback `n` times, returning an array of the results
         * of each callback execution. The callback is bound to `thisArg` and invoked
         * with one argument; (index).
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {number} n The number of times to execute the callback.
         * @param {Function} callback The function called per iteration.
         * @param {*} [thisArg] The `this` binding of `callback`.
         * @returns {Array} Returns an array of the results of each `callback` execution.
         * @example
         *
         * var diceRolls = _.times(3, _.partial(_.random, 1, 6));
         * // => [3, 6, 4]
         *
         * _.times(3, function(n) { mage.castSpell(n); });
         * // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
         *
         * _.times(3, function(n) { this.cast(n); }, mage);
         * // => also calls `mage.castSpell(n)` three times
         */

        function times(n, callback, thisArg) {
          n = (n = +n) > -1 ? n : 0;
          var index = -1,
            result = Array(n);
          callback = baseCreateCallback(callback, thisArg, 1);

          while (++index < n) {
            result[index] = callback(index);
          }

          return result;
        }
        /**
         * The inverse of `_.escape` this method converts the HTML entities
         * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to their
         * corresponding characters.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {string} string The string to unescape.
         * @returns {string} Returns the unescaped string.
         * @example
         *
         * _.unescape('Fred, Barney &amp; Pebbles');
         * // => 'Fred, Barney & Pebbles'
         */

        function unescape(string) {
          return string == null
            ? ''
            : String(string).replace(reEscapedHtml, unescapeHtmlChar);
        }
        /**
         * Generates a unique ID. If `prefix` is provided the ID will be appended to it.
         *
         * @static
         * @memberOf _
         * @category Utilities
         * @param {string} [prefix] The value to prefix the ID with.
         * @returns {string} Returns the unique ID.
         * @example
         *
         * _.uniqueId('contact_');
         * // => 'contact_104'
         *
         * _.uniqueId();
         * // => '105'
         */

        function uniqueId(prefix) {
          var id = ++idCounter;
          return String(prefix == null ? '' : prefix) + id;
        }
        /*--------------------------------------------------------------------------*/

        /**
         * Creates a `lodash` object that wraps the given value with explicit
         * method chaining enabled.
         *
         * @static
         * @memberOf _
         * @category Chaining
         * @param {*} value The value to wrap.
         * @returns {Object} Returns the wrapper object.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney',  'age': 36 },
         *   { 'name': 'fred',    'age': 40 },
         *   { 'name': 'pebbles', 'age': 1 }
         * ];
         *
         * var youngest = _.chain(characters)
         *     .sortBy('age')
         *     .map(function(chr) { return chr.name + ' is ' + chr.age; })
         *     .first()
         *     .value();
         * // => 'pebbles is 1'
         */

        function chain(value) {
          value = new lodashWrapper(value);
          value.__chain__ = true;
          return value;
        }
        /**
         * Invokes `interceptor` with the `value` as the first argument and then
         * returns `value`. The purpose of this method is to "tap into" a method
         * chain in order to perform operations on intermediate results within
         * the chain.
         *
         * @static
         * @memberOf _
         * @category Chaining
         * @param {*} value The value to provide to `interceptor`.
         * @param {Function} interceptor The function to invoke.
         * @returns {*} Returns `value`.
         * @example
         *
         * _([1, 2, 3, 4])
         *  .tap(function(array) { array.pop(); })
         *  .reverse()
         *  .value();
         * // => [3, 2, 1]
         */

        function tap(value, interceptor) {
          interceptor(value);
          return value;
        }
        /**
         * Enables explicit method chaining on the wrapper object.
         *
         * @name chain
         * @memberOf _
         * @category Chaining
         * @returns {*} Returns the wrapper object.
         * @example
         *
         * var characters = [
         *   { 'name': 'barney', 'age': 36 },
         *   { 'name': 'fred',   'age': 40 }
         * ];
         *
         * // without explicit chaining
         * _(characters).first();
         * // => { 'name': 'barney', 'age': 36 }
         *
         * // with explicit chaining
         * _(characters).chain()
         *   .first()
         *   .pick('age')
         *   .value();
         * // => { 'age': 36 }
         */

        function wrapperChain() {
          this.__chain__ = true;
          return this;
        }
        /**
         * Produces the `toString` result of the wrapped value.
         *
         * @name toString
         * @memberOf _
         * @category Chaining
         * @returns {string} Returns the string result.
         * @example
         *
         * _([1, 2, 3]).toString();
         * // => '1,2,3'
         */

        function wrapperToString() {
          return String(this.__wrapped__);
        }
        /**
         * Extracts the wrapped value.
         *
         * @name valueOf
         * @memberOf _
         * @alias value
         * @category Chaining
         * @returns {*} Returns the wrapped value.
         * @example
         *
         * _([1, 2, 3]).valueOf();
         * // => [1, 2, 3]
         */

        function wrapperValueOf() {
          return this.__wrapped__;
        }
        /*--------------------------------------------------------------------------*/
        // add functions that return wrapped values when chaining

        lodash.after = after;
        lodash.assign = assign;
        lodash.at = at;
        lodash.bind = bind;
        lodash.bindAll = bindAll;
        lodash.bindKey = bindKey;
        lodash.chain = chain;
        lodash.compact = compact;
        lodash.compose = compose;
        lodash.constant = constant;
        lodash.countBy = countBy;
        lodash.create = create;
        lodash.createCallback = createCallback;
        lodash.curry = curry;
        lodash.debounce = debounce;
        lodash.defaults = defaults;
        lodash.defer = defer;
        lodash.delay = delay;
        lodash.difference = difference;
        lodash.filter = filter;
        lodash.flatten = flatten;
        lodash.forEach = forEach;
        lodash.forEachRight = forEachRight;
        lodash.forIn = forIn;
        lodash.forInRight = forInRight;
        lodash.forOwn = forOwn;
        lodash.forOwnRight = forOwnRight;
        lodash.functions = functions;
        lodash.groupBy = groupBy;
        lodash.indexBy = indexBy;
        lodash.initial = initial;
        lodash.intersection = intersection;
        lodash.invert = invert;
        lodash.invoke = invoke;
        lodash.keys = keys;
        lodash.map = map;
        lodash.mapValues = mapValues;
        lodash.max = max;
        lodash.memoize = memoize;
        lodash.merge = merge;
        lodash.min = min;
        lodash.omit = omit;
        lodash.once = once;
        lodash.pairs = pairs;
        lodash.partial = partial;
        lodash.partialRight = partialRight;
        lodash.pick = pick;
        lodash.pluck = pluck;
        lodash.property = property;
        lodash.pull = pull;
        lodash.range = range;
        lodash.reject = reject;
        lodash.remove = remove;
        lodash.rest = rest;
        lodash.shuffle = shuffle;
        lodash.sortBy = sortBy;
        lodash.tap = tap;
        lodash.throttle = throttle;
        lodash.times = times;
        lodash.toArray = toArray;
        lodash.transform = transform;
        lodash.union = union;
        lodash.uniq = uniq;
        lodash.values = values;
        lodash.where = where;
        lodash.without = without;
        lodash.wrap = wrap;
        lodash.xor = xor;
        lodash.zip = zip;
        lodash.zipObject = zipObject; // add aliases

        lodash.collect = map;
        lodash.drop = rest;
        lodash.each = forEach;
        lodash.eachRight = forEachRight;
        lodash.extend = assign;
        lodash.methods = functions;
        lodash.object = zipObject;
        lodash.select = filter;
        lodash.tail = rest;
        lodash.unique = uniq;
        lodash.unzip = zip; // add functions to `lodash.prototype`

        mixin(lodash);
        /*--------------------------------------------------------------------------*/
        // add functions that return unwrapped values when chaining

        lodash.clone = clone;
        lodash.cloneDeep = cloneDeep;
        lodash.contains = contains;
        lodash.escape = escape;
        lodash.every = every;
        lodash.find = find;
        lodash.findIndex = findIndex;
        lodash.findKey = findKey;
        lodash.findLast = findLast;
        lodash.findLastIndex = findLastIndex;
        lodash.findLastKey = findLastKey;
        lodash.has = has;
        lodash.identity = identity;
        lodash.indexOf = indexOf;
        lodash.isArguments = isArguments;
        lodash.isArray = isArray;
        lodash.isBoolean = isBoolean;
        lodash.isDate = isDate;
        lodash.isElement = isElement;
        lodash.isEmpty = isEmpty;
        lodash.isEqual = isEqual;
        lodash.isFinite = isFinite;
        lodash.isFunction = isFunction;
        lodash.isNaN = isNaN;
        lodash.isNull = isNull;
        lodash.isNumber = isNumber;
        lodash.isObject = isObject;
        lodash.isPlainObject = isPlainObject;
        lodash.isRegExp = isRegExp;
        lodash.isString = isString;
        lodash.isUndefined = isUndefined;
        lodash.lastIndexOf = lastIndexOf;
        lodash.mixin = mixin;
        lodash.noConflict = noConflict;
        lodash.noop = noop;
        lodash.now = now;
        lodash.parseInt = parseInt;
        lodash.random = random;
        lodash.reduce = reduce;
        lodash.reduceRight = reduceRight;
        lodash.result = result;
        lodash.runInContext = runInContext;
        lodash.size = size;
        lodash.some = some;
        lodash.sortedIndex = sortedIndex;
        lodash.template = template;
        lodash.unescape = unescape;
        lodash.uniqueId = uniqueId; // add aliases

        lodash.all = every;
        lodash.any = some;
        lodash.detect = find;
        lodash.findWhere = find;
        lodash.foldl = reduce;
        lodash.foldr = reduceRight;
        lodash.include = contains;
        lodash.inject = reduce;
        mixin(
          (function() {
            var source = {};
            forOwn(lodash, function(func, methodName) {
              if (!lodash.prototype[methodName]) {
                source[methodName] = func;
              }
            });
            return source;
          })(),
          false
        );
        /*--------------------------------------------------------------------------*/
        // add functions capable of returning wrapped and unwrapped values when chaining

        lodash.first = first;
        lodash.last = last;
        lodash.sample = sample; // add aliases

        lodash.take = first;
        lodash.head = first;
        forOwn(lodash, function(func, methodName) {
          var callbackable = methodName !== 'sample';

          if (!lodash.prototype[methodName]) {
            lodash.prototype[methodName] = function(n, guard) {
              var chainAll = this.__chain__,
                result = func(this.__wrapped__, n, guard);
              return !chainAll &&
                (n == null ||
                  (guard && !(callbackable && typeof n == 'function')))
                ? result
                : new lodashWrapper(result, chainAll);
            };
          }
        });
        /*--------------------------------------------------------------------------*/

        /**
         * The semantic version number.
         *
         * @static
         * @memberOf _
         * @type string
         */

        lodash.VERSION = '2.4.2'; // add "Chaining" functions to the wrapper

        lodash.prototype.chain = wrapperChain;
        lodash.prototype.toString = wrapperToString;
        lodash.prototype.value = wrapperValueOf;
        lodash.prototype.valueOf = wrapperValueOf; // add `Array` functions that return unwrapped values

        forEach(['join', 'pop', 'shift'], function(methodName) {
          var func = arrayRef[methodName];

          lodash.prototype[methodName] = function() {
            var chainAll = this.__chain__,
              result = func.apply(this.__wrapped__, arguments);
            return chainAll ? new lodashWrapper(result, chainAll) : result;
          };
        }); // add `Array` functions that return the existing wrapped value

        forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
          var func = arrayRef[methodName];

          lodash.prototype[methodName] = function() {
            func.apply(this.__wrapped__, arguments);
            return this;
          };
        }); // add `Array` functions that return new wrapped values

        forEach(['concat', 'slice', 'splice'], function(methodName) {
          var func = arrayRef[methodName];

          lodash.prototype[methodName] = function() {
            return new lodashWrapper(
              func.apply(this.__wrapped__, arguments),
              this.__chain__
            );
          };
        });
        return lodash;
      }
      /*--------------------------------------------------------------------------*/
      // expose Lo-Dash

      var _ = runInContext(); // some AMD build optimizers like r.js check for condition patterns like the following:

      if (freeExports && freeModule) {
        // in Node.js or RingoJS
        if (moduleExports) {
          (freeModule.exports = _)._ = _;
        } // in Narwhal or Rhino -require
        else {
          freeExports._ = _;
        }
      } else {
        // in a browser or Rhino
        root._ = _;
      }
    }.call(this));
  });

  function sum(arr) {
    return arr.reduce(function(p, c, i, a) {
      return p + c;
    });
  }

  function ensureArr(arr) {
    if (Array.isArray(arr)) {
      return arr;
    } else if (typeof arr === 'string') {
      return arr.split('');
    } else {
      throw Error('Parameter must be a string or array.');
    }
  }
  /**
   * Computes the jaro-winkler distance for two given arrays.
   *
   * NOTE: this implementation is based on the one found in the
   * Lucene Java library.
   *
   * h3 Examples:
   *
   *     wuzzy.jarowinkler(
   *     		['D', 'W', 'A', 'Y', 'N', 'E'],
   *     		['D', 'U', 'A', 'N', 'E']
   *     	);
   *     	// -> 0.840
   *
   *     wuzzy.jarowinkler(
   *     		'DWAYNE',
   *     		'DUANE'
   *     	);
   *     	// -> 0.840
   *
   * @param  {String/Array} a - the first string/array to compare
   * @param  {String/Array} b - the second string/array to compare
   * @param  {Number} t - the threshold for adding
   * the winkler bonus (defaults to 0.7)
   * @return {Number}   returns the jaro-winkler distance for
   * the two provided arrays.
   */

  var jarowinkler = function(a, b, t) {
    a = ensureArr(a);
    b = ensureArr(b);
    var max, min;

    if (a.length > b.length) {
      max = a;
      min = b;
    } else {
      max = b;
      min = a;
    }

    var threshold = t ? t : 0.7;
    var weight = 0.1;
    var range = Math.floor(Math.max(max.length / 2 - 1, 0));
    var mIdx = [];
    var mFlg = [];
    var mi, xi, xn, c1;
    var matches = 0;

    for (mi = 0; mi < min.length; mi++) {
      c1 = min[mi];

      for (
        xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length);
        xi < xn;
        xi++
      ) {
        if (!mFlg[xi] && c1 === max[xi]) {
          mIdx[mi] = xi;
          mFlg[xi] = true;
          matches++;
          break;
        }
      }
    }

    var ma = [];
    var mb = [];
    var i, si;
    var trans = 0;
    var prefix = 0;

    for (i = 0, si = 0; i < min.length; i++) {
      if (mIdx[i] > -1) {
        ma[si] = min[i];
        si++;
      }
    }

    for (i = 0, si = 0; i < max.length; i++) {
      if (mFlg[i]) {
        mb[si] = max[i];
        si++;
      }
    }

    for (mi = 0; mi < ma.length; mi++) {
      if (ma[mi] !== mb[mi]) {
        trans++;
      }
    }

    for (mi = 0; mi < min.length; mi++) {
      if (a[mi] === b[mi]) {
        prefix++;
      } else {
        break;
      }
    }

    var m = matches;
    var t = trans / 2;

    if (!m) {
      return 0;
    } else {
      var j = (m / a.length + m / b.length + (m - t) / m) / 3;
      var jw =
        j < threshold
          ? j
          : j + Math.min(weight, 1 / max.length) * prefix * (1 - j);
      return jw;
    }
  };
  /**
   * Calculates the levenshtein distance for the
   * two provided arrays and returns the normalized
   * distance.
   *
   * h3 Examples:
   *
   *     wuzzy.levenshtein(
   *     		['D', 'W', 'A', 'Y', 'N', 'E'],
   *     		['D', 'U', 'A', 'N', 'E']
   *     	);
   *     	// -> 0.66666667
   *
   * 		or
   *
   *     wuzzy.levenshtein(
   *     		'DWAYNE',
   *     		'DUANE'
   *     	);
   *     	// -> 0.66666667
   *
   * @param  {String/Array} a - the first string/array to compare
   * @param  {String/Array} b - the second string/array to compare
   * @param  {Object} w - (optional) a set of key/value pairs
   * definining weights for the deletion (key: d), insertion
   * (key: i), and substitution (key: s). default values are
   * 1 for all operations.
   * @return {Number}   returns the levenshtein distance for
   * the two provided arrays.
   */

  var levenshtein = function(a, b, w) {
    a = ensureArr(a);
    b = ensureArr(b);

    if (a.length === 0) {
      return b.length;
    }

    if (b.length === 0) {
      return a.length;
    }

    var weights = w
      ? w
      : {
          d: 1,
          i: 1,
          s: 1,
        };
    var v0 = [];
    var v1 = [];
    var vlen = b.length + 1;
    var i, j;
    var cost;
    var mlen;

    for (i = 0; i < vlen; i++) {
      v0[i] = i;
    }

    for (i = 0; i < a.length; i++) {
      v1[0] = i + 1;

      for (j = 0; j < b.length; j++) {
        cost = a[i] === b[j] ? 0 : weights.s;
        v1[j + 1] = Math.min(
          v1[j] + weights.d,
          v0[j + 1] + weights.i,
          v0[j] + cost
        );
      }

      for (j = 0; j < vlen; j++) {
        v0[j] = v1[j];
      }
    }

    mlen = Math.max(a.length, b.length);
    return (mlen - v1[b.length]) / mlen;
  };
  /**
   * Computes the n-gram edit distance for any n (defaults to 2).
   *
   * NOTE: this implementation is based on the one found in the
   * Lucene Java library.
   *
   * h3 Examples:
   *
   *     wuzzy.ngram(
   *     		['D', 'W', 'A', 'Y', 'N', 'E'],
   *     		['D', 'U', 'A', 'N', 'E']
   *     	);
   *     	// -> 0.583
   *
   * 		or
   *
   *     wuzzy.ngram(
   *     		'DWAYNE',
   *     		'DUANE'
   *     	);
   *     	// -> 0.583
   *
   * @param  {String/Array} a - the first string/array to compare
   * @param  {String/Array} b - the second string/array to compare
   * @param  {Number} ng - (optional) the n-gram size to work with (defaults to 2)
   * @return {Number}   returns the ngram distance for
   * the two provided arrays.
   */

  var ngram = function(a, b, ng) {
    a = ensureArr(a);
    b = ensureArr(b);
    var al = a.length;
    var bl = b.length;
    var n = ng ? ng : 2;
    var cost;
    var i, j, ni, ti, tn, ec;
    var sa = [];
    var p = [];
    var d = [];
    var _d = [];
    var t_j = [];

    if (al === 0 || bl === 0) {
      if (al === bl) {
        return 1;
      } else {
        return 0;
      }
    } // smaller than n situation

    cost = 0;

    if (al < n || bl < n) {
      for (i = 0, ni = Math.min(al, bl); i < ni; i++) {
        if (a[i] === b[i]) {
          cost++;
        }
      }

      return cost / Math.max(al, bl);
    }

    for (i = 0; i < al + n - 1; i++) {
      if (i < n - 1) {
        sa[i] = 0;
      } else {
        sa[i] = a[i - n + 1];
      }
    }

    for (i = 0; i <= al; i++) {
      p[i] = i;
    }

    for (j = 1; j <= bl; j++) {
      if (j < n) {
        for (ti = 0; ti < n - j; ti++) {
          t_j[ti] = 0;
        }

        for (ti = n - j; ti < n; ti++) {
          t_j[ti] = b[ti - (n - j)];
        }
      } else {
        t_j = b.slice(j - n, j);
      }

      d[0] = j;

      for (i = 1; i <= al; i++) {
        cost = 0;
        tn = n;

        for (ni = 0; ni < n; ni++) {
          if (sa[i - 1 + ni] !== t_j[ni]) {
            cost++;
          } else if (sa[i - 1 + ni] === 0) {
            tn--;
          }
        }

        ec = cost / tn;
        d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + ec);
      }

      _d = p;
      p = d;
      d = _d;
    }

    return 1.0 - p[al] / Math.max(al, bl);
  };
  /**
   * Calculates a pearson correlation score for two given
   * objects (compares values of similar keys).
   *
   * h3 Examples:
   *
   *     wuzzy.pearson(
   *     		{a: 2.5, b: 3.5, c: 3.0, d: 3.5, e: 2.5, f: 3.0},
   *     		{a: 3.0, b: 3.5, c: 1.5, d: 5.0, e: 3.5, f: 3.0, g: 5.0}
   *     	);
   *     	// -> 0.396
   *
   * 		or
   *
   *     wuzzy.pearson(
   *     		{a: 2.5, b: 1},
   *     		{o: 3.5, e: 6.0}
   *     	);
   *     	// -> 1.0
   *
   * @param  {Object} a - the first object to compare
   * @param  {Object} b - the second object to compare
   * @return {Number}   returns the pearson correlation for
   * the two provided arrays.
   */

  var pearson = function(a, b) {
    var sk = [];
    Object.keys(a).forEach(function(k) {
      if (b[k]) {
        sk.push(k);
      }
    });
    var n = sk.length;

    if (n === 0) {
      return 0;
    }

    var sa = sum(
      sk.map(function(k) {
        return a[k];
      })
    );
    var sb = sum(
      sk.map(function(k) {
        return b[k];
      })
    );
    var sas = sum(
      sk.map(function(k) {
        return Math.pow(a[k], 2);
      })
    );
    var sbs = sum(
      sk.map(function(k) {
        return Math.pow(b[k], 2);
      })
    );
    var sp = sum(
      sk.map(function(k) {
        return a[k] * b[k];
      })
    );
    var num = sp - (sa * sb) / n;
    var den = Math.sqrt(
      (sas - Math.pow(sa, 2) / n) * (sbs - Math.pow(sb, 2) / n)
    );

    if (den === 0) {
      return 0;
    } else {
      return num / den;
    }
  };
  /**
   * Calculates the jaccard index for the two
   * provided arrays.
   *
   * h3 Examples:
   *
   *     wuzzy.jaccard(
   *     		['a', 'b', 'c', 'd', 'e', 'f'],
   *     		['a', 'e', 'f']
   *     	);
   *     	// -> 0.5
   *
   * 		or
   *
   *     wuzzy.jaccard(
   *     		'abcdef',
   *     		'aef'
   *     	);
   *     	// -> 0.5
   *
   * 		or
   *
   *     wuzzy.jaccard(
   *     		['abe', 'babe', 'cabe', 'dabe', 'eabe', 'fabe'],
   *     		['babe']
   *     	);
   *     	// -> 0.16666667
   *
   * @param  {String/Array} a - the first string/array to compare
   * @param  {String/Array} b - the second string/array to compare
   * @return {Number}   returns the jaccard index for
   * the two provided arrays.
   */

  var jaccard = function(a, b) {
    a = ensureArr(a);
    b = ensureArr(b);
    return lodash.intersection(a, b).length / lodash.union(a, b).length;
  };
  /**
   * Calculates the tanimoto distance (weighted jaccard index).
   *
   * h3 Examples:
   *
   *     wuzzy.tanimoto(
   *     		['a', 'b', 'c', 'd', 'd', 'e', 'f', 'f'],
   *     		['a', 'e', 'f']
   *     	);
   *     	// -> 0.375
   *
   * 		or
   *
   *     wuzzy.tanimoto(
   *     		'abcddeff',
   *     		'aef'
   *     	);
   *     	// -> 0.375
   *
   * 		or
   *
   *     wuzzy.tanimoto(
   *     		['abe', 'babe', 'cabe', 'dabe', 'eabe', 'fabe', 'fabe'],
   *     		['babe']
   *     	);
   *     	// -> 0.14285714
   *
   * @param  {String/Array} a - the first string/array to compare
   * @param  {String/Array} b - the second string/array to compare
   * @return {Number}   returns the tanimoto distance for
   * the two provided arrays.
   */

  var tanimoto = function(a, b) {
    a = ensureArr(a);
    b = ensureArr(b);

    var both = lodash.intersection(a, b).length;

    return both / (a.length + b.length - both);
  };

  var wuzzy = {
    jarowinkler: jarowinkler,
    levenshtein: levenshtein,
    ngram: ngram,
    pearson: pearson,
    jaccard: jaccard,
    tanimoto: tanimoto,
  };

  function extractBreadcrumbTitle(splitTitle, text) {
    // This must be a very breadcrumbed title, like:
    // The Best Gadgets on Earth : Bits : Blogs : NYTimes.com
    // NYTimes - Blogs - Bits - The Best Gadgets on Earth
    if (splitTitle.length >= 6) {
      // Look to see if we can find a breadcrumb splitter that happens
      // more than once. If we can, we'll be able to better pull out
      // the title.
      var termCounts = splitTitle.reduce(function(acc, titleText) {
        acc[titleText] = acc[titleText] ? acc[titleText] + 1 : 1;
        return acc;
      }, {});

      var _Reflect$ownKeys$redu = ownKeys$1(termCounts).reduce(
          function(acc, key) {
            if (acc[1] < termCounts[key]) {
              return [key, termCounts[key]];
            }

            return acc;
          },
          [0, 0]
        ),
        _Reflect$ownKeys$redu2 = slicedToArray(_Reflect$ownKeys$redu, 2),
        maxTerm = _Reflect$ownKeys$redu2[0],
        termCount = _Reflect$ownKeys$redu2[1]; // We found a splitter that was used more than once, so it
      // is probably the breadcrumber. Split our title on that instead.
      // Note: max_term should be <= 4 characters, so that " >> "
      // will match, but nothing longer than that.

      if (termCount >= 2 && maxTerm.length <= 4) {
        splitTitle = text.split(maxTerm);
      }

      var splitEnds = [splitTitle[0], splitTitle.slice(-1)];
      var longestEnd = splitEnds.reduce(function(acc, end) {
        return acc.length > end.length ? acc : end;
      }, '');

      if (longestEnd.length > 10) {
        return longestEnd;
      }

      return text;
    }

    return null;
  }

  function cleanDomainFromTitle(splitTitle, url$$1) {
    // Search the ends of the title, looking for bits that fuzzy match
    // the URL too closely. If one is found, discard it and return the
    // rest.
    //
    // Strip out the big TLDs - it just makes the matching a bit more
    // accurate. Not the end of the world if it doesn't strip right.
    var _URL$parse = url.parse(url$$1),
      host = _URL$parse.host;

    var nakedDomain = host.replace(DOMAIN_ENDINGS_RE, '');
    var startSlug = splitTitle[0].toLowerCase().replace(' ', '');
    var startSlugRatio = wuzzy.levenshtein(startSlug, nakedDomain);

    if (startSlugRatio > 0.4 && startSlug.length > 5) {
      return splitTitle.slice(2).join('');
    }

    var endSlug = splitTitle
      .slice(-1)[0]
      .toLowerCase()
      .replace(' ', '');
    var endSlugRatio = wuzzy.levenshtein(endSlug, nakedDomain);

    if (endSlugRatio > 0.4 && endSlug.length >= 5) {
      return splitTitle.slice(0, -2).join('');
    }

    return null;
  } // Given a title with separators in it (colons, dashes, etc),
  // resolve whether any of the segments should be removed.

  function resolveSplitTitle(title) {
    var url$$1 =
      arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
    // Splits while preserving splitters, like:
    // ['The New New York', ' - ', 'The Washington Post']
    var splitTitle = title.split(TITLE_SPLITTERS_RE);

    if (splitTitle.length === 1) {
      return title;
    }

    var newTitle = extractBreadcrumbTitle(splitTitle, title);
    if (newTitle) return newTitle;
    newTitle = cleanDomainFromTitle(splitTitle, url$$1);
    if (newTitle) return newTitle; // Fuzzy ratio didn't find anything, so this title is probably legit.
    // Just return it all.

    return title;
  }

  var Cleaners = {
    author: cleanAuthor,
    lead_image_url: clean$1,
    dek: cleanDek,
    date_published: cleanDatePublished,
    content: extractCleanNode,
    title: cleanTitle$$1,
  };

  // likely to be article text.
  //
  // If strip_unlikely_candidates is True, remove any elements that
  // match certain criteria first. (Like, does this element have a
  // classname of "comment")
  //
  // If weight_nodes is True, use classNames and IDs to determine the
  // worthiness of nodes.
  //
  // Returns a cheerio object $

  function extractBestNode($, opts) {
    // clone the node so we can get back to our
    // initial parsed state if needed
    // TODO Do I need this? – AP
    // let $root = $.root().clone()
    if (opts.stripUnlikelyCandidates) {
      $ = stripUnlikelyCandidates($);
    }

    $ = convertToParagraphs$$1($);
    $ = scoreContent$$1($, opts.weightNodes);
    var $topCandidate = findTopCandidate$$1($);
    return $topCandidate;
  }

  var GenericContentExtractor = {
    defaultOpts: {
      stripUnlikelyCandidates: true,
      weightNodes: true,
      cleanConditionally: true,
    },
    // Extract the content for this resource - initially, pass in our
    // most restrictive opts which will return the highest quality
    // content. On each failure, retry with slightly more lax opts.
    //
    // :param return_type: string. If "node", should return the content
    // as a cheerio node rather than as an HTML string.
    //
    // Opts:
    // stripUnlikelyCandidates: Remove any elements that match
    // non-article-like criteria first.(Like, does this element
    //   have a classname of "comment")
    //
    // weightNodes: Modify an elements score based on whether it has
    // certain classNames or IDs. Examples: Subtract if a node has
    // a className of 'comment', Add if a node has an ID of
    // 'entry-content'.
    //
    // cleanConditionally: Clean the node to return of some
    // superfluous content. Things like forms, ads, etc.
    extract: function extract(_ref, opts) {
      var $$$1 = _ref.$,
        html = _ref.html,
        title = _ref.title,
        url = _ref.url;
      opts = objectSpread({}, this.defaultOpts, opts);
      $$$1 = $$$1 || $.load(html); // Cascade through our extraction-specific opts in an ordered fashion,
      // turning them off as we try to extract content.

      var node = this.getContentNode($$$1, title, url, opts);

      if (nodeIsSufficient(node)) {
        return this.cleanAndReturnNode(node, $$$1);
      } // We didn't succeed on first pass, one by one disable our
      // extraction opts and try again.
      // eslint-disable-next-line no-restricted-syntax

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (
          var _iterator = getIterator$1(
              ownKeys$1(opts).filter(function(k) {
                return opts[k] === true;
              })
            ),
            _step;
          !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
          _iteratorNormalCompletion = true
        ) {
          var key = _step.value;
          opts[key] = false;
          $$$1 = $.load(html);
          node = this.getContentNode($$$1, title, url, opts);

          if (nodeIsSufficient(node)) {
            break;
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return this.cleanAndReturnNode(node, $$$1);
    },
    // Get node given current options
    getContentNode: function getContentNode($$$1, title, url, opts) {
      return extractCleanNode(extractBestNode($$$1, opts), {
        $: $$$1,
        cleanConditionally: opts.cleanConditionally,
        title: title,
        url: url,
      });
    },
    // Once we got here, either we're at our last-resort node, or
    // we broke early. Make sure we at least have -something- before we
    // move forward.
    cleanAndReturnNode: function cleanAndReturnNode(node, $$$1) {
      if (!node) {
        return null;
      }

      return normalizeSpaces($$$1.html(node)); // if return_type == "html":
      //     return normalize_spaces(node_to_html(node))
      // else:
      //     return node
    },
  };

  // TODO: It would be great if we could merge the meta and selector lists into
  // a list of objects, because we could then rank them better. For example,
  // .hentry .entry-title is far better suited than <meta title>.
  // An ordered list of meta tag names that denote likely article titles. All
  // attributes should be lowercase for faster case-insensitive matching. From
  // most distinct to least distinct.
  var STRONG_TITLE_META_TAGS = [
    'tweetmeme-title',
    'dc.title',
    'rbtitle',
    'headline',
    'title',
  ]; // og:title is weak because it typically contains context that we don't like,
  // for example the source site's name. Gotta get that brand into facebook!

  var WEAK_TITLE_META_TAGS = ['og:title']; // An ordered list of XPath Selectors to find likely article titles. From
  // most explicit to least explicit.
  //
  // Note - this does not use classes like CSS. This checks to see if the string
  // exists in the className, which is not as accurate as .className (which
  // splits on spaces/endlines), but for our purposes it's close enough. The
  // speed tradeoff is worth the accuracy hit.

  var STRONG_TITLE_SELECTORS = [
    '.hentry .entry-title',
    'h1#articleHeader',
    'h1.articleHeader',
    'h1.article',
    '.instapaper_title',
    '#meebo-title',
  ];
  var WEAK_TITLE_SELECTORS = [
    'article h1',
    '#entry-title',
    '.entry-title',
    '#entryTitle',
    '#entrytitle',
    '.entryTitle',
    '.entrytitle',
    '#articleTitle',
    '.articleTitle',
    'post post-title',
    'h1.title',
    'h2.article',
    'h1',
    'html head title',
    'title',
  ];

  var GenericTitleExtractor = {
    extract: function extract(_ref) {
      var $ = _ref.$,
        url = _ref.url,
        metaCache = _ref.metaCache;
      // First, check to see if we have a matching meta tag that we can make
      // use of that is strongly associated with the headline.
      var title;
      title = extractFromMeta$$1($, STRONG_TITLE_META_TAGS, metaCache);
      if (title)
        return cleanTitle$$1(title, {
          url: url,
          $: $,
        }); // Second, look through our content selectors for the most likely
      // article title that is strongly associated with the headline.

      title = extractFromSelectors$$1($, STRONG_TITLE_SELECTORS);
      if (title)
        return cleanTitle$$1(title, {
          url: url,
          $: $,
        }); // Third, check for weaker meta tags that may match.

      title = extractFromMeta$$1($, WEAK_TITLE_META_TAGS, metaCache);
      if (title)
        return cleanTitle$$1(title, {
          url: url,
          $: $,
        }); // Last, look for weaker selector tags that may match.

      title = extractFromSelectors$$1($, WEAK_TITLE_SELECTORS);
      if (title)
        return cleanTitle$$1(title, {
          url: url,
          $: $,
        }); // If no matches, return an empty string

      return '';
    },
  };

  // An ordered list of meta tag names that denote likely article authors. All
  // attributes should be lowercase for faster case-insensitive matching. From
  // most distinct to least distinct.
  //
  // Note: "author" is too often the -developer- of the page, so it is not
  // added here.
  var AUTHOR_META_TAGS = [
    'byl',
    'clmst',
    'dc.author',
    'dcsext.author',
    'dc.creator',
    'rbauthors',
    'authors',
  ];
  var AUTHOR_MAX_LENGTH = 300; // An ordered list of XPath Selectors to find likely article authors. From
  // most explicit to least explicit.
  //
  // Note - this does not use classes like CSS. This checks to see if the string
  // exists in the className, which is not as accurate as .className (which
  // splits on spaces/endlines), but for our purposes it's close enough. The
  // speed tradeoff is worth the accuracy hit.

  var AUTHOR_SELECTORS = [
    '.entry .entry-author',
    '.author.vcard .fn',
    '.author .vcard .fn',
    '.byline.vcard .fn',
    '.byline .vcard .fn',
    '.byline .by .author',
    '.byline .by',
    '.byline .author',
    '.post-author.vcard',
    '.post-author .vcard',
    'a[rel=author]',
    '#by_author',
    '.by_author',
    '#entryAuthor',
    '.entryAuthor',
    '.byline a[href*=author]',
    '#author .authorname',
    '.author .authorname',
    '#author',
    '.author',
    '.articleauthor',
    '.ArticleAuthor',
    '.byline',
  ]; // An ordered list of Selectors to find likely article authors, with
  // regular expression for content.

  var bylineRe = /^[\n\s]*By/i;
  var BYLINE_SELECTORS_RE = [['#byline', bylineRe], ['.byline', bylineRe]];

  var GenericAuthorExtractor = {
    extract: function extract(_ref) {
      var $ = _ref.$,
        metaCache = _ref.metaCache;
      var author; // First, check to see if we have a matching
      // meta tag that we can make use of.

      author = extractFromMeta$$1($, AUTHOR_META_TAGS, metaCache);

      if (author && author.length < AUTHOR_MAX_LENGTH) {
        return cleanAuthor(author);
      } // Second, look through our selectors looking for potential authors.

      author = extractFromSelectors$$1($, AUTHOR_SELECTORS, 2);

      if (author && author.length < AUTHOR_MAX_LENGTH) {
        return cleanAuthor(author);
      } // Last, use our looser regular-expression based selectors for
      // potential authors.
      // eslint-disable-next-line no-restricted-syntax

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (
          var _iterator = getIterator$1(BYLINE_SELECTORS_RE), _step;
          !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
          _iteratorNormalCompletion = true
        ) {
          var _ref4 = _step.value;

          var _ref3 = slicedToArray(_ref4, 2);

          var selector = _ref3[0];
          var regex = _ref3[1];
          var node = $(selector);

          if (node.length === 1) {
            var text = node.text();

            if (regex.test(text)) {
              return cleanAuthor(text);
            }
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return null;
    },
  };

  // An ordered list of meta tag names that denote
  // likely date published dates. All attributes
  // should be lowercase for faster case-insensitive matching.
  // From most distinct to least distinct.
  var DATE_PUBLISHED_META_TAGS = [
    'article:published_time',
    'displaydate',
    'dc.date',
    'dc.date.issued',
    'rbpubdate',
    'publish_date',
    'pub_date',
    'pagedate',
    'pubdate',
    'revision_date',
    'doc_date',
    'date_created',
    'content_create_date',
    'lastmodified',
    'created',
    'date',
  ]; // An ordered list of XPath Selectors to find
  // likely date published dates. From most explicit
  // to least explicit.

  var DATE_PUBLISHED_SELECTORS = [
    '.hentry .dtstamp.published',
    '.hentry .published',
    '.hentry .dtstamp.updated',
    '.hentry .updated',
    '.single .published',
    '.meta .published',
    '.meta .postDate',
    '.entry-date',
    '.byline .date',
    '.postmetadata .date',
    '.article_datetime',
    '.date-header',
    '.story-date',
    '.dateStamp',
    '#story .datetime',
    '.dateline',
    '.pubdate',
  ]; // An ordered list of compiled regular expressions to find likely date
  // published dates from the URL. These should always have the first
  // reference be a date string that is parseable by dateutil.parser.parse

  var abbrevMonthsStr = '(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)';
  var DATE_PUBLISHED_URL_RES = [
    // /2012/01/27/ but not /2012/01/293
    new RegExp('/(20\\d{2}/\\d{2}/\\d{2})/', 'i'), // 20120127 or 20120127T but not 2012012733 or 8201201733
    // /[^0-9](20\d{2}[01]\d[0-3]\d)([^0-9]|$)/i,
    // 2012-01-27
    new RegExp('(20\\d{2}-[01]\\d-[0-3]\\d)', 'i'), // /2012/jan/27/
    new RegExp('/(20\\d{2}/'.concat(abbrevMonthsStr, '/[0-3]\\d)/'), 'i'),
  ];

  var GenericDatePublishedExtractor = {
    extract: function extract(_ref) {
      var $ = _ref.$,
        url = _ref.url,
        metaCache = _ref.metaCache;
      var datePublished; // First, check to see if we have a matching meta tag
      // that we can make use of.
      // Don't try cleaning tags from this string

      datePublished = extractFromMeta$$1(
        $,
        DATE_PUBLISHED_META_TAGS,
        metaCache,
        false
      );
      if (datePublished) return cleanDatePublished(datePublished); // Second, look through our selectors looking for potential
      // date_published's.

      datePublished = extractFromSelectors$$1($, DATE_PUBLISHED_SELECTORS);
      if (datePublished) return cleanDatePublished(datePublished); // Lastly, look to see if a dately string exists in the URL

      datePublished = extractFromUrl(url, DATE_PUBLISHED_URL_RES);
      if (datePublished) return cleanDatePublished(datePublished);
      return null;
    },
  };

  // import {
  //   DEK_META_TAGS,
  //   DEK_SELECTORS,
  //   DEK_URL_RES,
  // } from './constants';
  // import { cleanDek } from 'cleaners';
  // import {
  //   extractFromMeta,
  //   extractFromSelectors,
  // } from 'utils/dom';
  // Currently there is only one selector for
  // deks. We should simply return null here
  // until we have a more robust generic option.
  // Below is the original source for this, for reference.
  var GenericDekExtractor = {
    // extract({ $, content, metaCache }) {
    extract: function extract() {
      return null;
    },
  };
  //     # First, check to see if we have a matching meta tag that we can make
  //     # use of.
  //     dek = self.extract_from_meta('dek', constants.DEK_META_TAGS)
  //     if not dek:
  //         # Second, look through our CSS/XPath selectors. This may return
  //         # an HTML fragment.
  //         dek = self.extract_from_selectors('dek',
  //                                            constants.DEK_SELECTORS,
  //                                            text_only=False)
  //
  //     if dek:
  //         # Make sure our dek isn't in the first few thousand characters
  //         # of the content, otherwise it's just the start of the article
  //         # and not a true dek.
  //         content = self.extract_content()
  //         content_chunk = normalize_spaces(strip_tags(content[:2000]))
  //         dek_chunk = normalize_spaces(dek[:100]) # Already has no tags.
  //
  //         # 80% or greater similarity means the dek was very similar to some
  //         # of the starting content, so we skip it.
  //         if fuzz.partial_ratio(content_chunk, dek_chunk) < 80:
  //             return dek
  //
  //     return None

  // An ordered list of meta tag names that denote likely article leading images.
  // All attributes should be lowercase for faster case-insensitive matching.
  // From most distinct to least distinct.
  var LEAD_IMAGE_URL_META_TAGS = ['og:image', 'twitter:image', 'image_src'];
  var LEAD_IMAGE_URL_SELECTORS = ['link[rel=image_src]'];
  var POSITIVE_LEAD_IMAGE_URL_HINTS = [
    'upload',
    'wp-content',
    'large',
    'photo',
    'wp-image',
  ];
  var POSITIVE_LEAD_IMAGE_URL_HINTS_RE = new RegExp(
    POSITIVE_LEAD_IMAGE_URL_HINTS.join('|'),
    'i'
  );
  var NEGATIVE_LEAD_IMAGE_URL_HINTS = [
    'spacer',
    'sprite',
    'blank',
    'throbber',
    'gradient',
    'tile',
    'bg',
    'background',
    'icon',
    'social',
    'header',
    'hdr',
    'advert',
    'spinner',
    'loader',
    'loading',
    'default',
    'rating',
    'share',
    'facebook',
    'twitter',
    'theme',
    'promo',
    'ads',
    'wp-includes',
  ];
  var NEGATIVE_LEAD_IMAGE_URL_HINTS_RE = new RegExp(
    NEGATIVE_LEAD_IMAGE_URL_HINTS.join('|'),
    'i'
  );
  var GIF_RE = /\.gif(\?.*)?$/i;
  var JPG_RE = /\.jpe?g(\?.*)?$/i;

  function getSig($node) {
    return ''
      .concat($node.attr('class') || '', ' ')
      .concat($node.attr('id') || '');
  } // Scores image urls based on a variety of heuristics.

  function scoreImageUrl(url) {
    url = url.trim();
    var score = 0;

    if (POSITIVE_LEAD_IMAGE_URL_HINTS_RE.test(url)) {
      score += 20;
    }

    if (NEGATIVE_LEAD_IMAGE_URL_HINTS_RE.test(url)) {
      score -= 20;
    } // TODO: We might want to consider removing this as
    // gifs are much more common/popular than they once were

    if (GIF_RE.test(url)) {
      score -= 10;
    }

    if (JPG_RE.test(url)) {
      score += 10;
    } // PNGs are neutral.

    return score;
  } // Alt attribute usually means non-presentational image.

  function scoreAttr($img) {
    if ($img.attr('alt')) {
      return 5;
    }

    return 0;
  } // Look through our parent and grandparent for figure-like
  // container elements, give a bonus if we find them

  function scoreByParents($img) {
    var score = 0;
    var $figParent = $img.parents('figure').first();

    if ($figParent.length === 1) {
      score += 25;
    }

    var $parent = $img.parent();
    var $gParent;

    if ($parent.length === 1) {
      $gParent = $parent.parent();
    }

    [$parent, $gParent].forEach(function($node) {
      if (PHOTO_HINTS_RE$1.test(getSig($node))) {
        score += 15;
      }
    });
    return score;
  } // Look at our immediate sibling and see if it looks like it's a
  // caption. Bonus if so.

  function scoreBySibling($img) {
    var score = 0;
    var $sibling = $img.next();
    var sibling = $sibling.get(0);

    if (sibling && sibling.tagName.toLowerCase() === 'figcaption') {
      score += 25;
    }

    if (PHOTO_HINTS_RE$1.test(getSig($sibling))) {
      score += 15;
    }

    return score;
  }
  function scoreByDimensions($img) {
    var score = 0;

    var width = _parseFloat$2($img.attr('width'));

    var height = _parseFloat$2($img.attr('height'));

    var src = $img.attr('src'); // Penalty for skinny images

    if (width && width <= 50) {
      score -= 50;
    } // Penalty for short images

    if (height && height <= 50) {
      score -= 50;
    }

    if (width && height && !src.includes('sprite')) {
      var area = width * height;

      if (area < 5000) {
        // Smaller than 50 x 100
        score -= 100;
      } else {
        score += Math.round(area / 1000);
      }
    }

    return score;
  }
  function scoreByPosition($imgs, index) {
    return $imgs.length / 2 - index;
  }

  // it. Like content and next page extraction, uses a scoring system
  // to determine what the most likely image may be. Short circuits
  // on really probable things like og:image meta tags.
  //
  // Potential signals to still take advantage of:
  //   * domain
  //   * weird aspect ratio

  var GenericLeadImageUrlExtractor = {
    extract: function extract(_ref) {
      var $ = _ref.$,
        content = _ref.content,
        metaCache = _ref.metaCache,
        html = _ref.html;
      var cleanUrl;

      if (!$.browser && $('head').length === 0) {
        $('*')
          .first()
          .prepend(html);
      } // Check to see if we have a matching meta tag that we can make use of.
      // Moving this higher because common practice is now to use large
      // images on things like Open Graph or Twitter cards.
      // images usually have for things like Open Graph.

      var imageUrl = extractFromMeta$$1(
        $,
        LEAD_IMAGE_URL_META_TAGS,
        metaCache,
        false
      );

      if (imageUrl) {
        cleanUrl = clean$1(imageUrl);
        if (cleanUrl) return cleanUrl;
      } // Next, try to find the "best" image via the content.
      // We'd rather not have to fetch each image and check dimensions,
      // so try to do some analysis and determine them instead.

      var $content = $(content);
      var imgs = $('img', $content).toArray();
      var imgScores = {};
      imgs.forEach(function(img, index) {
        var $img = $(img);
        var src = $img.attr('src');
        if (!src) return;
        var score = scoreImageUrl(src);
        score += scoreAttr($img);
        score += scoreByParents($img);
        score += scoreBySibling($img);
        score += scoreByDimensions($img);
        score += scoreByPosition(imgs, index);
        imgScores[src] = score;
      });

      var _Reflect$ownKeys$redu = ownKeys$1(imgScores).reduce(
          function(acc, key) {
            return imgScores[key] > acc[1] ? [key, imgScores[key]] : acc;
          },
          [null, 0]
        ),
        _Reflect$ownKeys$redu2 = slicedToArray(_Reflect$ownKeys$redu, 2),
        topUrl = _Reflect$ownKeys$redu2[0],
        topScore = _Reflect$ownKeys$redu2[1];

      if (topScore > 0) {
        cleanUrl = clean$1(topUrl);
        if (cleanUrl) return cleanUrl;
      } // If nothing else worked, check to see if there are any really
      // probable nodes in the doc, like <link rel="image_src" />.
      // eslint-disable-next-line no-restricted-syntax

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (
          var _iterator = getIterator$1(LEAD_IMAGE_URL_SELECTORS), _step;
          !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
          _iteratorNormalCompletion = true
        ) {
          var selector = _step.value;
          var $node = $(selector).first();
          var src = $node.attr('src');

          if (src) {
            cleanUrl = clean$1(src);
            if (cleanUrl) return cleanUrl;
          }

          var href = $node.attr('href');

          if (href) {
            cleanUrl = clean$1(href);
            if (cleanUrl) return cleanUrl;
          }

          var value = $node.attr('value');

          if (value) {
            cleanUrl = clean$1(value);
            if (cleanUrl) return cleanUrl;
          }
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return null;
    },
  };
  //     """
  //     # First, try to find the "best" image via the content.
  //     # We'd rather not have to fetch each image and check dimensions,
  //     # so try to do some analysis and determine them instead.
  //     content = self.extractor.extract_content(return_type="node")
  //     imgs = content.xpath('.//img')
  //     img_scores = defaultdict(int)
  //     logger.debug('Scoring %d images from content', len(imgs))
  //     for (i, img) in enumerate(imgs):
  //         img_score = 0
  //
  //         if not 'src' in img.attrib:
  //             logger.debug('No src attribute found')
  //             continue
  //
  //         try:
  //             parsed_img = urlparse(img.attrib['src'])
  //             img_path = parsed_img.path.lower()
  //         except ValueError:
  //             logger.debug('ValueError getting img path.')
  //             continue
  //         logger.debug('Image path is %s', img_path)
  //
  //         if constants.POSITIVE_LEAD_IMAGE_URL_HINTS_RE.match(img_path):
  //             logger.debug('Positive URL hints match. Adding 20.')
  //             img_score += 20
  //
  //         if constants.NEGATIVE_LEAD_IMAGE_URL_HINTS_RE.match(img_path):
  //             logger.debug('Negative URL hints match. Subtracting 20.')
  //             img_score -= 20
  //
  //         # Gifs are more often structure than photos
  //         if img_path.endswith('gif'):
  //             logger.debug('gif found. Subtracting 10.')
  //             img_score -= 10
  //
  //         # JPGs are more often photographs
  //         if img_path.endswith('jpg'):
  //             logger.debug('jpg found. Adding 10.')
  //             img_score += 10
  //
  //         # PNGs are neutral.
  //
  //         # Alt attribute usually means non-presentational image.
  //         if 'alt' in img.attrib and len(img.attrib['alt']) > 5:
  //             logger.debug('alt attribute found. Adding 5.')
  //             img_score += 5
  //
  //         # Look through our parent and grandparent for figure-like
  //         # container elements, give a bonus if we find them
  //         parents = [img.getparent()]
  //         if parents[0] is not None and parents[0].getparent() is not None:
  //             parents.append(parents[0].getparent())
  //         for p in parents:
  //             if p.tag == 'figure':
  //                 logger.debug('Parent with <figure> tag found. Adding 25.')
  //                 img_score += 25
  //
  //             p_sig = ' '.join([p.get('id', ''), p.get('class', '')])
  //             if constants.PHOTO_HINTS_RE.search(p_sig):
  //                 logger.debug('Photo hints regex match. Adding 15.')
  //                 img_score += 15
  //
  //         # Look at our immediate sibling and see if it looks like it's a
  //         # caption. Bonus if so.
  //         sibling = img.getnext()
  //         if sibling is not None:
  //             if sibling.tag == 'figcaption':
  //                 img_score += 25
  //
  //             sib_sig = ' '.join([sibling.get('id', ''),
  //                                 sibling.get('class', '')]).lower()
  //             if 'caption' in sib_sig:
  //                 img_score += 15
  //
  //         # Pull out width/height if they were set.
  //         img_width = None
  //         img_height = None
  //         if 'width' in img.attrib:
  //             try:
  //                 img_width = float(img.get('width'))
  //             except ValueError:
  //                 pass
  //         if 'height' in img.attrib:
  //             try:
  //                 img_height = float(img.get('height'))
  //             except ValueError:
  //                 pass
  //
  //         # Penalty for skinny images
  //         if img_width and img_width <= 50:
  //             logger.debug('Skinny image found. Subtracting 50.')
  //             img_score -= 50
  //
  //         # Penalty for short images
  //         if img_height and img_height <= 50:
  //             # Wide, short images are more common than narrow, tall ones
  //             logger.debug('Short image found. Subtracting 25.')
  //             img_score -= 25
  //
  //         if img_width and img_height and not 'sprite' in img_path:
  //             area = img_width * img_height
  //
  //             if area < 5000: # Smaller than 50x100
  //                 logger.debug('Image with small area found. Subtracting 100.')
  //                 img_score -= 100
  //             else:
  //                 img_score += round(area/1000.0)
  //
  //         # If the image is higher on the page than other images,
  //         # it gets a bonus. Penalty if lower.
  //         logger.debug('Adding page placement bonus of %d.', len(imgs)/2 - i)
  //         img_score += len(imgs)/2 - i
  //
  //         # Use the raw src here because we munged img_path for case
  //         # insensitivity
  //         logger.debug('Final score is %d.', img_score)
  //         img_scores[img.attrib['src']] += img_score
  //
  //     top_score = 0
  //     top_url = None
  //     for (url, score) in img_scores.items():
  //         if score > top_score:
  //             top_url = url
  //             top_score = score
  //
  //     if top_score > 0:
  //         logger.debug('Using top score image from content. Score was %d', top_score)
  //         return top_url
  //
  //
  //     # If nothing else worked, check to see if there are any really
  //     # probable nodes in the doc, like <link rel="image_src" />.
  //     logger.debug('Trying to find lead image in probable nodes')
  //     for selector in constants.LEAD_IMAGE_URL_SELECTORS:
  //         nodes = self.resource.extract_by_selector(selector)
  //         for node in nodes:
  //             clean_value = None
  //             if node.attrib.get('src'):
  //                 clean_value = self.clean(node.attrib['src'])
  //
  //             if not clean_value and node.attrib.get('href'):
  //                 clean_value = self.clean(node.attrib['href'])
  //
  //             if not clean_value and node.attrib.get('value'):
  //                 clean_value = self.clean(node.attrib['value'])
  //
  //             if clean_value:
  //                 logger.debug('Found lead image in probable nodes.')
  //                 logger.debug('Node was: %s', node)
  //                 return clean_value
  //
  //     return None

  var heap = createCommonjsModule(function(module, exports) {
    // Generated by CoffeeScript 1.8.0
    (function() {
      var Heap,
        defaultCmp,
        floor,
        heapify,
        heappop,
        heappush,
        heappushpop,
        heapreplace,
        insort,
        min,
        nlargest,
        nsmallest,
        updateItem,
        _siftdown,
        _siftup;

      (floor = Math.floor), (min = Math.min);
      /*
	  Default comparison function to be used
	   */

      defaultCmp = function(x, y) {
        if (x < y) {
          return -1;
        }

        if (x > y) {
          return 1;
        }

        return 0;
      };
      /*
	  Insert item x in list a, and keep it sorted assuming a is sorted.
	  
	  If x is already in a, insert it to the right of the rightmost x.
	  
	  Optional args lo (default 0) and hi (default a.length) bound the slice
	  of a to be searched.
	   */

      insort = function(a, x, lo, hi, cmp) {
        var mid;

        if (lo == null) {
          lo = 0;
        }

        if (cmp == null) {
          cmp = defaultCmp;
        }

        if (lo < 0) {
          throw new Error('lo must be non-negative');
        }

        if (hi == null) {
          hi = a.length;
        }

        while (lo < hi) {
          mid = floor((lo + hi) / 2);

          if (cmp(x, a[mid]) < 0) {
            hi = mid;
          } else {
            lo = mid + 1;
          }
        }

        return [].splice.apply(a, [lo, lo - lo].concat(x)), x;
      };
      /*
	  Push item onto heap, maintaining the heap invariant.
	   */

      heappush = function(array, item, cmp) {
        if (cmp == null) {
          cmp = defaultCmp;
        }

        array.push(item);
        return _siftdown(array, 0, array.length - 1, cmp);
      };
      /*
	  Pop the smallest item off the heap, maintaining the heap invariant.
	   */

      heappop = function(array, cmp) {
        var lastelt, returnitem;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        lastelt = array.pop();

        if (array.length) {
          returnitem = array[0];
          array[0] = lastelt;

          _siftup(array, 0, cmp);
        } else {
          returnitem = lastelt;
        }

        return returnitem;
      };
      /*
	  Pop and return the current smallest value, and add the new item.
	  
	  This is more efficient than heappop() followed by heappush(), and can be
	  more appropriate when using a fixed size heap. Note that the value
	  returned may be larger than item! That constrains reasonable use of
	  this routine unless written as part of a conditional replacement:
	      if item > array[0]
	        item = heapreplace(array, item)
	   */

      heapreplace = function(array, item, cmp) {
        var returnitem;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        returnitem = array[0];
        array[0] = item;

        _siftup(array, 0, cmp);

        return returnitem;
      };
      /*
	  Fast version of a heappush followed by a heappop.
	   */

      heappushpop = function(array, item, cmp) {
        var _ref;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        if (array.length && cmp(array[0], item) < 0) {
          (_ref = [array[0], item]), (item = _ref[0]), (array[0] = _ref[1]);

          _siftup(array, 0, cmp);
        }

        return item;
      };
      /*
	  Transform list into a heap, in-place, in O(array.length) time.
	   */

      heapify = function(array, cmp) {
        var i, _i, _len, _ref1, _results, _results1;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        _ref1 = function() {
          _results1 = [];

          for (
            var _j = 0, _ref = floor(array.length / 2);
            0 <= _ref ? _j < _ref : _j > _ref;
            0 <= _ref ? _j++ : _j--
          ) {
            _results1.push(_j);
          }

          return _results1;
        }
          .apply(this)
          .reverse();

        _results = [];

        for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
          i = _ref1[_i];

          _results.push(_siftup(array, i, cmp));
        }

        return _results;
      };
      /*
	  Update the position of the given item in the heap.
	  This function should be called every time the item is being modified.
	   */

      updateItem = function(array, item, cmp) {
        var pos;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        pos = array.indexOf(item);

        if (pos === -1) {
          return;
        }

        _siftdown(array, 0, pos, cmp);

        return _siftup(array, pos, cmp);
      };
      /*
	  Find the n largest elements in a dataset.
	   */

      nlargest = function(array, n, cmp) {
        var elem, result, _i, _len, _ref;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        result = array.slice(0, n);

        if (!result.length) {
          return result;
        }

        heapify(result, cmp);
        _ref = array.slice(n);

        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          elem = _ref[_i];
          heappushpop(result, elem, cmp);
        }

        return result.sort(cmp).reverse();
      };
      /*
	  Find the n smallest elements in a dataset.
	   */

      nsmallest = function(array, n, cmp) {
        var elem, i, los, result, _i, _j, _len, _ref, _ref1, _results;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        if (n * 10 <= array.length) {
          result = array.slice(0, n).sort(cmp);

          if (!result.length) {
            return result;
          }

          los = result[result.length - 1];
          _ref = array.slice(n);

          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            elem = _ref[_i];

            if (cmp(elem, los) < 0) {
              insort(result, elem, 0, null, cmp);
              result.pop();
              los = result[result.length - 1];
            }
          }

          return result;
        }

        heapify(array, cmp);
        _results = [];

        for (
          i = _j = 0, _ref1 = min(n, array.length);
          0 <= _ref1 ? _j < _ref1 : _j > _ref1;
          i = 0 <= _ref1 ? ++_j : --_j
        ) {
          _results.push(heappop(array, cmp));
        }

        return _results;
      };

      _siftdown = function(array, startpos, pos, cmp) {
        var newitem, parent, parentpos;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        newitem = array[pos];

        while (pos > startpos) {
          parentpos = (pos - 1) >> 1;
          parent = array[parentpos];

          if (cmp(newitem, parent) < 0) {
            array[pos] = parent;
            pos = parentpos;
            continue;
          }

          break;
        }

        return (array[pos] = newitem);
      };

      _siftup = function(array, pos, cmp) {
        var childpos, endpos, newitem, rightpos, startpos;

        if (cmp == null) {
          cmp = defaultCmp;
        }

        endpos = array.length;
        startpos = pos;
        newitem = array[pos];
        childpos = 2 * pos + 1;

        while (childpos < endpos) {
          rightpos = childpos + 1;

          if (
            rightpos < endpos &&
            !(cmp(array[childpos], array[rightpos]) < 0)
          ) {
            childpos = rightpos;
          }

          array[pos] = array[childpos];
          pos = childpos;
          childpos = 2 * pos + 1;
        }

        array[pos] = newitem;
        return _siftdown(array, startpos, pos, cmp);
      };

      Heap = (function() {
        Heap.push = heappush;
        Heap.pop = heappop;
        Heap.replace = heapreplace;
        Heap.pushpop = heappushpop;
        Heap.heapify = heapify;
        Heap.updateItem = updateItem;
        Heap.nlargest = nlargest;
        Heap.nsmallest = nsmallest;

        function Heap(cmp) {
          this.cmp = cmp != null ? cmp : defaultCmp;
          this.nodes = [];
        }

        Heap.prototype.push = function(x) {
          return heappush(this.nodes, x, this.cmp);
        };

        Heap.prototype.pop = function() {
          return heappop(this.nodes, this.cmp);
        };

        Heap.prototype.peek = function() {
          return this.nodes[0];
        };

        Heap.prototype.contains = function(x) {
          return this.nodes.indexOf(x) !== -1;
        };

        Heap.prototype.replace = function(x) {
          return heapreplace(this.nodes, x, this.cmp);
        };

        Heap.prototype.pushpop = function(x) {
          return heappushpop(this.nodes, x, this.cmp);
        };

        Heap.prototype.heapify = function() {
          return heapify(this.nodes, this.cmp);
        };

        Heap.prototype.updateItem = function(x) {
          return updateItem(this.nodes, x, this.cmp);
        };

        Heap.prototype.clear = function() {
          return (this.nodes = []);
        };

        Heap.prototype.empty = function() {
          return this.nodes.length === 0;
        };

        Heap.prototype.size = function() {
          return this.nodes.length;
        };

        Heap.prototype.clone = function() {
          var heap;
          heap = new Heap();
          heap.nodes = this.nodes.slice(0);
          return heap;
        };

        Heap.prototype.toArray = function() {
          return this.nodes.slice(0);
        };

        Heap.prototype.insert = Heap.prototype.push;
        Heap.prototype.top = Heap.prototype.peek;
        Heap.prototype.front = Heap.prototype.peek;
        Heap.prototype.has = Heap.prototype.contains;
        Heap.prototype.copy = Heap.prototype.clone;
        return Heap;
      })();

      (function(root, factory) {
        {
          return (module.exports = factory());
        }
      })(this, function() {
        return Heap;
      });
    }.call(this));
  });

  var heap$1 = heap;

  var difflib = createCommonjsModule(function(module, exports) {
    // Generated by CoffeeScript 1.3.1

    /*
	Module difflib -- helpers for computing deltas between objects.

	Function getCloseMatches(word, possibilities, n=3, cutoff=0.6):
	    Use SequenceMatcher to return list of the best "good enough" matches.

	Function contextDiff(a, b):
	    For two lists of strings, return a delta in context diff format.

	Function ndiff(a, b):
	    Return a delta: the difference between `a` and `b` (lists of strings).

	Function restore(delta, which):
	    Return one of the two sequences that generated an ndiff delta.

	Function unifiedDiff(a, b):
	    For two lists of strings, return a delta in unified diff format.

	Class SequenceMatcher:
	    A flexible class for comparing pairs of sequences of any type.

	Class Differ:
	    For producing human-readable deltas from sequences of lines of text.
	*/
    (function() {
      var Differ,
        Heap,
        IS_CHARACTER_JUNK,
        IS_LINE_JUNK,
        SequenceMatcher,
        contextDiff,
        floor,
        getCloseMatches,
        max,
        min,
        ndiff,
        restore,
        unifiedDiff,
        _any,
        _arrayCmp,
        _calculateRatio,
        _countLeading,
        _formatRangeContext,
        _formatRangeUnified,
        _has,
        __indexOf =
          [].indexOf ||
          function(item) {
            for (var i = 0, l = this.length; i < l; i++) {
              if (i in this && this[i] === item) return i;
            }

            return -1;
          };

      (floor = Math.floor), (max = Math.max), (min = Math.min);
      Heap = heap$1;

      _calculateRatio = function(matches, length) {
        if (length) {
          return (2.0 * matches) / length;
        } else {
          return 1.0;
        }
      };

      _arrayCmp = function(a, b) {
        var i, la, lb, _i, _ref, _ref1;

        (_ref = [a.length, b.length]), (la = _ref[0]), (lb = _ref[1]);

        for (
          i = _i = 0, _ref1 = min(la, lb);
          0 <= _ref1 ? _i < _ref1 : _i > _ref1;
          i = 0 <= _ref1 ? ++_i : --_i
        ) {
          if (a[i] < b[i]) {
            return -1;
          }

          if (a[i] > b[i]) {
            return 1;
          }
        }

        return la - lb;
      };

      _has = function(obj, key) {
        return Object.prototype.hasOwnProperty.call(obj, key);
      };

      _any = function(items) {
        var item, _i, _len;

        for (_i = 0, _len = items.length; _i < _len; _i++) {
          item = items[_i];

          if (item) {
            return true;
          }
        }

        return false;
      };

      SequenceMatcher = (function() {
        /*
	      SequenceMatcher is a flexible class for comparing pairs of sequences of
	      any type, so long as the sequence elements are hashable.  The basic
	      algorithm predates, and is a little fancier than, an algorithm
	      published in the late 1980's by Ratcliff and Obershelp under the
	      hyperbolic name "gestalt pattern matching".  The basic idea is to find
	      the longest contiguous matching subsequence that contains no "junk"
	      elements (R-O doesn't address junk).  The same idea is then applied
	      recursively to the pieces of the sequences to the left and to the right
	      of the matching subsequence.  This does not yield minimal edit
	      sequences, but does tend to yield matches that "look right" to people.
	    
	      SequenceMatcher tries to compute a "human-friendly diff" between two
	      sequences.  Unlike e.g. UNIX(tm) diff, the fundamental notion is the
	      longest *contiguous* & junk-free matching subsequence.  That's what
	      catches peoples' eyes.  The Windows(tm) windiff has another interesting
	      notion, pairing up elements that appear uniquely in each sequence.
	      That, and the method here, appear to yield more intuitive difference
	      reports than does diff.  This method appears to be the least vulnerable
	      to synching up on blocks of "junk lines", though (like blank lines in
	      ordinary text files, or maybe "<P>" lines in HTML files).  That may be
	      because this is the only method of the 3 that has a *concept* of
	      "junk" <wink>.
	    
	      Example, comparing two strings, and considering blanks to be "junk":
	    
	      >>> isjunk = (c) -> c is ' '
	      >>> s = new SequenceMatcher(isjunk,
	                                  'private Thread currentThread;',
	                                  'private volatile Thread currentThread;')
	    
	      .ratio() returns a float in [0, 1], measuring the "similarity" of the
	      sequences.  As a rule of thumb, a .ratio() value over 0.6 means the
	      sequences are close matches:
	    
	      >>> s.ratio().toPrecision(3)
	      '0.866'
	    
	      If you're only interested in where the sequences match,
	      .getMatchingBlocks() is handy:
	    
	      >>> for [a, b, size] in s.getMatchingBlocks()
	      ...   console.log("a[#{a}] and b[#{b}] match for #{size} elements");
	      a[0] and b[0] match for 8 elements
	      a[8] and b[17] match for 21 elements
	      a[29] and b[38] match for 0 elements
	    
	      Note that the last tuple returned by .get_matching_blocks() is always a
	      dummy, (len(a), len(b), 0), and this is the only case in which the last
	      tuple element (number of elements matched) is 0.
	    
	      If you want to know how to change the first sequence into the second,
	      use .get_opcodes():
	    
	      >>> for [op, a1, a2, b1, b2] in s.getOpcodes()
	      ...   console.log "#{op} a[#{a1}:#{a2}] b[#{b1}:#{b2}]"
	      equal a[0:8] b[0:8]
	      insert a[8:8] b[8:17]
	      equal a[8:29] b[17:38]
	    
	      See the Differ class for a fancy human-friendly file differencer, which
	      uses SequenceMatcher both to compare sequences of lines, and to compare
	      sequences of characters within similar (near-matching) lines.
	    
	      See also function getCloseMatches() in this module, which shows how
	      simple code building on SequenceMatcher can be used to do useful work.
	    
	      Timing:  Basic R-O is cubic time worst case and quadratic time expected
	      case.  SequenceMatcher is quadratic time for the worst case and has
	      expected-case behavior dependent in a complicated way on how many
	      elements the sequences have in common; best case time is linear.
	    
	      Methods:
	    
	      constructor(isjunk=null, a='', b='')
	          Construct a SequenceMatcher.
	    
	      setSeqs(a, b)
	          Set the two sequences to be compared.
	    
	      setSeq1(a)
	          Set the first sequence to be compared.
	    
	      setSeq2(b)
	          Set the second sequence to be compared.
	    
	      findLongestMatch(alo, ahi, blo, bhi)
	          Find longest matching block in a[alo:ahi] and b[blo:bhi].
	    
	      getMatchingBlocks()
	          Return list of triples describing matching subsequences.
	    
	      getOpcodes()
	          Return list of 5-tuples describing how to turn a into b.
	    
	      ratio()
	          Return a measure of the sequences' similarity (float in [0,1]).
	    
	      quickRatio()
	          Return an upper bound on .ratio() relatively quickly.
	    
	      realQuickRatio()
	          Return an upper bound on ratio() very quickly.
	    */
        function SequenceMatcher(isjunk, a, b, autojunk) {
          this.isjunk = isjunk;

          if (a == null) {
            a = '';
          }

          if (b == null) {
            b = '';
          }

          this.autojunk = autojunk != null ? autojunk : true;
          /*
	          Construct a SequenceMatcher.
	      
	          Optional arg isjunk is null (the default), or a one-argument
	          function that takes a sequence element and returns true iff the
	          element is junk.  Null is equivalent to passing "(x) -> 0", i.e.
	          no elements are considered to be junk.  For example, pass
	              (x) -> x in ' \t'
	          if you're comparing lines as sequences of characters, and don't
	          want to synch up on blanks or hard tabs.
	      
	          Optional arg a is the first of two sequences to be compared.  By
	          default, an empty string.  The elements of a must be hashable.  See
	          also .setSeqs() and .setSeq1().
	      
	          Optional arg b is the second of two sequences to be compared.  By
	          default, an empty string.  The elements of b must be hashable. See
	          also .setSeqs() and .setSeq2().
	      
	          Optional arg autojunk should be set to false to disable the
	          "automatic junk heuristic" that treats popular elements as junk
	          (see module documentation for more information).
	      */

          this.a = this.b = null;
          this.setSeqs(a, b);
        }

        SequenceMatcher.prototype.setSeqs = function(a, b) {
          /* 
	      Set the two sequences to be compared. 
	      
	      >>> s = new SequenceMatcher()
	      >>> s.setSeqs('abcd', 'bcde')
	      >>> s.ratio()
	      0.75
	      */
          this.setSeq1(a);
          return this.setSeq2(b);
        };

        SequenceMatcher.prototype.setSeq1 = function(a) {
          /* 
	      Set the first sequence to be compared. 
	      
	      The second sequence to be compared is not changed.
	      
	      >>> s = new SequenceMatcher(null, 'abcd', 'bcde')
	      >>> s.ratio()
	      0.75
	      >>> s.setSeq1('bcde')
	      >>> s.ratio()
	      1.0
	      
	      SequenceMatcher computes and caches detailed information about the
	      second sequence, so if you want to compare one sequence S against
	      many sequences, use .setSeq2(S) once and call .setSeq1(x)
	      repeatedly for each of the other sequences.
	      
	      See also setSeqs() and setSeq2().
	      */
          if (a === this.a) {
            return;
          }

          this.a = a;
          return (this.matchingBlocks = this.opcodes = null);
        };

        SequenceMatcher.prototype.setSeq2 = function(b) {
          /*
	          Set the second sequence to be compared. 
	      
	          The first sequence to be compared is not changed.
	      
	          >>> s = new SequenceMatcher(null, 'abcd', 'bcde')
	          >>> s.ratio()
	          0.75
	          >>> s.setSeq2('abcd')
	          >>> s.ratio()
	          1.0
	      
	          SequenceMatcher computes and caches detailed information about the
	          second sequence, so if you want to compare one sequence S against
	          many sequences, use .setSeq2(S) once and call .setSeq1(x)
	          repeatedly for each of the other sequences.
	      
	          See also setSeqs() and setSeq1().
	      */
          if (b === this.b) {
            return;
          }

          this.b = b;
          this.matchingBlocks = this.opcodes = null;
          this.fullbcount = null;
          return this._chainB();
        };

        SequenceMatcher.prototype._chainB = function() {
          var b,
            b2j,
            elt,
            i,
            idxs,
            indices,
            isjunk,
            junk,
            n,
            ntest,
            popular,
            _i,
            _j,
            _len,
            _len1,
            _ref;

          b = this.b;
          this.b2j = b2j = {};

          for (i = _i = 0, _len = b.length; _i < _len; i = ++_i) {
            elt = b[i];
            indices = _has(b2j, elt) ? b2j[elt] : (b2j[elt] = []);
            indices.push(i);
          }

          junk = {};
          isjunk = this.isjunk;

          if (isjunk) {
            _ref = Object.keys(b2j);

            for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
              elt = _ref[_j];

              if (isjunk(elt)) {
                junk[elt] = true;
                delete b2j[elt];
              }
            }
          }

          popular = {};
          n = b.length;

          if (this.autojunk && n >= 200) {
            ntest = floor(n / 100) + 1;

            for (elt in b2j) {
              idxs = b2j[elt];

              if (idxs.length > ntest) {
                popular[elt] = true;
                delete b2j[elt];
              }
            }
          }

          this.isbjunk = function(b) {
            return _has(junk, b);
          };

          return (this.isbpopular = function(b) {
            return _has(popular, b);
          });
        };

        SequenceMatcher.prototype.findLongestMatch = function(
          alo,
          ahi,
          blo,
          bhi
        ) {
          /* 
	      Find longest matching block in a[alo...ahi] and b[blo...bhi].  
	      
	      If isjunk is not defined:
	      
	      Return [i,j,k] such that a[i...i+k] is equal to b[j...j+k], where
	          alo <= i <= i+k <= ahi
	          blo <= j <= j+k <= bhi
	      and for all [i',j',k'] meeting those conditions,
	          k >= k'
	          i <= i'
	          and if i == i', j <= j'
	      
	      In other words, of all maximal matching blocks, return one that
	      starts earliest in a, and of all those maximal matching blocks that
	      start earliest in a, return the one that starts earliest in b.
	      
	      >>> isjunk = (x) -> x is ' '
	      >>> s = new SequenceMatcher(isjunk, ' abcd', 'abcd abcd')
	      >>> s.findLongestMatch(0, 5, 0, 9)
	      [1, 0, 4]
	      
	      >>> s = new SequenceMatcher(null, 'ab', 'c')
	      >>> s.findLongestMatch(0, 2, 0, 1)
	      [0, 0, 0]
	      */
          var a,
            b,
            b2j,
            besti,
            bestj,
            bestsize,
            i,
            isbjunk,
            j,
            j2len,
            k,
            newj2len,
            _i,
            _j,
            _len,
            _ref,
            _ref1,
            _ref2,
            _ref3,
            _ref4,
            _ref5;

          (_ref = [this.a, this.b, this.b2j, this.isbjunk]),
            (a = _ref[0]),
            (b = _ref[1]),
            (b2j = _ref[2]),
            (isbjunk = _ref[3]);
          (_ref1 = [alo, blo, 0]),
            (besti = _ref1[0]),
            (bestj = _ref1[1]),
            (bestsize = _ref1[2]);
          j2len = {};

          for (
            i = _i = alo;
            alo <= ahi ? _i < ahi : _i > ahi;
            i = alo <= ahi ? ++_i : --_i
          ) {
            newj2len = {};
            _ref2 = _has(b2j, a[i]) ? b2j[a[i]] : [];

            for (_j = 0, _len = _ref2.length; _j < _len; _j++) {
              j = _ref2[_j];

              if (j < blo) {
                continue;
              }

              if (j >= bhi) {
                break;
              }

              k = newj2len[j] = (j2len[j - 1] || 0) + 1;

              if (k > bestsize) {
                (_ref3 = [i - k + 1, j - k + 1, k]),
                  (besti = _ref3[0]),
                  (bestj = _ref3[1]),
                  (bestsize = _ref3[2]);
              }
            }

            j2len = newj2len;
          }

          while (
            besti > alo &&
            bestj > blo &&
            !isbjunk(b[bestj - 1]) &&
            a[besti - 1] === b[bestj - 1]
          ) {
            (_ref4 = [besti - 1, bestj - 1, bestsize + 1]),
              (besti = _ref4[0]),
              (bestj = _ref4[1]),
              (bestsize = _ref4[2]);
          }

          while (
            besti + bestsize < ahi &&
            bestj + bestsize < bhi &&
            !isbjunk(b[bestj + bestsize]) &&
            a[besti + bestsize] === b[bestj + bestsize]
          ) {
            bestsize++;
          }

          while (
            besti > alo &&
            bestj > blo &&
            isbjunk(b[bestj - 1]) &&
            a[besti - 1] === b[bestj - 1]
          ) {
            (_ref5 = [besti - 1, bestj - 1, bestsize + 1]),
              (besti = _ref5[0]),
              (bestj = _ref5[1]),
              (bestsize = _ref5[2]);
          }

          while (
            besti + bestsize < ahi &&
            bestj + bestsize < bhi &&
            isbjunk(b[bestj + bestsize]) &&
            a[besti + bestsize] === b[bestj + bestsize]
          ) {
            bestsize++;
          }

          return [besti, bestj, bestsize];
        };

        SequenceMatcher.prototype.getMatchingBlocks = function() {
          /*
	          Return list of triples describing matching subsequences.
	      
	          Each triple is of the form [i, j, n], and means that
	          a[i...i+n] == b[j...j+n].  The triples are monotonically increasing in
	          i and in j.  it's also guaranteed that if
	          [i, j, n] and [i', j', n'] are adjacent triples in the list, and
	          the second is not the last triple in the list, then i+n != i' or
	          j+n != j'.  IOW, adjacent triples never describe adjacent equal
	          blocks.
	      
	          The last triple is a dummy, [a.length, b.length, 0], and is the only
	          triple with n==0.
	      
	          >>> s = new SequenceMatcher(null, 'abxcd', 'abcd')
	          >>> s.getMatchingBlocks()
	          [[0, 0, 2], [3, 2, 2], [5, 4, 0]]
	      */
          var ahi,
            alo,
            bhi,
            blo,
            i,
            i1,
            i2,
            j,
            j1,
            j2,
            k,
            k1,
            k2,
            la,
            lb,
            matchingBlocks,
            nonAdjacent,
            queue,
            x,
            _i,
            _len,
            _ref,
            _ref1,
            _ref2,
            _ref3,
            _ref4;

          if (this.matchingBlocks) {
            return this.matchingBlocks;
          }

          (_ref = [this.a.length, this.b.length]),
            (la = _ref[0]),
            (lb = _ref[1]);
          queue = [[0, la, 0, lb]];
          matchingBlocks = [];

          while (queue.length) {
            (_ref1 = queue.pop()),
              (alo = _ref1[0]),
              (ahi = _ref1[1]),
              (blo = _ref1[2]),
              (bhi = _ref1[3]);
            (_ref2 = x = this.findLongestMatch(alo, ahi, blo, bhi)),
              (i = _ref2[0]),
              (j = _ref2[1]),
              (k = _ref2[2]);

            if (k) {
              matchingBlocks.push(x);

              if (alo < i && blo < j) {
                queue.push([alo, i, blo, j]);
              }

              if (i + k < ahi && j + k < bhi) {
                queue.push([i + k, ahi, j + k, bhi]);
              }
            }
          }

          matchingBlocks.sort(_arrayCmp);
          i1 = j1 = k1 = 0;
          nonAdjacent = [];

          for (_i = 0, _len = matchingBlocks.length; _i < _len; _i++) {
            (_ref3 = matchingBlocks[_i]),
              (i2 = _ref3[0]),
              (j2 = _ref3[1]),
              (k2 = _ref3[2]);

            if (i1 + k1 === i2 && j1 + k1 === j2) {
              k1 += k2;
            } else {
              if (k1) {
                nonAdjacent.push([i1, j1, k1]);
              }

              (_ref4 = [i2, j2, k2]),
                (i1 = _ref4[0]),
                (j1 = _ref4[1]),
                (k1 = _ref4[2]);
            }
          }

          if (k1) {
            nonAdjacent.push([i1, j1, k1]);
          }

          nonAdjacent.push([la, lb, 0]);
          return (this.matchingBlocks = nonAdjacent);
        };

        SequenceMatcher.prototype.getOpcodes = function() {
          /* 
	      Return list of 5-tuples describing how to turn a into b.
	      
	      Each tuple is of the form [tag, i1, i2, j1, j2].  The first tuple
	      has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
	      tuple preceding it, and likewise for j1 == the previous j2.
	      
	      The tags are strings, with these meanings:
	      
	      'replace':  a[i1...i2] should be replaced by b[j1...j2]
	      'delete':   a[i1...i2] should be deleted.
	                  Note that j1==j2 in this case.
	      'insert':   b[j1...j2] should be inserted at a[i1...i1].
	                  Note that i1==i2 in this case.
	      'equal':    a[i1...i2] == b[j1...j2]
	      
	      >>> s = new SequenceMatcher(null, 'qabxcd', 'abycdf')
	      >>> s.getOpcodes()
	      [ [ 'delete'  , 0 , 1 , 0 , 0 ] ,
	        [ 'equal'   , 1 , 3 , 0 , 2 ] ,
	        [ 'replace' , 3 , 4 , 2 , 3 ] ,
	        [ 'equal'   , 4 , 6 , 3 , 5 ] ,
	        [ 'insert'  , 6 , 6 , 5 , 6 ] ]
	      */
          var ai, answer, bj, i, j, size, tag, _i, _len, _ref, _ref1, _ref2;

          if (this.opcodes) {
            return this.opcodes;
          }

          i = j = 0;
          this.opcodes = answer = [];
          _ref = this.getMatchingBlocks();

          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            (_ref1 = _ref[_i]),
              (ai = _ref1[0]),
              (bj = _ref1[1]),
              (size = _ref1[2]);
            tag = '';

            if (i < ai && j < bj) {
              tag = 'replace';
            } else if (i < ai) {
              tag = 'delete';
            } else if (j < bj) {
              tag = 'insert';
            }

            if (tag) {
              answer.push([tag, i, ai, j, bj]);
            }

            (_ref2 = [ai + size, bj + size]), (i = _ref2[0]), (j = _ref2[1]);

            if (size) {
              answer.push(['equal', ai, i, bj, j]);
            }
          }

          return answer;
        };

        SequenceMatcher.prototype.getGroupedOpcodes = function(n) {
          var codes,
            group,
            groups,
            i1,
            i2,
            j1,
            j2,
            nn,
            tag,
            _i,
            _len,
            _ref,
            _ref1,
            _ref2,
            _ref3;

          if (n == null) {
            n = 3;
          }
          /* 
	      Isolate change clusters by eliminating ranges with no changes.
	      
	      Return a list groups with upto n lines of context.
	      Each group is in the same format as returned by get_opcodes().
	      
	      >>> a = [1...40].map(String)
	      >>> b = a.slice()
	      >>> b[8...8] = 'i'
	      >>> b[20] += 'x'
	      >>> b[23...28] = []
	      >>> b[30] += 'y'
	      >>> s = new SequenceMatcher(null, a, b)
	      >>> s.getGroupedOpcodes()
	      [ [ [ 'equal'  , 5 , 8  , 5 , 8 ],
	          [ 'insert' , 8 , 8  , 8 , 9 ],
	          [ 'equal'  , 8 , 11 , 9 , 12 ] ],
	        [ [ 'equal'   , 16 , 19 , 17 , 20 ],
	          [ 'replace' , 19 , 20 , 20 , 21 ],
	          [ 'equal'   , 20 , 22 , 21 , 23 ],
	          [ 'delete'  , 22 , 27 , 23 , 23 ],
	          [ 'equal'   , 27 , 30 , 23 , 26 ] ],
	        [ [ 'equal'   , 31 , 34 , 27 , 30 ],
	          [ 'replace' , 34 , 35 , 30 , 31 ],
	          [ 'equal'   , 35 , 38 , 31 , 34 ] ] ]
	      */

          codes = this.getOpcodes();

          if (!codes.length) {
            codes = [['equal', 0, 1, 0, 1]];
          }

          if (codes[0][0] === 'equal') {
            (_ref = codes[0]),
              (tag = _ref[0]),
              (i1 = _ref[1]),
              (i2 = _ref[2]),
              (j1 = _ref[3]),
              (j2 = _ref[4]);
            codes[0] = [tag, max(i1, i2 - n), i2, max(j1, j2 - n), j2];
          }

          if (codes[codes.length - 1][0] === 'equal') {
            (_ref1 = codes[codes.length - 1]),
              (tag = _ref1[0]),
              (i1 = _ref1[1]),
              (i2 = _ref1[2]),
              (j1 = _ref1[3]),
              (j2 = _ref1[4]);
            codes[codes.length - 1] = [
              tag,
              i1,
              min(i2, i1 + n),
              j1,
              min(j2, j1 + n),
            ];
          }

          nn = n + n;
          groups = [];
          group = [];

          for (_i = 0, _len = codes.length; _i < _len; _i++) {
            (_ref2 = codes[_i]),
              (tag = _ref2[0]),
              (i1 = _ref2[1]),
              (i2 = _ref2[2]),
              (j1 = _ref2[3]),
              (j2 = _ref2[4]);

            if (tag === 'equal' && i2 - i1 > nn) {
              group.push([tag, i1, min(i2, i1 + n), j1, min(j2, j1 + n)]);
              groups.push(group);
              group = [];
              (_ref3 = [max(i1, i2 - n), max(j1, j2 - n)]),
                (i1 = _ref3[0]),
                (j1 = _ref3[1]);
            }

            group.push([tag, i1, i2, j1, j2]);
          }

          if (
            group.length &&
            !(group.length === 1 && group[0][0] === 'equal')
          ) {
            groups.push(group);
          }

          return groups;
        };

        SequenceMatcher.prototype.ratio = function() {
          /*
	          Return a measure of the sequences' similarity (float in [0,1]).
	      
	          Where T is the total number of elements in both sequences, and
	          M is the number of matches, this is 2.0*M / T.
	          Note that this is 1 if the sequences are identical, and 0 if
	          they have nothing in common.
	      
	          .ratio() is expensive to compute if you haven't already computed
	          .getMatchingBlocks() or .getOpcodes(), in which case you may
	          want to try .quickRatio() or .realQuickRatio() first to get an
	          upper bound.
	          
	          >>> s = new SequenceMatcher(null, 'abcd', 'bcde')
	          >>> s.ratio()
	          0.75
	          >>> s.quickRatio()
	          0.75
	          >>> s.realQuickRatio()
	          1.0
	      */
          var match, matches, _i, _len, _ref;

          matches = 0;
          _ref = this.getMatchingBlocks();

          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            match = _ref[_i];
            matches += match[2];
          }

          return _calculateRatio(matches, this.a.length + this.b.length);
        };

        SequenceMatcher.prototype.quickRatio = function() {
          /*
	          Return an upper bound on ratio() relatively quickly.
	      
	          This isn't defined beyond that it is an upper bound on .ratio(), and
	          is faster to compute.
	      */
          var avail,
            elt,
            fullbcount,
            matches,
            numb,
            _i,
            _j,
            _len,
            _len1,
            _ref,
            _ref1;

          if (!this.fullbcount) {
            this.fullbcount = fullbcount = {};
            _ref = this.b;

            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              elt = _ref[_i];
              fullbcount[elt] = (fullbcount[elt] || 0) + 1;
            }
          }

          fullbcount = this.fullbcount;
          avail = {};
          matches = 0;
          _ref1 = this.a;

          for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
            elt = _ref1[_j];

            if (_has(avail, elt)) {
              numb = avail[elt];
            } else {
              numb = fullbcount[elt] || 0;
            }

            avail[elt] = numb - 1;

            if (numb > 0) {
              matches++;
            }
          }

          return _calculateRatio(matches, this.a.length + this.b.length);
        };

        SequenceMatcher.prototype.realQuickRatio = function() {
          /*
	          Return an upper bound on ratio() very quickly.
	      
	          This isn't defined beyond that it is an upper bound on .ratio(), and
	          is faster to compute than either .ratio() or .quickRatio().
	      */
          var la, lb, _ref;

          (_ref = [this.a.length, this.b.length]),
            (la = _ref[0]),
            (lb = _ref[1]);
          return _calculateRatio(min(la, lb), la + lb);
        };

        return SequenceMatcher;
      })();

      getCloseMatches = function(word, possibilities, n, cutoff) {
        var result, s, score, x, _i, _j, _len, _len1, _ref, _results;

        if (n == null) {
          n = 3;
        }

        if (cutoff == null) {
          cutoff = 0.6;
        }
        /*
	      Use SequenceMatcher to return list of the best "good enough" matches.
	    
	      word is a sequence for which close matches are desired (typically a
	      string).
	    
	      possibilities is a list of sequences against which to match word
	      (typically a list of strings).
	    
	      Optional arg n (default 3) is the maximum number of close matches to
	      return.  n must be > 0.
	    
	      Optional arg cutoff (default 0.6) is a float in [0, 1].  Possibilities
	      that don't score at least that similar to word are ignored.
	    
	      The best (no more than n) matches among the possibilities are returned
	      in a list, sorted by similarity score, most similar first.
	    
	      >>> getCloseMatches('appel', ['ape', 'apple', 'peach', 'puppy'])
	      ['apple', 'ape']
	      >>> KEYWORDS = require('coffee-script').RESERVED
	      >>> getCloseMatches('wheel', KEYWORDS)
	      ['when', 'while']
	      >>> getCloseMatches('accost', KEYWORDS)
	      ['const']
	    */

        if (!(n > 0)) {
          throw new Error('n must be > 0: (' + n + ')');
        }

        if (!(0.0 <= cutoff && cutoff <= 1.0)) {
          throw new Error('cutoff must be in [0.0, 1.0]: (' + cutoff + ')');
        }

        result = [];
        s = new SequenceMatcher();
        s.setSeq2(word);

        for (_i = 0, _len = possibilities.length; _i < _len; _i++) {
          x = possibilities[_i];
          s.setSeq1(x);

          if (
            s.realQuickRatio() >= cutoff &&
            s.quickRatio() >= cutoff &&
            s.ratio() >= cutoff
          ) {
            result.push([s.ratio(), x]);
          }
        }

        result = Heap.nlargest(result, n, _arrayCmp);
        _results = [];

        for (_j = 0, _len1 = result.length; _j < _len1; _j++) {
          (_ref = result[_j]), (score = _ref[0]), (x = _ref[1]);

          _results.push(x);
        }

        return _results;
      };

      _countLeading = function(line, ch) {
        /*
	      Return number of `ch` characters at the start of `line`.
	    
	      >>> _countLeading('   abc', ' ')
	      3
	    */
        var i, n, _ref;

        (_ref = [0, line.length]), (i = _ref[0]), (n = _ref[1]);

        while (i < n && line[i] === ch) {
          i++;
        }

        return i;
      };

      Differ = (function() {
        /*
	      Differ is a class for comparing sequences of lines of text, and
	      producing human-readable differences or deltas.  Differ uses
	      SequenceMatcher both to compare sequences of lines, and to compare
	      sequences of characters within similar (near-matching) lines.
	    
	      Each line of a Differ delta begins with a two-letter code:
	    
	          '- '    line unique to sequence 1
	          '+ '    line unique to sequence 2
	          '  '    line common to both sequences
	          '? '    line not present in either input sequence
	    
	      Lines beginning with '? ' attempt to guide the eye to intraline
	      differences, and were not present in either input sequence.  These lines
	      can be confusing if the sequences contain tab characters.
	    
	      Note that Differ makes no claim to produce a *minimal* diff.  To the
	      contrary, minimal diffs are often counter-intuitive, because they synch
	      up anywhere possible, sometimes accidental matches 100 pages apart.
	      Restricting synch points to contiguous matches preserves some notion of
	      locality, at the occasional cost of producing a longer diff.
	    
	      Example: Comparing two texts.
	    
	      >>> text1 = ['1. Beautiful is better than ugly.\n',
	      ...   '2. Explicit is better than implicit.\n',
	      ...   '3. Simple is better than complex.\n',
	      ...   '4. Complex is better than complicated.\n']
	      >>> text1.length
	      4
	      >>> text2 = ['1. Beautiful is better than ugly.\n',
	      ...   '3.   Simple is better than complex.\n',
	      ...   '4. Complicated is better than complex.\n',
	      ...   '5. Flat is better than nested.\n']
	    
	      Next we instantiate a Differ object:
	    
	      >>> d = new Differ()
	    
	      Note that when instantiating a Differ object we may pass functions to
	      filter out line and character 'junk'.
	    
	      Finally, we compare the two:
	    
	      >>> result = d.compare(text1, text2)
	      [ '  1. Beautiful is better than ugly.\n',
	        '- 2. Explicit is better than implicit.\n',
	        '- 3. Simple is better than complex.\n',
	        '+ 3.   Simple is better than complex.\n',
	        '?   ++\n',
	        '- 4. Complex is better than complicated.\n',
	        '?          ^                     ---- ^\n',
	        '+ 4. Complicated is better than complex.\n',
	        '?         ++++ ^                      ^\n',
	        '+ 5. Flat is better than nested.\n' ]
	    
	      Methods:
	    
	      constructor(linejunk=null, charjunk=null)
	          Construct a text differencer, with optional filters.
	      compare(a, b)
	          Compare two sequences of lines; generate the resulting delta.
	    */
        function Differ(linejunk, charjunk) {
          this.linejunk = linejunk;
          this.charjunk = charjunk;
          /*
	          Construct a text differencer, with optional filters.
	      
	          The two optional keyword parameters are for filter functions:
	      
	          - `linejunk`: A function that should accept a single string argument,
	            and return true iff the string is junk. The module-level function
	            `IS_LINE_JUNK` may be used to filter out lines without visible
	            characters, except for at most one splat ('#').  It is recommended
	            to leave linejunk null. 
	      
	          - `charjunk`: A function that should accept a string of length 1. The
	            module-level function `IS_CHARACTER_JUNK` may be used to filter out
	            whitespace characters (a blank or tab; **note**: bad idea to include
	            newline in this!).  Use of IS_CHARACTER_JUNK is recommended.
	      */
        }

        Differ.prototype.compare = function(a, b) {
          /*
	          Compare two sequences of lines; generate the resulting delta.
	      
	          Each sequence must contain individual single-line strings ending with
	          newlines. Such sequences can be obtained from the `readlines()` method
	          of file-like objects.  The delta generated also consists of newline-
	          terminated strings, ready to be printed as-is via the writeline()
	          method of a file-like object.
	      
	          Example:
	      
	          >>> d = new Differ
	          >>> d.compare(['one\n', 'two\n', 'three\n'],
	          ...           ['ore\n', 'tree\n', 'emu\n'])
	          [ '- one\n',
	            '?  ^\n',
	            '+ ore\n',
	            '?  ^\n',
	            '- two\n',
	            '- three\n',
	            '?  -\n',
	            '+ tree\n',
	            '+ emu\n' ]
	      */
          var ahi,
            alo,
            bhi,
            blo,
            cruncher,
            g,
            line,
            lines,
            tag,
            _i,
            _j,
            _len,
            _len1,
            _ref,
            _ref1;

          cruncher = new SequenceMatcher(this.linejunk, a, b);
          lines = [];
          _ref = cruncher.getOpcodes();

          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            (_ref1 = _ref[_i]),
              (tag = _ref1[0]),
              (alo = _ref1[1]),
              (ahi = _ref1[2]),
              (blo = _ref1[3]),
              (bhi = _ref1[4]);

            switch (tag) {
              case 'replace':
                g = this._fancyReplace(a, alo, ahi, b, blo, bhi);
                break;

              case 'delete':
                g = this._dump('-', a, alo, ahi);
                break;

              case 'insert':
                g = this._dump('+', b, blo, bhi);
                break;

              case 'equal':
                g = this._dump(' ', a, alo, ahi);
                break;

              default:
                throw new Error('unknow tag (' + tag + ')');
            }

            for (_j = 0, _len1 = g.length; _j < _len1; _j++) {
              line = g[_j];
              lines.push(line);
            }
          }

          return lines;
        };

        Differ.prototype._dump = function(tag, x, lo, hi) {
          /*
	          Generate comparison results for a same-tagged range.
	      */
          var i, _i, _results;

          _results = [];

          for (
            i = _i = lo;
            lo <= hi ? _i < hi : _i > hi;
            i = lo <= hi ? ++_i : --_i
          ) {
            _results.push('' + tag + ' ' + x[i]);
          }

          return _results;
        };

        Differ.prototype._plainReplace = function(a, alo, ahi, b, blo, bhi) {
          var first, g, line, lines, second, _i, _j, _len, _len1, _ref;

          if (bhi - blo < ahi - alo) {
            first = this._dump('+', b, blo, bhi);
            second = this._dump('-', a, alo, ahi);
          } else {
            first = this._dump('-', a, alo, ahi);
            second = this._dump('+', b, blo, bhi);
          }

          lines = [];
          _ref = [first, second];

          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            g = _ref[_i];

            for (_j = 0, _len1 = g.length; _j < _len1; _j++) {
              line = g[_j];
              lines.push(line);
            }
          }

          return lines;
        };

        Differ.prototype._fancyReplace = function(a, alo, ahi, b, blo, bhi) {
          /*
	          When replacing one block of lines with another, search the blocks
	          for *similar* lines; the best-matching pair (if any) is used as a
	          synch point, and intraline difference marking is done on the
	          similar pair. Lots of work, but often worth it.
	      
	          Example:
	          >>> d = new Differ
	          >>> d._fancyReplace(['abcDefghiJkl\n'], 0, 1,
	          ...                 ['abcdefGhijkl\n'], 0, 1)
	          [ '- abcDefghiJkl\n',
	            '?    ^  ^  ^\n',
	            '+ abcdefGhijkl\n',
	            '?    ^  ^  ^\n' ]
	      */
          var aelt,
            ai,
            ai1,
            ai2,
            atags,
            belt,
            bestRatio,
            besti,
            bestj,
            bj,
            bj1,
            bj2,
            btags,
            cruncher,
            cutoff,
            eqi,
            eqj,
            i,
            j,
            la,
            lb,
            line,
            lines,
            tag,
            _i,
            _j,
            _k,
            _l,
            _len,
            _len1,
            _len2,
            _len3,
            _len4,
            _m,
            _n,
            _o,
            _ref,
            _ref1,
            _ref10,
            _ref11,
            _ref12,
            _ref2,
            _ref3,
            _ref4,
            _ref5,
            _ref6,
            _ref7,
            _ref8,
            _ref9;

          (_ref = [0.74, 0.75]), (bestRatio = _ref[0]), (cutoff = _ref[1]);
          cruncher = new SequenceMatcher(this.charjunk);
          (_ref1 = [null, null]), (eqi = _ref1[0]), (eqj = _ref1[1]);
          lines = [];

          for (
            j = _i = blo;
            blo <= bhi ? _i < bhi : _i > bhi;
            j = blo <= bhi ? ++_i : --_i
          ) {
            bj = b[j];
            cruncher.setSeq2(bj);

            for (
              i = _j = alo;
              alo <= ahi ? _j < ahi : _j > ahi;
              i = alo <= ahi ? ++_j : --_j
            ) {
              ai = a[i];

              if (ai === bj) {
                if (eqi === null) {
                  (_ref2 = [i, j]), (eqi = _ref2[0]), (eqj = _ref2[1]);
                }

                continue;
              }

              cruncher.setSeq1(ai);

              if (
                cruncher.realQuickRatio() > bestRatio &&
                cruncher.quickRatio() > bestRatio &&
                cruncher.ratio() > bestRatio
              ) {
                (_ref3 = [cruncher.ratio(), i, j]),
                  (bestRatio = _ref3[0]),
                  (besti = _ref3[1]),
                  (bestj = _ref3[2]);
              }
            }
          }

          if (bestRatio < cutoff) {
            if (eqi === null) {
              _ref4 = this._plainReplace(a, alo, ahi, b, blo, bhi);

              for (_k = 0, _len = _ref4.length; _k < _len; _k++) {
                line = _ref4[_k];
                lines.push(line);
              }

              return lines;
            }

            (_ref5 = [eqi, eqj, 1.0]),
              (besti = _ref5[0]),
              (bestj = _ref5[1]),
              (bestRatio = _ref5[2]);
          } else {
            eqi = null;
          }

          _ref6 = this._fancyHelper(a, alo, besti, b, blo, bestj);

          for (_l = 0, _len1 = _ref6.length; _l < _len1; _l++) {
            line = _ref6[_l];
            lines.push(line);
          }

          (_ref7 = [a[besti], b[bestj]]), (aelt = _ref7[0]), (belt = _ref7[1]);

          if (eqi === null) {
            atags = btags = '';
            cruncher.setSeqs(aelt, belt);
            _ref8 = cruncher.getOpcodes();

            for (_m = 0, _len2 = _ref8.length; _m < _len2; _m++) {
              (_ref9 = _ref8[_m]),
                (tag = _ref9[0]),
                (ai1 = _ref9[1]),
                (ai2 = _ref9[2]),
                (bj1 = _ref9[3]),
                (bj2 = _ref9[4]);
              (_ref10 = [ai2 - ai1, bj2 - bj1]),
                (la = _ref10[0]),
                (lb = _ref10[1]);

              switch (tag) {
                case 'replace':
                  atags += Array(la + 1).join('^');
                  btags += Array(lb + 1).join('^');
                  break;

                case 'delete':
                  atags += Array(la + 1).join('-');
                  break;

                case 'insert':
                  btags += Array(lb + 1).join('+');
                  break;

                case 'equal':
                  atags += Array(la + 1).join(' ');
                  btags += Array(lb + 1).join(' ');
                  break;

                default:
                  throw new Error('unknow tag (' + tag + ')');
              }
            }

            _ref11 = this._qformat(aelt, belt, atags, btags);

            for (_n = 0, _len3 = _ref11.length; _n < _len3; _n++) {
              line = _ref11[_n];
              lines.push(line);
            }
          } else {
            lines.push('  ' + aelt);
          }

          _ref12 = this._fancyHelper(a, besti + 1, ahi, b, bestj + 1, bhi);

          for (_o = 0, _len4 = _ref12.length; _o < _len4; _o++) {
            line = _ref12[_o];
            lines.push(line);
          }

          return lines;
        };

        Differ.prototype._fancyHelper = function(a, alo, ahi, b, blo, bhi) {
          var g;
          g = [];

          if (alo < ahi) {
            if (blo < bhi) {
              g = this._fancyReplace(a, alo, ahi, b, blo, bhi);
            } else {
              g = this._dump('-', a, alo, ahi);
            }
          } else if (blo < bhi) {
            g = this._dump('+', b, blo, bhi);
          }

          return g;
        };

        Differ.prototype._qformat = function(aline, bline, atags, btags) {
          /*
	          Format "?" output and deal with leading tabs.
	      
	          Example:
	      
	          >>> d = new Differ
	          >>> d._qformat('\tabcDefghiJkl\n', '\tabcdefGhijkl\n',
	          [ '- \tabcDefghiJkl\n',
	            '? \t ^ ^  ^\n',
	            '+ \tabcdefGhijkl\n',
	            '? \t ^ ^  ^\n' ]
	      */
          var common, lines;
          lines = [];
          common = min(_countLeading(aline, '\t'), _countLeading(bline, '\t'));
          common = min(common, _countLeading(atags.slice(0, common), ' '));
          common = min(common, _countLeading(btags.slice(0, common), ' '));
          atags = atags.slice(common).replace(/\s+$/, '');
          btags = btags.slice(common).replace(/\s+$/, '');
          lines.push('- ' + aline);

          if (atags.length) {
            lines.push('? ' + Array(common + 1).join('\t') + atags + '\n');
          }

          lines.push('+ ' + bline);

          if (btags.length) {
            lines.push('? ' + Array(common + 1).join('\t') + btags + '\n');
          }

          return lines;
        };

        return Differ;
      })();

      IS_LINE_JUNK = function(line, pat) {
        if (pat == null) {
          pat = /^\s*#?\s*$/;
        }
        /*
	      Return 1 for ignorable line: iff `line` is blank or contains a single '#'.
	        
	      Examples:
	    
	      >>> IS_LINE_JUNK('\n')
	      true
	      >>> IS_LINE_JUNK('  #   \n')
	      true
	      >>> IS_LINE_JUNK('hello\n')
	      false
	    */

        return pat.test(line);
      };

      IS_CHARACTER_JUNK = function(ch, ws) {
        if (ws == null) {
          ws = ' \t';
        }
        /*
	      Return 1 for ignorable character: iff `ch` is a space or tab.
	    
	      Examples:
	      >>> IS_CHARACTER_JUNK(' ').should.be.true
	      true
	      >>> IS_CHARACTER_JUNK('\t').should.be.true
	      true
	      >>> IS_CHARACTER_JUNK('\n').should.be.false
	      false
	      >>> IS_CHARACTER_JUNK('x').should.be.false
	      false
	    */

        return __indexOf.call(ws, ch) >= 0;
      };

      _formatRangeUnified = function(start, stop) {
        /*
	      Convert range to the "ed" format'
	    */
        var beginning, length;
        beginning = start + 1;
        length = stop - start;

        if (length === 1) {
          return '' + beginning;
        }

        if (!length) {
          beginning--;
        }

        return '' + beginning + ',' + length;
      };

      unifiedDiff = function(a, b, _arg) {
        var file1Range,
          file2Range,
          first,
          fromdate,
          fromfile,
          fromfiledate,
          group,
          i1,
          i2,
          j1,
          j2,
          last,
          line,
          lines,
          lineterm,
          n,
          started,
          tag,
          todate,
          tofile,
          tofiledate,
          _i,
          _j,
          _k,
          _l,
          _len,
          _len1,
          _len2,
          _len3,
          _len4,
          _m,
          _ref,
          _ref1,
          _ref2,
          _ref3,
          _ref4,
          _ref5,
          _ref6;

        (_ref = _arg != null ? _arg : {}),
          (fromfile = _ref.fromfile),
          (tofile = _ref.tofile),
          (fromfiledate = _ref.fromfiledate),
          (tofiledate = _ref.tofiledate),
          (n = _ref.n),
          (lineterm = _ref.lineterm);
        /*
	      Compare two sequences of lines; generate the delta as a unified diff.
	    
	      Unified diffs are a compact way of showing line changes and a few
	      lines of context.  The number of context lines is set by 'n' which
	      defaults to three.
	    
	      By default, the diff control lines (those with ---, +++, or @@) are
	      created with a trailing newline.  
	    
	      For inputs that do not have trailing newlines, set the lineterm
	      argument to "" so that the output will be uniformly newline free.
	    
	      The unidiff format normally has a header for filenames and modification
	      times.  Any or all of these may be specified using strings for
	      'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
	      The modification times are normally expressed in the ISO 8601 format.
	    
	      Example:
	    
	      >>> unifiedDiff('one two three four'.split(' '),
	      ...             'zero one tree four'.split(' '), {
	      ...               fromfile: 'Original'
	      ...               tofile: 'Current',
	      ...               fromfiledate: '2005-01-26 23:30:50',
	      ...               tofiledate: '2010-04-02 10:20:52',
	      ...               lineterm: ''
	      ...             })
	      [ '--- Original\t2005-01-26 23:30:50',
	        '+++ Current\t2010-04-02 10:20:52',
	        '@@ -1,4 +1,4 @@',
	        '+zero',
	        ' one',
	        '-two',
	        '-three',
	        '+tree',
	        ' four' ]
	    */

        if (fromfile == null) {
          fromfile = '';
        }

        if (tofile == null) {
          tofile = '';
        }

        if (fromfiledate == null) {
          fromfiledate = '';
        }

        if (tofiledate == null) {
          tofiledate = '';
        }

        if (n == null) {
          n = 3;
        }

        if (lineterm == null) {
          lineterm = '\n';
        }

        lines = [];
        started = false;
        _ref1 = new SequenceMatcher(null, a, b).getGroupedOpcodes();

        for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
          group = _ref1[_i];

          if (!started) {
            started = true;
            fromdate = fromfiledate ? '\t' + fromfiledate : '';
            todate = tofiledate ? '\t' + tofiledate : '';
            lines.push('--- ' + fromfile + fromdate + lineterm);
            lines.push('+++ ' + tofile + todate + lineterm);
          }

          (_ref2 = [group[0], group[group.length - 1]]),
            (first = _ref2[0]),
            (last = _ref2[1]);
          file1Range = _formatRangeUnified(first[1], last[2]);
          file2Range = _formatRangeUnified(first[3], last[4]);
          lines.push(
            '@@ -' + file1Range + ' +' + file2Range + ' @@' + lineterm
          );

          for (_j = 0, _len1 = group.length; _j < _len1; _j++) {
            (_ref3 = group[_j]),
              (tag = _ref3[0]),
              (i1 = _ref3[1]),
              (i2 = _ref3[2]),
              (j1 = _ref3[3]),
              (j2 = _ref3[4]);

            if (tag === 'equal') {
              _ref4 = a.slice(i1, i2);

              for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) {
                line = _ref4[_k];
                lines.push(' ' + line);
              }

              continue;
            }

            if (tag === 'replace' || tag === 'delete') {
              _ref5 = a.slice(i1, i2);

              for (_l = 0, _len3 = _ref5.length; _l < _len3; _l++) {
                line = _ref5[_l];
                lines.push('-' + line);
              }
            }

            if (tag === 'replace' || tag === 'insert') {
              _ref6 = b.slice(j1, j2);

              for (_m = 0, _len4 = _ref6.length; _m < _len4; _m++) {
                line = _ref6[_m];
                lines.push('+' + line);
              }
            }
          }
        }

        return lines;
      };

      _formatRangeContext = function(start, stop) {
        /*
	      Convert range to the "ed" format'
	    */
        var beginning, length;
        beginning = start + 1;
        length = stop - start;

        if (!length) {
          beginning--;
        }

        if (length <= 1) {
          return '' + beginning;
        }

        return '' + beginning + ',' + (beginning + length - 1);
      };

      contextDiff = function(a, b, _arg) {
        var file1Range,
          file2Range,
          first,
          fromdate,
          fromfile,
          fromfiledate,
          group,
          i1,
          i2,
          j1,
          j2,
          last,
          line,
          lines,
          lineterm,
          n,
          prefix,
          started,
          tag,
          todate,
          tofile,
          tofiledate,
          _,
          _i,
          _j,
          _k,
          _l,
          _len,
          _len1,
          _len2,
          _len3,
          _len4,
          _m,
          _ref,
          _ref1,
          _ref2,
          _ref3,
          _ref4,
          _ref5,
          _ref6;

        (_ref = _arg != null ? _arg : {}),
          (fromfile = _ref.fromfile),
          (tofile = _ref.tofile),
          (fromfiledate = _ref.fromfiledate),
          (tofiledate = _ref.tofiledate),
          (n = _ref.n),
          (lineterm = _ref.lineterm);
        /*
	      Compare two sequences of lines; generate the delta as a context diff.
	    
	      Context diffs are a compact way of showing line changes and a few
	      lines of context.  The number of context lines is set by 'n' which
	      defaults to three.
	    
	      By default, the diff control lines (those with *** or ---) are
	      created with a trailing newline.  This is helpful so that inputs
	      created from file.readlines() result in diffs that are suitable for
	      file.writelines() since both the inputs and outputs have trailing
	      newlines.
	    
	      For inputs that do not have trailing newlines, set the lineterm
	      argument to "" so that the output will be uniformly newline free.
	    
	      The context diff format normally has a header for filenames and
	      modification times.  Any or all of these may be specified using
	      strings for 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
	      The modification times are normally expressed in the ISO 8601 format.
	      If not specified, the strings default to blanks.
	    
	      Example:
	      >>> a = ['one\n', 'two\n', 'three\n', 'four\n']
	      >>> b = ['zero\n', 'one\n', 'tree\n', 'four\n']
	      >>> contextDiff(a, b, {fromfile: 'Original', tofile: 'Current'})
	      [ '*** Original\n',
	        '--- Current\n',
	        '***************\n',
	        '*** 1,4 ****\n',
	        '  one\n',
	        '! two\n',
	        '! three\n',
	        '  four\n',
	        '--- 1,4 ----\n',
	        '+ zero\n',
	        '  one\n',
	        '! tree\n',
	        '  four\n' ]
	    */

        if (fromfile == null) {
          fromfile = '';
        }

        if (tofile == null) {
          tofile = '';
        }

        if (fromfiledate == null) {
          fromfiledate = '';
        }

        if (tofiledate == null) {
          tofiledate = '';
        }

        if (n == null) {
          n = 3;
        }

        if (lineterm == null) {
          lineterm = '\n';
        }

        prefix = {
          insert: '+ ',
          delete: '- ',
          replace: '! ',
          equal: '  ',
        };
        started = false;
        lines = [];
        _ref1 = new SequenceMatcher(null, a, b).getGroupedOpcodes();

        for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
          group = _ref1[_i];

          if (!started) {
            started = true;
            fromdate = fromfiledate ? '\t' + fromfiledate : '';
            todate = tofiledate ? '\t' + tofiledate : '';
            lines.push('*** ' + fromfile + fromdate + lineterm);
            lines.push('--- ' + tofile + todate + lineterm);
            (_ref2 = [group[0], group[group.length - 1]]),
              (first = _ref2[0]),
              (last = _ref2[1]);
            lines.push('***************' + lineterm);
            file1Range = _formatRangeContext(first[1], last[2]);
            lines.push('*** ' + file1Range + ' ****' + lineterm);

            if (
              _any(
                (function() {
                  var _j, _len1, _ref3, _results;

                  _results = [];

                  for (_j = 0, _len1 = group.length; _j < _len1; _j++) {
                    (_ref3 = group[_j]),
                      (tag = _ref3[0]),
                      (_ = _ref3[1]),
                      (_ = _ref3[2]),
                      (_ = _ref3[3]),
                      (_ = _ref3[4]);

                    _results.push(tag === 'replace' || tag === 'delete');
                  }

                  return _results;
                })()
              )
            ) {
              for (_j = 0, _len1 = group.length; _j < _len1; _j++) {
                (_ref3 = group[_j]),
                  (tag = _ref3[0]),
                  (i1 = _ref3[1]),
                  (i2 = _ref3[2]),
                  (_ = _ref3[3]),
                  (_ = _ref3[4]);

                if (tag !== 'insert') {
                  _ref4 = a.slice(i1, i2);

                  for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) {
                    line = _ref4[_k];
                    lines.push(prefix[tag] + line);
                  }
                }
              }
            }

            file2Range = _formatRangeContext(first[3], last[4]);
            lines.push('--- ' + file2Range + ' ----' + lineterm);

            if (
              _any(
                (function() {
                  var _l, _len3, _ref5, _results;

                  _results = [];

                  for (_l = 0, _len3 = group.length; _l < _len3; _l++) {
                    (_ref5 = group[_l]),
                      (tag = _ref5[0]),
                      (_ = _ref5[1]),
                      (_ = _ref5[2]),
                      (_ = _ref5[3]),
                      (_ = _ref5[4]);

                    _results.push(tag === 'replace' || tag === 'insert');
                  }

                  return _results;
                })()
              )
            ) {
              for (_l = 0, _len3 = group.length; _l < _len3; _l++) {
                (_ref5 = group[_l]),
                  (tag = _ref5[0]),
                  (_ = _ref5[1]),
                  (_ = _ref5[2]),
                  (j1 = _ref5[3]),
                  (j2 = _ref5[4]);

                if (tag !== 'delete') {
                  _ref6 = b.slice(j1, j2);

                  for (_m = 0, _len4 = _ref6.length; _m < _len4; _m++) {
                    line = _ref6[_m];
                    lines.push(prefix[tag] + line);
                  }
                }
              }
            }
          }
        }

        return lines;
      };

      ndiff = function(a, b, linejunk, charjunk) {
        if (charjunk == null) {
          charjunk = IS_CHARACTER_JUNK;
        }
        /*
	      Compare `a` and `b` (lists of strings); return a `Differ`-style delta.
	    
	      Optional keyword parameters `linejunk` and `charjunk` are for filter
	      functions (or None):
	    
	      - linejunk: A function that should accept a single string argument, and
	        return true iff the string is junk.  The default is null, and is
	        recommended; 
	    
	      - charjunk: A function that should accept a string of length 1. The
	        default is module-level function IS_CHARACTER_JUNK, which filters out
	        whitespace characters (a blank or tab; note: bad idea to include newline
	        in this!).
	    
	      Example:
	      >>> a = ['one\n', 'two\n', 'three\n']
	      >>> b = ['ore\n', 'tree\n', 'emu\n']
	      >>> ndiff(a, b)
	      [ '- one\n',
	        '?  ^\n',
	        '+ ore\n',
	        '?  ^\n',
	        '- two\n',
	        '- three\n',
	        '?  -\n',
	        '+ tree\n',
	        '+ emu\n' ]
	    */

        return new Differ(linejunk, charjunk).compare(a, b);
      };

      restore = function(delta, which) {
        /*
	      Generate one of the two sequences that generated a delta.
	    
	      Given a `delta` produced by `Differ.compare()` or `ndiff()`, extract
	      lines originating from file 1 or 2 (parameter `which`), stripping off line
	      prefixes.
	    
	      Examples:
	      >>> a = ['one\n', 'two\n', 'three\n']
	      >>> b = ['ore\n', 'tree\n', 'emu\n']
	      >>> diff = ndiff(a, b)
	      >>> restore(diff, 1)
	      [ 'one\n',
	        'two\n',
	        'three\n' ]
	      >>> restore(diff, 2)
	      [ 'ore\n',
	        'tree\n',
	        'emu\n' ]
	    */
        var line, lines, prefixes, tag, _i, _len, _ref;

        tag = {
          1: '- ',
          2: '+ ',
        }[which];

        if (!tag) {
          throw new Error('unknow delta choice (must be 1 or 2): ' + which);
        }

        prefixes = ['  ', tag];
        lines = [];

        for (_i = 0, _len = delta.length; _i < _len; _i++) {
          line = delta[_i];

          if (
            ((_ref = line.slice(0, 2)), __indexOf.call(prefixes, _ref) >= 0)
          ) {
            lines.push(line.slice(2));
          }
        }

        return lines;
      };

      exports._arrayCmp = _arrayCmp;
      exports.SequenceMatcher = SequenceMatcher;
      exports.getCloseMatches = getCloseMatches;
      exports._countLeading = _countLeading;
      exports.Differ = Differ;
      exports.IS_LINE_JUNK = IS_LINE_JUNK;
      exports.IS_CHARACTER_JUNK = IS_CHARACTER_JUNK;
      exports._formatRangeUnified = _formatRangeUnified;
      exports.unifiedDiff = unifiedDiff;
      exports._formatRangeContext = _formatRangeContext;
      exports.contextDiff = contextDiff;
      exports.ndiff = ndiff;
      exports.restore = restore;
    }.call(this));
  });
  var difflib_1 = difflib._arrayCmp;
  var difflib_2 = difflib.SequenceMatcher;
  var difflib_3 = difflib.getCloseMatches;
  var difflib_4 = difflib._countLeading;
  var difflib_5 = difflib.Differ;
  var difflib_6 = difflib.IS_LINE_JUNK;
  var difflib_7 = difflib.IS_CHARACTER_JUNK;
  var difflib_8 = difflib._formatRangeUnified;
  var difflib_9 = difflib.unifiedDiff;
  var difflib_10 = difflib._formatRangeContext;
  var difflib_11 = difflib.contextDiff;
  var difflib_12 = difflib.ndiff;
  var difflib_13 = difflib.restore;

  var difflib$1 = difflib;

  function scoreSimilarity(score, articleUrl, href) {
    // Do this last and only if we have a real candidate, because it's
    // potentially expensive computationally. Compare the link to this
    // URL using difflib to get the % similarity of these URLs. On a
    // sliding scale, subtract points from this link based on
    // similarity.
    if (score > 0) {
      var similarity = new difflib$1.SequenceMatcher(
        null,
        articleUrl,
        href
      ).ratio(); // Subtract .1 from diff_percent when calculating modifier,
      // which means that if it's less than 10% different, we give a
      // bonus instead. Ex:
      //  3% different = +17.5 points
      // 10% different = 0 points
      // 20% different = -25 points

      var diffPercent = 1.0 - similarity;
      var diffModifier = -(250 * (diffPercent - 0.2));
      return score + diffModifier;
    }

    return 0;
  }

  function scoreLinkText(linkText, pageNum) {
    // If the link text can be parsed as a number, give it a minor
    // bonus, with a slight bias towards lower numbered pages. This is
    // so that pages that might not have 'next' in their text can still
    // get scored, and sorted properly by score.
    var score = 0;

    if (IS_DIGIT_RE.test(linkText.trim())) {
      var linkTextAsNum = _parseInt$2(linkText, 10); // If it's the first page, we already got it on the first call.
      // Give it a negative score. Otherwise, up to page 10, give a
      // small bonus.

      if (linkTextAsNum < 2) {
        score = -30;
      } else {
        score = Math.max(0, 10 - linkTextAsNum);
      } // If it appears that the current page number is greater than
      // this links page number, it's a very bad sign. Give it a big
      // penalty.

      if (pageNum && pageNum >= linkTextAsNum) {
        score -= 50;
      }
    }

    return score;
  }

  function scorePageInLink(pageNum, isWp) {
    // page in the link = bonus. Intentionally ignore wordpress because
    // their ?p=123 link style gets caught by this even though it means
    // separate documents entirely.
    if (pageNum && !isWp) {
      return 50;
    }

    return 0;
  }

  var DIGIT_RE$2 = /\d/; // A list of words that, if found in link text or URLs, likely mean that
  // this link is not a next page link.

  var EXTRANEOUS_LINK_HINTS$1 = [
    'print',
    'archive',
    'comment',
    'discuss',
    'e-mail',
    'email',
    'share',
    'reply',
    'all',
    'login',
    'sign',
    'single',
    'adx',
    'entry-unrelated',
  ];
  var EXTRANEOUS_LINK_HINTS_RE$1 = new RegExp(
    EXTRANEOUS_LINK_HINTS$1.join('|'),
    'i'
  ); // Match any link text/classname/id that looks like it could mean the next
  // page. Things like: next, continue, >, >>, » but not >|, »| as those can
  // mean last page.

  var NEXT_LINK_TEXT_RE$1 = new RegExp(
    '(next|weiter|continue|>([^|]|$)|»([^|]|$))',
    'i'
  ); // Match any link text/classname/id that looks like it is an end link: things
  // like "first", "last", "end", etc.

  var CAP_LINK_TEXT_RE$1 = new RegExp('(first|last|end)', 'i'); // Match any link text/classname/id that looks like it means the previous
  // page.

  var PREV_LINK_TEXT_RE$1 = new RegExp('(prev|earl|old|new|<|«)', 'i'); // Match any phrase that looks like it could be page, or paging, or pagination

  function scoreExtraneousLinks(href) {
    // If the URL itself contains extraneous values, give a penalty.
    if (EXTRANEOUS_LINK_HINTS_RE$1.test(href)) {
      return -25;
    }

    return 0;
  }

  function makeSig($link) {
    return ''
      .concat($link.attr('class') || '', ' ')
      .concat($link.attr('id') || '');
  }

  function scoreByParents$1($link) {
    // If a parent node contains paging-like classname or id, give a
    // bonus. Additionally, if a parent_node contains bad content
    // (like 'sponsor'), give a penalty.
    var $parent = $link.parent();
    var positiveMatch = false;
    var negativeMatch = false;
    var score = 0;

    from_1$1(range(0, 4)).forEach(function() {
      if ($parent.length === 0) {
        return;
      }

      var parentData = makeSig($parent, ' '); // If we have 'page' or 'paging' in our data, that's a good
      // sign. Add a bonus.

      if (!positiveMatch && PAGE_RE.test(parentData)) {
        positiveMatch = true;
        score += 25;
      } // If we have 'comment' or something in our data, and
      // we don't have something like 'content' as well, that's
      // a bad sign. Give a penalty.

      if (
        !negativeMatch &&
        NEGATIVE_SCORE_RE.test(parentData) &&
        EXTRANEOUS_LINK_HINTS_RE$1.test(parentData)
      ) {
        if (!POSITIVE_SCORE_RE.test(parentData)) {
          negativeMatch = true;
          score -= 25;
        }
      }

      $parent = $parent.parent();
    });

    return score;
  }

  function scorePrevLink(linkData) {
    // If the link has something like "previous", its definitely
    // an old link, skip it.
    if (PREV_LINK_TEXT_RE$1.test(linkData)) {
      return -200;
    }

    return 0;
  }

  function shouldScore(
    href,
    articleUrl,
    baseUrl,
    parsedUrl,
    linkText,
    previousUrls
  ) {
    // skip if we've already fetched this url
    if (
      previousUrls.find(function(url$$1) {
        return href === url$$1;
      }) !== undefined
    ) {
      return false;
    } // If we've already parsed this URL, or the URL matches the base
    // URL, or is empty, skip it.

    if (!href || href === articleUrl || href === baseUrl) {
      return false;
    }

    var hostname = parsedUrl.hostname;

    var _URL$parse = url.parse(href),
      linkHost = _URL$parse.hostname; // Domain mismatch.

    if (linkHost !== hostname) {
      return false;
    } // If href doesn't contain a digit after removing the base URL,
    // it's certainly not the next page.

    var fragment = href.replace(baseUrl, '');

    if (!DIGIT_RE$2.test(fragment)) {
      return false;
    } // This link has extraneous content (like "comment") in its link
    // text, so we skip it.

    if (EXTRANEOUS_LINK_HINTS_RE$1.test(linkText)) {
      return false;
    } // Next page link text is never long, skip if it is too long.

    if (linkText.length > 25) {
      return false;
    }

    return true;
  }

  function scoreBaseUrl(href, baseRegex) {
    // If the baseUrl isn't part of this URL, penalize this
    // link. It could still be the link, but the odds are lower.
    // Example:
    // http://www.actionscript.org/resources/articles/745/1/JavaScript-and-VBScript-Injection-in-ActionScript-3/Page1.html
    if (!baseRegex.test(href)) {
      return -25;
    }

    return 0;
  }

  function scoreNextLinkText(linkData) {
    // Things like "next", ">>", etc.
    if (NEXT_LINK_TEXT_RE$1.test(linkData)) {
      return 50;
    }

    return 0;
  }

  function scoreCapLinks(linkData) {
    // Cap links are links like "last", etc.
    if (CAP_LINK_TEXT_RE$1.test(linkData)) {
      // If we found a link like "last", but we've already seen that
      // this link is also "next", it's fine. If it's not been
      // previously marked as "next", then it's probably bad.
      // Penalize.
      if (NEXT_LINK_TEXT_RE$1.test(linkData)) {
        return -65;
      }
    }

    return 0;
  }

  function makeBaseRegex(baseUrl) {
    return new RegExp('^'.concat(baseUrl), 'i');
  }

  function makeSig$1($link, linkText) {
    return ''
      .concat(linkText || $link.text(), ' ')
      .concat($link.attr('class') || '', ' ')
      .concat($link.attr('id') || '');
  }

  function scoreLinks(_ref) {
    var links = _ref.links,
      articleUrl = _ref.articleUrl,
      baseUrl = _ref.baseUrl,
      parsedUrl = _ref.parsedUrl,
      $ = _ref.$,
      _ref$previousUrls = _ref.previousUrls,
      previousUrls = _ref$previousUrls === void 0 ? [] : _ref$previousUrls;
    parsedUrl = parsedUrl || url.parse(articleUrl);
    var baseRegex = makeBaseRegex(baseUrl);
    var isWp = isWordpress($); // Loop through all links, looking for hints that they may be next-page
    // links. Things like having "page" in their textContent, className or
    // id, or being a child of a node with a page-y className or id.
    //
    // After we do that, assign each page a score, and pick the one that
    // looks most like the next page link, as long as its score is strong
    // enough to have decent confidence.

    var scoredPages = links.reduce(function(possiblePages, link) {
      // Remove any anchor data since we don't do a good job
      // standardizing URLs (it's hard), we're going to do
      // some checking with and without a trailing slash
      var attrs = getAttrs(link); // if href is undefined, return

      if (!attrs.href) return possiblePages;
      var href = removeAnchor(attrs.href);
      var $link = $(link);
      var linkText = $link.text();

      if (
        !shouldScore(
          href,
          articleUrl,
          baseUrl,
          parsedUrl,
          linkText,
          previousUrls
        )
      ) {
        return possiblePages;
      } // ## PASSED THE FIRST-PASS TESTS. Start scoring. ##

      if (!possiblePages[href]) {
        possiblePages[href] = {
          score: 0,
          linkText: linkText,
          href: href,
        };
      } else {
        possiblePages[href].linkText = ''
          .concat(possiblePages[href].linkText, '|')
          .concat(linkText);
      }

      var possiblePage = possiblePages[href];
      var linkData = makeSig$1($link, linkText);
      var pageNum = pageNumFromUrl(href);
      var score = scoreBaseUrl(href, baseRegex);
      score += scoreNextLinkText(linkData);
      score += scoreCapLinks(linkData);
      score += scorePrevLink(linkData);
      score += scoreByParents$1($link);
      score += scoreExtraneousLinks(href);
      score += scorePageInLink(pageNum, isWp);
      score += scoreLinkText(linkText, pageNum);
      score += scoreSimilarity(score, articleUrl, href);
      possiblePage.score = score;
      return possiblePages;
    }, {});
    return ownKeys$1(scoredPages).length === 0 ? null : scoredPages;
  }

  // for multi-page articles

  var GenericNextPageUrlExtractor = {
    extract: function extract(_ref) {
      var $ = _ref.$,
        url$$1 = _ref.url,
        parsedUrl = _ref.parsedUrl,
        _ref$previousUrls = _ref.previousUrls,
        previousUrls = _ref$previousUrls === void 0 ? [] : _ref$previousUrls;
      parsedUrl = parsedUrl || url.parse(url$$1);
      var articleUrl = removeAnchor(url$$1);
      var baseUrl = articleBaseUrl(url$$1, parsedUrl);
      var links = $('a[href]').toArray();
      var scoredLinks = scoreLinks({
        links: links,
        articleUrl: articleUrl,
        baseUrl: baseUrl,
        parsedUrl: parsedUrl,
        $: $,
        previousUrls: previousUrls,
      }); // If no links were scored, return null

      if (!scoredLinks) return null; // now that we've scored all possible pages,
      // find the biggest one.

      var topPage = ownKeys$1(scoredLinks).reduce(
        function(acc, link) {
          var scoredLink = scoredLinks[link];
          return scoredLink.score > acc.score ? scoredLink : acc;
        },
        {
          score: -100,
        }
      ); // If the score is less than 50, we're not confident enough to use it,
      // so we fail.

      if (topPage.score >= 50) {
        return topPage.href;
      }

      return null;
    },
  };

  var CANONICAL_META_SELECTORS = ['og:url'];

  function parseDomain(url$$1) {
    var parsedUrl = url.parse(url$$1);
    var hostname = parsedUrl.hostname;
    return hostname;
  }

  function result(url$$1) {
    return {
      url: url$$1,
      domain: parseDomain(url$$1),
    };
  }

  var GenericUrlExtractor = {
    extract: function extract(_ref) {
      var $ = _ref.$,
        url$$1 = _ref.url,
        metaCache = _ref.metaCache;
      var $canonical = $('link[rel=canonical]');

      if ($canonical.length !== 0) {
        var href = $canonical.attr('href');

        if (href) {
          return result(href);
        }
      }

      var metaUrl = extractFromMeta$$1($, CANONICAL_META_SELECTORS, metaCache);

      if (metaUrl) {
        return result(metaUrl);
      }

      return result(url$$1);
    },
  };

  var defaults = {
    ellipse: '…',
    chars: [' ', '-'],
    max: 140,
    truncate: true,
  };

  function ellipsize(str, max, ellipse, chars, truncate) {
    if (str.length < max) return str;
    var last = 0,
      c = '',
      midMax = Math.floor(max / 2),
      computedMax = truncate === 'middle' ? midMax : max;

    for (var i = 0, len = str.length; i < len; i++) {
      c = str.charAt(i);

      if (chars.indexOf(c) !== -1 && truncate !== 'middle') {
        last = i;
      }

      if (i < computedMax) continue;

      if (last === 0) {
        return !truncate
          ? ''
          : str.substring(0, computedMax - 1) +
              ellipse +
              (truncate === 'middle'
                ? str.substring(str.length - midMax, str.length)
                : '');
      }

      return str.substring(0, last) + ellipse;
    }

    return str;
  }

  var ellipsize_1 = function(str, max, opts) {
    if (typeof str !== 'string' || str.length === 0) return '';
    if (max === 0) return '';
    opts = opts || {};

    for (var key in defaults) {
      if (opts[key] === null || typeof opts[key] === 'undefined') {
        opts[key] = defaults[key];
      }
    }

    opts.max = max || opts.max;
    return ellipsize(str, opts.max, opts.ellipse, opts.chars, opts.truncate);
  };

  var EXCERPT_META_SELECTORS = ['og:description', 'twitter:description'];

  function clean$2(content, $) {
    var maxLength =
      arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 200;
    content = content.replace(/[\s\n]+/g, ' ').trim();
    return ellipsize_1(content, maxLength, {
      ellipse: '&hellip;',
    });
  }
  var GenericExcerptExtractor = {
    extract: function extract(_ref) {
      var $ = _ref.$,
        content = _ref.content,
        metaCache = _ref.metaCache;
      var excerpt = extractFromMeta$$1($, EXCERPT_META_SELECTORS, metaCache);

      if (excerpt) {
        return clean$2(stripTags(excerpt, $));
      } // Fall back to excerpting from the extracted content

      var maxLength = 200;
      var shortContent = content.slice(0, maxLength * 5);
      return clean$2($(shortContent).text(), $, maxLength);
    },
  };

  var GenericWordCountExtractor = {
    extract: function extract(_ref) {
      var content = _ref.content;
      var $$$1 = $.load(content);
      var $content = $$$1('div').first();
      var text = normalizeSpaces($content.text());
      return text.split(/\s/).length;
    },
  };

  var GenericExtractor = {
    // This extractor is the default for all domains
    domain: '*',
    title: GenericTitleExtractor.extract,
    date_published: GenericDatePublishedExtractor.extract,
    author: GenericAuthorExtractor.extract,
    content: GenericContentExtractor.extract.bind(GenericContentExtractor),
    lead_image_url: GenericLeadImageUrlExtractor.extract,
    dek: GenericDekExtractor.extract,
    next_page_url: GenericNextPageUrlExtractor.extract,
    url_and_domain: GenericUrlExtractor.extract,
    excerpt: GenericExcerptExtractor.extract,
    word_count: GenericWordCountExtractor.extract,
    direction: function direction(_ref) {
      var title = _ref.title;
      return stringDirection.getDirection(title);
    },
    extract: function extract(options) {
      var html = options.html,
        $$$1 = options.$;

      if (html && !$$$1) {
        var loaded = $.load(html);
        options.$ = loaded;
      }

      var title = this.title(options);
      var date_published = this.date_published(options);
      var author = this.author(options);
      var content = this.content(
        objectSpread({}, options, {
          title: title,
        })
      );
      var lead_image_url = this.lead_image_url(
        objectSpread({}, options, {
          content: content,
        })
      );
      var dek = this.dek(
        objectSpread({}, options, {
          content: content,
        })
      );
      var next_page_url = this.next_page_url(options);
      var excerpt = this.excerpt(
        objectSpread({}, options, {
          content: content,
        })
      );
      var word_count = this.word_count(
        objectSpread({}, options, {
          content: content,
        })
      );
      var direction = this.direction({
        title: title,
      });

      var _this$url_and_domain = this.url_and_domain(options),
        url = _this$url_and_domain.url,
        domain = _this$url_and_domain.domain;

      return {
        title: title,
        author: author,
        date_published: date_published || null,
        dek: dek,
        lead_image_url: lead_image_url,
        content: content,
        next_page_url: next_page_url,
        url: url,
        domain: domain,
        excerpt: excerpt,
        word_count: word_count,
        direction: direction,
      };
    },
  };

  var Detectors = {
    'meta[name="al:ios:app_name"][value="Medium"]': MediumExtractor,
    'meta[name="generator"][value="blogger"]': BloggerExtractor,
  };
  function detectByHtml($) {
    var selector = ownKeys$1(Detectors).find(function(s) {
      return $(s).length > 0;
    });

    return Detectors[selector];
  }

  function getExtractor(url$$1, parsedUrl, $) {
    parsedUrl = parsedUrl || url.parse(url$$1);
    var _parsedUrl = parsedUrl,
      hostname = _parsedUrl.hostname;
    var baseDomain = hostname
      .split('.')
      .slice(-2)
      .join('.');
    return (
      Extractors[hostname] ||
      Extractors[baseDomain] ||
      detectByHtml($) ||
      GenericExtractor
    );
  }

  function cleanBySelectors($content, $, _ref) {
    var clean = _ref.clean;
    if (!clean) return $content;
    $(clean.join(','), $content).remove();
    return $content;
  } // Transform matching elements

  function transformElements($content, $, _ref2) {
    var transforms = _ref2.transforms;
    if (!transforms) return $content;

    ownKeys$1(transforms).forEach(function(key) {
      var $matches = $(key, $content);
      var value = transforms[key]; // If value is a string, convert directly

      if (typeof value === 'string') {
        $matches.each(function(index, node) {
          convertNodeTo$$1($(node), $, transforms[key]);
        });
      } else if (typeof value === 'function') {
        // If value is function, apply function to node
        $matches.each(function(index, node) {
          var result = value($(node), $); // If function returns a string, convert node to that value

          if (typeof result === 'string') {
            convertNodeTo$$1($(node), $, result);
          }
        });
      }
    });

    return $content;
  }

  function findMatchingSelector($, selectors, extractHtml) {
    return selectors.find(function(selector) {
      if (isArray$1(selector)) {
        if (extractHtml) {
          return selector.reduce(function(acc, s) {
            return acc && $(s).length > 0;
          }, true);
        }

        var _selector = slicedToArray(selector, 2),
          s = _selector[0],
          attr = _selector[1];

        return (
          $(s).length === 1 &&
          $(s).attr(attr) &&
          $(s)
            .attr(attr)
            .trim() !== ''
        );
      }

      return (
        $(selector).length === 1 &&
        $(selector)
          .text()
          .trim() !== ''
      );
    });
  }

  function select(opts) {
    var $ = opts.$,
      type = opts.type,
      extractionOpts = opts.extractionOpts,
      _opts$extractHtml = opts.extractHtml,
      extractHtml = _opts$extractHtml === void 0 ? false : _opts$extractHtml; // Skip if there's not extraction for this type

    if (!extractionOpts) return null; // If a string is hardcoded for a type (e.g., Wikipedia
    // contributors), return the string

    if (typeof extractionOpts === 'string') return extractionOpts;
    var selectors = extractionOpts.selectors,
      _extractionOpts$defau = extractionOpts.defaultCleaner,
      defaultCleaner =
        _extractionOpts$defau === void 0 ? true : _extractionOpts$defau;
    var matchingSelector = findMatchingSelector($, selectors, extractHtml);
    if (!matchingSelector) return null; // Declaring result; will contain either
    // text or html, which will be cleaned
    // by the appropriate cleaner type
    // If the selector type requests html as its return type
    // transform and clean the element with provided selectors

    var $content;

    if (extractHtml) {
      // If matching selector is an array, we're considering this a
      // multi-match selection, which allows the parser to choose several
      // selectors to include in the result. Note that all selectors in the
      // array must match in order for this selector to trigger
      if (isArray$1(matchingSelector)) {
        $content = $(matchingSelector.join(','));
        var $wrapper = $('<div></div>');
        $content.each(function(index, element) {
          $wrapper.append(element);
        });
        $content = $wrapper;
      } else {
        $content = $(matchingSelector);
      } // Wrap in div so transformation can take place on root element

      $content.wrap($('<div></div>'));
      $content = $content.parent();
      $content = transformElements($content, $, extractionOpts);
      $content = cleanBySelectors($content, $, extractionOpts);
      $content = Cleaners[type](
        $content,
        objectSpread({}, opts, {
          defaultCleaner: defaultCleaner,
        })
      );
      return $.html($content);
    }

    var result; // if selector is an array (e.g., ['img', 'src']),
    // extract the attr

    if (isArray$1(matchingSelector)) {
      var _matchingSelector = slicedToArray(matchingSelector, 2),
        selector = _matchingSelector[0],
        attr = _matchingSelector[1];

      result = $(selector)
        .attr(attr)
        .trim();
    } else {
      var $node = $(matchingSelector);
      $node = cleanBySelectors($node, $, extractionOpts);
      $node = transformElements($node, $, extractionOpts);
      result = $node.text().trim();
    } // Allow custom extractor to skip default cleaner
    // for this type; defaults to true

    if (defaultCleaner) {
      return Cleaners[type](result, objectSpread({}, opts, extractionOpts));
    }

    return result;
  }

  function extractResult(opts) {
    var type = opts.type,
      extractor = opts.extractor,
      _opts$fallback = opts.fallback,
      fallback = _opts$fallback === void 0 ? true : _opts$fallback;
    var result = select(
      objectSpread({}, opts, {
        extractionOpts: extractor[type],
      })
    ); // If custom parser succeeds, return the result

    if (result) {
      return result;
    } // If nothing matches the selector, and fallback is enabled,
    // run the Generic extraction

    if (fallback) return GenericExtractor[type](opts);
    return null;
  }

  var RootExtractor = {
    extract: function extract() {
      var extractor =
        arguments.length > 0 && arguments[0] !== undefined
          ? arguments[0]
          : GenericExtractor;
      var opts = arguments.length > 1 ? arguments[1] : undefined;
      var _opts = opts,
        contentOnly = _opts.contentOnly,
        extractedTitle = _opts.extractedTitle; // This is the generic extractor. Run its extract method

      if (extractor.domain === '*') return extractor.extract(opts);
      opts = objectSpread({}, opts, {
        extractor: extractor,
      });

      if (contentOnly) {
        var _content = extractResult(
          objectSpread({}, opts, {
            type: 'content',
            extractHtml: true,
            title: extractedTitle,
          })
        );

        return {
          content: _content,
        };
      }

      var title = extractResult(
        objectSpread({}, opts, {
          type: 'title',
        })
      );
      var date_published = extractResult(
        objectSpread({}, opts, {
          type: 'date_published',
        })
      );
      var author = extractResult(
        objectSpread({}, opts, {
          type: 'author',
        })
      );
      var next_page_url = extractResult(
        objectSpread({}, opts, {
          type: 'next_page_url',
        })
      );
      var content = extractResult(
        objectSpread({}, opts, {
          type: 'content',
          extractHtml: true,
          title: title,
        })
      );
      var lead_image_url = extractResult(
        objectSpread({}, opts, {
          type: 'lead_image_url',
          content: content,
        })
      );
      var excerpt = extractResult(
        objectSpread({}, opts, {
          type: 'excerpt',
          content: content,
        })
      );
      var dek = extractResult(
        objectSpread({}, opts, {
          type: 'dek',
          content: content,
          excerpt: excerpt,
        })
      );
      var word_count = extractResult(
        objectSpread({}, opts, {
          type: 'word_count',
          content: content,
        })
      );
      var direction = extractResult(
        objectSpread({}, opts, {
          type: 'direction',
          title: title,
        })
      );

      var _ref3 = extractResult(
          objectSpread({}, opts, {
            type: 'url_and_domain',
          })
        ) || {
          url: null,
          domain: null,
        },
        url = _ref3.url,
        domain = _ref3.domain;

      return {
        title: title,
        content: content,
        author: author,
        date_published: date_published,
        lead_image_url: lead_image_url,
        dek: dek,
        next_page_url: next_page_url,
        url: url,
        domain: domain,
        excerpt: excerpt,
        word_count: word_count,
        direction: direction,
      };
    },
  };

  function collectAllPages(_x) {
    return _collectAllPages.apply(this, arguments);
  }

  function _collectAllPages() {
    _collectAllPages = asyncToGenerator(
      /*#__PURE__*/
      regenerator.mark(function _callee(_ref) {
        var next_page_url,
          html,
          $,
          metaCache,
          result,
          Extractor,
          title,
          url,
          pages,
          previousUrls,
          extractorOpts,
          nextPageResult,
          word_count;
        return regenerator.wrap(
          function _callee$(_context) {
            while (1) {
              switch ((_context.prev = _context.next)) {
                case 0:
                  (next_page_url = _ref.next_page_url),
                    (html = _ref.html),
                    ($ = _ref.$),
                    (metaCache = _ref.metaCache),
                    (result = _ref.result),
                    (Extractor = _ref.Extractor),
                    (title = _ref.title),
                    (url = _ref.url);
                  // At this point, we've fetched just the first page
                  pages = 1;
                  previousUrls = [removeAnchor(url)]; // If we've gone over 26 pages, something has
                // likely gone wrong.

                case 3:
                  if (!(next_page_url && pages < 26)) {
                    _context.next = 16;
                    break;
                  }

                  pages += 1; // eslint-disable-next-line no-await-in-loop

                  _context.next = 7;
                  return Resource.create(next_page_url);

                case 7:
                  $ = _context.sent;
                  html = $.html();
                  extractorOpts = {
                    url: next_page_url,
                    html: html,
                    $: $,
                    metaCache: metaCache,
                    contentOnly: true,
                    extractedTitle: title,
                    previousUrls: previousUrls,
                  };
                  nextPageResult = RootExtractor.extract(
                    Extractor,
                    extractorOpts
                  );
                  previousUrls.push(next_page_url);
                  result = objectSpread({}, result, {
                    content: ''
                      .concat(result.content, '<hr><h4>Page ')
                      .concat(pages, '</h4>')
                      .concat(nextPageResult.content),
                  }); // eslint-disable-next-line prefer-destructuring

                  next_page_url = nextPageResult.next_page_url;
                  _context.next = 3;
                  break;

                case 16:
                  word_count = GenericExtractor.word_count({
                    content: '<div>'.concat(result.content, '</div>'),
                  });
                  return _context.abrupt(
                    'return',
                    objectSpread({}, result, {
                      total_pages: pages,
                      pages_rendered: pages,
                      word_count: word_count,
                    })
                  );

                case 18:
                case 'end':
                  return _context.stop();
              }
            }
          },
          _callee,
          this
        );
      })
    );
    return _collectAllPages.apply(this, arguments);
  }

  var Mercury = {
    parse: function parse$$1(url$$1, html) {
      var opts =
        arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
      return asyncToGenerator(
        /*#__PURE__*/
        regenerator.mark(function _callee() {
          var _opts$fetchAllPages,
            fetchAllPages,
            _opts$fallback,
            fallback,
            parsedUrl,
            $$$1,
            Extractor,
            metaCache,
            result,
            _result,
            title,
            next_page_url;

          return regenerator.wrap(
            function _callee$(_context) {
              while (1) {
                switch ((_context.prev = _context.next)) {
                  case 0:
                    (_opts$fetchAllPages = opts.fetchAllPages),
                      (fetchAllPages =
                        _opts$fetchAllPages === void 0
                          ? true
                          : _opts$fetchAllPages),
                      (_opts$fallback = opts.fallback),
                      (fallback =
                        _opts$fallback === void 0 ? true : _opts$fallback); // if no url was passed and this is the browser version,
                    // set url to window.location.href and load the html
                    // from the current page

                    if (!url$$1 && $.browser) {
                      url$$1 = window.location.href; // eslint-disable-line no-undef

                      html = html || $.html();
                    }

                    parsedUrl = url.parse(url$$1);

                    if (validateUrl(parsedUrl)) {
                      _context.next = 5;
                      break;
                    }

                    return _context.abrupt('return', Errors.badUrl);

                  case 5:
                    _context.next = 7;
                    return Resource.create(url$$1, html, parsedUrl);

                  case 7:
                    $$$1 = _context.sent;
                    Extractor = getExtractor(url$$1, parsedUrl, $$$1); // console.log(`Using extractor for ${Extractor.domain}`);
                    // If we found an error creating the resource, return that error

                    if (!$$$1.failed) {
                      _context.next = 11;
                      break;
                    }

                    return _context.abrupt('return', $$$1);

                  case 11:
                    // if html still has not been set (i.e., url passed to Mercury.parse),
                    // set html from the response of Resource.create
                    if (!html) {
                      html = $$$1.html();
                    } // Cached value of every meta name in our document.
                    // Used when extracting title/author/date_published/dek

                    metaCache = $$$1('meta')
                      .map(function(_, node) {
                        return $$$1(node).attr('name');
                      })
                      .toArray();
                    result = RootExtractor.extract(Extractor, {
                      url: url$$1,
                      html: html,
                      $: $$$1,
                      metaCache: metaCache,
                      parsedUrl: parsedUrl,
                      fallback: fallback,
                    });
                    (_result = result),
                      (title = _result.title),
                      (next_page_url = _result.next_page_url); // Fetch more pages if next_page_url found

                    if (!(fetchAllPages && next_page_url)) {
                      _context.next = 21;
                      break;
                    }

                    _context.next = 18;
                    return collectAllPages({
                      Extractor: Extractor,
                      next_page_url: next_page_url,
                      html: html,
                      $: $$$1,
                      metaCache: metaCache,
                      result: result,
                      title: title,
                      url: url$$1,
                    });

                  case 18:
                    result = _context.sent;
                    _context.next = 22;
                    break;

                  case 21:
                    result = objectSpread({}, result, {
                      total_pages: 1,
                      rendered_pages: 1,
                    });

                  case 22:
                    return _context.abrupt('return', result);

                  case 23:
                  case 'end':
                    return _context.stop();
                }
              }
            },
            _callee,
            this
          );
        })
      )();
    },
    browser: !!$.browser,
    // A convenience method for getting a resource
    // to work with, e.g., for custom extractor generator
    fetchResource: function fetchResource(url$$1) {
      return Resource.create(url$$1);
    },
  };

  return Mercury;
})();
