/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 50);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Definition of Filter class and its subclasses.
 */

const {contentTypes, RESOURCE_TYPES} = __webpack_require__(6);
const {filterToRegExp} = __webpack_require__(34);
const {parseDomains, domainSuffixes} = __webpack_require__(9);
const {filterState} = __webpack_require__(14);

const resources = __webpack_require__(53);

/**
 * Map of internal resources for URL rewriting.
 * @type {Map.<string,string>}
 */
let resourceMap = new Map(
  Object.keys(resources).map(key => [key, resources[key]])
);

/**
 * Regular expression used to match the `||` prefix in an otherwise literal
 * pattern.
 * @type {RegExp}
 */
let extendedAnchorRegExp = new RegExp(filterToRegExp("||") + "$");

/**
 * Regular expression used to match the `^` suffix in an otherwise literal
 * pattern.
 * @type {RegExp}
 */
// Note: This should match the pattern in lib/common.js
let separatorRegExp = /[\x00-\x24\x26-\x2C\x2F\x3A-\x40\x5B-\x5E\x60\x7B-\x7F]/;

/**
 * Checks whether the given pattern is a string of literal characters with no
 * wildcards or any other special characters.
 *
 * If the pattern is prefixed with a `||` or suffixed with a `^` but otherwise
 * contains no special characters, it is still considered to be a literal
 * pattern.
 *
 * @param {string} pattern
 *
 * @returns {boolean}
 */
function isLiteralPattern(pattern)
{
  return !/[*^|]/.test(pattern.replace(/^\|{1,2}/, "").replace(/[|^]$/, ""));
}

let isActiveFilter =
/**
 * Checks whether the given filter is an active filter.
 *
 * Filters of type `blocking`, `allowing`, `elemhide`, `elemhideexception`,
 * `elemhideemulation`, and `snippet` are considered active; filters of type
 * `invalid` and `comment` are not considered active.
 *
 * @param {?Filter} filter The filter.
 *
 * @returns {boolean} Whether the filter is active.
 */
exports.isActiveFilter = function isActiveFilter(filter)
{
  return filter instanceof ActiveFilter;
};

let Filter =
/**
 * Abstract base class for filters
 */
exports.Filter = class Filter
{
  /**
   * @param {string} text   string representation of the filter
   * @private
   */
  constructor(text)
  {
    this._text = text;
  }

  /**
   * String representation of the filter
   * @type {string}
   */
  get text()
  {
    return this._text;
  }

  /**
   * Filter type as a string, e.g. "blocking".
   * @type {string}
   */
  get type()
  {
    throw new Error("Please define filter type in the subclass");
  }

  /**
   * Serializes the filter for writing out on disk.
   * @yields {string}
   */
  *serialize()
  {
    let {text} = this;

    yield "[Filter]";
    yield "text=" + text;
  }

  toString()
  {
    return this.text;
  }
};

/**
 * Cache for known filters, maps string representation to filter objects.
 * @type {Map.<string,module:filterClasses.Filter>}
 */
Filter.knownFilters = new Map();

/**
 * Regular expression that content filters should match
 * @type {RegExp}
 */
Filter.contentRegExp = /^([^/|@"!]*?)#([@?$])?#(.+)$/;
/**
 * Regular expression that options on a RegExp filter should match
 * @type {RegExp}
 */
Filter.optionsRegExp = /\$(~?[\w-]+(?:=[^,]*)?(?:,~?[\w-]+(?:=[^,]*)?)*)$/;
/**
 * Regular expression that matches an invalid Content Security Policy
 * @type {RegExp}
 */
Filter.invalidCSPRegExp = /(;|^) ?(base-uri|referrer|report-to|report-uri|upgrade-insecure-requests)\b/i;

/**
 * Creates a filter of correct type from its text representation - does the
 * basic parsing and calls the right constructor then.
 *
 * @param {string} text   as in Filter()
 * @return {module:filterClasses.Filter}
 */
Filter.fromText = function(text)
{
  let filter = Filter.knownFilters.get(text);
  if (filter)
    return filter;

  if (text[0] == "!")
  {
    filter = new CommentFilter(text);
  }
  else
  {
    let match = text.includes("#") ? Filter.contentRegExp.exec(text) : null;
    if (match)
      filter = ContentFilter.fromText(text, match[1], match[2], match[3]);
    else
      filter = URLFilter.fromText(text);
  }

  Filter.knownFilters.set(filter.text, filter);
  return filter;
};

/**
 * Deserializes a filter
 *
 * @param {Object}  obj map of serialized properties and their values
 * @return {module:filterClasses.Filter} filter or null if the filter couldn't
 *   be created
 */
Filter.fromObject = function(obj)
{
  let filter = Filter.fromText(obj.text);
  if (isActiveFilter(filter))
    filterState.fromObject(filter.text, obj);
  return filter;
};

/**
 * Removes unnecessary whitespaces from filter text, will only return null if
 * the input parameter is null.
 * @param {string} text
 * @return {string}
 */
Filter.normalize = function(text)
{
  if (!text)
    return text;

  // Remove line breaks, tabs etc
  text = text.replace(/[^\S ]+/g, "");

  if (!text.includes(" "))
    return text;

  // Don't remove spaces inside comments
  if (/^ *!/.test(text))
    return text.trim();

  // Special treatment for content filters, right side is allowed to contain
  // spaces
  if (Filter.contentRegExp.test(text))
  {
    let [, domains, separator, body] = /^(.*?)(#[@?$]?#?)(.*)$/.exec(text);
    return domains.replace(/ +/g, "") + separator + body.trim();
  }

  // For most regexp filters we strip all spaces, but $csp filter options
  // are allowed to contain single (non trailing) spaces.
  let strippedText = text.replace(/ +/g, "");
  if (!strippedText.includes("$") || !/\b(csp|header)=/i.test(strippedText))
    return strippedText;

  let optionsMatch = Filter.optionsRegExp.exec(strippedText);
  if (!optionsMatch)
    return strippedText;

  // For $csp filters we must first separate out the options part of the
  // text, being careful to preserve its spaces.
  let beforeOptions = strippedText.substring(0, optionsMatch.index);
  let strippedDollarIndex = -1;
  let dollarIndex = -1;
  do
  {
    strippedDollarIndex = beforeOptions.indexOf("$", strippedDollarIndex + 1);
    dollarIndex = text.indexOf("$", dollarIndex + 1);
  }
  while (strippedDollarIndex != -1);
  let optionsText = text.substring(dollarIndex + 1);

  // Then we can normalize spaces in the options part safely
  let options = optionsText.split(",");
  for (let i = 0; i < options.length; i++)
  {
    let option = options[i];
    let optionMatch = /^ *(c *s *p|h *e *a *d *e *r) *=/i.exec(option);
    if (optionMatch)
    {
      options[i] = optionMatch[0].replace(/ +/g, "") +
                   option.substring(optionMatch[0].length).trim().replace(/ +/g, " ");
    }
    else
    {
      options[i] = option.replace(/ +/g, "");
    }
  }

  return beforeOptions + "$" + options.join();
};

let InvalidFilter =
/**
 * Class for invalid filters
 */
exports.InvalidFilter = class InvalidFilter extends Filter
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} reason Reason why this filter is invalid
   * @private
   */
  constructor(text, reason)
  {
    super(text);

    this._reason = reason;
  }

  get type()
  {
    return "invalid";
  }

  *serialize() {}

  /**
   * Reason why this filter is invalid
   * @type {string}
   */
  get reason()
  {
    return this._reason;
  }
};

let CommentFilter =
/**
 * Class for comments
 */
exports.CommentFilter = class CommentFilter extends Filter
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @private
   */
  constructor(text)
  {
    super(text);
  }

  get type()
  {
    return "comment";
  }

  *serialize() {}
};

let ActiveFilter =
/**
 * Abstract base class for filters that can get hits
 */
exports.ActiveFilter = class ActiveFilter extends Filter
{
  /**
   * @param {string} text
   *   see {@link module:filterClasses.Filter Filter()}
   * @param {string} [domains]
   *   Domains that the filter is restricted to separated by domainSeparator
   *   e.g. "foo.com|bar.com|~baz.com"
   * @private
   */
  constructor(text, domains)
  {
    super(text);

    /**
     * String that the domains property should be generated from
     * @type {?string}
     */
    this.domainSource = domains ? domains.toLowerCase() : null;

    /**
     * Separator character used in domainSource property, must be
     * overridden by subclasses
     * @type {string}
     */
    this.domainSeparator = null;

    /**
     * String that the sitekey property should be generated from
     * @type {?string}
     */
    this.sitekeySource = null;

    /**
     * Number of filters contained, will always be 1 (required to
     * optimize {@link module:matcher.Matcher Matcher}).
     * @type {number}
     * @package
     */
    this.size = 1;
  }

  /**
   * See Filter.serialize()
   * @inheritdoc
   */
  *serialize()
  {
    yield* filterState.serialize(this.text);
  }

  /**
   * Defines whether the filter is disabled
   * @type {boolean}
   */
  get disabled()
  {
    return !filterState.isEnabled(this.text);
  }
  set disabled(value)
  {
    filterState.setEnabled(this.text, !value);
  }

  /**
   * Number of hits on the filter since the last reset
   * @type {number}
   */
  get hitCount()
  {
    return filterState.getHitCount(this.text);
  }
  set hitCount(value)
  {
    filterState.setHitCount(this.text, value);
  }

  /**
   * Last time the filter had a hit (in milliseconds since the beginning of the
   * epoch)
   * @type {number}
   */
  get lastHit()
  {
    return filterState.getLastHit(this.text);
  }
  set lastHit(value)
  {
    filterState.setLastHit(this.text, value);
  }

  /**
   * Map containing domains that this filter should match on/not match
   * on or null if the filter should match on all domains
   * @type {?Map.<string,boolean>}
   */
  get domains()
  {
    let {domainSource} = this;
    if (!domainSource)
      return null;

    let value = parseDomains(domainSource, this.domainSeparator);
    Object.defineProperty(this, "domains", {value});
    return value;
  }

  /**
   * Array containing public keys of websites that this filter should apply to
   * @type {?Array.<string>}
   */
  get sitekeys()
  {
    return null;
  }

  /**
   * Checks whether this filter is active on a domain.
   * @param {?string} [docDomain] domain name of the document that loads the URL
   * @param {string} [sitekey] public key provided by the document
   * @return {boolean} true in case of the filter being active
   */
  isActiveOnDomain(docDomain, sitekey)
  {
    // Sitekeys are case-sensitive so we shouldn't convert them to
    // upper-case to avoid false positives here. Instead we need to
    // change the way filter options are parsed.
    if (this.sitekeys &&
        (!sitekey || !this.sitekeys.includes(sitekey.toUpperCase())))
      return false;

    let {domains} = this;

    // If no domains are set the rule matches everywhere
    if (!domains)
      return true;

    if (docDomain == null)
      docDomain = "";
    else if (docDomain[docDomain.length - 1] == ".")
      docDomain = docDomain.substring(0, docDomain.length - 1);

    // If the document has no host name, match only if the filter
    // isn't restricted to specific domains
    if (!docDomain)
      return domains.get("");

    for (docDomain of domainSuffixes(docDomain))
    {
      let isDomainIncluded = domains.get(docDomain);
      if (typeof isDomainIncluded != "undefined")
        return isDomainIncluded;
    }

    return domains.get("");
  }

  /**
   * Checks whether this filter is active only on a domain and its subdomains.
   * @param {?string} [docDomain]
   * @return {boolean}
   */
  isActiveOnlyOnDomain(docDomain)
  {
    let {domains} = this;

    if (!domains || domains.get(""))
      return false;

    if (docDomain == null)
      docDomain = "";
    else if (docDomain[docDomain.length - 1] == ".")
      docDomain = docDomain.substring(0, docDomain.length - 1);

    if (!docDomain)
      return false;

    for (let [domain, isIncluded] of domains)
    {
      if (isIncluded && domain != docDomain)
      {
        if (domain.length <= docDomain.length)
          return false;

        if (!domain.endsWith("." + docDomain))
          return false;
      }
    }

    return true;
  }

  /**
   * Checks whether this filter is generic or specific
   * @return {boolean}
   */
  isGeneric()
  {
    let {sitekeys, domains} = this;

    return !(sitekeys && sitekeys.length) && (!domains || domains.get(""));
  }

  /**
   * Yields the filter itself (required to optimize
   *   {@link module:matcher.Matcher Matcher}).
   * @yields {module:filterClasses.ActiveFilter}
   * @package
   */
  *[Symbol.iterator]()
  {
    yield this;
  }
};

let URLFilter =
/**
 * Abstract base class for URL filters
 */
exports.URLFilter = class URLFilter extends ActiveFilter
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} regexpSource
   *   filter part that the regular expression should be build from
   * @param {number} [contentType]
   *   Content types the filter applies to, combination of values from
   *   `{@link module:contentTypes.contentTypes}`
   * @param {boolean} [matchCase]
   *   Defines whether the filter should distinguish between lower and upper
   *   case letters
   * @param {string} [domains]
   *   Domains that the filter is restricted to, e.g. "foo.com|bar.com|~baz.com"
   * @param {boolean} [thirdParty]
   *   Defines whether the filter should apply to third-party or first-party
   *   content only
   * @param {string} [sitekeys]
   *   Public keys of websites that this filter should apply to
   * @param {?string} [header]
   *   Header-based filtering.
   * @param {?string} [rewrite]
   *   The name of the internal resource to which to rewrite the
   *   URL. e.g. if the value of the `$rewrite` option is
   *   `abp-resource:blank-html`, this should be `blank-html`.
   *
   * @private
   */
  constructor(text, regexpSource, contentType, matchCase, domains, thirdParty,
              sitekeys, header, rewrite)
  {
    super(text, domains);

    /**
     * @see ActiveFilter.domainSeparator
     */
    this.domainSeparator = "|";

    /**
     * Expression from which a regular expression should be generated -
     * for delayed creation of the regexp property
     * @type {?string}
     */
    this.pattern = null;

    /**
     * Content types the filter applies to, combination of values from
     * `{@link module:contentTypes.contentTypes}`
     * @type {number}
     */
    this.contentType = contentType != null ? contentType : RESOURCE_TYPES;

    /**
     * Defines whether the filter should distinguish between lower and
     * upper case letters
     * @type {boolean}
     */
    this.matchCase = matchCase || false;

    /**
     * Defines whether the filter should apply to third-party or
     * first-party content only. Can be null (apply to all content).
     * @type {?boolean}
     */
    this.thirdParty = thirdParty != null ? thirdParty : null;

    /**
     * Header-based filtering expression. Refer to the filter
     * documentation reference for the syntax, or
     * `{@link BlockingFilter.filterHeaders}` for the reference
     * implementation.
     * @type {?string}
     */
    this.header = header != null ? header : null;

    /**
     * The name of the internal resource to which to rewrite the
     * URL. e.g. if the value of the `$rewrite` option is
     * `abp-resource:blank-html`, this should be `blank-html`.
     * @type {?string}
     */
    this.rewrite = rewrite != null ? rewrite : null;

    if (sitekeys != null)
      this.sitekeySource = sitekeys;

    if (!this.matchCase)
      regexpSource = regexpSource.toLowerCase();

    if (regexpSource.length >= 2 &&
        regexpSource[0] == "/" &&
        regexpSource[regexpSource.length - 1] == "/")
    {
      // The filter is a regular expression - convert it immediately to
      // catch syntax errors
      let regexp =
        new RegExp(regexpSource.substring(1, regexpSource.length - 1));
      Object.defineProperty(this, "regexp", {value: regexp});
    }
    else
    {
      // Patterns like /foo/bar/* exist so that they are not treated as regular
      // expressions. We drop any superfluous wildcards here so our
      // optimizations can kick in.
      regexpSource = regexpSource.replace(/^\*+/, "").replace(/\*+$/, "");

      // No need to convert this filter to regular expression yet, do it on
      // demand
      this.pattern = regexpSource;
    }
  }

  /**
   * Regular expression to be used when testing against this filter
   * @type {RegExp}
   */
  get regexp()
  {
    let value = null;

    let {pattern} = this;
    if (!isLiteralPattern(pattern))
      value = new RegExp(filterToRegExp(pattern));

    Object.defineProperty(this, "regexp", {value});
    return value;
  }

  /**
   * @see ActiveFilter.sitekeys
   */
  get sitekeys()
  {
    let {sitekeySource} = this;
    if (!sitekeySource)
      return null;

    let value = sitekeySource.split("|");
    Object.defineProperty(this, "sitekeys", {value});
    return value;
  }

  /**
   * Tests whether the URL request matches this filter
   * @param {module:url.URLRequest} request URL request to be tested
   * @param {number} typeMask bitmask of content / request types to match
   * @param {?string} [sitekey] public key provided by the document
   * @return {boolean} true in case of a match
   */
  matches(request, typeMask, sitekey)
  {
    return (this.contentType & typeMask) != 0 &&
           (this.thirdParty == null || this.thirdParty == request.thirdParty) &&
           (this.regexp ?
              this.isActiveOnDomain(request.documentHostname, sitekey) &&
              this._matchesLocation(request) :
              this._matchesLocation(request) &&
              this.isActiveOnDomain(request.documentHostname, sitekey));
  }

  /**
   * Checks whether the given URL request matches this filter's pattern.
   * @param {module:url.URLRequest} request The URL request to check.
   * @returns {boolean} `true` if the URL request matches.
   * @private
   */
  _matchesLocation(request)
  {
    let location = this.matchCase ? request.href : request.lowerCaseHref;

    let {regexp} = this;

    if (regexp)
      return regexp.test(location);

    let {pattern} = this;

    let startsWithAnchor = pattern[0] == "|";
    let startsWithExtendedAnchor = startsWithAnchor && pattern[1] == "|";
    let endsWithSeparator = pattern[pattern.length - 1] == "^";
    let endsWithAnchor = !endsWithSeparator &&
                         pattern[pattern.length - 1] == "|";

    if (startsWithExtendedAnchor)
      pattern = pattern.substr(2);
    else if (startsWithAnchor)
      pattern = pattern.substr(1);

    if (endsWithSeparator || endsWithAnchor)
      pattern = pattern.slice(0, -1);

    let index = location.indexOf(pattern);

    while (index != -1)
    {
      // The "||" prefix requires that the text that follows does not start
      // with a forward slash.
      if ((startsWithExtendedAnchor ?
             location[index] != "/" &&
             extendedAnchorRegExp.test(location.substring(0, index)) :
             startsWithAnchor ?
               index == 0 :
               true) &&
          (endsWithSeparator ?
             !location[index + pattern.length] ||
             separatorRegExp.test(location[index + pattern.length]) :
             endsWithAnchor ?
               index == location.length - pattern.length :
               true))
        return true;

      if (pattern == "")
        return true;

      index = location.indexOf(pattern, index + 1);
    }

    return false;
  }
};

/**
 * Creates a URL filter from its text representation
 * @param {string} text   same as in Filter()
 * @return {module:filterClasses.Filter}
 */
URLFilter.fromText = function(text)
{
  let blocking = true;
  let origText = text;
  if (text[0] == "@" && text[1] == "@")
  {
    blocking = false;
    text = text.substring(2);
  }

  let contentType = null;
  let matchCase = null;
  let domains = null;
  let sitekeys = null;
  let thirdParty = null;
  let csp = null;
  let rewrite = null;
  let header = null;
  let options;
  let match = text.includes("$") ? Filter.optionsRegExp.exec(text) : null;
  if (match)
  {
    options = match[1].split(",");
    text = match.input.substring(0, match.index);
    for (let option of options)
    {
      let value = null;
      let separatorIndex = option.indexOf("=");
      if (separatorIndex >= 0)
      {
        value = option.substring(separatorIndex + 1);
        option = option.substring(0, separatorIndex);
      }

      let inverse = option[0] == "~";
      if (inverse)
        option = option.substring(1);

      let type = contentTypes[option.replace(/-/, "_").toUpperCase()];
      if (type)
      {
        if (inverse)
        {
          if (contentType == null)
            contentType = RESOURCE_TYPES;
          contentType &= ~type;
        }
        else
        {
          contentType |= type;

          switch (type)
          {
            case contentTypes.CSP:
              if (blocking && !value)
                return new InvalidFilter(origText, "filter_invalid_csp");
              csp = value;
              break;
            case contentTypes.HEADER:
              if (blocking && !value)
                return new InvalidFilter(origText, "filter_invalid_header");
              if (value)
              {
                let equal = value.indexOf("=");
                if (equal == 0)
                  return new InvalidFilter(origText, "filter_invalid_header");
                if (equal != -1 && value.length >= equal + 3 &&
                    value[equal + 1] == "/" && value[value.length - 1] == "/")
                  return new InvalidFilter(origText, "filter_invalid_header");
                header = value.replace(/([^\\])\\x2c/, "$1,");
              }
              break;
          }
        }
      }
      else
      {
        switch (option.toLowerCase())
        {
          case "match-case":
            matchCase = !inverse;
            break;
          case "domain":
            if (!value)
              return new InvalidFilter(origText, "filter_unknown_option");
            domains = value;
            break;
          case "third-party":
            thirdParty = !inverse;
            break;
          case "sitekey":
            if (!value)
              return new InvalidFilter(origText, "filter_unknown_option");
            sitekeys = value.toUpperCase();
            break;
          case "rewrite":
            if (value == null)
              return new InvalidFilter(origText, "filter_unknown_option");
            if (!value.startsWith("abp-resource:"))
              return new InvalidFilter(origText, "filter_invalid_rewrite");
            rewrite = value.substring("abp-resource:".length);
            break;
          default:
            return new InvalidFilter(origText, "filter_unknown_option");
        }
      }
    }
  }

  try
  {
    if (blocking)
    {
      if (csp && Filter.invalidCSPRegExp.test(csp))
        return new InvalidFilter(origText, "filter_invalid_csp");

      if (rewrite)
      {
        if (text[0] == "|" && text[1] == "|")
        {
          if (!domains && thirdParty != false)
            return new InvalidFilter(origText, "filter_invalid_rewrite");
        }
        else if (text[0] == "*")
        {
          if (!domains)
            return new InvalidFilter(origText, "filter_invalid_rewrite");
        }
        else
        {
          return new InvalidFilter(origText, "filter_invalid_rewrite");
        }
      }

      return new BlockingFilter(origText, text, contentType, matchCase, domains,
                                thirdParty, sitekeys, header, rewrite, csp);
    }
    return new AllowingFilter(origText, text, contentType, matchCase, domains,
                              thirdParty, sitekeys, header);
  }
  catch (e)
  {
    return new InvalidFilter(origText, "filter_invalid_regexp");
  }
};

/**
 * @deprecated Use <code>{@link contentTypes}</code> instead.
 * @see contentTypes
 */
// For backwards compatibility.
URLFilter.typeMap = contentTypes;

let BlockingFilter =
/**
 * Class for blocking filters
 */
exports.BlockingFilter = class BlockingFilter extends URLFilter
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} regexpSource see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {number} [contentType] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {boolean} [matchCase] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {string} [domains] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {boolean} [thirdParty] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {string} [sitekeys] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {?string} [header] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {?string} [rewrite]
   *   The name of the internal resource to which to rewrite the
   *   URL. e.g. if the value of the `$rewrite` option is
   *   `abp-resource:blank-html`, this should be `blank-html`.
   * @param {?string} [csp]
   *   Content Security Policy to inject when the filter matches
   *
   * @private
   */
  constructor(text, regexpSource, contentType, matchCase, domains, thirdParty,
              sitekeys, header, rewrite, csp)
  {
    super(text, regexpSource, contentType, matchCase, domains, thirdParty,
          sitekeys, header, rewrite);

    /**
     * Content Security Policy to inject for matching requests.
     * @type {?string}
     */
    this.csp = csp != null ? csp : null;
  }

  get type()
  {
    return "blocking";
  }

  /**
   * Rewrites an URL.
   * @param {string} url the URL to rewrite
   * @return {string} the rewritten URL, or the original in case of failure
   */
  rewriteUrl(url)
  {
    return resourceMap.get(this.rewrite) || url;
  }

  /**
   * Filter headers.
   *
   * This function would be called by the request blocker code after
   * matching the request.
   *
   * @param {webRequest.HttpHeaders} headers the HTTP response headers
   *   to match, as they are returned by the request blocker. They
   *   follow the {@link webRequest API
   *   https://developer.mozilla.org/en-US/docs/Web/API/webRequest/HttpHeaders}.
   * @return {boolean} Whether the headers match. Will return true if
   *   there is nothing to match against, or if the header is present
   *   but no value.
   */
  filterHeaders(headers)
  {
    if (!this.header)
      return true;

    let value;
    let name;
    let separatorIndex = this.header.indexOf("=");
    if (separatorIndex >= 0)
    {
      value = this.header.substring(separatorIndex + 1);
      name = this.header.substring(0, separatorIndex).toLowerCase();
    }
    else
    {
      name = this.header;
    }

    for (let header of headers)
    {
      if (header.name.toLowerCase() == name)
      {
        if (value)
        {
          if (header.value.includes(value))
            return true;
        }
        else
        {
          return true;
        }
      }
    }

    return false;
  }
};

let AllowingFilter =
/**
 * Class for allowing (allowlisting) filters
 */
exports.AllowingFilter = class AllowingFilter extends URLFilter
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} regexpSource see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {number} [contentType] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {boolean} [matchCase] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {string} [domains] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {boolean} [thirdParty] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {string} [sitekeys] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   * @param {?string} [header] see
   *   {@link module:filterClasses.URLFilter URLFilter()}
   *
   * @private
   */
  constructor(text, regexpSource, contentType, matchCase, domains, thirdParty,
              sitekeys, header)
  {
    super(text, regexpSource, contentType, matchCase, domains, thirdParty,
          sitekeys, header);
  }

  get type()
  {
    return "allowing";
  }
};

let ContentFilter =
/**
 * Base class for content filters
 */
exports.ContentFilter = class ContentFilter extends ActiveFilter
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} [domains] Host names or domains the filter should be
   *                           restricted to
   * @param {string} body      The body of the filter
   *
   * @private
   */
  constructor(text, domains, body)
  {
    super(text, domains || null);

    this._body = body;

    /**
     * @see ActiveFilter.domainSeparator
     */
    this.domainSeparator = ",";
  }

  /**
   * The body of the filter
   * @type {string}
   */
  get body()
  {
    return this._body;
  }
};

/**
 * Creates a content filter from a pre-parsed text representation
 *
 * @param {string} text         same as in Filter()
 * @param {string} [domains]
 *   domains part of the text representation
 * @param {string} [type]
 *   rule type, either:
 *     * "" for an element hiding filter
 *     * "@" for an element hiding exception filter
 *     * "?" for an element hiding emulation filter
 *     * "$" for a snippet filter
 * @param {string} body
 *   body part of the text representation, either a CSS selector or a snippet
 *   script
 * @return {module:filterClasses.ElemHideFilter|
 *          module:filterClasses.ElemHideException|
 *          module:filterClasses.ElemHideEmulationFilter|
 *          module:filterClasses.SnippetFilter|
 *          module:filterClasses.InvalidFilter}
 */
ContentFilter.fromText = function(text, domains, type, body)
{
  // We don't allow content filters which have any empty domains.
  // Note: The ContentFilter.prototype.domainSeparator is duplicated here, if
  // that changes this must be changed too.
  if (domains && /(^|,)~?(,|$)/.test(domains))
    return new InvalidFilter(text, "filter_invalid_domain");

  if (type == "@")
    return new ElemHideException(text, domains, body);

  if (type == "?" || type == "$")
  {
    // Element hiding emulation and snippet filters are inefficient so we need
    // to make sure that they're only applied if they specify active domains
    if (!(/,[^~][^,.]*\.[^,]/.test("," + domains) ||
          ("," + domains + ",").includes(",localhost,")))
    {
      return new InvalidFilter(text, type == "?" ?
                                       "filter_elemhideemulation_nodomain" :
                                       "filter_snippet_nodomain");
    }

    if (type == "?")
      return new ElemHideEmulationFilter(text, domains, body);

    return new SnippetFilter(text, domains, body);
  }

  return new ElemHideFilter(text, domains, body);
};

let ElemHideBase =
/**
 * Base class for element hiding filters
 */
exports.ElemHideBase = class ElemHideBase extends ContentFilter
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} [domains] see
   *   {@link module:filterClasses.ContentFilter ContentFilter()}
   * @param {string} selector  CSS selector for the HTML elements that should be
   *                           hidden
   *
   * @private
   */
  constructor(text, domains, selector)
  {
    super(text, domains, selector);
  }

  /**
   * CSS selector for the HTML elements that should be hidden
   * @type {string}
   */
  get selector()
  {
    return this.body;
  }
};

let ElemHideFilter =
/**
 * Class for element hiding filters
 */
exports.ElemHideFilter = class ElemHideFilter extends ElemHideBase
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} [domains]  see
   *   {@link module:filterClasses.ElemHideBase ElemHideBase()}
   * @param {string} selector see
   *   {@link module:filterClasses.ElemHideBase ElemHideBase()}
   *
   * @private
   */
  constructor(text, domains, selector)
  {
    super(text, domains, selector);
  }

  get type()
  {
    return "elemhide";
  }
};

let ElemHideException =
/**
 * Class for element hiding exceptions
 */
exports.ElemHideException = class ElemHideException extends ElemHideBase
{
  /**
   * @param {string} text see {@link module:filterClasses.Filter Filter()}
   * @param {string} [domains]  see
   *   {@link module:filterClasses.ElemHideBase ElemHideBase()}
   * @param {string} selector see
   *   {@link module:filterClasses.ElemHideBase ElemHideBase()}
   *
   * @private
   */
  constructor(text, domains, selector)
  {
    super(text, domains, selector);
  }

  get type()
  {
    return "elemhideexception";
  }
};

let ElemHideEmulationFilter =
/**
 * Class for element hiding emulation filters
 */
exports.ElemHideEmulationFilter =
class ElemHideEmulationFilter extends ElemHideBase
{
  /**
   * @param {string} text    see {@link module:filterClasses.Filter Filter()}
   * @param {string} domains see
   *   {@link module:filterClasses.ElemHideBase ElemHideBase()}
   * @param {string} selector see
   *   {@link module:filterClasses.ElemHideBase ElemHideBase()}
   * @constructor
   * @augments module:filterClasses.ElemHideBase
   *
   * @private
   */
  constructor(text, domains, selector)
  {
    super(text, domains, selector);
  }

  get type()
  {
    return "elemhideemulation";
  }
};

let SnippetFilter =
/**
 * Class for snippet filters
 */
exports.SnippetFilter = class SnippetFilter extends ContentFilter
{
  /**
   * @param {string} text see Filter()
   * @param {string} [domains] see ContentFilter()
   * @param {string} script    Script that should be executed
   * @constructor
   * @augments module:filterClasses.ContentFilter
   *
   * @private
   */
  constructor(text, domains, script)
  {
    super(text, domains, script);
  }

  get type()
  {
    return "snippet";
  }

  /**
   * Script that should be executed
   * @type {string}
   */
  get script()
  {
    return this.body;
  }
};


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

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "port", function() { return port; });
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12);
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0__);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module messaging */



/**
 * Communication port wrapping ext.onMessage to receive messages.
 *
 * @constructor
 */
class Port
{
  constructor()
  {
    this._eventEmitter = new _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0__["EventEmitter"]();
    this._onMessage = this._onMessage.bind(this);
    ext.onMessage.addListener(this._onMessage);
  }

  _onMessage(message, sender, sendResponse)
  {
    let async = false;
    let callbacks = this._eventEmitter.listeners(message.type);

    for (let callback of callbacks)
    {
      let response = callback(message, sender);

      if (response && typeof response.then == "function")
      {
        response.then(
          sendResponse,
          reason =>
          {
            console.error(reason);
            sendResponse();
          }
        );
        async = true;
      }
      else
      {
        sendResponse(response);
      }
    }

    return async;
  }

  /**
   * Function to be called when a particular message is received.
   *
   * @callback Port~messageCallback
   * @param {object} message
   * @param {object} sender
   * @return The callback can return undefined (no response),
   *         a value (response to be sent to sender immediately)
   *         or a promise (asynchronous response).
   */

  /**
   * Adds a callback for the specified message.
   *
   * The return value of the callback (if not undefined) is sent as response.
   * @param {string}   name
   * @param {Port~messageCallback} callback
   */
  on(name, callback)
  {
    this._eventEmitter.on(name, callback);
  }

  /**
   * Removes a callback for the specified message.
   *
   * @param {string}   name
   * @param {Port~messageCallback} callback
   */
  off(name, callback)
  {
    this._eventEmitter.off(name, callback);
  }

  /**
   * Disables the port and makes it stop listening to incoming messages.
   */
  disconnect()
  {
    ext.onMessage.removeListener(this._onMessage);
  }
}

/**
 * The default port to receive messages.
 *
 * @type {Port}
 */
let port = new Port();


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Definition of Subscription class and its subclasses.
 */

const {recommendations} = __webpack_require__(35);
const {isActiveFilter} = __webpack_require__(0);
const {filterNotifier} = __webpack_require__(4);
const {Downloader} = __webpack_require__(25);
const {profiler} = __webpack_require__(36);

/**
 * Subscription types by URL.
 *
 * @type {Map.<string, string>}
 */
let typesByURL = new Map(
  (function*()
  {
    for (let {type, url} of recommendations())
      yield [url, type];
  })()
);

let Subscription =
/**
 * The `Subscription` class represents a filter subscription.
 * @abstract
 */
exports.Subscription = class Subscription
{
  /**
   * Creates a `Subscription` object.
   * @param {string} url The URL of the subscription.
   * @param {string} [title] The title of the subscription.
   * @private
   */
  constructor(url, title)
  {
    /**
     * The URL of the subscription.
     * @type {string}
     * @see module:subscriptionClasses.Subscription#url
     * @private
     */
    this._url = url;

    /**
     * Whether the URL of the subscription is a valid subscription URL.
     * @type {boolean}
     * @private
     * @see module:subscriptionClasses.Subscription#valid
     */
    this._urlValid = Subscription.isValidURL(url);

    /**
     * The type of the subscription.
     * @type {?string}
     * @default <code>null</code>
     * @private
     * @see module:subscriptionClasses.Subscription#type
     */
    this._type = typesByURL.get(url) || null;

    /**
     * Filter text contained in the subscription.
     * @type {Array.<string>}
     * @private
     */
    this._filterText = [];

    /**
     * A searchable index of filter text in the subscription.
     * @type {Set.<string>}
     * @private
     */
    this._filterTextIndex = new Set();

    /**
     * The title of the subscription.
     * @type {?string}
     * @default <code>null</code>
     * @private
     * @see module:subscriptionClasses.Subscription#title
     */
    this._title = null;

    if (title)
      this._title = title;

    /**
     * Whether the title of the subscription is non-editable.
     * @type {boolean}
     * @default <code>false</code>
     * @private
     * @see module:subscriptionClasses.Subscription#fixedTitle
     */
    this._fixedTitle = false;

    /**
     * Whether the subscription is disabled.
     * @type {boolean}
     * @default <code>false</code>
     * @private
     * @see module:subscriptionClasses.Subscription#disabled
     */
    this._disabled = false;

    Subscription.knownSubscriptions.set(url, this);
  }

  /**
   * The URL of the subscription.
   * @type {string}
   */
  get url()
  {
    return this._url;
  }

  /**
   * Whether the subscription is valid.
   * @type {boolean}
   * @package
   */
  get valid()
  {
    // This should return a value based on Subscription#_urlValid after
    // https://gitlab.com/eyeo/adblockplus/abpui/adblockplusui/-/issues/753
    return true;
  }

  /**
   * The type of the subscription.
   * @type {?string}
   * @default <code>null</code>
   */
  get type()
  {
    return this._type;
  }

  /**
   * The title of the subscription.
   * @type {string}
   */
  get title()
  {
    return this._title;
  }

  set title(value)
  {
    if (value != this._title)
    {
      let oldValue = this._title;
      this._title = value;
      filterNotifier.emit("subscription.title", this, value, oldValue);
    }
  }

  /**
   * Whether the title of the subscription is non-editable.
   * @type {boolean}
   * @default <code>false</code>
   */
  get fixedTitle()
  {
    return this._fixedTitle;
  }

  set fixedTitle(value)
  {
    if (value != this._fixedTitle)
    {
      let oldValue = this._fixedTitle;
      this._fixedTitle = value;
      filterNotifier.emit("subscription.fixedTitle", this, value, oldValue);
    }
  }

  /**
   * Whether the subscription is disabled.
   * @type {boolean}
   * @default <code>false</code>
   */
  get disabled()
  {
    return this._disabled;
  }

  set disabled(value)
  {
    if (value != this._disabled)
    {
      let oldValue = this._disabled;
      this._disabled = value;
      filterNotifier.emit("subscription.disabled", this, value, oldValue);
    }
  }

  /**
   * The number of filters in the subscription.
   * @type {number}
   * @default <code>0</code>
   */
  get filterCount()
  {
    return this._filterText.length;
  }

  /**
   * Returns an iterator that yields the text for each filter in the
   * subscription.
   * @returns {Iterator.<string>}
   */
  filterText()
  {
    return this._filterText[Symbol.iterator]();
  }

  /**
   * Checks whether the subscription has the given filter text.
   * @param {string} filterText The filter text.
   * @returns {boolean} Whether the subscription has the filter text.
   * @package
   */
  hasFilterText(filterText)
  {
    return this._filterTextIndex.has(filterText);
  }

  /**
   * Returns the filter text at the given `0`-based index.
   * @param {number} index The `0`-based index. If the index is out of bounds,
   *   the return value is `null`.
   * @returns {?module:filterClasses.Filter} The filter text.
   */
  filterTextAt(index)
  {
    return this._filterText[index] || null;
  }

  /**
   * Returns the `0`-based index of the given filter.
   *
   * @param {module:filterClasses.Filter} filter The filter.
   * @param {number} [fromIndex] The `0`-based index from which to start the
   *   search.
   *
   * @returns {number} The `0`-based index at which the filter is found. If the
   *   filter is not found in the subscription, the return value is `-1`.
   */
  findFilterIndex(filter, fromIndex = 0)
  {
    return this._filterText.indexOf(filter.text, fromIndex);
  }

  /**
   * Removes all filters from the subscription.
   */
  clearFilters()
  {
    this._filterText = [];
    this._filterTextIndex.clear();
  }

  /**
   * Adds a filter to the subscription.
   * @param {Filter} filter The filter.
   */
  addFilter(filter)
  {
    this._filterText.push(filter.text);
    this._filterTextIndex.add(filter.text);
  }

  /**
   * Inserts a filter into the subscription at the given `0`-based index.
   *
   * @param {module:filterClasses.Filter} filter The filter.
   * @param {number} index The `0`-based index. If the index is out of bounds,
   *   the filter is inserted at the beginning or at the end accordingly.
   */
  insertFilterAt(filter, index)
  {
    this._filterText.splice(index, 0, filter.text);
    this._filterTextIndex.add(filter.text);
  }

  /**
   * Deletes a filter from the subscription at the given `0`-based index.
   * @param {number} index The `0`-based index. If the index is out of bounds,
   *   no filter is deleted.
   */
  deleteFilterAt(index)
  {
    // Ignore index if out of bounds on the negative side, for consistency.
    if (index < 0)
      return;

    let [filterText] = this._filterText.splice(index, 1);
    if (!this._filterText.includes(filterText))
      this._filterTextIndex.delete(filterText);
  }

  /**
   * Updates the filter text of the subscription.
   * @param {Array.<string>} filterText The new filter text.
   * @returns {{added: Array.<string>, removed: Array.<string>}} An object
   *   containing two lists of the text of added and removed filters
   *   respectively.
   * @package
   */
  updateFilterText(filterText)
  {
    let added = [];
    let removed = [];

    if (this._filterText.length == 0)
    {
      added = [...filterText];
    }
    else if (filterText.length > 0)
    {
      for (let text of filterText)
      {
        if (!this._filterTextIndex.has(text))
          added.push(text);
      }
    }

    this._filterTextIndex = new Set(filterText);

    if (filterText.length == 0)
    {
      removed = [...this._filterText];
    }
    else if (this._filterText.length > 0)
    {
      for (let text of this._filterText)
      {
        if (!this._filterTextIndex.has(text))
          removed.push(text);
      }
    }

    this._filterText = [...filterText];

    return {added, removed};
  }

  /**
   * Serializes the subscription for writing out on disk.
   * @yields {string}
   * @package
   */
  *serialize()
  {
    let {url, _title, _fixedTitle, _disabled} = this;

    yield "[Subscription]";
    yield "url=" + url;

    if (_title)
      yield "title=" + _title;
    if (_fixedTitle)
      yield "fixedTitle=true";
    if (_disabled)
      yield "disabled=true";
  }

  /**
   * Serializes the subscription's filter text for writing out on disk.
   * @yields {string}
   * @package
   */
  *serializeFilters()
  {
    let {_filterText} = this;

    yield "[Subscription filters]";

    for (let text of _filterText)
      yield text.replace(/\[/g, "\\[");
  }

  /**
   * Returns a string representing the subscription.
   * @returns {string}
   */
  toString()
  {
    return [...this.serialize()].join("\n");
  }
};

/**
 * Cache for known filter subscriptions that maps subscription URLs to
 * subscription objects.
 * @type {Map.<string, module:subscriptionClasses.Subscription>}
 * @package
 */
exports.Subscription.knownSubscriptions = new Map();

/**
 * Returns the subscription object for a subscription URL.
 *
 * Every subscription URL maps to its own unique object. If no such object
 * exists, a new one is created internally; otherwise the existing object is
 * used.
 *
 * @param {string} url The subscription URL.
 *
 * @returns {module:subscriptionClasses.Subscription} A subscription object.
 */
exports.Subscription.fromURL = function(url)
{
  let subscription = Subscription.knownSubscriptions.get(url);
  if (subscription)
    return subscription;

  if (url[0] != "~")
  {
    subscription = new DownloadableSubscription(url, null);

    return subscription;
  }

  return new SpecialSubscription(url);
};

/**
 * Deserializes a subscription.
 * @param {object} obj A map of serialized properties and their values.
 * @returns {module:subscriptionClasses.Subscription} A subscription object.
 * @package
 */
exports.Subscription.fromObject = function(obj)
{
  let result;
  if (obj.url[0] != "~")
  {
    // URL is valid - this is a downloadable subscription
    result = new DownloadableSubscription(obj.url, obj.title);

    if (result.type)
      result.abtest = obj.abtest;

    if ("downloadStatus" in obj)
      result._downloadStatus = obj.downloadStatus;
    if ("lastSuccess" in obj)
      result.lastSuccess = parseInt(obj.lastSuccess, 10) || 0;
    if ("lastCheck" in obj)
      result._lastCheck = parseInt(obj.lastCheck, 10) || 0;
    if ("expires" in obj)
      result.expires = parseInt(obj.expires, 10) || 0;
    if ("softExpiration" in obj)
      result.softExpiration = parseInt(obj.softExpiration, 10) || 0;
    if ("errors" in obj)
      result._errors = parseInt(obj.errors, 10) || 0;
    if ("version" in obj)
      result.version = parseInt(obj.version, 10) || 0;
    if ("requiredVersion" in obj)
      result.requiredVersion = obj.requiredVersion;
    if ("homepage" in obj)
      result._homepage = obj.homepage;
    if ("lastDownload" in obj)
      result._lastDownload = parseInt(obj.lastDownload, 10) || 0;
    if ("downloadCount" in obj)
      result.downloadCount = parseInt(obj.downloadCount, 10) || 0;
  }
  else
  {
    result = new SpecialSubscription(obj.url, obj.title);
    if ("defaults" in obj)
      result.defaults = obj.defaults.split(" ");
  }
  if ("fixedTitle" in obj)
    result._fixedTitle = (obj.fixedTitle == "true");
  if ("disabled" in obj)
    result._disabled = (obj.disabled == "true");

  return result;
};

/**
 * Checks whether a URL is a valid subscription URL.
 * @param {string} url The URL.
 * @returns {boolean} Whether the URL is a valid subscription URL.
 */
exports.Subscription.isValidURL = function isValidURL(url)
{
  return url.startsWith("~user~") || Downloader.isValidURL(url);
};

let SpecialSubscription =
/**
 * The `SpecialSubscription` class represents a special filter subscription.
 *
 * This type of subscription is used for keeping user-defined filters.
 */
exports.SpecialSubscription = class SpecialSubscription extends Subscription
{
  /**
   * Creates a `SpecialSubscription` object.
   * @param {string} url The URL of the subscription.
   * @param {string} [title] The title of the subscription.
   * @private
   */
  constructor(url, title)
  {
    super(url, title);

    /**
     * Filter types that should be added to this subscription by default.
     *
     * Entries should correspond to keys in
     * `{@link module:subscriptionClasses.SpecialSubscription.defaultsMap}`.
     *
     * @type {?Array.<string>}
     *
     * @package
     */
    this.defaults = null;
  }

  /**
   * Checks whether the given filter should be added to this subscription by
   * default.
   * @param {Filter} filter The filter.
   * @returns {boolean} Whether the filter should be added to this subscription
   *   by default.
   * @package
   */
  isDefaultFor(filter)
  {
    if (this.defaults && this.defaults.length)
    {
      for (let type of this.defaults)
      {
        if (SpecialSubscription.defaultsMap.get(type).includes(filter.type))
          return true;
        if (!isActiveFilter(filter) && type == "blocking")
          return true;
      }
    }

    return false;
  }

  /**
   * Serializes the subscription for writing out on disk.
   * @yields {string}
   * @package
   */
  *serialize()
  {
    let {defaults, _lastDownload} = this;

    yield* super.serialize();

    if (defaults)
    {
      yield "defaults=" +
            defaults.map(
              // remap for the stored format.
              type => type == "allowing" ? "whitelist" : type
            ).filter(
              type => SpecialSubscription.defaultsMap.has(type)
            ).join(" ");
    }
    if (_lastDownload)
      yield "lastDownload=" + _lastDownload;
  }
};

/**
 * A map of filter types.
 * @type {Map.<string, Array.<string>>}
 * @package
 */
exports.SpecialSubscription.defaultsMap = new Map([
  ["allowing", ["allowing"]],
  // deprecated terminology
  ["whitelist", ["allowing"]],
  ["blocking", ["blocking"]],
  ["elemhide", ["elemhide", "elemhideexception", "elemhideemulation"]]
]);

/**
 * Creates a new special subscription.
 * @param {string} [title] The title of the subscription.
 * @returns {module:subscriptionClasses.SpecialSubscription} A new special
 *   subscription.
 * @package
 */
exports.SpecialSubscription.create = function(title)
{
  let url;
  do
    url = "~user~" + Math.round(Math.random() * 1000000);
  while (Subscription.knownSubscriptions.has(url));
  return new SpecialSubscription(url, title);
};

/**
 * Creates a new special subscription and adds the given filter to it.
 *
 * Once created, the subscription acts as the default for all filters of the
 * {@link module:filterClasses.Filter#type type}.
 *
 * @param {module:filterClasses.Filter} filter The filter.
 *
 * @returns {module:subscriptionClasses.SpecialSubscription} A new special
 *   subscription.
 *
 * @package
 */
exports.SpecialSubscription.createForFilter = function(filter)
{
  let subscription = SpecialSubscription.create();
  subscription.addFilter(filter);
  for (let [type, mappedTypes] of SpecialSubscription.defaultsMap)
  {
    if (mappedTypes.includes(filter.type))
      subscription.defaults = [type];
  }
  if (!subscription.defaults)
    subscription.defaults = ["blocking"];
  return subscription;
};

let RegularSubscription =
/**
 * The `RegularSubscription` class represents a regular filter subscription.
 * @abstract
 */
exports.RegularSubscription = class RegularSubscription extends Subscription
{
  /**
   * Creates a `RegularSubscription` object.
   * @param {string} url The URL of the subscription.
   * @param {string} [title] The title of the subscription.
   * @private
   */
  constructor(url, title)
  {
    super(url, title || url);

    /**
     * The homepage of the subscription.
     * @type {?string}
     * @default <code>null</code>
     * @private
     * @see module:subscriptionClasses.RegularSubscription#homepage
     */
    this._homepage = null;

    /**
     * The last time the subscription was downloaded, in seconds since the
     * beginning of the Unix epoch.
     * @type {number}
     * @default <code>0</code>
     * @private
     * @see module:subscriptionClasses.RegularSubscription#lastDownload
     */
    this._lastDownload = 0;
  }

  /**
   * The homepage of the subscription.
   * @type {?string}
   * @default <code>null</code>
   */
  get homepage()
  {
    return this._homepage;
  }

  set homepage(value)
  {
    if (value != this._homepage)
    {
      let oldValue = this._homepage;
      this._homepage = value;
      filterNotifier.emit("subscription.homepage", this, value, oldValue);
    }
  }

  /**
   * The last time the subscription was downloaded, in seconds since the
   * beginning of the Unix epoch.
   * @type {number}
   * @default <code>0</code>
   */
  get lastDownload()
  {
    return this._lastDownload;
  }

  set lastDownload(value)
  {
    if (value != this._lastDownload)
    {
      let oldValue = this._lastDownload;
      this._lastDownload = value;
      filterNotifier.emit("subscription.lastDownload", this, value, oldValue);
    }
  }

  /**
   * Serializes the subscription for writing out on disk.
   * @yields {string}
   * @package
   */
  *serialize()
  {
    let {_homepage, _lastDownload} = this;

    yield* super.serialize();

    if (_homepage)
      yield "homepage=" + _homepage;
    if (_lastDownload)
      yield "lastDownload=" + _lastDownload;
  }
};

/**
 * Once initialized, the shared Synchronizer singleton will be stored in here.
 * @type {module:synchronizer~Synchronizer}
 */
let synchronizer = null;

let DownloadableSubscription =
/**
 * The `DownloadableSubscription` class represents a regular filter
 * subscription that is downloaded by Adblock Plus.
 */
exports.DownloadableSubscription =
class DownloadableSubscription extends RegularSubscription
{
  /**
   * Allows downloadable subscriptions to update themselves once re-enabled,
   * via receiving the Synchronizer singleton.
   * @param {module:synchronizer~Synchronizer} reference the Synchronizer
   */
  static useSynchronizer(reference)
  {
    synchronizer = reference;
  }

  /**
   * Creates a `DownloadableSubscription` object.
   * @param {string} url The URL of the subscription.
   * @param {string} [title] The title of the subscription.
   * @private
   */
  constructor(url, title)
  {
    super(url, title);

    /**
     * The status of the last download.
     * @type {?string}
     * @default <code>null</code>
     * @private
     * @see module:subscriptionClasses.DownloadableSubscription#downloadStatus
     */
    this._downloadStatus = null;

    /**
     * The last time the subscription was considered for an update, in seconds
     * since the beginning of the Unix epoch.
     * @type {number}
     * @default <code>0</code>
     * @private
     * @see module:subscriptionClasses.DownloadableSubscription#lastCheck
     */
    this._lastCheck = 0;

    /**
     * The number of download failures since the last successful download.
     * @type {number}
     * @default <code>0</code>
     * @private
     * @see module:subscriptionClasses.DownloadableSubscription#errors
     */
    this._errors = 0;

    /**
     * The last time the subscription was successfully downloaded, in seconds
     * since the beginning of the Unix epoch.
     * @type {number}
     * @default <code>0</code>
     */
    this.lastSuccess = 0;

    /**
     * The hard expiration time of the subscription, in seconds since the
     * beginning of the Unix epoch.
     * @type {number}
     * @default <code>0</code>
     */
    this.expires = 0;

    /**
     * The soft expiration time of the subscription, in seconds since the
     * beginning of the Unix epoch.
     * @type {number}
     * @default <code>0</code>
     */
    this.softExpiration = 0;

    /**
     * The version of the subscription data that was retrieved on last
     * successful download.
     * @type {number}
     * @default <code>0</code>
     */
    this.version = 0;

    /**
     * The minimal Adblock Plus version required for the subscription.
     * @type {?string}
     * @default <code>null</code>
     */
    this.requiredVersion = null;

    /**
     * The number of times the subscription has been downloaded.
     * @type {number}
     * @default <code>0</code>
     */
    this.downloadCount = 0;

    this._p = profiler(`DownloadableSubscription@${url}`);
    this._p.start();
  }

  /**
   * Whether the subscription is disabled. Once re-enabled, it ensures the
   * synchronizer downloads latest version of this subscription.
   * @type {boolean}
   * @default <code>false</code>
   */
  get disabled()
  {
    return super.disabled;
  }

  set disabled(value)
  {
    let {_disabled} = this;
    super.disabled = value;
    if (synchronizer && _disabled && !value)
      synchronizer.execute(this);
  }

  /**
   * The status of the last download.
   *
   * This is a message ID like `synchronize_ok` or
   * `synchronize_connection_error`.
   *
   * @type {?string}
   * @default <code>null</code>
   */
  get downloadStatus()
  {
    return this._downloadStatus;
  }

  set downloadStatus(value)
  {
    let oldValue = this._downloadStatus;
    this._downloadStatus = value;
    filterNotifier.emit("subscription.downloadStatus", this, value, oldValue);
  }

  /**
   * The last time the subscription was considered for an update, in seconds
   * since the beginning of the Unix epoch.
   *
   * This is used to increase the soft expiration time if the user doesn't use
   * Adblock Plus for some time.
   *
   * @type {number}
   * @default <code>0</code>
   */
  get lastCheck()
  {
    return this._lastCheck;
  }

  set lastCheck(value)
  {
    if (value != this._lastCheck)
    {
      let oldValue = this._lastCheck;
      this._lastCheck = value;
      filterNotifier.emit("subscription.lastCheck", this, value, oldValue);
    }
  }

  /**
   * The number of download failures since the last successful download.
   * @type {number}
   * @default <code>0</code>
   */
  get errors()
  {
    return this._errors;
  }

  set errors(value)
  {
    if (value != this._errors)
    {
      let oldValue = this._errors;
      this._errors = value;
      filterNotifier.emit("subscription.errors", this, value, oldValue);
    }
  }

  /**
   * Serializes the subscription for writing out on disk.
   * @yields {string}
   * @package
   */
  *serialize()
  {
    let {downloadStatus, lastSuccess, lastCheck, expires,
         softExpiration, errors, version, requiredVersion,
         downloadCount} = this;

    yield* super.serialize();

    if (downloadStatus)
      yield "downloadStatus=" + downloadStatus;
    if (lastSuccess)
      yield "lastSuccess=" + lastSuccess;
    if (lastCheck)
      yield "lastCheck=" + lastCheck;
    if (expires)
      yield "expires=" + expires;
    if (softExpiration)
      yield "softExpiration=" + softExpiration;
    if (errors)
      yield "errors=" + errors;
    if (version)
      yield "version=" + version;
    if (requiredVersion)
      yield "requiredVersion=" + requiredVersion;
    if (downloadCount)
      yield "downloadCount=" + downloadCount;
  }

  /**
   * Put a benchmarking event
   * @param {string} event benchmarking event
   */
  mark(event)
  {
    this._p.mark(event);
  }
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview `filterStorage` object responsible for managing the user's
 * subscriptions and filters.
 */

const {IO} = __webpack_require__(56);
const {Prefs} = __webpack_require__(5);
const {isActiveFilter, Filter} = __webpack_require__(0);
const {Subscription, SpecialSubscription} = __webpack_require__(2);
const {filterNotifier} = __webpack_require__(4);
const {INIParser} = __webpack_require__(57);
const {filterState} = __webpack_require__(14);

/**
 * @typedef {{exists: boolean, lastModified: number}} Stats
 */

/**
 * A cache for all source files and backup stats.
 * @type {Map<string, Stats>}
 * @private
 */
let stats = new Map();

/**
 * An asynchronous guard for multiple backups renmaing operations. It gets
 * reassigned to a new Promise that rename all backups one more time.
 * @type {Promise<void>}
 * @private
 */
let backupQueue = Promise.resolve();

/**
 * Version number of the filter storage file format.
 * @type {number}
 */
const FORMAT_VERSION = 5;

/**
 * `{@link module:filterStorage.filterStorage filterStorage}` implementation.
 */
class FilterStorage
{
  /**
   * @hideconstructor
   */
  constructor()
  {
    /**
     * Will be set to `true` after the initial
     * `{@link module:filterStorage~FilterStorage#loadFromDisk loadFromDisk()}`
     * call completes.
     * @type {boolean}
     */
    this.initialized = false;

    /**
     * Will be set to `true` if no `patterns.ini` file exists.
     * @type {boolean}
     */
    this.firstRun = false;

    /**
     * Map of properties listed in the filter storage file before the sections
     * start. Right now this should be only the format version.
     * @type {object}
     */
    this.fileProperties = Object.create(null);

    /**
     * Map of subscriptions already on the list, by their URL/identifier.
     * @type {Map.<string,module:subscriptionClasses.Subscription>}
     * @private
     */
    this._knownSubscriptions = new Map();

    /**
     * Will be set to `true` if
     * `{@link module:filterStorage~FilterStorage#saveToDisk saveToDisk()}`
     * is running (reentrance protection).
     * @type {boolean}
     * @private
     */
    this._saving = false;

    /**
     * Will be set to `true` if a
     * `{@link module:filterStorage~FilterStorage#saveToDisk saveToDisk()}`
     * call arrives while
     * `{@link module:filterStorage~FilterStorage#saveToDisk saveToDisk()}`
     * is already running (delayed execution).
     * @type {boolean}
     * @private
     */
    this._needsSave = false;

    /**
     * This property is for testing purpose only and it should never be used
     * directly via code.
     * @type {Map<string, Stats>}
     * @private
     */
    this._stats = stats;
  }

  /**
   * The version number of the `patterns.ini` format used.
   * @type {number}
   */
  get formatVersion()
  {
    return FORMAT_VERSION;
  }

  /**
   * The file containing the subscriptions.
   * @type {string}
   */
  get sourceFile()
  {
    return "patterns.ini";
  }

  /**
   * Yields subscriptions in the storage.
   * @param {?string} [filterText] The filter text for which to look. If
   *   specified, the function yields only those subscriptions that contain the
   *   given filter text. By default the function yields all subscriptions.
   * @yields {module:subscriptionClasses.Subscription}
   */
  *subscriptions(filterText = null)
  {
    if (filterText == null)
    {
      yield* this._knownSubscriptions.values();
    }
    else
    {
      for (let subscription of this._knownSubscriptions.values())
      {
        if (subscription.hasFilterText(filterText))
          yield subscription;
      }
    }
  }

  /**
   * Returns the number of subscriptions in the storage.
   * @param {?string} [filterText] The filter text for which to look. If
   *   specified, the function counts only those subscriptions that contain the
   *   given filter text. By default the function counts all subscriptions.
   * @returns {number}
   */
  getSubscriptionCount(filterText = null)
  {
    if (filterText == null)
      return this._knownSubscriptions.size;

    let count = 0;
    for (let subscription of this._knownSubscriptions.values())
    {
      if (subscription.hasFilterText(filterText))
        count++;
    }
    return count;
  }

  /**
   * Finds the filter group that a filter should be added to by default. Will
   * return `null` if this group doesn't exist yet.
   * @param {Filter} filter
   * @returns {?module:subscriptionClasses.SpecialSubscription}
   */
  getGroupForFilter(filter)
  {
    let generalSubscription = null;
    for (let subscription of this._knownSubscriptions.values())
    {
      if (subscription instanceof SpecialSubscription && !subscription.disabled)
      {
        // Always prefer specialized subscriptions
        if (subscription.isDefaultFor(filter))
          return subscription;

        // If this is a general subscription - store it as fallback
        if (!generalSubscription &&
            (!subscription.defaults || !subscription.defaults.length))
          generalSubscription = subscription;
      }
    }
    return generalSubscription;
  }

  /**
   * Checks whether a given subscription is in the storage.
   * @param {module:subscriptionClasses.Subscription} subscription
   * @returns {boolean}
   */
  hasSubscription(subscription)
  {
    return this._knownSubscriptions.has(subscription.url);
  }

  /**
   * Adds a subscription to the storage.
   * @param {module:subscriptionClasses.Subscription} subscription The
   *   subscription to be added.
   */
  addSubscription(subscription)
  {
    if (this._knownSubscriptions.has(subscription.url))
      return;

    this._knownSubscriptions.set(subscription.url, subscription);

    filterNotifier.emit("subscription.added", subscription);
  }

  /**
   * Removes a subscription from the storage.
   * @param {module:subscriptionClasses.Subscription} subscription The
   *   subscription to be removed.
   */
  removeSubscription(subscription)
  {
    if (!this._knownSubscriptions.has(subscription.url))
      return;

    this._knownSubscriptions.delete(subscription.url);

    // This should be the last remaining reference to the Subscription
    // object.
    Subscription.knownSubscriptions.delete(subscription.url);

    filterNotifier.emit("subscription.removed", subscription);
  }

  /**
   * Replaces the list of filters in a subscription with a new list.
   * @param {module:subscriptionClasses.Subscription} subscription The
   *   subscription to be updated.
   * @param {Array.<string>} filterText The new filter text.
   */
  updateSubscriptionFilters(subscription, filterText)
  {
    filterNotifier.emit("subscription.updated", subscription,
                        subscription.updateFilterText(filterText));
  }

  /**
   * Adds a user-defined filter to the storage.
   * @param {Filter} filter
   * @param {?module:subscriptionClasses.SpecialSubscription} [subscription]
   *   The subscription that the filter should be added to.
   * @param {number} [position] The position within the subscription at which
   *   the filter should be added. If not specified, the filter is added at the
   *   end of the subscription.
   */
  addFilter(filter, subscription, position)
  {
    if (!subscription)
    {
      for (let currentSubscription of this._knownSubscriptions.values())
      {
        if (currentSubscription instanceof SpecialSubscription &&
            !currentSubscription.disabled &&
            currentSubscription.hasFilterText(filter.text))
          return;   // No need to add
      }
      subscription = this.getGroupForFilter(filter);
    }
    if (!subscription)
    {
      // No group for this filter exists, create one
      subscription = SpecialSubscription.createForFilter(filter);
      this.addSubscription(subscription);
      return;
    }

    if (typeof position == "undefined")
      position = subscription.filterCount;

    subscription.insertFilterAt(filter, position);
    filterNotifier.emit("filter.added", filter, subscription, position);
  }

  /**
   * Removes a user-defined filter from the storage.
   * @param {module:filterClasses.Filter} filter
   * @param {?module:subscriptionClasses.SpecialSubscription} [subscription]
   *   The subscription that the filter should be removed from. If not
   *   specified, the filter will be removed from all subscriptions.
   * @param {number} [position] The position within the subscription at which
   *   the filter should be removed. If not specified, all instances of the
   *   filter will be removed.
   */
  removeFilter(filter, subscription, position)
  {
    let subscriptions = (
      subscription ? [subscription] : this._knownSubscriptions.values()
    );
    for (let currentSubscription of subscriptions)
    {
      if (currentSubscription instanceof SpecialSubscription &&
          (currentSubscription == subscription ||
           currentSubscription.hasFilterText(filter.text)))
      {
        let positions = [];
        if (typeof position == "undefined")
        {
          let index = -1;
          do
          {
            index = currentSubscription.findFilterIndex(filter, index + 1);
            if (index >= 0)
              positions.push(index);
          } while (index >= 0);
        }
        else
        {
          positions.push(position);
        }

        for (let j = positions.length - 1; j >= 0; j--)
        {
          let currentPosition = positions[j];
          let currentFilterText =
            currentSubscription.filterTextAt(currentPosition);
          if (currentFilterText && currentFilterText == filter.text)
          {
            currentSubscription.deleteFilterAt(currentPosition);
            filterNotifier.emit("filter.removed", filter, currentSubscription,
                                currentPosition);
          }
        }
      }
    }
  }

  /**
   * Moves a user-defined filter to a new position.
   * @param {module:filterClasses.Filter} filter
   * @param {module:subscriptionClasses.SpecialSubscription} subscription The
   *   subscription where the filter is located.
   * @param {number} oldPosition The current position of the filter.
   * @param {number} newPosition The new position of the filter.
   */
  moveFilter(filter, subscription, oldPosition, newPosition)
  {
    if (!(subscription instanceof SpecialSubscription))
      return;

    let currentFilterText = subscription.filterTextAt(oldPosition);
    if (!currentFilterText || currentFilterText != filter.text)
      return;

    newPosition = Math.min(Math.max(newPosition, 0),
                           subscription.filterCount - 1);
    if (oldPosition == newPosition)
      return;

    subscription.deleteFilterAt(oldPosition);
    subscription.insertFilterAt(filter, newPosition);
    filterNotifier.emit("filter.moved", filter, subscription, oldPosition,
                        newPosition);
  }

  /**
   * Increases the hit count for a filter by one.
   * @param {Filter} filter
   */
  increaseHitCount(filter)
  {
    if (!Prefs.savestats || !isActiveFilter(filter))
      return;

    filterState.registerHit(filter.text);
  }

  /**
   * Resets hit count for some filters.
   * @param {?Array.<Filter>} [filters] The filters to be reset. If not
   *   specified, all filters will be reset.
   */
  resetHitCounts(filters)
  {
    if (!filters)
      filters = Filter.knownFilters.values();

    for (let filter of filters)
      filterState.resetHits(filter.text);
  }

  /**
   * @callback TextSink
   * @param {string?} line
   */

  /**
   * Allows importing previously serialized filter data.
   * @param {boolean} silent If `true`, no "load" notification will be sent
   *   out.
   * @returns {TextSink} The function to be called for each line of data.
   *   Calling it with `null` as the argument finalizes the import and replaces
   *   existing data. No changes will be applied before finalization, so import
   *   can be "aborted" by forgetting this callback.
   * @package
   */
  importData(silent)
  {
    let parser = new INIParser();
    return line =>
    {
      parser.process(line);
      if (line === null)
      {
        let knownSubscriptions = new Map();
        for (let subscription of parser.subscriptions)
        {
          // Convert to the new terminology when loading.
          if (Array.isArray(subscription.defaults))
          {
            subscription.defaults.forEach((type, i, arr) =>
            {
              if (type == "whitelist")
                arr[i] = "allowing";
            });
          }
          knownSubscriptions.set(subscription.url, subscription);
        }

        this.fileProperties = parser.fileProperties;
        this._knownSubscriptions = knownSubscriptions;

        if (!silent)
          filterNotifier.emit("load");
      }
    };
  }

  /**
   * Loads all subscriptions from disk.
   * @returns {Promise} A promise resolved or rejected when loading is complete.
   * @package
   */
  async loadFromDisk()
  {
    let tryBackup = async backupIndex =>
    {
      try
      {
        await this.restoreBackup(backupIndex, true);

        if (this._knownSubscriptions.size == 0)
          return tryBackup(backupIndex + 1);
      }
      catch (error)
      {
        // Give up
      }
    };

    try
    {
      let statData = await statFile(this.sourceFile);

      if (!statData.exists)
      {
        this.firstRun = true;
        return;
      }

      let parser = this.importData(true);
      await IO.readFromFile(this.sourceFile, parser);
      parser(null);

      if (this._knownSubscriptions.size == 0)
      {
        // No filter subscriptions in the file, this isn't right.
        throw new Error("No data in the file");
      }
    }
    catch (error)
    {
      console.warn(error);
      await tryBackup(1);
    }

    this.initialized = true;
    filterNotifier.emit("load");
  }

  /**
   * Constructs the file name for a `patterns.ini` backup.
   * @param {number} backupIndex Number of the backup file (1 being the most
   *   recent).
   * @returns {string} Backup file name.
   * @package
   */
  getBackupName(backupIndex)
  {
    let [name, extension] = this.sourceFile.split(".", 2);
    return (name + "-backup" + backupIndex + "." + extension);
  }

  /**
   * Restores an automatically created backup.
   * @param {number} backupIndex Number of the backup to restore (1 being the
   *   most recent).
   * @param {boolean} silent If `true`, no "load" notification will be sent
   *   out.
   * @returns {Promise} A promise resolved or rejected when restoration is
   *   complete.
   * @package
   */
  async restoreBackup(backupIndex, silent)
  {
    let backupFile = this.getBackupName(backupIndex);
    let parser = this.importData(silent);
    await IO.readFromFile(backupFile, parser);
    parser(null);
    return this.saveToDisk();
  }

  /**
   * Generator serializing filter data and yielding it line by line.
   * @yields {string}
   */
  *exportData()
  {
    // Do not persist external subscriptions
    let subscriptions = [];
    for (let subscription of this._knownSubscriptions.values())
    {
      if (!(subscription instanceof SpecialSubscription &&
            subscription.filterCount == 0))
        subscriptions.push(subscription);
    }

    yield "# Adblock Plus preferences";
    yield "version=" + this.formatVersion;

    let saved = new Set();

    // Save subscriptions
    for (let subscription of subscriptions)
    {
      yield* subscription.serialize();
      yield* subscription.serializeFilters();
    }

    // Save filter data
    for (let subscription of subscriptions)
    {
      for (let text of subscription.filterText())
      {
        if (!saved.has(text))
        {
          yield* filterState.serialize(text);
          saved.add(text);
        }
      }
    }
  }

  /**
   * Saves all subscriptions back to disk.
   * @returns {Promise} A promise resolved or rejected when saving is complete.
   * @package
   */
  async saveToDisk()
  {
    if (this._saving)
    {
      this._needsSave = true;
      return;
    }

    this._saving = true;

    try
    {
      let {patternsbackups} = Prefs;
      let isBackupRequired = async() =>
      {
        // First check whether we need to create a backup
        if (patternsbackups <= 0)
          return false;

        let statData = await statFile(this.sourceFile);
        if (!statData.exists)
          return false;

        let backupStatData = await statFile(this.getBackupName(1));
        if (backupStatData.exists &&
            (Date.now() - backupStatData.lastModified) / 3600000 <
              Prefs.patternsbackupinterval)
          return false;

        return true;
      };

      if (await isBackupRequired())
      {
        try
        {
          // if patternsbackups is 1 just create it, otherwise create a
          // backup-0 that will be shifted among others later on
          let i = patternsbackups > 1 ? 0 : 1;
          await renameFile(this.sourceFile, this.getBackupName(i));

          // if there is more than a backup, backup-0 up to backup-X need to be
          // renamed but without blocking this callback
          if (patternsbackups > 1)
          {
            // keep queueing backups as these come, considering backup1 and
            // backup 0 are always safe thanks to the this._saving flag
            backupQueue = backupQueue.then(() => new Promise(resolve =>
            {
              let renameAll = async index =>
              {
                if (index > 0)
                {
                  try
                  {
                    let source = this.getBackupName(index - 1);
                    let dest = this.getBackupName(index);
                    await renameFile(source, dest);
                  }
                  catch (error)
                  {
                    // Expected error, backup file doesn't exist.
                  }
                  renameAll(index - 1);
                }
                else
                {
                  resolve();
                }
              };
              renameAll(patternsbackups);
            }));
          }
        }
        catch (error)
        {
          // This is actually an unexpected error that could happen only if
          // the disk had issues in renaming the source file.
          console.warn(error);
        }
      }
    }
    catch (error)
    {
      // Errors during backup creation shouldn't prevent writing filters.
      console.warn(error);
    }

    try
    {
      await IO.writeToFile(this.sourceFile, this.exportData());
      stats.set(this.sourceFile, {exists: true, lastModified: Date.now()});
      filterNotifier.emit("save");
    }
    catch (error)
    {
      // If saving failed, report error but continue - we still have to process
      // flags.
      console.warn(error);
      stats.delete(this.sourceFile);
    }

    this._saving = false;
    if (this._needsSave)
    {
      this._needsSave = false;
      this.saveToDisk();
    }
  }

  /**
   * @typedef FileInfo
   * @type {object}
   * @property {number} index
   * @property {number} lastModified
   */

  /**
   * Returns a promise resolving in a list of existing backup files.
   * @returns {Promise.<Array.<FileInfo>>}
   * @package
   */
  async getBackupFiles()
  {
    let backups = [];

    let checkBackupFile = async index =>
    {
      try
      {
        let statData = await statFile(this.getBackupName(index));
        if (!statData.exists)
          return backups;

        backups.push({
          index,
          lastModified: statData.lastModified
        });

        return checkBackupFile(index + 1);
      }
      catch (error)
      {
        // Something went wrong, return whatever data we got so far.
        console.warn(error);
        return backups;
      }
    };

    return checkBackupFile(1);
  }
}

/**
 * Reads the user's filters from disk, manages them in memory, and writes them
 * back to disk.
 * @type {module:filterStorage~FilterStorage}
 */
exports.filterStorage = new FilterStorage();

/**
 * Given a path, return its stats, if known, or a Stats object with properties
 * exists = false and lastModified = 0.
 * @param {string} path
 * @returns {Stats}
 */
async function statFile(path)
{
  let known = stats.get(path);
  if (known)
    return known;

  try
  {
    known = await IO.statFile(path);
  }
  catch (error)
  {
    known = {exists: false, lastModified: 0};
  }
  stats.set(path, known);
  return known;
}

/**
 * Given a source path and a destination path, tries to rename the source and,
 * if it succeed, remove the source from the stats and set stats for dest.
 * @param {string} source
 * @param {string} dest
 */
async function renameFile(source, dest)
{
  await IO.renameFile(source, dest);
  stats.delete(source);
  stats.set(dest, {exists: true, lastModified: Date.now()});
}


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview This component manages listeners and calls them to distribute
 * messages about filter changes.
 */

const {EventEmitter} = __webpack_require__(12);

/**
 * This object allows registering and triggering listeners for filter events.
 * @type {module:events.EventEmitter}
 */
exports.filterNotifier = new EventEmitter();


/***/ }),
/* 5 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Prefs", function() { return Prefs; });
/* harmony import */ var info__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7);
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12);
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _messaging_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(1);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module prefs */





const keyPrefix = "pref:";

let eventEmitter = new _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1__["EventEmitter"]();
let overrides = Object.create(null);

/** @lends module:prefs.Prefs */
let defaults = Object.create(null);

/**
 * @see https://adblockplus.org/en/preferences#analytics
 * @type {object}
 */
defaults.analytics = {
  trustedHosts: ["adblockplus.org", "notification.adblockplus.org",
                 "easylist-downloads.adblockplus.org"]
};
/**
 * The application version as set during initialization. Used to detect updates.
 *
 * @type {string}
 */
defaults.currentVersion = "";
/**
 * @see https://adblockplus.org/en/preferences#patternsbackups
 * @type {number}
 */
defaults.patternsbackups = 0;
/**
 * @see https://adblockplus.org/en/preferences#patternsbackupinterval
 * @type {number}
 */
defaults.patternsbackupinterval = 24;
/**
 * Only for compatibility with core code. Please do not change!
 *
 * @type {boolean}
 */
defaults.savestats = false;
/**
 * @see https://adblockplus.org/en/preferences#subscriptions_fallbackerrors
 * @type {number}
 */
defaults.subscriptions_fallbackerrors = 5;
/**
 * @see https://adblockplus.org/en/preferences#subscriptions_fallbackurl
 * @type {string}
 */
defaults.subscriptions_fallbackurl = "https://adblockplus.org/getSubscription?version=%VERSION%&url=%SUBSCRIPTION%&downloadURL=%URL%&error=%ERROR%&responseStatus=%RESPONSESTATUS%";
/**
 * @see https://adblockplus.org/en/preferences#subscriptions_autoupdate
 * @type {boolean}
 */
defaults.subscriptions_autoupdate = true;
/**
 * @see https://adblockplus.org/en/preferences#subscriptions_exceptionsurl
 * @type {string}
 */
defaults.subscriptions_exceptionsurl = "https://easylist-downloads.adblockplus.org/exceptionrules.txt";
/**
 * @see https://adblockplus.org/en/preferences#subscriptions_exceptionsurl_privacy
 * @type {string}
 */
defaults.subscriptions_exceptionsurl_privacy = "https://easylist-downloads.adblockplus.org/exceptionrules-privacy-friendly.txt";
/**
 * Used to ensure the anti-circumvention subscription is opted in by default.
 * @type {boolean}
 */
defaults.subscriptions_addedanticv = false;
/**
 * @see https://adblockplus.org/en/preferences#documentation_link
 * @type {string}
 */
defaults.documentation_link = "https://adblockplus.org/redirect?link=%LINK%&lang=%LANG%";
/**
 * @see https://adblockplus.org/en/preferences#notificationdata
 * @type {object}
 */
defaults.notificationdata = {};
/**
 * @see https://adblockplus.org/en/preferences#notificationurl
 * @type {string}
 */
defaults.notificationurl = "https://notification.adblockplus.org/notification.json";
/**
 * The total number of requests blocked by the extension.
 *
 * @type {number}
 */
defaults.blocked_total = 0;
/**
 * Whether to show a badge in the toolbar icon indicating the number
 * of blocked ads.
 *
 * @type {boolean}
 */
defaults.show_statsinicon = true;
/**
 * Whether to show the number of blocked ads in the popup.
 *
 * @type {boolean}
 */
defaults.show_statsinpopup = true;
/**
 * Whether to show the "Block element" context menu entry.
 *
 * @type {boolean}
 */
defaults.shouldShowBlockElementMenu = true;

/**
 * Whether to show tracking warning in options page when both
 * Acceptable Ads and subscription of type "Privacy" are enabled.
 *
 * @type {boolean}
 */
defaults.ui_warn_tracking = true;

/**
 * Notification categories to be ignored.
 *
 * @type {string[]}
 */
defaults.notifications_ignoredcategories = [];

/**
 * Whether to show the developer tools panel.
 *
 * @type {boolean}
 */
defaults.show_devtools_panel = true;

/**
 * Prevents unsolicited UI elements from showing up after installation. This
 * preference isn't set by the extension but can be pre-configured externally.
 *
 * @see https://adblockplus.org/development-builds/suppressing-the-first-run-page-on-chrome
 * @type {boolean}
 */
defaults.suppress_first_run_page = false;

/**
 * Additonal subscriptions to be automatically added when the extension is
 * loaded. This preference isn't set by the extension but can be pre-configured
 * externally.
 *
 * @type {string[]}
 */
defaults.additional_subscriptions = [];

/**
 * The version of major updates that the user is aware of. If it's too low,
 * the updates page will be shown to inform the user about intermediate changes.
 *
 * @type {number}
 */
defaults.last_updates_page_displayed = 0;

/**
 * Causes elements targeted by element hiding (and element hiding emulation)
 * to be highlighted instead of hidden.
 *
 * @type {boolean}
 */
defaults.elemhide_debug = false;

/**
 * Address of page to open on first run.
 *
 * @type {string}
 */
defaults.remote_first_run_page_url = "https://welcome.adblockplus.org/%LANG%/installed?an=%ADDON_NAME%&av=%ADDON_VERSION%&ap=%APPLICATION_NAME%&apv=%APPLICATION_VERSION%&p=%PLATFORM_NAME%&pv=%PLATFORM_VERSION%";

/**
  * @namespace
  * @static
  */
let Prefs = {
  /**
   * Sets the given preference.
   *
   * @param {string} preference
   * @param {any}    value
   * @return {Promise} A promise that resolves when the underlying
                       browser.storage.local.set/remove() operation completes
   */
  set(preference, value)
  {
    let defaultValue = defaults[preference];

    if (typeof value != typeof defaultValue)
      throw new Error("Attempt to change preference type");

    if (value == defaultValue)
    {
      let oldValue = overrides[preference];
      delete overrides[preference];

      // Firefox 66 fails to emit storage.local.onChanged events for falsey
      // values. https://bugzilla.mozilla.org/show_bug.cgi?id=1541449
      if (!oldValue &&
          info__WEBPACK_IMPORTED_MODULE_0__["platform"] == "gecko" && parseInt(info__WEBPACK_IMPORTED_MODULE_0__["platformVersion"], 10) == 66)
        onChanged({[prefToKey(preference)]: {oldValue}}, "local");

      return browser.storage.local.remove(prefToKey(preference));
    }

    overrides[preference] = value;
    return (customSave.get(preference) || savePref)(preference);
  },

  /**
   * Adds a callback that is called when the
   * value of a specified preference changed.
   *
   * @param {string}   preference
   * @param {function} callback
   */
  on(preference, callback)
  {
    eventEmitter.on(preference, callback);
  },

  /**
   * Removes a callback for the specified preference.
   *
   * @param {string}   preference
   * @param {function} callback
   */
  off(preference, callback)
  {
    eventEmitter.off(preference, callback);
  },

  /**
   * Reads the documentation_link preference and substitutes placeholders.
   *
   * @param {string} linkID
   * @return {string}
   */
  getDocLink(linkID)
  {
    return this.documentation_link
      .replace(/%LINK%/g, linkID)
      .replace(/%LANG%/g, browser.i18n.getUILanguage());
  },

  /**
   * A promise that is fullfilled when all preferences have been loaded.
   * Wait for this promise to be fulfilled before using preferences during
   * extension initialization.
   *
   * @type {Promise}
   */
  untilLoaded: null
};

function keyToPref(key)
{
  if (key.indexOf(keyPrefix) != 0)
    return null;

  return key.substr(keyPrefix.length);
}

function prefToKey(pref)
{
  return keyPrefix + pref;
}

function savePref(pref)
{
  return browser.storage.local.set({[prefToKey(pref)]: overrides[pref]});
}

let customSave = new Map();
if (info__WEBPACK_IMPORTED_MODULE_0__["platform"] == "gecko" && parseInt(info__WEBPACK_IMPORTED_MODULE_0__["platformVersion"], 10) < 66)
{
  // Saving one storage value causes all others to be saved as well for
  // Firefox versions <66. Make sure that updating ad counter doesn't cause
  // the filters data to be saved frequently as a side-effect.
  let promise = null;
  customSave.set("blocked_total", pref =>
  {
    if (!promise)
    {
      promise = new Promise((resolve, reject) =>
      {
        setTimeout(
          () =>
          {
            promise = null;
            savePref(pref).then(resolve, reject);
          },
          60 * 1000
        );
      });
    }
    return promise;
  });
}

function addPreference(pref)
{
  Object.defineProperty(Prefs, pref, {
    get() { return (pref in overrides ? overrides : defaults)[pref]; },
    set(value)
    {
      Prefs.set(pref, value);
    },
    enumerable: true
  });
}

function onChanged(changes)
{
  for (let key in changes)
  {
    let pref = keyToPref(key);
    if (pref && pref in defaults)
    {
      let change = changes[key];
      if ("newValue" in change && change.newValue != defaults[pref])
        overrides[pref] = change.newValue;
      else
        delete overrides[pref];

      eventEmitter.emit(pref);
    }
  }
}

async function init()
{
  let prefs = Object.keys(defaults);
  prefs.forEach(addPreference);

  let isEdgeChromium = info__WEBPACK_IMPORTED_MODULE_0__["application"] == "edge" &&
                       info__WEBPACK_IMPORTED_MODULE_0__["platform"] == "chromium";

  // When upgrading from EdgeHTML to Edge Chromium (v79) data stored in
  // browser.storage.local gets corrupted.
  // To fix it, we have to call JSON.parse twice.
  // See: https://gitlab.com/eyeo/adblockplus/adblockpluschrome/issues/152
  if (isEdgeChromium)
  {
    let items = await browser.storage.local.get(null);

    let fixedItems = {};
    for (let key in items)
    {
      if (typeof items[key] == "string")
      {
        try
        {
          fixedItems[key] = JSON.parse(JSON.parse(items[key]));
        }
        catch (e) {}
      }
    }

    await browser.storage.local.set(fixedItems);
  }

  {
    let items = await browser.storage.local.get(prefs.map(prefToKey));
    for (let key in items)
      overrides[keyToPref(key)] = items[key];
  }

  if ("managed" in browser.storage)
  {
    try
    {
      let items = await browser.storage.managed.get(null);
      for (let key in items)
        defaults[key] = items[key];
    }
    catch (e)
    {
      // Opera doesn't support browser.storage.managed, but instead of simply
      // removing the API, it gives an asynchronous error which we ignore here.
    }
  }

  browser.storage.onChanged.addListener(onChanged);

  // Migrate the first and current version from notificationdata over to the
  // new analytics preference for existing users. The analytics module takes
  // care of new users.
  if (!("data" in Prefs.analytics) &&
      "firstVersion" in Prefs.notificationdata &&
      Prefs.notificationdata.firstVersion != "0")
  {
    // JSON values aren't saved unless they are assigned a different object
    // and we don't want to mutate the default value of Prefs.analytics.
    let notificationdata = JSON.parse(JSON.stringify(Prefs.notificationdata));
    let analytics = JSON.parse(JSON.stringify(Prefs.analytics));

    // Migrate the version data.
    analytics.data = {
      firstVersion: notificationdata.firstVersion,
      currentVersion: notificationdata.data.version
    };
    delete notificationdata.firstVersion;

    // Write the changes back to Prefs and storage.
    Prefs.notificationdata = notificationdata;
    Prefs.analytics = analytics;
  }
}

Prefs.untilLoaded = init();

/**
 * Returns the value of the given preference key.
 *
 * @event "prefs.get"
 * @property {string} key - The preference key.
 * @returns {string|string[]|number|boolean}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_2__["port"].on("prefs.get", (message, sender) => Prefs[message.key]);

/**
 * Sets the value of the given preference key to the given value.
 *
 * @event "prefs.set"
 * @property {string} key - The preference key.
 * @property {string} key - The value to set.
 * @returns {string|string[]|number|boolean|undefined}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_2__["port"].on("prefs.set", async(message, sender) =>
{
  if (message.key == "notifications_ignoredcategories")
  {
    let {notifications} =
      await Promise.resolve(/* import() */).then(__webpack_require__.t.bind(null, 22, 7));
    return notifications.toggleIgnoreCategory("*", !!message.value);
  }

  return Prefs[message.key] = message.value;
});

/**
 * Toggles the value of the given preference key.
 *
 * @event "prefs.toggle"
 * @property {string} key - The preference key
 * @returns {?boolean}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_2__["port"].on("prefs.toggle", async(message, sender) =>
{
  if (message.key == "notifications_ignoredcategories")
  {
    let {notifications} =
      await Promise.resolve(/* import() */).then(__webpack_require__.t.bind(null, 22, 7));
    return notifications.toggleIgnoreCategory("*");
  }

  return Prefs[message.key] = !Prefs[message.key];
});

/**
 * Returns a link to a page on our website, in the user's locale if possible.
 *
 * @event "prefs.getDocLink"
 * @property {string} link
 *   The link ID to generate the doc link for.
 * @returns {string}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_2__["port"].on("prefs.getDocLink", (message, sender) =>
{
  let {application, platform} = info__WEBPACK_IMPORTED_MODULE_0__;
  if (platform == "chromium" && application != "opera" && application != "edge")
    application = "chrome";
  else if (platform == "gecko")
    application = "firefox";

  return Prefs.getDocLink(message.link.replace("{browser}", application));
});


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



let contentTypes =
/**
 * Content types for request blocking and allowing (allowlisting).
 *
 * There are two kinds of content types: resource types, and special
 * (non-resource) types.
 *
 * Resource types include web resources like scripts, images, and so on.
 *
 * Special types include filter options for popup blocking and CSP header
 * injection as well as flags for allowing documents.
 *
 * By default a filter matches any resource type, but if a filter has an
 * explicit resource type, special option, or allowing flag, like
 * `$script`, `$popup`, or `$elemhide`, then it matches only the given type,
 * option, or flag.
 *
 * @type {object}
 *
 * @public
 */
exports.contentTypes = {
  // Types of web resources.
  OTHER: 1,
  SCRIPT: 2,
  IMAGE: 4,
  STYLESHEET: 8,
  OBJECT: 16,
  SUBDOCUMENT: 32,
  WEBSOCKET: 128,
  WEBRTC: 256,
  PING: 1024,
  XMLHTTPREQUEST: 2048, // 1 << 11

  MEDIA: 16384,
  FONT: 32768, // 1 << 15

  // Special filter options.
  POPUP: 1 << 24,
  CSP: 1 << 25,
  HEADER: 1 << 26,

  // Allowing flags.
  DOCUMENT: 1 << 27,
  GENERICBLOCK: 1 << 28,
  ELEMHIDE: 1 << 29,
  GENERICHIDE: 1 << 30
};

// Backwards compatibility.
contentTypes.BACKGROUND = contentTypes.IMAGE;
contentTypes.XBL = contentTypes.OTHER;
contentTypes.DTD = contentTypes.OTHER;

const RESOURCE_TYPES =
/**
 * Bitmask for resource types like `$script`, `$image`, `$stylesheet`, and so
 * on.
 *
 * If a filter has no explicit content type, it applies to all resource types
 * (but not to any {@link module:contentTypes.SPECIAL_TYPES special types}).
 *
 * @const {number}
 *
 * @package
 */
// The first 24 bits are reserved for resource types like "script", "image",
// and so on.
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webRequest/ResourceType
exports.RESOURCE_TYPES = (1 << 24) - 1;

const SPECIAL_TYPES = ~RESOURCE_TYPES & (1 << 31) - 1;
/**
 * Bitmask for special "types" (options and flags) like `$csp`, `$elemhide`,
 * and so on.
 *
 * @const {number}
 *
 * @package
 */
exports.SPECIAL_TYPES = SPECIAL_TYPES;

/**
 * Bitmask for "types" (flags) that are for exception rules only, like
 * `$document`, `$elemhide`, and so on.
 *
 * @const {number}
 *
 * @package
 */
exports.ALLOWING_TYPES = contentTypes.DOCUMENT |
                         contentTypes.GENERICBLOCK |
                         contentTypes.ELEMHIDE |
                         contentTypes.GENERICHIDE;

/**
 * Yields individual types from a filter's type mask.
 *
 * @param {number} contentType A filter's type mask.
 * @param {number} [selection] Which types to yield.
 *
 * @generator
 * @yields {number}
 *
 * @package
 */
exports.enumerateTypes = function* enumerateTypes(contentType, selection = ~0)
{
  for (let mask = contentType & selection, bitIndex = 0;
       mask != 0; mask >>>= 1, bitIndex++)
  {
    if ((mask & 1) != 0)
    {
      // Note: The zero-fill right shift by zero is necessary for dropping the
      // sign.
      yield 1 << bitIndex >>> 0;
    }
  }
};


/***/ }),
/* 7 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addonName", function() { return addonName; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addonVersion", function() { return addonVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "application", function() { return application; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applicationVersion", function() { return applicationVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "platform", function() { return platform; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "platformVersion", function() { return platformVersion; });
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

let addonName = "adblockchrome";
let addonVersion = "4.44.0";
let application = null;
let applicationVersion;
let platform = "chromium";
let platformVersion = null;

let regexp = /(\S+)\/(\S+)(?:\s*\(.*?\))?/g;
let match;

while (match = regexp.exec(navigator.userAgent))
{
  let app = match[1];
  let ver = match[2];

  if (app == "Chrome")
  {
    platformVersion = ver;
  }
  else if (app != "Mozilla" && app != "AppleWebKit" && app != "Safari")
  {
    // For compatibility with legacy websites, Chrome's UA
    // also includes a Mozilla, AppleWebKit and Safari token.
    // Any further name/version pair indicates a fork.
    application = app == "OPR" ? "opera" : app.toLowerCase();
    applicationVersion = ver;
  }
}

// not a Chromium-based UA, probably modifed by the user
if (!platformVersion)
{
  application = "unknown";
  applicationVersion = platformVersion = "0";
}

// no additional name/version, so this is upstream Chrome
if (!application)
{
  application = "chrome";
  applicationVersion = platformVersion;
}


/***/ }),
/* 8 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "allowlistedDomainRegexp", function() { return allowlistedDomainRegexp; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "checkAllowlisted", function() { return checkAllowlisted; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "listAllowlistingFilters", function() { return listAllowlistingFilters; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getKey", function() { return getKey; });
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
/* harmony import */ var _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(14);
/* harmony import */ var _adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3);
/* harmony import */ var _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _url_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(13);
/* harmony import */ var _messaging_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(1);
/* harmony import */ var _hitLogger_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(11);
/* harmony import */ var _adblockpluscore_lib_rsa_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(46);
/* harmony import */ var _adblockpluscore_lib_rsa_js__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_rsa_js__WEBPACK_IMPORTED_MODULE_9__);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module allowlisting */












let sitekeys = new ext.PageMap();
let allowlistedDomainRegexp = /^@@\|\|([^/:]+)\^\$document$/;

function match(page, url, typeMask, docDomain, sitekey)
{
  let filter = _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__["defaultMatcher"].match(url, typeMask, docDomain, sitekey);

  if (filter && page)
    Object(_hitLogger_js__WEBPACK_IMPORTED_MODULE_8__["logAllowlistedDocument"])(page.id, url.href, typeMask, docDomain, filter);

  return filter;
}

function* frameDetails(page, frame, originUrl, typeMask)
{
  if (frame || originUrl)
  {
    while (frame)
    {
      let parentFrame = frame.parent;

      yield [frame.url, typeMask,
             Object(_url_js__WEBPACK_IMPORTED_MODULE_6__["extractHostFromFrame"])(parentFrame, originUrl) || frame.url.hostname,
             getKey(page, frame, originUrl)];

      frame = parentFrame;
    }

    if (originUrl)
    {
      yield [originUrl, typeMask, originUrl.hostname,
             getKey(null, null, originUrl)];
    }
  }
  else if (page)
  {
    yield [page.url, typeMask, page.url.hostname, null];
  }
}

/**
 * Gets the active allowing filter for the document associated
 * with the given page/frame, or null if it's not allowlisted.
 *
 * @param {?Page}   page
 * @param {?Frame} [frame]
 * @param {?URL}   [originUrl]
 * @param {number} [typeMask=contentTypes.DOCUMENT]
 * @return {?AllowingFilter}
 */
function checkAllowlisted(page, frame, originUrl,
                                 typeMask = _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].DOCUMENT)
{
  for (let details of frameDetails(page, frame, originUrl, typeMask))
  {
    let filter = match(page, ...details);
    if (filter)
      return filter;
  }
}

/**
 * Returns all allowing filters that apply the document associated
 * with the given page/frame.
 *
 * @param {?Page}   page
 * @param {?Frame} [frame]
 * @param {?URL}   [originUrl]
 * @param {number} [typeMask=contentTypes.DOCUMENT]
 * @return {Array.<AllowingFilter>}
 */
function listAllowlistingFilters(page, frame, originUrl,
                                        typeMask = _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].DOCUMENT)
{
  let filters = new Set([]);

  for (let details of frameDetails(page, frame, originUrl, typeMask))
  {
    let {allowing} = _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__["defaultMatcher"].search(...details, false, "allowing");
    for (let filter of allowing)
      filters.add(filter);
  }

  return Array.from(filters);
}

/**
 * @typedef {object} filtersIsAllowlistedResult
 * @property {boolean} hostname
 *   True if an allowing filter for an entire domain matches the given page.
 * @property {boolean} page
 *   True if an allowing filter _not_ for an entire domain matches the given
 *   page.
 */

/**
 * Checks if the given page is allowlisted.
 *
 * @event "filters.isWhitelisted"
 * @returns {filtersIsAllowlistedResult}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_7__["port"].on("filters.isWhitelisted", message =>
{
  let pageAllowlisted = false;
  let hostnameAllowlisted = false;

  for (let filter of listAllowlistingFilters(new ext.Page(message.tab)))
  {
    if (allowlistedDomainRegexp.test(filter.text))
      hostnameAllowlisted = true;
    else
      pageAllowlisted = true;

    if (pageAllowlisted && hostnameAllowlisted)
      break;
  }

  return {hostname: hostnameAllowlisted, page: pageAllowlisted};
});

/**
 * Adds an allowing filter for the given page's hostname, if it is not
 * already allowlisted. Note: If a disabled allowing filter exists, we
 * enable that instead.
 *
 * @event "filters.whitelist"
 * @property {boolean} [singlePage=false]
 *   If true we add an allowing filter for the given page's URL instead.
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_7__["port"].on("filters.whitelist", message =>
{
  let page = new ext.Page(message.tab);
  let filter;
  if (!message.singlePage)
  {
    let host = page.url.hostname.replace(/^www\./, "");
    filter = _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__["Filter"].fromText("@@||" + host + "^$document");
  }
  else
  {
    // We generate a filter which only applies to the same protocol (e.g. http)
    // and subdomain, but one which doesn't consider the exact query string or
    // fragment.
    // Our logic here is taken from the legacy Firefox extension.
    // See https://hg.adblockplus.org/adblockplus/file/tip/lib/ui.js#l1517
    let ending = "|";
    page.url.hash = "";
    if (page.url.search && page.url.search.includes("&"))
    {
      page.url.search = "";
      ending = "?";
    }
    filter = _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__["Filter"].fromText("@@|" + page.url.href + ending + "$document");
  }

  _adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_4__["filterState"].setEnabled(filter.text, true);
  if (_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_5__["filterStorage"].getSubscriptionCount(filter.text) == 0)
    _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_5__["filterStorage"].addFilter(filter);
});

/**
 * Remove any allowing filters which apply to the given page's URL.
 *
 * @event "filters.unwhitelist"
 * @property {boolean} [singlePage=false]
 *   If true we only remove allowing filters which are not for an entire
 *   domain.
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_7__["port"].on("filters.unwhitelist", message =>
{
  let page = new ext.Page(message.tab);
  for (let filter of listAllowlistingFilters(page))
  {
    if (message.singlePage && allowlistedDomainRegexp.test(filter.text))
      continue;

    _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_5__["filterStorage"].removeFilter(filter);
    if (_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_5__["filterStorage"].getSubscriptionCount(filter.text) != 0)
      _adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_4__["filterState"].setEnabled(filter.text, false);
  }
});

function revalidateAllowlistingState(page)
{
  _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_3__["filterNotifier"].emit(
    "page.AllowlistingStateRevalidate",
    page, checkAllowlisted(page)
  );
}

_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_3__["filterNotifier"].on("filter.behaviorChanged", async() =>
{
  let tabs = await browser.tabs.query({});
  for (let tab of tabs)
    revalidateAllowlistingState(new ext.Page(tab));
});

ext.pages.onLoading.addListener(revalidateAllowlistingState);

/**
 * Gets the public key, previously recorded for the given page
 * and frame, to be considered for the $sitekey filter option.
 *
 * @param {?Page}   page
 * @param {?Frame}  frame
 * @param {URL}    [originUrl]
 * @return {string}
 */
function getKey(page, frame, originUrl)
{
  if (page)
  {
    let keys = sitekeys.get(page);
    if (keys)
    {
      for (; frame; frame = frame.parent)
      {
        let key = keys.get(frame.url.href);
        if (key)
          return key;
      }
    }
  }

  if (originUrl)
  {
    for (let keys of sitekeys._map.values())
    {
      let key = keys.get(originUrl.href);
      if (key)
        return key;
    }
  }

  return null;
}

function checkKey(token, url)
{
  let parts = token.split("_");
  if (parts.length < 2)
    return false;

  let key = parts[0].replace(/=/g, "");
  let signature = parts[1];
  let data = url.pathname + url.search + "\0" +
             url.host + "\0" +
             self.navigator.userAgent;
  if (!Object(_adblockpluscore_lib_rsa_js__WEBPACK_IMPORTED_MODULE_9__["verifySignature"])(key, signature, data))
    return false;

  return key;
}

function recordKey(key, page, url)
{
  let keys = sitekeys.get(page);
  if (!keys)
  {
    keys = new Map();
    sitekeys.set(page, keys);
  }
  keys.set(url.href, key);
}

/**
 * Record the given sitekey if it is valid.
 *
 * @event "filters.addKey"
 * @property {string} token - The sitekey token found in the document element's
 *                            data-adblockkey attribute.
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_7__["port"].on("filters.addKey", (message, sender) =>
{
  let key = checkKey(message.token, sender.frame.url);
  if (key)
    recordKey(key, sender.page, sender.frame.url);
});

function onHeadersReceived(details)
{
  let page = new ext.Page({id: details.tabId});

  for (let header of details.responseHeaders)
  {
    if (header.name.toLowerCase() == "x-adblock-key" && header.value)
    {
      let url = new URL(details.url);
      let key = checkKey(header.value, url);
      if (key)
      {
        recordKey(key, page, url);
        break;
      }
    }
  }
}

if (typeof browser == "object")
{
  browser.webRequest.onHeadersReceived.addListener(
    onHeadersReceived,
    {
      urls: ["http://*/*", "https://*/*"],
      types: ["main_frame", "sub_frame"]
    },
    ["responseHeaders"]
  );
}


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



const {Cache} = __webpack_require__(24);

const publicSuffixes = __webpack_require__(52);

/**
 * Map of public suffixes to their offsets.
 * @type {Map.<string,number>}
 */
let publicSuffixMap = buildPublicSuffixMap();

/**
 * Cache of domain maps.
 *
 * The domains part of filter text (e.g. `example.com,~mail.example.com`) is
 * often repeated across filters. This cache enables deduplication of the
 * `Map` objects that specify on which domains the filter does and does not
 * apply, which reduces memory usage and improves performance.
 *
 * @type {Map.<string, Map.<string, boolean>>}
 */
let domainsCache = new Cache(1000);

/**
 * Builds a map of public suffixes to their offsets.
 * @returns {Map.<string,number>}
 */
function buildPublicSuffixMap()
{
  let map = new Map();

  for (let key in publicSuffixes)
    map.set(key, publicSuffixes[key]);

  return map;
}

/**
 * A `URLInfo` object represents information about a URL.
 *
 * It is returned by `{@link module:url.parseURL parseURL()}`.
 */
class URLInfo
{
  /**
   * Creates a `URLInfo` object.
   *
   * @param {string} href The entire URL.
   * @param {string} protocol The protocol scheme of the URL, including the
   *   final `:`.
   * @param {string} [hostname] The hostname of the URL.
   *
   * @private
   */
  constructor(href, protocol, hostname = "")
  {
    this._href = href;
    this._protocol = protocol;
    this._hostname = hostname;
  }

  /**
   * The entire URL.
   * @type {string}
   */
  get href()
  {
    return this._href;
  }

  /**
   * The protocol scheme of the URL, including the final `:`.
   * @type {string}
   */
  get protocol()
  {
    return this._protocol;
  }

  /**
   * The hostname of the URL.
   * @type {string}
   */
  get hostname()
  {
    return this._hostname;
  }

  /**
   * Returns the entire URL.
   * @returns {string} The entire URL.
   */
  toString()
  {
    return this._href;
  }
}

let parseURL =
/**
 * Parses a URL to extract the protocol and the hostname.
 *
 * __This is a lightweight alternative to the native `URL` object intended for
 * use primarily within Adblock Plus. Unlike the `URL` object, the `parseURL()`
 * function is not robust and will give incorrect results for invalid URLs. Use
 * this function with valid,
 * [normalized](https://url.spec.whatwg.org/#concept-basic-url-parser),
 * properly encoded (IDNA, etc.) URLs only.__
 *
 * @param {string} url The URL.
 *
 * @returns {module:url~URLInfo} Information about the URL.
 *
 * @public
 */
exports.parseURL = function parseURL(url)
{
  let match = /^([^:]+:)(?:\/\/(?:[^/]*@)?(\[[^\]]*\]|[^:/]+))?/.exec(url);
  return new URLInfo(url, match[1], match[2]);
};

let domainSuffixes =
/**
 * Yields all suffixes for a domain.
 *
 * For example, given the domain `www.example.com`, this function yields
 * `www.example.com`, `example.com`, and `com`, in that order.
 *
 * If the domain ends with a dot, the dot is ignored.
 *
 * @param {string} domain The domain.
 * @param {boolean} [includeBlank] Whether to include the blank suffix at the
 *   end.
 *
 * @generator
 * @yields {string} The next suffix for the domain.
 *
 * @package
 */
exports.domainSuffixes = function* domainSuffixes(domain, includeBlank = false)
{
  // Since any IP address is already expected to be normalized, there's no need
  // to validate it.
  if (isIPAddress(domain))
  {
    yield domain;
  }
  else
  {
    if (domain[domain.length - 1] == ".")
      domain = domain.substring(0, domain.length - 1);

    while (domain != "")
    {
      yield domain;

      let dotIndex = domain.indexOf(".");
      domain = dotIndex == -1 ? "" : domain.substr(dotIndex + 1);
    }
  }

  if (includeBlank)
    yield "";
};

/**
 * Checks whether the given hostname refers to
 * {@link https://en.wikipedia.org/wiki/Localhost localhost}.
 *
 * If the hostname is `localhost`, `127.0.0.1`, or `[::1]`, the function
 * returns `true`; otherwise, it returns `false`.
 *
 * @param {string} hostname The hostname.
 *
 * @returns {boolean} Whether the hostname refers to localhost.
 *
 * @package
 */
exports.isLocalhost = function isLocalhost(hostname)
{
  return hostname == "localhost" || hostname == "127.0.0.1" ||
         hostname == "[::1]";
};

/**
 * Checks whether the given hostname is an IP address.
 *
 * Unlike `{@link module:url~isValidIPv4Address isValidIPv4Address()}`, this
 * function only checks whether the hostname _looks like_ an IP address. Use
 * this function with valid, normalized, properly encoded (IDNA) hostnames
 * only.
 *
 * @param {string} hostname An IDNA-encoded hostname.
 *
 * @returns {boolean} Whether the hostname is an IP address.
 */
function isIPAddress(hostname)
{
  // Does it look like an IPv6 address?
  if (hostname[0] == "[" && hostname[hostname.length - 1] == "]")
    return true;

  // Note: The first condition helps us avoid the more expensive regular
  // expression match for most hostnames.
  return hostname[hostname.length - 1] >= 0 &&
         /^\d+\.\d+\.\d+\.\d+$/.test(hostname);
}

/**
 * Checks whether a given address is a valid IPv4 address.
 *
 * Only a normalized IPv4 address is considered valid. e.g. `0x7f.0x0.0x0.0x1`
 * is invalid, whereas `127.0.0.1` is valid.
 *
 * @param {string} address The address to check.
 *
 * @returns {boolean} Whether the address is a valid IPv4 address.
 */
function isValidIPv4Address(address)
{
  return /^(((2[0-4]|1[0-9]|[1-9])?[0-9]|25[0-5])\.){4}$/.test(address + ".");
}

/**
 * Checks whether a given hostname is valid.
 *
 * This function is used for filter validation.
 *
 * A hostname occurring in a filter must be normalized. For example,
 * <code>&#x1f642;</code> (slightly smiling face) should be normalized to
 * `xn--938h`; otherwise this function returns `false` for such a hostname.
 * Similarly, IP addresses should be normalized.
 *
 * @param {string} hostname The hostname to check.
 *
 * @returns {boolean} Whether the hostname is valid.
 */
exports.isValidHostname = function isValidHostname(hostname)
{
  if (isValidIPv4Address(hostname))
    return true;

  // This does not in fact validate the IPv6 address but it's alright for now.
  if (hostname[0] == "[" && hostname[hostname.length - 1] == "]")
    return true;

  // Based on
  // https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_hostnames
  if (hostname[hostname.length - 1] == ".")
    hostname = hostname.substring(0, hostname.length - 1);

  if (hostname.length > 253)
    return false;

  let labels = hostname.split(".");

  for (let label of labels)
  {
    if (!/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/i.test(label))
      return false;
  }

  // Based on https://tools.ietf.org/html/rfc3696#section-2
  if (!/\D/.test(labels[labels.length - 1]))
    return false;

  return true;
};

let getBaseDomain =
/**
 * Gets the base domain for the given hostname.
 *
 * @param {string} hostname
 *
 * @returns {string}
 *
 * @package
 */
exports.getBaseDomain = function getBaseDomain(hostname)
{
  let slices = [];
  let cutoff = NaN;

  for (let suffix of domainSuffixes(hostname))
  {
    slices.push(suffix);

    let offset = publicSuffixMap.get(suffix);

    if (typeof offset != "undefined")
    {
      cutoff = slices.length - 1 - offset;
      break;
    }
  }

  if (isNaN(cutoff))
    return slices.length > 2 ? slices[slices.length - 2] : hostname;

  if (cutoff <= 0)
    return hostname;

  return slices[cutoff];
};

/**
 * Checks whether a request's origin is different from its document's origin.
 *
 * @param {string} requestHostname The IDNA-encoded hostname of the request.
 * @param {string} documentHostname The IDNA-encoded hostname of the document.
 *
 * @returns {boolean}
 */
function isThirdParty(requestHostname, documentHostname)
{
  if (requestHostname[requestHostname.length - 1] == ".")
    requestHostname = requestHostname.substring(0, requestHostname.length - 1);

  if (documentHostname[documentHostname.length - 1] == ".")
  {
    documentHostname =
      documentHostname.substring(0, documentHostname.length - 1);
  }

  if (requestHostname == documentHostname)
    return false;

  if (!requestHostname || !documentHostname)
    return true;

  if (isIPAddress(requestHostname) || isIPAddress(documentHostname))
    return true;

  return getBaseDomain(requestHostname) != getBaseDomain(documentHostname);
}

let URLRequest =
/**
 * The `URLRequest` class represents a URL request.
 */
exports.URLRequest = class URLRequest
{
  /**
   * @private
   */
  constructor() {}

  /**
   * The URL of the request.
   * @type {string}
   */
  get href()
  {
    return this._href;
  }

  /**
   * Information about the URL of the request.
   * @type {module:url~URLInfo}
   * @package
   */
  get urlInfo()
  {
    if (!this._urlInfo)
      this._urlInfo = parseURL(this._href);

    return this._urlInfo;
  }

  /**
   * The hostname of the document making the request.
   * @type {?string}
   */
  get documentHostname()
  {
    return this._documentHostname == null ? null : this._documentHostname;
  }

  /**
   * Whether this is a third-party request.
   * @type {boolean}
   */
  get thirdParty()
  {
    if (typeof this._thirdParty == "undefined")
    {
      this._thirdParty = this._documentHostname == null ? false :
                           isThirdParty(this.urlInfo.hostname,
                                        this._documentHostname);
    }

    return this._thirdParty;
  }

  /**
   * Returns the URL of the request.
   * @returns {string}
   */
  toString()
  {
    return this._href;
  }

  /**
   * The lower-case version of the URL of the request.
   * @type {string}
   * @package
   */
  get lowerCaseHref()
  {
    if (this._lowerCaseHref == null)
      this._lowerCaseHref = this._href.toLowerCase();

    return this._lowerCaseHref;
  }
};

/**
 * Returns a `{@link module:url.URLRequest URLRequest}` object for the given
 * URL.
 *
 * @param {string|module:url~URLInfo|URL} url The URL. If this is a `string`,
 *   it must be a canonicalized URL (see
 *   `{@link module:url.parseURL parseURL()}`).
 * @param {?string} [documentHostname] The IDNA-encoded hostname of the
 *   document making the request.
 *
 * @returns {module:url.URLRequest}
 */
exports.URLRequest.from = function(url, documentHostname = null)
{
  let request = new URLRequest();

  if (typeof url == "string")
  {
    request._href = url;
  }
  else
  {
    request._urlInfo = url instanceof URLInfo ? url :
                         new URLInfo(url.href, url.protocol, url.hostname);
    request._href = url.href;
  }

  if (documentHostname != null)
    request._documentHostname = documentHostname;

  return request;
};

/**
 * Parses the domains part of a filter text
 * (e.g. `example.com,~mail.example.com`) into a `Map` object.
 *
 * @param {string} source The domains part of a filter text.
 * @param {string} separator The string used to separate two or more domains in
 *   the domains part of a filter text.
 *
 * @returns {?Map.<string, boolean>}
 *
 * @package
 */
exports.parseDomains = function parseDomains(source, separator)
{
  let domains = domainsCache.get(source);
  if (typeof domains != "undefined")
    return domains;

  if (source[0] != "~" && !source.includes(separator))
  {
    // Fast track for the common one-domain scenario.
    domains = new Map([["", false], [source, true]]);
  }
  else
  {
    domains = null;

    let hasIncludes = false;
    for (let domain of source.split(separator))
    {
      if (domain == "")
        continue;

      let include;
      if (domain[0] == "~")
      {
        include = false;
        domain = domain.substring(1);
      }
      else
      {
        include = true;
        hasIncludes = true;
      }

      if (!domains)
        domains = new Map();

      domains.set(domain, include);
    }

    if (domains)
      domains.set("", !hasIncludes);
  }

  domainsCache.set(source, domains);

  return domains;
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Matcher class implementing matching addresses against
 *               a list of filters.
 */

const {RESOURCE_TYPES, SPECIAL_TYPES, ALLOWING_TYPES,
       enumerateTypes} = __webpack_require__(6);
const {compilePatterns} = __webpack_require__(58);
const {domainSuffixes, URLRequest} = __webpack_require__(9);
const {FiltersByDomain, FilterMap} = __webpack_require__(37);
const {Cache} = __webpack_require__(24);

/**
 * Regular expression for matching a keyword in a filter.
 * @type {RegExp}
 */
let keywordRegExp = /[^a-z0-9%*][a-z0-9%]{2,}(?=[^a-z0-9%*])/;

/**
 * Regular expression for matching all keywords in a filter.
 * @type {RegExp}
 */
let allKeywordsRegExp = new RegExp(keywordRegExp, "g");

/**
 * Checks if the keyword is bad for use.
 * @param {string} keyword
 * @returns {boolean}
 */
function isBadKeyword(keyword)
{
  return keyword == "https" || keyword == "http" || keyword == "com" ||
         keyword == "js";
}

/**
 * Adds a filter by a given keyword to a map.
 * @param {module:filterClasses.URLFilter} filter
 * @param {string} keyword
 * @param {Map.<string,(module:filterClasses.URLFilter|
 *                      Set.<module:filterClasses.URLFilter>)>} map
 */
function addFilterByKeyword(filter, keyword, map)
{
  let set = map.get(keyword);
  if (typeof set == "undefined")
  {
    map.set(keyword, filter);
  }
  else if (set.size == 1)
  {
    if (filter != set)
      map.set(keyword, new Set([set, filter]));
  }
  else
  {
    set.add(filter);
  }
}

/**
 * Removes a filter by a given keyword from a map.
 * @param {module:filterClasses.URLFilter} filter
 * @param {string} keyword
 * @param {Map.<string,(module:filterClasses.URLFilter|
 *                      Set.<module:filterClasses.URLFilter>)>} map
 */
function removeFilterByKeyword(filter, keyword, map)
{
  let set = map.get(keyword);
  if (typeof set == "undefined")
    return;

  if (set.size == 1)
  {
    if (filter == set)
      map.delete(keyword);
  }
  else
  {
    set.delete(filter);

    if (set.size == 1)
      map.set(keyword, [...set][0]);
  }
}

/**
 * Checks whether a filter matches a given URL request.
 *
 * @param {module:filterClasses.URLFilter} filter The filter.
 * @param {module:url.URLRequest} request The URL request.
 * @param {number} typeMask A mask specifying the content type of the URL
 *   request.
 * @param {?string} [sitekey] An optional public key associated with the
 *   URL request.
 * @param {?Array} [collection] An optional list to which to append the filter
 *   if it matches. If omitted, the function directly returns the filter if it
 *   matches.
 *
 * @returns {?module:filterClasses.URLFilter} The filter if it matches and
 *   `collection` is omitted; otherwise `null`.
 */
function matchFilter(filter, request, typeMask, sitekey, collection)
{
  if (filter.matches(request, typeMask, sitekey))
  {
    if (!collection)
      return filter;

    collection.push(filter);
  }

  return null;
}

/**
 * Checks whether a particular filter is slow.
 * @param {module:filterClasses.URLFilter} filter
 * @returns {boolean}
 */
exports.isSlowFilter = function isSlowFilter(filter)
{
  return !filter.pattern || !keywordRegExp.test(filter.pattern);
};

let Matcher =
/**
 * Blocking/allowing filter matching
 */
exports.Matcher = class Matcher
{
  constructor()
  {
    /**
     * Lookup table for keywords by their associated filter
     * @type {Map.<module:filterClasses.URLFilter,string>}
     * @private
     */
    this._keywordByFilter = new Map();

    /**
     * Lookup table for simple filters by their associated keyword
     * @type {Map.<string,(module:filterClasses.URLFilter|
     *                     Set.<module:filterClasses.URLFilter>)>}
     * @private
     */
    this._simpleFiltersByKeyword = new Map();

    /**
     * Lookup table for complex filters by their associated keyword
     * @type {Map.<string,(module:filterClasses.URLFilter|
     *                     Set.<module:filterClasses.URLFilter>)>}
     * @private
     */
    this._complexFiltersByKeyword = new Map();

    /**
     * Lookup table of compiled patterns for simple filters by their associated
     * keyword
     * @type {Map.<string,?module:patterns~CompiledPatterns>}
     * @private
     */
    this._compiledPatternsByKeyword = new Map();

    /**
     * Compiled patterns for generic complex filters with no associated
     * keyword.
     * @type {?module:patterns~CompiledPatterns|boolean}
     * @private
     */
    this._keywordlessCompiledPatterns = false;

    /**
     * Lookup table of domain maps for complex filters by their associated
     * keyword
     * @type {Map.<string,
     *             Map.<string,
     *                  (module:filterClasses.URLFilter|
     *                   Map.<module:filterClasses.URLFilter,boolean>)>>}
     * @private
     */
    this._filterDomainMapsByKeyword = new Map();

    /**
     * Lookup table of type-specific lookup tables for complex filters by their
     * associated keyword
     * @type {Map.<string,
     *             Map.<string,
     *                  (module:filterClasses.URLFilter|
     *                   Set.<module:filterClasses.URLFilter>)>>}
     * @private
     */
    this._filterMapsByType = new Map();
  }

  /**
   * Removes all known filters
   */
  clear()
  {
    this._keywordByFilter.clear();
    this._simpleFiltersByKeyword.clear();
    this._complexFiltersByKeyword.clear();
    this._compiledPatternsByKeyword.clear();
    this._keywordlessCompiledPatterns = false;
    this._filterDomainMapsByKeyword.clear();
    this._filterMapsByType.clear();
  }

  /**
   * Adds a filter to the matcher
   * @param {module:filterClasses.URLFilter} filter
   */
  add(filter)
  {
    if (this._keywordByFilter.has(filter))
      return;

    // Look for a suitable keyword
    let keyword = this.findKeyword(filter);
    let simple = filter.contentType == RESOURCE_TYPES && filter.isGeneric();

    addFilterByKeyword(filter, keyword,
                       simple ? this._simpleFiltersByKeyword :
                         this._complexFiltersByKeyword);

    this._keywordByFilter.set(filter, keyword);

    if (simple)
    {
      if (this._compiledPatternsByKeyword.size > 0)
        this._compiledPatternsByKeyword.delete(keyword);

      return;
    }

    if (keyword == "")
      this._keywordlessCompiledPatterns = false;

    for (let type of enumerateTypes(filter.contentType, SPECIAL_TYPES))
    {
      let map = this._filterMapsByType.get(type);
      if (!map)
        this._filterMapsByType.set(type, map = new Map());

      addFilterByKeyword(filter, keyword, map);
    }

    let {domains} = filter;

    let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword);
    if (!filtersByDomain)
    {
      // In most cases, there is only one pure generic filter to a keyword.
      // Instead of Map { "foo" => Map { "" => Map { filter => true } } }, we
      // can just reduce it to Map { "foo" => filter } and save a lot of
      // memory.
      if (!domains)
      {
        this._filterDomainMapsByKeyword.set(keyword, filter);
        return;
      }

      filtersByDomain = new FiltersByDomain();
      this._filterDomainMapsByKeyword.set(keyword, filtersByDomain);
    }
    else if (!(filtersByDomain instanceof FiltersByDomain))
    {
      filtersByDomain = new FiltersByDomain([["", filtersByDomain]]);
      this._filterDomainMapsByKeyword.set(keyword, filtersByDomain);
    }

    filtersByDomain.add(filter, domains);
  }

  /**
   * Removes a filter from the matcher
   * @param {module:filterClasses.URLFilter} filter
   */
  remove(filter)
  {
    let keyword = this._keywordByFilter.get(filter);
    if (typeof keyword == "undefined")
      return;

    let simple = filter.contentType == RESOURCE_TYPES && filter.isGeneric();

    removeFilterByKeyword(filter, keyword,
                          simple ? this._simpleFiltersByKeyword :
                            this._complexFiltersByKeyword);

    this._keywordByFilter.delete(filter);

    if (simple)
    {
      if (this._compiledPatternsByKeyword.size > 0)
        this._compiledPatternsByKeyword.delete(keyword);

      return;
    }

    if (keyword == "")
      this._keywordlessCompiledPatterns = false;

    for (let type of enumerateTypes(filter.contentType, SPECIAL_TYPES))
    {
      let map = this._filterMapsByType.get(type);
      if (map)
        removeFilterByKeyword(filter, keyword, map);
    }

    let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword);
    if (filtersByDomain)
    {
      // Because of the memory optimization in the add function, most of the
      // time this will be a filter rather than a map.
      if (!(filtersByDomain instanceof FiltersByDomain))
      {
        this._filterDomainMapsByKeyword.delete(keyword);
        return;
      }

      filtersByDomain.remove(filter);

      if (filtersByDomain.size == 0)
      {
        this._filterDomainMapsByKeyword.delete(keyword);
      }
      else if (filtersByDomain.size == 1)
      {
        for (let [lastDomain, map] of filtersByDomain.entries())
        {
          // Reduce Map { "foo" => Map { "" => filter } } to
          // Map { "foo" => filter }
          if (lastDomain == "" && !(map instanceof FilterMap))
            this._filterDomainMapsByKeyword.set(keyword, map);

          break;
        }
      }
    }
  }

  /**
   * Checks whether a filter exists in the matcher
   * @param {module:filterClasses.URLFilter} filter
   * @returns {boolean}
   */
  has(filter)
  {
    return this._keywordByFilter.has(filter);
  }

  /**
   * Chooses a keyword to be associated with the filter.
   *
   * Because it will perform some internal optimizations, there is no
   * guarantee that this function will always return the same result when
   * called with the same filter.
   *
   * @param {module:filterClasses.Filter} filter
   * @returns {string} keyword or an empty string if no keyword could be found
   * @protected
   */
  findKeyword(filter)
  {
    let result = "";

    let {pattern} = filter;
    if (pattern == null)
      return result;

    let candidates = pattern.toLowerCase().match(allKeywordsRegExp);
    if (!candidates)
      return result;

    let resultCount = 0xFFFFFF;
    let resultLength = 0;

    for (let i = 0, l = candidates.length; i < l; i++)
    {
      let candidate = candidates[i].substring(1);

      if (isBadKeyword(candidate))
        continue;

      let simpleFilters = this._simpleFiltersByKeyword.get(candidate);
      let complexFilters = this._complexFiltersByKeyword.get(candidate);

      let count = (typeof simpleFilters != "undefined" ?
                     simpleFilters.size : 0) +
                  (typeof complexFilters != "undefined" ?
                     complexFilters.size : 0);

      if (count < resultCount ||
          (count == resultCount && candidate.length > resultLength))
      {
        result = candidate;
        resultCount = count;
        resultLength = candidate.length;
      }
    }

    return result;
  }

  _matchFiltersByDomain(filtersByDomain, request, typeMask, sitekey,
                        specificOnly, collection)
  {
    let excluded = null;

    let domain = request.documentHostname || "";
    for (let suffix of domainSuffixes(domain, !specificOnly))
    {
      let map = filtersByDomain.get(suffix);
      if (map)
      {
        if (map instanceof FilterMap)
        {
          for (let [filter, include] of map.entries())
          {
            if (!include)
            {
              if (excluded)
                excluded.add(filter);
              else
                excluded = new Set([filter]);
            }
            else if ((!excluded || !excluded.has(filter)) &&
                     matchFilter(filter, request, typeMask, sitekey,
                                 collection))
            {
              return filter;
            }
          }
        }
        else if ((!excluded || !excluded.has(map)) &&
                 matchFilter(map, request, typeMask, sitekey, collection))
        {
          return map;
        }
      }
    }

    return null;
  }

  _checkEntryMatchSimpleQuickCheck(keyword, request, filters)
  {
    let compiled = this._compiledPatternsByKeyword.get(keyword);
    if (typeof compiled == "undefined")
    {
      compiled = compilePatterns(filters);
      this._compiledPatternsByKeyword.set(keyword, compiled);
    }

    // If compilation failed (e.g. too many filters), return true because this
    // is only a pre-check.
    return !compiled || compiled.test(request);
  }

  _checkEntryMatchSimple(keyword, request, collection)
  {
    let filters = this._simpleFiltersByKeyword.get(keyword);

    // For simple filters where there's more than one filter to the keyword, we
    // do a quick check using a single compiled pattern that combines all the
    // patterns. This is a lot faster for requests that are not going to be
    // blocked (i.e. most requests).
    if (filters && (filters.size == 1 ||
                    this._checkEntryMatchSimpleQuickCheck(keyword, request,
                                                          filters)))
    {
      for (let filter of filters)
      {
        // Simple filters match any resource type.
        if (matchFilter(filter, request, RESOURCE_TYPES, null, collection))
          return filter;
      }
    }

    return null;
  }

  _checkEntryMatchForType(keyword, request, typeMask, sitekey, specificOnly,
                          collection)
  {
    let filtersForType = this._filterMapsByType.get(typeMask);
    if (filtersForType)
    {
      let filters = filtersForType.get(keyword);
      if (filters)
      {
        for (let filter of filters)
        {
          if (specificOnly && filter.isGeneric())
            continue;

          if (matchFilter(filter, request, typeMask, sitekey, collection))
            return filter;
        }
      }
    }

    return null;
  }

  _checkEntryMatchByDomain(keyword, request, typeMask, sitekey, specificOnly,
                           collection)
  {
    let filtersByDomain = this._filterDomainMapsByKeyword.get(keyword);
    if (filtersByDomain)
    {
      if (filtersByDomain instanceof FiltersByDomain)
      {
        if (keyword == "" && !specificOnly)
        {
          let compiled = this._keywordlessCompiledPatterns;

          // If the value is false, it indicates that we need to initialize it
          // to either a CompiledPatterns object or null.
          if (compiled == false)
          {
            // Compile all the patterns from the generic filters into a single
            // object. It is worth doing this for the keywordless generic
            // complex filters because they must be checked against every
            // single URL request that has not already been blocked by one of
            // the simple filters (i.e. most URL requests).
            let map = filtersByDomain.get("");
            if (map instanceof FilterMap)
              compiled = compilePatterns(new Set(map.keys()));

            this._keywordlessCompiledPatterns = compiled || null;
          }

          // We can skip the generic filters if none of them pass the test.
          if (compiled && !compiled.test(request))
            specificOnly = true;
        }

        return this._matchFiltersByDomain(filtersByDomain, request, typeMask,
                                          sitekey, specificOnly, collection);
      }

      // Because of the memory optimization in the add function, most of the
      // time this will be a filter rather than a map.

      // Also see #7312: If it's a single filter, it's always the equivalent of
      // Map { "" => Map { filter => true } } (i.e. applies to any domain). If
      // the specific-only flag is set, we skip it.
      if (!specificOnly)
      {
        return matchFilter(filtersByDomain, request, typeMask, sitekey,
                           collection);
      }
    }

    return null;
  }

  /**
   * Checks whether the entries for a particular keyword match a URL
   * @param {string} keyword
   * @param {module:url.URLRequest} request
   * @param {number} typeMask
   * @param {?string} [sitekey]
   * @param {boolean} [specificOnly]
   * @param {?Array.<module:filterClasses.Filter>} [collection] An optional
   *   list of filters to which to append any results. If specified, the
   *   function adds *all* matching filters to the list; if omitted,
   *   the function directly returns the first matching filter.
   * @returns {?module:filterClasses.Filter}
   * @protected
   */
  checkEntryMatch(keyword, request, typeMask, sitekey, specificOnly,
                  collection)
  {
    // We need to skip the simple (location-only) filters if the type mask does
    // not contain any resource types.
    if (!specificOnly && (typeMask & RESOURCE_TYPES) != 0)
    {
      let filter = this._checkEntryMatchSimple(keyword, request, collection);
      if (filter)
        return filter;
    }

    // If the type mask contains a special type (first condition) and it is
    // the only type in the mask (second condition), we can use the
    // type-specific map, which typically contains a lot fewer filters. This
    // enables faster lookups for allowing types like $document, $elemhide,
    // and so on, as well as other special types like $csp.
    if ((typeMask & SPECIAL_TYPES) != 0 && (typeMask & typeMask - 1) == 0)
    {
      return this._checkEntryMatchForType(keyword, request, typeMask,
                                          sitekey, specificOnly, collection);
    }

    return this._checkEntryMatchByDomain(keyword, request, typeMask,
                                         sitekey, specificOnly, collection);
  }

  /**
   * @see #match
   * @deprecated
   * @inheritdoc
   */
  matchesAny(url, typeMask, docDomain, sitekey, specificOnly)
  {
    return this.match(url, typeMask, docDomain, sitekey, specificOnly);
  }

  /**
   * Tests whether the URL matches any of the known filters
   * @param {URL|module:url~URLInfo|string} url
   *   URL to be tested
   * @param {number} typeMask
   *   bitmask of content / request types to match
   * @param {?string} [docDomain]
   *   domain name of the document that loads the URL
   * @param {?string} [sitekey]
   *   public key provided by the document
   * @param {boolean} [specificOnly]
   *   should be `true` if generic matches should be ignored
   * @returns {?module:filterClasses.URLFilter}
   *   matching filter or `null`
   */
  match(url, typeMask, docDomain, sitekey, specificOnly)
  {
    let request = URLRequest.from(url, docDomain);
    let candidates = request.lowerCaseHref.match(/[a-z0-9%]{2,}|$/g);

    for (let i = 0, l = candidates.length; i < l; i++)
    {
      if (isBadKeyword(candidates[i]))
        continue;

      let result = this.checkEntryMatch(candidates[i], request, typeMask,
                                        sitekey, specificOnly);
      if (result)
        return result;
    }

    return null;
  }
};

let CombinedMatcher =
/**
 * Combines a matcher for blocking and exception rules, automatically sorts
 * rules into two `{@link module:matcher.Matcher Matcher}` instances.
 */
exports.CombinedMatcher = class CombinedMatcher
{
  constructor()
  {
    /**
     * Matcher for blocking rules.
     * @type {module:matcher.Matcher}
     * @private
     */
    this._blocking = new Matcher();

    /**
     * Matcher for exception rules.
     * @type {module:matcher.Matcher}
     * @private
     */
    this._allowing = new Matcher();

    /**
     * Lookup table of previous match results
     * @type {module:caching.Cache.<string, ?(module:filterClasses.URLFilter|
     *                                        MatcherSearchResults)>}
     * @private
     */
    this._resultCache = new Cache(10000);
  }

  /**
   * @see module:matcher.Matcher#clear
   */
  clear()
  {
    this._blocking.clear();
    this._allowing.clear();
    this._resultCache.clear();
  }

  /**
   * @see module:matcher.Matcher#add
   * @param {module:filterClasses.Filter} filter
   */
  add(filter)
  {
    if (filter.type == "allowing")
      this._allowing.add(filter);
    else
      this._blocking.add(filter);

    this._resultCache.clear();
  }

  /**
   * @see module:matcher.Matcher#remove
   * @param {module:filterClasses.Filter} filter
   */
  remove(filter)
  {
    if (filter.type == "allowing")
      this._allowing.remove(filter);
    else
      this._blocking.remove(filter);

    this._resultCache.clear();
  }

  /**
   * @see module:matcher.Matcher#has
   * @param {module:filterClasses.Filter} filter
   * @returns {boolean}
   */
  has(filter)
  {
    if (filter.type == "allowing")
      return this._allowing.has(filter);
    return this._blocking.has(filter);
  }

  /**
   * @see module:matcher.Matcher#findKeyword
   * @param {module:filterClasses.Filter} filter
   * @returns {string} keyword
   * @protected
   */
  findKeyword(filter)
  {
    if (filter.type == "allowing")
      return this._allowing.findKeyword(filter);
    return this._blocking.findKeyword(filter);
  }

  _matchInternal(url, typeMask, docDomain, sitekey, specificOnly)
  {
    let request = URLRequest.from(url, docDomain);
    let candidates = request.lowerCaseHref.match(/[a-z0-9%]{2,}|$/g);

    let allowingHit = null;
    let blockingHit = null;

    // If the type mask includes no types other than allowing types, we
    // can skip the blocking filters.
    if ((typeMask & ~ALLOWING_TYPES) != 0)
    {
      for (let i = 0, l = candidates.length; !blockingHit && i < l; i++)
      {
        if (isBadKeyword(candidates[i]))
          continue;

        blockingHit = this._blocking.checkEntryMatch(candidates[i], request,
                                                     typeMask, sitekey,
                                                     specificOnly);
      }
    }

    // If the type mask includes any allowing types, we need to check the
    // allowing filters.
    if (blockingHit || (typeMask & ALLOWING_TYPES) != 0)
    {
      for (let i = 0, l = candidates.length; !allowingHit && i < l; i++)
      {
        if (isBadKeyword(candidates[i]))
          continue;

        allowingHit = this._allowing.checkEntryMatch(candidates[i], request,
                                                     typeMask, sitekey);
      }
    }

    return allowingHit || blockingHit;
  }

  _searchInternal(url, typeMask, docDomain, sitekey, specificOnly, filterType)
  {
    let hits = {};

    let searchBlocking = filterType == "blocking" || filterType == "all";
    let searchAllowing = filterType == "allowing" || filterType == "all";

    if (searchBlocking)
      hits.blocking = [];

    if (searchAllowing)
      hits.allowing = [];

    // If the type mask includes no types other than allowing types, we
    // can skip the blocking filters.
    if ((typeMask & ~ALLOWING_TYPES) == 0)
      searchBlocking = false;

    let request = URLRequest.from(url, docDomain);
    let candidates = request.lowerCaseHref.match(/[a-z0-9%]{2,}|$/g);

    for (let i = 0, l = candidates.length; i < l; i++)
    {
      if (isBadKeyword(candidates[i]))
        continue;

      if (searchBlocking)
      {
        this._blocking.checkEntryMatch(candidates[i], request, typeMask,
                                       sitekey, specificOnly, hits.blocking);
      }

      if (searchAllowing)
      {
        this._allowing.checkEntryMatch(candidates[i], request, typeMask,
                                       sitekey, false, hits.allowing);
      }
    }

    return hits;
  }

  /**
   * @see #match
   * @deprecated
   * @inheritdoc
   */
  matchesAny(url, typeMask, docDomain, sitekey, specificOnly)
  {
    return this.match(url, typeMask, docDomain, sitekey, specificOnly);
  }

  /**
   * @see module:matcher.Matcher#match
   * @inheritdoc
   */
  match(url, typeMask, docDomain, sitekey, specificOnly)
  {
    let key = `${url} ${typeMask} ${docDomain} ${sitekey} ${specificOnly}`;
    let result = this._resultCache.get(key);
    if (typeof result != "undefined")
      return result;

    result = this._matchInternal(url, typeMask, docDomain, sitekey,
                                 specificOnly);

    this._resultCache.set(key, result);

    return result;
  }

  /**
   * @typedef {object} MatcherSearchResults
   * @property {Array.<module:filterClasses.BlockingFilter>} [blocking] List of
   *   blocking filters found.
   * @property {Array.<module:filterClasses.AllowingFilter>} [allowing] List
   *   of allowing filters found.
   */

  /**
   * Searches all blocking and allowing filters and returns results matching
   * the given parameters.
   *
   * @param {URL|module:url~URLInfo|string} url
   * @param {number} typeMask
   * @param {?string} [docDomain]
   * @param {?string} [sitekey]
   * @param {boolean} [specificOnly]
   * @param {string} [filterType] The types of filters to look for. This can be
   *   `"blocking"`, `"allowing"`, or `"all"` (default).
   *
   * @returns {MatcherSearchResults}
   */
  search(url, typeMask, docDomain, sitekey, specificOnly, filterType = "all")
  {
    let key = `* ${url} ${typeMask} ${docDomain} ${sitekey} ` +
              `${specificOnly} ${filterType}`;

    let result = this._resultCache.get(key);
    if (typeof result != "undefined")
      return result;

    result = this._searchInternal(url, typeMask, docDomain, sitekey,
                                  specificOnly, filterType);

    this._resultCache.set(key, result);

    return result;
  }

  /**
   * Tests whether the URL is allowlisted
   * @see module:matcher.Matcher#match
   * @inheritdoc
   * @returns {boolean}
   */
  isAllowlisted(url, typeMask, docDomain, sitekey)
  {
    return !!this._allowing.match(url, typeMask, docDomain, sitekey);
  }
};

/**
 * Shared `{@link module:matcher.CombinedMatcher CombinedMatcher}` instance
 * that should usually be used.
 * @type {module:matcher.CombinedMatcher}
 */
exports.defaultMatcher = new CombinedMatcher();


/***/ }),
/* 11 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "nonRequestTypes", function() { return nonRequestTypes; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HitLogger", function() { return HitLogger; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "logRequest", function() { return logRequest; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "logAllowlistedDocument", function() { return logAllowlistedDocument; });
/* harmony import */ var _url_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(13);
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12);
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
/* harmony import */ var _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _messaging_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(1);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(0);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _allowlisting_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module hitLogger */









let nonRequestTypes = [
  "DOCUMENT", "ELEMHIDE", "SNIPPET", "GENERICBLOCK", "GENERICHIDE", "CSP"
];

let eventEmitter = new _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_1__["EventEmitter"]();

/**
 * @namespace
 * @static
 */
let HitLogger = {
  /**
   * Adds a listener for requests, filter hits etc related to the tab.
   *
   * Note: Calling code is responsible for removing the listener again,
   *       it will not be automatically removed when the tab is closed.
   *
   * @param {number} tabId
   * @param {function} listener
   */
  addListener: eventEmitter.on.bind(eventEmitter),

  /**
   * Removes a listener for the tab.
   *
   * @param {number} tabId
   * @param {function} listener
   */
  removeListener: eventEmitter.off.bind(eventEmitter),

  /**
   * Checks whether a tab is being inspected by anything.
   *
   * @param {number} tabId
   * @return {boolean}
   */
  hasListener: eventEmitter.hasListeners.bind(eventEmitter)
};

/**
 * Logs a request associated with a tab or multiple tabs.
 *
 * @param {number[]} tabIds
 *   The tabIds associated with the request
 * @param {Object} request
 *   The request to log
 * @param {string} request.url
 *   The URL of the request
 * @param {string} request.type
 *  The request type
 * @param {string} request.docDomain
 *  The hostname of the document
 * @param {boolean} request.thirdParty
 *   Whether the origin of the request and document differs
 * @param {?string} request.sitekey
 *   The active sitekey if there is any
 * @param {?boolean} request.specificOnly
 *   Whether generic filters should be ignored
 * @param {?BlockingFilter} filter
 *  The matched filter or null if there is no match
 */
function logRequest(tabIds, request, filter)
{
  for (let tabId of tabIds)
    eventEmitter.emit(tabId, request, filter);
}

function logHiddenElements(page, frame, selectors, filters, docDomain)
{
  if (HitLogger.hasListener(page.id))
  {
    for (let subscription of _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_2__["filterStorage"].subscriptions())
    {
      if (subscription.disabled)
        continue;

      for (let text of subscription.filterText())
      {
        let filter = _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_4__["Filter"].fromText(text);

        // We only know the exact filter in case of element hiding emulation.
        // For regular element hiding filters, the content script only knows
        // the selector, so we have to find a filter that has an identical
        // selector and is active on the domain the match was reported from.
        let isActiveElemHideFilter = filter instanceof _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_4__["ElemHideFilter"] &&
                                     selectors.includes(filter.selector) &&
                                     filter.isActiveOnDomain(docDomain);

        if (isActiveElemHideFilter || filters.includes(text))
        {
          // For generic filters we need to additionally check whether
          // they were not applied to the page due to an exception rule.
          if (filter.isGeneric())
          {
            let specificOnly = Object(_allowlisting_js__WEBPACK_IMPORTED_MODULE_6__["checkAllowlisted"])(
              page, frame, null,
              _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_5__["contentTypes"].GENERICHIDE
            );
            if (specificOnly)
              continue;
          }

          eventEmitter.emit(page.id, {type: "ELEMHIDE", docDomain}, filter);
        }
      }
    }
  }
}

/**
 * Logs an allowing filter that disables (some kind of)
 * blocking for a particular document.
 *
 * @param {number}       tabId     The tabId the allowlisting is active for
 * @param {string}       url       The url of the allowlisted document
 * @param {number}       typeMask  The bit mask of allowing types checked
 *                                 for
 * @param {string}       docDomain The hostname of the parent document
 * @param {AllowingFilter} filter  The matched allowing filter
 */
function logAllowlistedDocument(tabId, url, typeMask, docDomain, filter)
{
  if (HitLogger.hasListener(tabId))
  {
    for (let type of nonRequestTypes)
    {
      if (typeMask & filter.contentType & _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_5__["contentTypes"][type])
        eventEmitter.emit(tabId, {url, type, docDomain}, filter);
    }
  }
}

/**
 * Logs active element hiding filters for a tab.
 *
 * @event "hitLogger.traceElemHide"
 * @property {string[]} selectors  The selectors of applied ElemHideFilters
 * @property {string[]} filters    The text of applied ElemHideEmulationFilters
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_3__["port"].on("hitLogger.traceElemHide", (message, sender) =>
{
  logHiddenElements(
    sender.page, sender.frame, message.selectors, message.filters,
    Object(_url_js__WEBPACK_IMPORTED_MODULE_0__["extractHostFromFrame"])(sender.frame)
  );
});


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * Registers and emits named events.
 */
exports.EventEmitter = class EventEmitter
{
  constructor()
  {
    this._listeners = new Map();
  }

  /**
   * Adds a listener for the specified event name.
   *
   * @param {string}   name
   * @param {function} listener
   */
  on(name, listener)
  {
    let listeners = this._listeners.get(name);
    if (listeners)
      listeners.push(listener);
    else
      this._listeners.set(name, [listener]);
  }

  /**
   * Removes a listener for the specified event name.
   *
   * @param {string}   name
   * @param {function} listener
   */
  off(name, listener)
  {
    let listeners = this._listeners.get(name);
    if (listeners)
    {
      if (listeners.length > 1)
      {
        let idx = listeners.indexOf(listener);
        if (idx != -1)
          listeners.splice(idx, 1);
      }
      else if (listeners[0] === listener)
      {
        // We must use strict equality above for compatibility with
        // Array.prototype.indexOf
        this._listeners.delete(name);
      }
    }
  }

  /**
   * Returns a copy of the array of listeners for the specified event.
   *
   * @param {string} name
   *
   * @returns {Array.<function>}
   */
  listeners(name)
  {
    let listeners = this._listeners.size > 0 ? this._listeners.get(name) : null;
    return listeners ? listeners.slice() : [];
  }

  /**
   * Checks whether there are any listeners for the specified event.
   *
   * @param {string} [name] The name of the event. If omitted, checks whether
   *   there are any listeners for any event.
   *
   * @returns {boolean}
   */
  hasListeners(name)
  {
    return this._listeners.size > 0 &&
           (typeof name == "undefined" || this._listeners.has(name));
  }

  /**
   * Calls all previously added listeners for the given event name.
   *
   * @param {string} name
   * @param {...*}   [args]
   */
  emit(name, ...args)
  {
    let listeners = this._listeners.size > 0 ? this._listeners.get(name) : null;
    if (listeners)
    {
      for (let listener of listeners.slice())
        listener(...args);
    }
  }
};


/***/ }),
/* 13 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "extractHostFromFrame", function() { return extractHostFromFrame; });
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module url */

/**
 * Gets the IDN-decoded hostname from the URL of a frame.
 * If the URL don't have host information (like "about:blank"
 * and "data:" URLs) it falls back to the parent frame.
 *
 * @param {?Frame}  frame
 * @param {URL}    [originUrl]
 * @return {string}
 */
function extractHostFromFrame(frame, originUrl)
{
  for (; frame; frame = frame.parent)
  {
    let {hostname} = frame.url;
    if (hostname)
      return hostname;
  }

  return originUrl ? originUrl.hostname : "";
}


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



const {filterNotifier} = __webpack_require__(4);

/**
 * Internal map containing filter state.
 * @type {Map.<string, object>}
 * @private
 */
const map = new Map();

/**
 * `{@link module:filterState.filterState filterState}` implementation.
 */

/**
 * Maintains filter state.
 * @type {module:filterState~FilterState}
 */
exports.filterState = {
  /**
   * Checks whether a filter is enabled.
   * @param {string} filterText The text of the filter.
   * @returns {boolean} Whether the filter is enabled.
   */
  isEnabled(filterText)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (state)
      return !state.disabled;

    return true;
  },

  /**
   * Sets the enabled state of a filter.
   * @param {string} filterText The text of the filter.
   * @param {boolean} enabled The new enabled state of the filter.
   */
  setEnabled(filterText, enabled)
  {
    setEnabledWithState(filterText, enabled, map.size > 0 ?
                                             map.get(filterText) :
                                             void 0);
  },

  /**
   * Toggles the enabled state of a filter.
   * @param {string} filterText The text of the filter.
   */
  toggleEnabled(filterText)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;

    setEnabledWithState(filterText, state ? state.disabled : false, state);
  },

  /**
   * Resets the enabled state of a filter.
   * @param {string} filterText The text of the filter.
   */
  resetEnabled(filterText)
  {
    this.setEnabled(filterText, true);
  },

  /**
   * Returns the hit count of a filter.
   * @param {string} filterText The text of the filter.
   * @returns {number} The hit count of the filter.
   */
  getHitCount(filterText)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (state)
      return state.hitCount;

    return 0;
  },

  /**
   * Sets the hit count of a filter.
   * @param {string} filterText The text of the filter.
   * @param {number} hitCount The new hit count of the filter.
   */
  setHitCount(filterText, hitCount)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (state)
    {
      let oldHitCount = state.hitCount;

      if (hitCount == 0 && !state.disabled && state.lastHit == 0)
        map.delete(filterText);
      else
        state.hitCount = hitCount;

      if (hitCount != oldHitCount)
      {
        filterNotifier.emit("filterState.hitCount", filterText, hitCount,
                            oldHitCount);
      }
    }
    else if (hitCount != 0)
    {
      map.set(filterText, {disabled: false, hitCount, lastHit: 0});

      filterNotifier.emit("filterState.hitCount", filterText, hitCount, 0);
    }
  },

  /**
   * Resets the hit count of a filter.
   * @param {string} filterText The text of the filter.
   */
  resetHitCount(filterText)
  {
    this.setHitCount(filterText, 0);
  },

  /**
   * Returns the last hit time of a filter.
   * @param {string} filterText The text of the filter.
   * @returns {number} The last hit time of the filter in milliseconds since
   *   the Unix epoch.
   */
  getLastHit(filterText)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (state)
      return state.lastHit;

    return 0;
  },

  /**
   * Sets the last hit time of a filter.
   * @param {string} filterText The text of the filter.
   * @param {number} lastHit The new last hit time of the filter in
   *   milliseconds since the Unix epoch.
   */
  setLastHit(filterText, lastHit)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (state)
    {
      let oldLastHit = state.lastHit;

      if (lastHit == 0 && !state.disabled && state.hitCount == 0)
        map.delete(filterText);
      else
        state.lastHit = lastHit;

      if (lastHit != oldLastHit)
      {
        filterNotifier.emit("filterState.lastHit", filterText, lastHit,
                            oldLastHit);
      }
    }
    else if (lastHit != 0)
    {
      map.set(filterText, {disabled: false, hitCount: 0, lastHit});

      filterNotifier.emit("filterState.lastHit", filterText, lastHit, 0);
    }
  },

  /**
   * Resets the last hit time of a filter.
   * @param {string} filterText The text of the filter.
   */
  resetLastHit(filterText)
  {
    this.setLastHit(filterText, 0);
  },

  /**
   * Registers a filter hit by incrementing the hit count of the filter and
   * setting the last hit time of the filter to the current time.
   * @param {string} filterText The text of the filter.
   */
  registerHit(filterText)
  {
    let now = Date.now();

    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (state)
    {
      let oldHitCount = state.hitCount;
      let oldLastHit = state.lastHit;

      state.hitCount++;
      state.lastHit = now;

      if (state.hitCount != oldHitCount)
      {
        filterNotifier.emit("filterState.hitCount", filterText, state.hitCount,
                            oldHitCount);
      }

      if (state.lastHit != oldLastHit)
      {
        filterNotifier.emit("filterState.lastHit", filterText, state.lastHit,
                            oldLastHit);
      }
    }
    else
    {
      map.set(filterText, {disabled: false, hitCount: 1, lastHit: now});

      filterNotifier.emit("filterState.hitCount", filterText, 1, 0);
      filterNotifier.emit("filterState.lastHit", filterText, now, 0);
    }
  },

  /**
   * Resets the hit count and last hit time of a filter.
   * @param {string} filterText The text of the filter.
   */
  resetHits(filterText)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (!state)
      return;

    let oldHitCount = state.hitCount;
    let oldLastHit = state.lastHit;

    if (state.disabled)
    {
      state.hitCount = 0;
      state.lastHit = 0;
    }
    else
    {
      map.delete(filterText);
    }

    if (oldHitCount != 0)
      filterNotifier.emit("filterState.hitCount", filterText, 0, oldHitCount);

    if (oldLastHit != 0)
      filterNotifier.emit("filterState.lastHit", filterText, 0, oldLastHit);
  },

  /**
   * Resets the enabled state, hit count, and last hit time of a filter.
   * @param {string} filterText The text of the filter.
   */
  reset(filterText)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (!state)
      return;

    let oldDisabled = state.disabled;
    let oldHitCount = state.hitCount;
    let oldLastHit = state.lastHit;

    map.delete(filterText);

    if (oldDisabled)
      filterNotifier.emit("filterState.disabled", filterText, false, true);

    if (oldHitCount != 0)
      filterNotifier.emit("filterState.hitCount", filterText, 0, oldHitCount);

    if (oldLastHit != 0)
      filterNotifier.emit("filterState.lastHit", filterText, 0, oldLastHit);
  },

  /**
   * Serializes the state of a filter.
   * @param {string} filterText The text of the filter.
   * @yields {string} The next line in the serialized representation of the
   *   state of the filter.
   * @see module:filterState~FilterState#fromObject
   * @package
   */
  *serialize(filterText)
  {
    let state = map.size > 0 ? map.get(filterText) : void 0;
    if (!state)
      return;

    yield "[Filter]";
    yield "text=" + filterText;

    if (state.disabled)
      yield "disabled=true";
    if (state.hitCount != 0)
      yield "hitCount=" + state.hitCount;
    if (state.lastHit != 0)
      yield "lastHit=" + state.lastHit;
  },

  /**
   * Reads the state of a filter from an object representation.
   * @param {string} filterText The text of the filter.
   * @param {object} object An object containing at least one of `disabled`,
   *   `hitCount`, and `lastHit` properties and their appropriate values.
   * @see module:filterState~FilterState#serialize
   * @package
   */
  fromObject(filterText, object)
  {
    if (!("disabled" in object || "hitCount" in object || "lastHit" in object))
      return;

    let state = {
      disabled: String(object.disabled) == "true",
      hitCount: parseInt(object.hitCount, 10) || 0,
      lastHit: parseInt(object.lastHit, 10) || 0
    };

    if (!state.disabled && state.hitCount == 0 && state.lastHit == 0)
      map.delete(filterText);
    else
      map.set(filterText, state);
  }
};

function setEnabledWithState(filterText, enabled, state)
{
  let oldEnabled = state ? !state.disabled : true;

  if (enabled)
  {
    if (state)
    {
      state.disabled = false;

      if (state.hitCount == 0 && state.lastHit == 0)
        map.delete(filterText);
    }
  }
  else if (state)
  {
    state.disabled = true;
  }
  else
  {
    map.set(filterText, {disabled: true, hitCount: 0, lastHit: 0});
  }

  if (enabled != oldEnabled)
  {
    filterNotifier.emit("filterState.enabled", filterText, enabled,
                        oldEnabled);
  }
}


/***/ }),
/* 15 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setBadge", function() { return setBadge; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setIconImageData", function() { return setIconImageData; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setIconPath", function() { return setIconPath; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "toggleBadge", function() { return toggleBadge; });
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module browserAction */

let changesByTabId = new Map();
let badgeStateByPage = new ext.PageMap();

function setBadgeState(tabId, key, value)
{
  let page = new ext.Page(tabId);
  let badgeState = badgeStateByPage.get(page);

  if (!badgeState)
  {
    badgeState = {
      hiddenState: "visible",
      text: ""
    };
    badgeStateByPage.set(page, badgeState);
  }

  // We need to ignore any text changes while we're hiding the badge
  if (!(badgeState.hiddenState == "hiding" && key == "text"))
    badgeState[key] = value;

  return badgeState;
}

function applyChanges(tabId, changes)
{
  return Promise.all(Object.keys(changes).map(change =>
  {
    // Firefox for Android displays the browser action not as an icon but
    // as a menu item. There is no icon, but such an option may be added
    // in the future.
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1331746
    if (change == "iconPath" && "setIcon" in browser.browserAction)
    {
      return browser.browserAction.setIcon({
        tabId,
        path: {
          16: changes.iconPath.replace("$size", "16"),
          20: changes.iconPath.replace("$size", "20"),
          32: changes.iconPath.replace("$size", "32"),
          40: changes.iconPath.replace("$size", "40")
        }
      });
    }

    if (change == "iconImageData" && "setIcon" in browser.browserAction)
    {
      return browser.browserAction.setIcon({
        tabId,
        imageData: changes.iconImageData
      });
    }

    // There is no badge on Firefox for Android; the browser action is
    // simply a menu item.
    if (change == "badgeText" && "setBadgeText" in browser.browserAction)
    {
      // Remember changes to the badge text but don't apply them yet
      // as long as the badge is hidden.
      let badgeState = setBadgeState(tabId, "text", changes.badgeText);
      if (badgeState.hiddenState == "hidden")
        return;

      return browser.browserAction.setBadgeText({
        tabId,
        text: changes.badgeText
      });
    }

    // There is no badge on Firefox for Android; the browser action is
    // simply a menu item.
    if (change == "badgeColor" &&
        "setBadgeBackgroundColor" in browser.browserAction)
    {
      return browser.browserAction.setBadgeBackgroundColor({
        tabId,
        color: changes.badgeColor
      });
    }
  }));
}

async function addChange(tabId, name, value)
{
  let changes = changesByTabId.get(tabId);
  if (!changes)
  {
    changes = {};
    changesByTabId.set(tabId, changes);
  }
  changes[name] = value;

  function cleanup()
  {
    changesByTabId.delete(tabId);
  }

  async function onReplaced(addedTabId, removedTabId)
  {
    if (addedTabId == tabId)
    {
      browser.tabs.onReplaced.removeListener(onReplaced);
      try
      {
        await applyChanges(tabId, changes);
        cleanup();
      }
      catch (e)
      {
        cleanup();
      }
    }
  }

  if (!browser.tabs.onReplaced.hasListener(onReplaced))
  {
    try
    {
      await applyChanges(tabId, changes);
      cleanup();
    }
    catch (e)
    {
      // If the tab is prerendered, browser.browserAction.set* fails
      // and we have to delay our changes until the currently visible tab
      // is replaced with the prerendered tab.
      browser.tabs.onReplaced.addListener(onReplaced);
    }
  }
}

/**
 * Sets icon badge for given tab.
 *
 * @param {number} tabId
 * @param {object} badge
 * @param {string} badge.color
 * @param {string} badge.number
 */
function setBadge(tabId, badge)
{
  if (!badge)
  {
    addChange(tabId, "badgeText", "");
  }
  else
  {
    if ("number" in badge)
      addChange(tabId, "badgeText", badge.number.toString());

    if ("color" in badge)
      addChange(tabId, "badgeColor", badge.color);
  }
}

/**
 * Sets icon image for given tab using image data.
 *
 * @param  {number} tabId
 * @param  {object} imageData
 */
function setIconImageData(tabId, imageData)
{
  addChange(tabId, "iconImageData", imageData);
}

/**
 * Sets icon image for given tab using file path.
 *
 * @param  {number} tabId
 * @param  {string} path - expected to include "$size" placeholder
 */
function setIconPath(tabId, path)
{
  addChange(tabId, "iconPath", path);
}

/**
 * Toggles icon badge for given tab.
 *
 * @param  {number} tabId
 * @param  {boolean} shouldHide
 */
async function toggleBadge(tabId, shouldHide)
{
  if (shouldHide)
  {
    setBadgeState(tabId, "hiddenState", "hiding");
    addChange(tabId, "badgeText", "");
    setBadgeState(tabId, "hiddenState", "hidden");
  }
  else
  {
    let badgeState = setBadgeState(tabId, "hiddenState", "visible");
    addChange(tabId, "badgeText", badgeState.text);
  }
}


/***/ }),
/* 16 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBlockedPerPage", function() { return getBlockedPerPage; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "recordBlockedRequest", function() { return recordBlockedRequest; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Stats", function() { return Stats; });
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12);
/* harmony import */ var _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _browserAction_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(15);
/* harmony import */ var _messaging_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(1);
/* harmony import */ var _prefs_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module stats */







const badgeColor = "#646464";
const badgeRefreshRate = 4;

let eventEmitter = new _adblockpluscore_lib_events_js__WEBPACK_IMPORTED_MODULE_0__["EventEmitter"]();
let blockedPerPage = new ext.PageMap();

/**
 * Gets the number of requests blocked on the given page.
 *
 * @param  {Page} page
 * @return {Number}
 */
function getBlockedPerPage(page)
{
  return blockedPerPage.get(page) || 0;
}

let activeTabIds = new Set();
let activeTabIdByWindowId = new Map();

let badgeUpdateScheduled = false;

function updateBadge(tabId)
{
  if (!_prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].show_statsinicon)
    return;

  for (let id of (typeof tabId == "undefined" ? activeTabIds : [tabId]))
  {
    let page = new ext.Page({id});
    let blockedCount = blockedPerPage.get(page);

    Object(_browserAction_js__WEBPACK_IMPORTED_MODULE_2__["setBadge"])(page.id, blockedCount && {
      color: badgeColor,
      number: blockedCount
    });
  }
}

function scheduleBadgeUpdate(tabId)
{
  if (!badgeUpdateScheduled && _prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].show_statsinicon &&
      (typeof tabId == "undefined" || activeTabIds.has(tabId)))
  {
    setTimeout(() => { badgeUpdateScheduled = false; updateBadge(); },
               1000 / badgeRefreshRate);
    badgeUpdateScheduled = true;
  }
}

// Once nagivation for the tab has been committed to (e.g. it's no longer
// being prerendered) we clear its badge, or if some requests were already
// blocked beforehand we display those on the badge now.
browser.webNavigation.onCommitted.addListener(details =>
{
  if (details.frameId == 0)
    updateBadge(details.tabId);
});

/**
 * Records a blocked request.
 *
 * @param {Filter} filter
 * @param {Array.<number>} tabIds
 */
async function recordBlockedRequest(filter, tabIds)
{
  if (!(filter instanceof _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__["BlockingFilter"]))
    return;

  for (let tabId of tabIds)
  {
    let page = new ext.Page({id: tabId});
    let blocked = blockedPerPage.get(page) || 0;
    ++blocked;

    blockedPerPage.set(page, blocked);
    scheduleBadgeUpdate(tabId);

    eventEmitter.emit("blocked_per_page", {tabId, blocked});
  }

  // Don't update the total for incognito tabs.
  let tabs = await Promise.all(tabIds.map(id => browser.tabs.get(id)));
  if (tabs.some(tab => tab.incognito))
    return;

  // Make sure blocked_total is only read after the storage was loaded.
  await _prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].untilLoaded;

  _prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].blocked_total++;
  eventEmitter.emit("blocked_total", _prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].blocked_total);
}

/**
  * @namespace
  * @static
  */
let Stats = {
  /**
   * Adds a callback that is called when the
   * value of a specified stat changed.
   *
   * @param {string}   stat
   * @param {function} callback
   */
  on(stat, callback)
  {
    eventEmitter.on(stat, callback);
  },

  /**
   * Removes a callback for the specified stat.
   *
   * @param {string}   stat
   * @param {function} callback
   */
  off(stat, callback)
  {
    eventEmitter.off(stat, callback);
  },

  /**
   * The total number of blocked requests on non-incognito pages.
   *
   * @type {number}
   */
  get blocked_total()
  {
    return _prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].blocked_total;
  }
};

_prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].on("show_statsinicon", async() =>
{
  let tabs = await browser.tabs.query({});
  for (let tab of tabs)
  {
    if (_prefs_js__WEBPACK_IMPORTED_MODULE_4__["Prefs"].show_statsinicon)
      updateBadge(tab.id);
    else
      Object(_browserAction_js__WEBPACK_IMPORTED_MODULE_2__["setBadge"])(tab.id, null);
  }
});

/**
 * Returns the number of blocked requests for the sender's page.
 *
 * @event "stats.getBlockedPerPage"
 * @returns {number}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_3__["port"].on("stats.getBlockedPerPage",
        message => getBlockedPerPage(new ext.Page(message.tab)));

/**
 * Returns the total number of blocked requests on non-incognito pages.
 *
 * @event "stats.getBlockedTotal"
 * @returns {number}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_3__["port"].on("stats.getBlockedTotal", () => Stats.blocked_total);

browser.tabs.query({active: true}).then(tabs =>
{
  for (let tab of tabs)
  {
    activeTabIds.add(tab.id);
    activeTabIdByWindowId.set(tab.windowId, tab.id);
  }

  scheduleBadgeUpdate();
});

browser.tabs.onActivated.addListener(tab =>
{
  let lastActiveTabId = activeTabIdByWindowId.get(tab.windowId);
  if (typeof lastActiveTabId != "undefined")
    activeTabIds.delete(lastActiveTabId);

  activeTabIds.add(tab.tabId);
  activeTabIdByWindowId.set(tab.windowId, tab.tabId);

  scheduleBadgeUpdate();
});

if ("windows" in browser)
{
  browser.windows.onRemoved.addListener(windowId =>
  {
    activeTabIds.delete(activeTabIdByWindowId.get(windowId));
    activeTabIdByWindowId.delete(windowId);
  });
}


/***/ }),
/* 17 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addonName", function() { return addonName; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "addonVersion", function() { return addonVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "application", function() { return application; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "applicationVersion", function() { return applicationVersion; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "platform", function() { return platform; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "platformVersion", function() { return platformVersion; });
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

let addonName = "adblockchrome";
let addonVersion = "4.44.0";
let application = null;
let applicationVersion;
let platform = "chromium";
let platformVersion = null;

let regexp = /(\S+)\/(\S+)(?:\s*\(.*?\))?/g;
let match;

while (match = regexp.exec(navigator.userAgent))
{
  let app = match[1];
  let ver = match[2];

  if (app == "Chrome")
  {
    platformVersion = ver;
  }
  else if (app != "Mozilla" && app != "AppleWebKit" && app != "Safari")
  {
    // For compatibility with legacy websites, Chrome's UA
    // also includes a Mozilla, AppleWebKit and Safari token.
    // Any further name/version pair indicates a fork.
    application = app == "OPR" ? "opera" : app.toLowerCase();
    applicationVersion = ver;
  }
}

// not a Chromium-based UA, probably modifed by the user
if (!platformVersion)
{
  application = "unknown";
  applicationVersion = platformVersion = "0";
}

// no additional name/version, so this is upstream Chrome
if (!application)
{
  application = "chrome";
  applicationVersion = platformVersion;
}


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Manages synchronization of filter subscriptions.
 */

const {Prefs} = __webpack_require__(5);

const {MILLIS_IN_SECOND, MILLIS_IN_MINUTE, MILLIS_IN_HOUR,
       MILLIS_IN_DAY} = __webpack_require__(20);
const {Downloader, Downloadable} = __webpack_require__(25);
const {Filter} = __webpack_require__(0);
const {filterStorage} = __webpack_require__(3);
const {filterNotifier} = __webpack_require__(4);
const {Subscription,
       DownloadableSubscription} = __webpack_require__(2);
const {analytics} = __webpack_require__(40);

const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
const DEFAULT_EXPIRATION_INTERVAL = 5 * MILLIS_IN_DAY;

/**
 * Downloads filter subscriptions whenever necessary.
 */
class Synchronizer
{
  /**
   * @hideconstructor
   */
  constructor()
  {
    /**
     * Whether the downloading of subscriptions has been started.
     * @private
     */
    this._started = false;

    /**
     * The object providing actual downloading functionality.
     * @type {module:downloader.Downloader}
     */
    this._downloader = new Downloader(this._getDownloadables.bind(this));

    this._downloader.onExpirationChange = this._onExpirationChange.bind(this);
    this._downloader.onDownloadStarted = this._onDownloadStarted.bind(this);
    this._downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
    this._downloader.onDownloadError = this._onDownloadError.bind(this);
  }

  /**
   * Starts downloading subscriptions.
   *
   * No subscriptions are downloaded until this function has been called at
   * least once.
   */
  start()
  {
    if (this._started)
      return;

    this._downloader.scheduleChecks(CHECK_INTERVAL, INITIAL_DELAY);
    this._started = true;
  }

  /**
   * Clear any further downloader scheduled check and set its internal state
   * as not started.
   */
  stop()
  {
    this._started = false;
    this._downloader.unscheduleChecks();
  }

  /**
   * Checks whether a subscription is currently being downloaded.
   * @param {string} url  URL of the subscription
   * @returns {boolean}
   */
  isExecuting(url)
  {
    return this._downloader.isDownloading(url);
  }

  /**
   * Starts the download of a subscription.
   * @param {module:subscriptionClasses.DownloadableSubscription} subscription
   *   Subscription to be downloaded
   * @param {boolean} manual
   *   `true` for a manually started download (should not trigger fallback
   *   requests)
   */
  execute(subscription, manual)
  {
    this._downloader.download(this._getDownloadable(subscription, manual));
  }

  /**
   * Yields `{@link module:downloader.Downloadable Downloadable}` instances for
   * all subscriptions that can be downloaded.
   * @yields {module:downloader.Downloadable}
   */
  *_getDownloadables()
  {
    if (!Prefs.subscriptions_autoupdate)
      return;

    for (let subscription of filterStorage.subscriptions())
    {
      if (subscription instanceof DownloadableSubscription)
        yield this._getDownloadable(subscription, false);
    }
  }

  /**
   * Creates a `{@link module:downloader.Downloadable Downloadable}` instance
   * for a subscription.
   * @param {module:subscriptionClasses.Subscription} subscription
   * @param {boolean} manual
   * @returns {module:downloader.Downloadable}
   */
  _getDownloadable(subscription, manual)
  {
    let {url, lastDownload, lastSuccess, lastCheck, version, softExpiration,
         expires, downloadCount, disabled} = subscription;

    let result = new Downloadable(url);

    if (analytics.isTrusted(url))
      result.firstVersion = analytics.getFirstVersion();

    if (lastDownload != lastSuccess)
      result.lastError = lastDownload * MILLIS_IN_SECOND;

    result.lastCheck = lastCheck * MILLIS_IN_SECOND;
    result.lastVersion = version;
    result.softExpiration = softExpiration * MILLIS_IN_SECOND;
    result.hardExpiration = expires * MILLIS_IN_SECOND;
    result.manual = manual;
    result.downloadCount = downloadCount;
    if (disabled)
      result.method = "HEAD";

    return result;
  }

  _onExpirationChange(downloadable)
  {
    let subscription = Subscription.fromURL(downloadable.url);
    subscription.lastCheck = Math.round(
      downloadable.lastCheck / MILLIS_IN_SECOND
    );
    subscription.softExpiration = Math.round(
      downloadable.softExpiration / MILLIS_IN_SECOND
    );
    subscription.expires = Math.round(
      downloadable.hardExpiration / MILLIS_IN_SECOND
    );
  }

  _onDownloadStarted(downloadable)
  {
    let subscription = Subscription.fromURL(downloadable.url);
    filterNotifier.emit("subscription.downloading", subscription);
    subscription.mark("downloading.started");
  }

  _onDownloadSuccess(downloadable, responseText, errorCallback,
                     redirectCallback)
  {
    let subscription = Subscription.fromURL(downloadable.redirectURL ||
                                            downloadable.url);
    subscription.mark("downloading.finished");
    subscription.mark("parsing.started");

    let isHEAD = downloadable.method === "HEAD";

    let {error, lines, params,
         minVersion} = isHEAD ? {params: {}} : parseFilters(responseText);

    if (error)
      return errorCallback(error);

    if (params.redirect)
      return redirectCallback(params.redirect);

    subscription.mark("parsing.finished");

    // Handle redirects
    if (downloadable.redirectURL &&
        downloadable.redirectURL != downloadable.url)
    {
      let oldSubscription = Subscription.fromURL(downloadable.url);
      subscription.title = oldSubscription.title;
      subscription.disabled = oldSubscription.disabled;
      subscription.lastCheck = oldSubscription.lastCheck;

      let listed = filterStorage.hasSubscription(oldSubscription);
      if (listed)
        filterStorage.removeSubscription(oldSubscription);

      Subscription.knownSubscriptions.delete(oldSubscription.url);

      if (listed)
        filterStorage.addSubscription(subscription);
    }

    // The download actually succeeded
    subscription.lastSuccess = subscription.lastDownload = Math.round(
      Date.now() / MILLIS_IN_SECOND
    );
    subscription.downloadStatus = "synchronize_ok";
    subscription.downloadCount = downloadable.downloadCount;
    subscription.errors = 0;

    // Process parameters
    if (params.homepage)
    {
      let url;
      try
      {
        url = new URL(params.homepage);
      }
      catch (e)
      {
        url = null;
      }

      if (url && (url.protocol == "http:" || url.protocol == "https:"))
        subscription.homepage = url.href;
    }

    if (params.title)
    {
      subscription.title = params.title;
      subscription.fixedTitle = true;
    }
    else
    {
      subscription.fixedTitle = false;
    }

    if (params.version)
    {
      subscription.version = parseInt(params.version, 10);

      if (analytics.isTrusted(downloadable.redirectURL || downloadable.url))
        analytics.recordVersion(params.version);
    }
    else
    {
      subscription.version = isHEAD ? downloadable.lastVersion : 0;
    }

    if (subscription.type)
      subscription.abtest = params.abtest;

    let expirationInterval = isHEAD ?
                              MILLIS_IN_DAY : DEFAULT_EXPIRATION_INTERVAL;
    if (params.expires)
    {
      let match = /^(\d+)\s*(h)?/.exec(params.expires);
      if (match)
      {
        let interval = parseInt(match[1], 10);
        if (match[2])
          expirationInterval = interval * MILLIS_IN_HOUR;
        else
          expirationInterval = interval * MILLIS_IN_DAY;
      }
    }

    let [
      softExpiration,
      hardExpiration
    ] = this._downloader.processExpirationInterval(expirationInterval);
    subscription.softExpiration = Math.round(softExpiration / MILLIS_IN_SECOND);
    subscription.expires = Math.round(hardExpiration / MILLIS_IN_SECOND);

    if (minVersion)
      subscription.requiredVersion = minVersion;
    else
      delete subscription.requiredVersion;

    // In case of HEAD request (disabled subscription) notify an update so that
    // the last version of the subscription will be stored for the next time.
    if (isHEAD)
      filterNotifier.emit("subscription.updated", subscription);
    else
      processFilters(subscription, lines);
  }

  _onDownloadError(downloadable, downloadURL, error, responseStatus,
                   redirectCallback)
  {
    let subscription = Subscription.fromURL(downloadable.url);
    subscription.mark("downloading.finished");
    subscription.lastDownload = Math.round(Date.now() / MILLIS_IN_SECOND);
    subscription.downloadStatus = error;

    // Request fallback URL if necessary - for automatic updates only
    if (!downloadable.manual)
    {
      subscription.errors++;

      if (redirectCallback &&
          subscription.errors >= Prefs.subscriptions_fallbackerrors &&
          /^https?:\/\//i.test(subscription.url))
      {
        subscription.errors = 0;

        let fallbackURL = Prefs.subscriptions_fallbackurl;
        const {addonVersion} = __webpack_require__(7);
        fallbackURL = fallbackURL.replace(/%VERSION%/g,
                                          encodeURIComponent(addonVersion));
        fallbackURL = fallbackURL.replace(/%SUBSCRIPTION%/g,
                                          encodeURIComponent(subscription.url));
        fallbackURL = fallbackURL.replace(/%URL%/g,
                                          encodeURIComponent(downloadURL));
        fallbackURL = fallbackURL.replace(/%ERROR%/g,
                                          encodeURIComponent(error));
        fallbackURL = fallbackURL.replace(/%RESPONSESTATUS%/g,
                                          encodeURIComponent(responseStatus));

        let initObj = {
          cache: "no-store",
          credentials: "omit",
          referrer: "no-referrer",
          method: downloadable.method
        };

        fetch(fallbackURL, initObj).then(response => response.text())
        .then(responseText =>
        {
          if (!filterStorage.hasSubscription(subscription))
            return;

          let match = /^(\d+)(?:\s+(\S+))?$/.exec(responseText);
          if (match && match[1] == "301" &&    // Moved permanently
              match[2] && /^https?:\/\//i.test(match[2]))
          {
            redirectCallback(match[2]);
          }
          else if (match && match[1] == "410") // Gone
          {
            let data = "[Adblock]\n" +
              [...subscription.filterText()].join("\n");
            redirectCallback("data:text/plain," + encodeURIComponent(data));
          }
        });
      }
    }
  }
}

let synchronizer =
/**
 * This object is responsible for downloading filter subscriptions whenever
 * necessary.
 * @type {module:synchronizer~Synchronizer}
 */
exports.synchronizer = new Synchronizer();

// allow DownloadableSubscription to update themselves once re-enabled
DownloadableSubscription.useSynchronizer(synchronizer);

/**
 * Given a valid subscription and some text, it parses all filters and add
 * these in bulk to the specified subscription.
 * @param {module:subscriptionClasses.Subscription} subscription The
 *  Subscription to use as reference for manually added filters.
 * @param {string} filters The filters file/text to add.
 * @param {function} errorCallback A callback invoked if errors occur.
 */
exports.addSubscriptionFilters = function(subscription, filters,
                                          errorCallback)
{
  let {error, lines} = parseFilters(filters);
  if (error)
    errorCallback(error);
  else
    processFilters(subscription, lines);
};

/**
 * Given some text containing filters, parse each line and return all details.
 * @param {string} filters The filters file/text to parse.
 * @returns {Object.<error?, lines?, params?, minVersion?>} All parsed details,
 *  if available.
 */
function parseFilters(filters)
{
  let lines = filters.split(/[\r\n]+/);
  let headerMatch = /\[Adblock(?:\s*Plus\s*([\d.]+)?)?\]/i.exec(lines[0]);

  if (!headerMatch)
    return {error: "synchronize_invalid_data"};

  let minVersion = headerMatch[1];

  let params = {
    redirect: null,
    homepage: null,
    title: null,
    version: null,
    expires: null,
    abtest: null
  };

  for (let {hasOwnProperty} = Object.prototype, i = 1; i < lines.length; i++)
  {
    let match = /^\s*!\s*(.*?)\s*:\s*(.*)/.exec(lines[i]);
    if (!match)
      break;

    let keyword = match[1].toLowerCase();
    if (hasOwnProperty.call(params, keyword))
    {
      params[keyword] = match[2];
      lines.splice(i--, 1);
    }
  }

  return {lines, params, minVersion};
}

exports.parseFilters = parseFilters;

/**
 * Given a list of parsed filters, normalize each line and update the
 * subscription.
 * @private
 * @param {module:subscriptionClasses.Subscription} subscription The
 *  Subscription to use as reference for manually added filters.
 * @param {string[]} lines The parsed filters lines.
 */
function processFilters(subscription, lines)
{
  subscription.mark("processing.started");

  lines.shift();
  let filterText = [];
  for (let line of lines)
  {
    line = Filter.normalize(line);
    if (line)
      filterText.push(line);
  }

  filterStorage.updateSubscriptionFilters(subscription, filterText);

  subscription.mark("processing.finished");
}


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global exports, browser, STATS, log, logging, determineUserLanguage */

// Log an 'error' message on GAB log server.
const ServerMessages = (function serverMessages() {
  const postFilterStatsToLogServer = function (data, callback) {
    if (!data) {
      return;
    }
    const payload = { event: 'filter_stats', payload: data };
    $.ajax({
      jsonp: false,
      type: 'POST',
      url: 'https://log.getadblock.com/v2/record_log.php',
      data: JSON.stringify(payload),
      success(text, status, xhr) {
        if (typeof callback === 'function') {
          callback(text, status, xhr);
        }
      },
      error(xhr, textStatus, errorThrown) {
        log('message server returned error: ', textStatus, errorThrown);
        if (callback) {
          callback(errorThrown, textStatus, xhr);
        }
      },
    });
  };

  // Log a message on GAB log server. The user's userid will be prepended to the
  // message.
  // If callback() is specified, call callback() after logging has completed
  const sendMessageToLogServer = function (payload, callback) {
    $.ajax({
      jsonp: false,
      type: 'POST',
      url: 'https://log.getadblock.com/v2/record_log.php',
      data: JSON.stringify(payload),
      success() {
        if (typeof callback === 'function') {
          callback();
        }
      },

      error(e) {
        log('message server returned error: ', e.status);
        // Remove following if statement when Edge migration is no longer needed
        if (payload.event === 'cm_migration_finished' && typeof callback === 'function') {
          callback();
        }
      },
    });
  };

  // Log a message on GAB log server. The user's userid will be prepended to the
  // message.
  // If callback() is specified, call callback() after logging has completed
  const recordMessageWithUserID = function (msg, queryType, callback, additionalParams) {
    if (!msg || !queryType) {
      return;
    }
    const payload = {
      u: STATS.userId(),
      f: STATS.flavor,
      o: STATS.os,
      l: determineUserLanguage(),
      t: queryType,
      v: browser.runtime.getManifest().version,
    };
    if (typeof additionalParams === 'object') {
      for (const prop in additionalParams) {
        payload[prop] = additionalParams[prop];
      }
    }
    const eventWithPayload = { event: msg, payload };
    sendMessageToLogServer(eventWithPayload, callback);
  };

  // Log a message on GAB log server.
  // If callback() is specified, call callback() after logging has completed
  const recordAnonymousMessage = function (msg, queryType, callback, additionalParams) {
    if (!msg || !queryType) {
      return;
    }

    const payload = {
      f: STATS.flavor,
      o: STATS.os,
      l: determineUserLanguage(),
      t: queryType,
    };
    if (typeof additionalParams === 'object') {
      for (const prop in additionalParams) {
        payload[prop] = additionalParams[prop];
      }
    }
    const eventWithPayload = { event: msg, payload };
    sendMessageToLogServer(eventWithPayload, callback);
  };

  // Log a error message on GAB log server.
  // If callback() is specified, call callback() after logging has completed
  const recordAnonymousErrorMessage = function (msg, callback, additionalParams) {
    if (!msg) {
      return;
    }

    const payload = {
      f: STATS.flavor,
      o: STATS.os,
      l: determineUserLanguage(),
      t: 'error',
    };
    if (typeof additionalParams === 'object') {
      for (const prop in additionalParams) {
        payload[prop] = additionalParams[prop];
      }
    }
    const eventWithPayload = { event: msg, payload };
    sendMessageToLogServer(eventWithPayload, callback);
  };

  const recordErrorMessage = function (msg, callback, additionalParams) {
    recordMessageWithUserID(msg, 'error', callback, additionalParams);
  };

  // Log an 'status' related message on GAB log server.
  const recordStatusMessage = function (msg, callback, additionalParams) {
    recordMessageWithUserID(msg, 'stats', callback, additionalParams);
  };

  // Log a 'general' message on GAB log server.
  const recordGeneralMessage = function (msg, callback, additionalParams) {
    recordMessageWithUserID(msg, 'general', callback, additionalParams);
  };

  // Log a 'adreport' message on GAB log server.
  const recordAdreportMessage = function (msg, callback, additionalParams) {
    recordMessageWithUserID(msg, 'adreport', callback, additionalParams);
  };

  browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.command !== 'recordGeneralMessage' || !message.msg) {
      return;
    }
    recordGeneralMessage(message.msg, undefined, message.additionalParams);
    sendResponse({});
  });

  return {
    recordErrorMessage,
    recordAnonymousMessage,
    recordAnonymousErrorMessage,
    postFilterStatsToLogServer,
    recordStatusMessage,
    recordGeneralMessage,
    recordAdreportMessage,
  };
}());

exports.ServerMessages = ServerMessages;


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * Number of milliseconds in a second.
 * @const {number}
 * @default 1000
 * @package
 */
exports.MILLIS_IN_SECOND = 1000;

/**
 * Number of milliseconds in a minute.
 * @const {number}
 * @default 60000
 * @package
 */
exports.MILLIS_IN_MINUTE = 60000;

/**
 * Number of milliseconds in an hour.
 * @const {number}
 * @default 3600000
 * @package
 */
exports.MILLIS_IN_HOUR = 3600000;

/**
 * Number of milliseconds in a day.
 * @const {number}
 * @default 86400000
 * @package
 */
exports.MILLIS_IN_DAY = 86400000;


/***/ }),
/* 21 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "statsInIconKey", function() { return statsInIconKey; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "stopIconAnimation", function() { return stopIconAnimation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "startIconAnimation", function() { return startIconAnimation; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NEW_BADGE_REASONS", function() { return NEW_BADGE_REASONS; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "showIconBadgeCTA", function() { return showIconBadgeCTA; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getNewBadgeTextReason", function() { return getNewBadgeTextReason; });
/* harmony import */ var filterNotifier__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
/* harmony import */ var filterNotifier__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(filterNotifier__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockplusui_adblockpluschrome_lib_browserAction__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(15);
/* harmony import */ var info__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(17);
/*
 * Same as the original source adblockpluschrome/lib/icon.js
 * except:
 * - updated image file names from 'abp-' to 'ab-'
 * - updated the 'import' paths
 * - use the term 'whitelisted' instead of 'allowlisted' for now
 * - call renderIcons() at the end of the module for all platforms,
 *   not just Chromium
 * - added the showIconBadgeCTA, getNewBadgeTextReason functions, and related
 *   message listeners
 */
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module icon */






const browserAction = __webpack_require__(15);

const ANIMATION_LOOPS = 3;
const FRAME_IN_MS = 100;

const statsInIconKey = 'current_show_statsinicon';

let frameOpacities = calculateFrameOpacities(9, 7);
let frameOpacitiesCritical = calculateFrameOpacities(5, 3);

let stopRequested = false;
let canUpdateIcon = true;
let notRunning = Promise.resolve();
let allowlistedState = new ext.PageMap();

let icons = [null, null];

function easeOut(progress) {
  // This is merely an approximation to the built-in ease-out timing function
  // https://css-tricks.com/emulating-css-timing-functions-javascript/
  return 1 - Math.pow(1 - progress, 1.675);
}

function calculateFrameOpacities(keyframeFrames, transitionFrames) {
  let opacities = [];

  // Show second half of first keyframe
  // Omit first frame because it's only shown after the first timeout
  for (let i = 0; i < keyframeFrames / 2 - 1; i++)
    opacities.push(0);
  // Transition from first to second keyframe
  for (let i = 0; i < transitionFrames; i++)
    opacities.push(easeOut((i + 1) / (transitionFrames + 1)));
  // Show second keyframe
  for (let i = 0; i < keyframeFrames; i++)
    opacities.push(1);
  // Transition from second to first keyframe
  for (let i = 0; i < transitionFrames; i++)
    opacities.push(easeOut((transitionFrames - i) / (transitionFrames + 1)));
  // Show first half of first keyframe
  // Omit last frame due to an additional timeout that resets the icon
  for (let i = 0; i < keyframeFrames / 2 - 1; i++)
    opacities.push(0);

  return opacities;
}

async function loadImage(url) {
  let response = await fetch(url);
  let blob = await response.blob();
  return createImageBitmap(blob);
}

async function renderIcons() {
  let paths = [
    "icons/ab-16.png", "icons/ab-16-whitelisted.png",
    "icons/ab-32.png", "icons/ab-32-whitelisted.png"
  ];

  for (let path of paths) {
    let image = await loadImage(path);
    let [, size, allowlisted] = /\/ab-(16|32)(-whitelisted)?\./.exec(path);

    let canvas = new OffscreenCanvas(size, size);
    let context = canvas.getContext("2d");
    let imageData = icons[!!allowlisted | 0] || {};

    context.globalAlpha = 1;
    context.drawImage(image, 0, 0);
    imageData[size] = context.getImageData(0, 0, size, size);

    icons[!!allowlisted | 0] = imageData;
  }
}

function setIcon(page, opacity, frames) {
  opacity = opacity || 0;
  let allowlisted = !!allowlistedState.get(page);

  if (!frames) {
    if (opacity > 0.5) {
      Object(_adblockplusui_adblockpluschrome_lib_browserAction__WEBPACK_IMPORTED_MODULE_1__["setIconPath"])(
        page.id,
        "/icons/ab-$size-notification.png"
      );
    }
    else if (icons[allowlisted | 0]) {
      Object(_adblockplusui_adblockpluschrome_lib_browserAction__WEBPACK_IMPORTED_MODULE_1__["setIconImageData"])(page.id, icons[allowlisted | 0]);
    }
    else {
      Object(_adblockplusui_adblockpluschrome_lib_browserAction__WEBPACK_IMPORTED_MODULE_1__["setIconPath"])(
        page.id,
        "/icons/ab-$size" + (allowlisted ? "-allowlisted" : "") + ".png"
      );
    }
  }
  else {
    browser.browserAction.setIcon({
      tabId: page.id,
      imageData: frames["" + opacity + allowlisted]
    });
  }
}

filterNotifier__WEBPACK_IMPORTED_MODULE_0__["filterNotifier"].on("page.AllowlistingStateRevalidate", (page, filter) => {
  allowlistedState.set(page, !!filter);
  if (canUpdateIcon)
    setIcon(page);
});

async function renderFrames(opacities) {
  let images = await Promise.all([
    loadImage("icons/ab-16.png"),
    loadImage("icons/ab-16-whitelisted.png"),
    loadImage("icons/ab-16-whitelisted.png"),
    loadImage("icons/ab-20.png"),
    loadImage("icons/ab-20-whitelisted.png"),
    loadImage("icons/ab-20-whitelisted.png"),
    loadImage("icons/ab-32.png"),
    loadImage("icons/ab-32-whitelisted.png"),
    loadImage("icons/ab-32-whitelisted.png"),
    loadImage("icons/ab-40.png"),
    loadImage("icons/ab-40-whitelisted.png"),
    loadImage("icons/ab-40-whitelisted.png"),
  ]);
  opacities = new Set(opacities);
  let imageMap = {
    16: { base: [images[0], images[1]], overlay: images[2] },
    20: { base: [images[3], images[4]], overlay: images[5] },
    32: { base: [images[6], images[7]], overlay: images[8] },
    40: { base: [images[9], images[10]], overlay: images[11] }
  };

  let frames = {};
  let canvas = new OffscreenCanvas(0, 0);
  let context = canvas.getContext("2d");

  for (let allowlisted of [false, true]) {
    for (let opacity of opacities) {
      let imageData = {};
      let sizes = [16, 20, 32, 40];
      for (let size of sizes) {
        canvas.width = size;
        canvas.height = size;
        context.globalAlpha = 1;
        context.drawImage(imageMap[size]["base"][allowlisted | 0], 0, 0);
        context.globalAlpha = opacity;
        context.drawImage(imageMap[size]["overlay"], 0, 0);
        imageData[size] = context.getImageData(0, 0, size, size);
      }
      frames["" + opacity + allowlisted] = imageData;
    }
  }

  return frames;
}

async function animateIcon(opacities, frames) {
  let tabs = await browser.tabs.query({ active: true });
  let pages = tabs.map(tab => new ext.Page(tab));

  let animationLoop = 0;
  let animationStep = 0;
  let numberOfFrames = opacities.length;
  let opacity = 0;

  let onActivated = page => {
    pages.push(page);
    setIcon(page, opacity, frames);
    Object(_adblockplusui_adblockpluschrome_lib_browserAction__WEBPACK_IMPORTED_MODULE_1__["toggleBadge"])(page.id, true);
  };
  ext.pages.onActivated.addListener(onActivated);

  canUpdateIcon = false;
  for (let page of pages)
    Object(_adblockplusui_adblockpluschrome_lib_browserAction__WEBPACK_IMPORTED_MODULE_1__["toggleBadge"])(page.id, true);
  return new Promise((resolve, reject) => {
    let interval = setInterval(() => {
      let oldOpacity = opacity;
      opacity = opacities[animationStep++];

      if (opacity != oldOpacity) {
        for (let page of pages) {
          if (allowlistedState.has(page))
            setIcon(page, opacity, frames);
        }
      }

      if (animationStep > numberOfFrames) {
        if (++animationLoop > ANIMATION_LOOPS - 1 || stopRequested) {
          clearInterval(interval);
          ext.pages.onActivated.removeListener(onActivated);
          for (let page of pages)
            Object(_adblockplusui_adblockpluschrome_lib_browserAction__WEBPACK_IMPORTED_MODULE_1__["toggleBadge"])(page.id, false);
          canUpdateIcon = true;
          resolve();
        }
        else {
          animationStep = 0;
        }
      }
    }, FRAME_IN_MS);
  });
}

/**
 * Stops to animate the browser action icon
 * after the current interval has been finished.
 *
 * @return {Promise} A promise that is fullfilled when
 *                   the icon animation has been stopped.
 */
async function stopIconAnimation() {
  stopRequested = true;
  await notRunning;
  stopRequested = false;
}

/**
 * Starts to animate the browser action icon to indicate a pending notifcation.
 * If the icon is already animated, it replaces the previous
 * animation as soon as the current interval has been finished.
 *
 * @param {string} type  The notification type (i.e: "information" or
 *                       "critical".)
 */
function startIconAnimation(type) {
  let opacities = frameOpacities;
  if (type == "critical")
    opacities = frameOpacitiesCritical;

  notRunning = Promise.all([renderFrames(opacities), stopIconAnimation()])
    .then(results => {
      if (stopRequested)
        return;

      let frames = results[0];
      return animateIcon(opacities, frames);
    });
}

renderIcons();

/**
 * Returns the Object containing all of the reasons the text on the toolbar icon / badge is 'new'
 *
 */
const NEW_BADGE_REASONS = {
  SEVEN_DAY: 'seven day',
  UPDATE: 'update',
  VPN_CTA: 'vpn cta',
  FREE_DC_UPDATE: 'free dc update',
};

/**
 * Handles the display of the New badge on the toolbar icon.
 * @param {Boolean} [showBadge] true shows the badge, false removes the badge
 */

let newBadgeTextReason = "";

function showIconBadgeCTA(showBadge, reason) {
  if (!License.shouldShowPremiumCTA()) {
    return;
  }
  if (showBadge) {
    let newBadgeText = translate('new_badge');
    // Text that exceeds 4 characters is truncated on the toolbar badge,
    // so we default to English
    if (!newBadgeText || newBadgeText.length >= 5) {
      newBadgeText = 'New';
    }
    storageSet(statsInIconKey, Prefs.show_statsinicon);
    Prefs.show_statsinicon = false;
    // wait 10 seconds to allow any other ABP setup tasks to finish
    setTimeout(() => {
      // process all currently opened tabs
      browser.tabs.query({}).then((tabs) => {
        for (const tab of tabs) {
          if (tab.url && tab.url.startsWith('http')) {
            browserAction.setBadge(tab.id, { color: '#03bcfc', number: newBadgeText });
            newBadgeTextReason = reason || '';
          }
        }
      });
    }, 10000); // 10 seconds
  } else {
    // Restore show_statsinicon if we previously stored its value
    const storedValue = storageGet(statsInIconKey);
    if (typeof storedValue === 'boolean') {
      Prefs.show_statsinicon = storedValue;
      storageSet(statsInIconKey); // remove the data, since we no longer need it
      browser.tabs.query({}).then((tabs) => {
        for (const tab of tabs) {
          browser.browserAction.setBadgeText({
            tabId: tab.id,
            text: '',
          });
        }
      });
      browser.browserAction.setBadgeText({ text: ' ' });
    }
  }
};

/**
 * Returns the String reason the text on the toolbar icon / badge is 'new'
 *
 */
function getNewBadgeTextReason() {
  return newBadgeTextReason;
};


browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'showIconBadgeCTA' && typeof request.value === 'boolean') {
    showIconBadgeCTA(request.value);
    sendResponse({});
  }
});

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'getNewBadgeTextReason') {
    sendResponse({ reason: getNewBadgeTextReason() });
  }
});


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Handles notifications.
 */

const {Prefs} = __webpack_require__(5);

const {MILLIS_IN_MINUTE, MILLIS_IN_HOUR, MILLIS_IN_DAY} = __webpack_require__(20);
const {Downloader, Downloadable} = __webpack_require__(25);
const {compareVersions} = __webpack_require__(31);
const {analytics} = __webpack_require__(40);

const INITIAL_DELAY = 1 * MILLIS_IN_MINUTE;
const CHECK_INTERVAL = 1 * MILLIS_IN_HOUR;
const EXPIRATION_INTERVAL = 1 * MILLIS_IN_DAY;

/**
 * The default locale for the localization of notification texts.
 * @type {string}
 * @default
 */
const DEFAULT_LOCALE = "en-US";

/**
 * Returns the numerical severity of a notification.
 * @param {object} notification The notification.
 * @returns {number} The numerical severity of the notification.
 */
function getNumericalSeverity(notification)
{
  switch (notification.type)
  {
    case "information":
      return 0;
    case "newtab":
    case "relentless":
      return 1;
    case "critical":
      return 2;
  }

  return 0;
}

/**
 * Saves notification data to preferences.
 * @param {string} [key] The key to save.
 */
function saveNotificationData(key = "notificationdata")
{
  // JSON values aren't saved unless they are assigned a different object.
  Prefs[key] = JSON.parse(JSON.stringify(Prefs[key]));
}

/**
 * Localizes a notification text.
 *
 * @param {object} translations The set of translations from which to select
 *   the localization.
 * @param {string} locale The locale string to use for the selection. If no
 *   localized version is found in the `translations` object for the given
 *   locale, the
 *   {@link module:notifications~DEFAULT_LOCALE default locale} is used.
 *
 * @returns {*} The localized text; `undefined` if no localized version is
 *   found in the `translations` object.
 */
function localize(translations, locale)
{
  if (locale in translations)
    return translations[locale];

  let languagePart = locale.substring(0, locale.indexOf("-"));
  if (languagePart && languagePart in translations)
    return translations[languagePart];

  return translations[DEFAULT_LOCALE];
}

function isValidNotification(notification)
{
  // Only notifications that are meant to be opened in a new tab must
  // contain at least one URL to open.
  if (notification.type == "newtab" &&
      !(notification.links && notification.links.length > 0))
    return false;

  return true;
}

/**
 * `{@link module:notifications.notifications}` implementation.
 */
class Notifications
{
  /**
   * @hideconstructor
   */
  constructor()
  {
    /**
     * Whether the fetching of notifications has been started.
     * @private
     */
    this._started = false;

    /**
     * Whether all ignorable notifications should be ignored.
     * @type {boolean}
     */
    this.ignored = false;

    /**
     * The locale for the localization of notification texts.
     * @type {string}
     * @default {@link module:notifications~DEFAULT_LOCALE}
     */
    this.locale = DEFAULT_LOCALE;

    /**
     * Listeners for notifications to be shown.
     * @type {Set.<function>}
     * @private
     */
    this._showListeners = new Set();

    /**
     * Local notifications added via
     * `{@link module:notifications~Notifications#addNotification
     *         addNotification()}`.
     * @type {Set.<object>}
     * @private
     */
    this._localNotifications = new Set();

    /**
     * The object providing actual downloading functionality.
     * @type {module:downloader.Downloader}
     * @private
     */
    this._downloader = new Downloader(this._getDownloadables.bind(this));

    this._downloader.onExpirationChange = this._onExpirationChange.bind(this);
    this._downloader.onDownloadSuccess = this._onDownloadSuccess.bind(this);
    this._downloader.onDownloadError = this._onDownloadError.bind(this);
    this._onBlockedTotal = this._onBlockedTotal.bind(this);
  }

  /**
   * Starts fetching notifications.
   *
   * No notifications are fetched until this function has been called at least
   * once.
   */
  start()
  {
    if (this._started)
      return;

    Prefs.on("blocked_total", this._onBlockedTotal);

    this._downloader.scheduleChecks(CHECK_INTERVAL, INITIAL_DELAY);
    this._started = true;
  }

  /**
   * Stops fetching notifications.
   */
  stop()
  {
    this._started = false;
    this._downloader.unscheduleChecks();

    Prefs.off("blocked_total", this._onBlockedTotal);
  }

  /**
   * Yields a `{@link module:downloader.Downloadable Downloadable}` instance
   * for the notifications download.
   * @yields {module:downloader.Downloadable}
   * @private
   */
  *_getDownloadables()
  {
    let {notificationurl: url, notificationdata} = Prefs;

    let downloadable = new Downloadable(url);

    if (analytics.isTrusted(url))
      downloadable.firstVersion = analytics.getFirstVersion();

    if (typeof notificationdata.lastError == "number")
      downloadable.lastError = notificationdata.lastError;
    if (typeof notificationdata.lastCheck == "number")
      downloadable.lastCheck = notificationdata.lastCheck;

    if (typeof notificationdata.data == "object" &&
        "version" in notificationdata.data)
      downloadable.lastVersion = notificationdata.data.version;

    if (typeof notificationdata.softExpiration == "number")
      downloadable.softExpiration = notificationdata.softExpiration;
    if (typeof notificationdata.hardExpiration == "number")
      downloadable.hardExpiration = notificationdata.hardExpiration;
    if (typeof notificationdata.downloadCount == "number")
      downloadable.downloadCount = notificationdata.downloadCount;

    yield downloadable;
  }

  _onExpirationChange(downloadable)
  {
    Prefs.notificationdata.lastCheck = downloadable.lastCheck;
    Prefs.notificationdata.softExpiration = downloadable.softExpiration;
    Prefs.notificationdata.hardExpiration = downloadable.hardExpiration;

    saveNotificationData();
  }

  _onDownloadSuccess(downloadable, responseText, errorCallback,
                     redirectCallback)
  {
    try
    {
      let data = JSON.parse(responseText);

      if (typeof data.version == "string" &&
          analytics.isTrusted(downloadable.redirectURL || downloadable.url))
        analytics.recordVersion(data.version);

      let notifications = [];
      for (let notification of data.notifications)
      {
        if (!isValidNotification(notification))
        {
          console.warn(`Invalid notification with ID "${notification.id}"`);
          continue;
        }

        if ("severity" in notification)
        {
          if (!("type" in notification))
            notification.type = notification.severity;
          delete notification.severity;
        }

        notifications.push(notification);
      }
      data.notifications = notifications;

      Prefs.notificationdata.data = data;
    }
    catch (error)
    {
      console.warn(error);
      errorCallback("synchronize_invalid_data");
      return;
    }

    Prefs.notificationdata.lastError = 0;
    Prefs.notificationdata.downloadStatus = "synchronize_ok";
    [
      Prefs.notificationdata.softExpiration,
      Prefs.notificationdata.hardExpiration
    ] = this._downloader.processExpirationInterval(EXPIRATION_INTERVAL);
    Prefs.notificationdata.downloadCount = downloadable.downloadCount;

    saveNotificationData();

    this.showNext();
  }

  _onDownloadError(downloadable, downloadURL, error, responseStatus,
                   redirectCallback)
  {
    Prefs.notificationdata.lastError = Date.now();
    Prefs.notificationdata.downloadStatus = error;

    saveNotificationData();
  }

  _onBlockedTotal()
  {
    this.showNext();
  }

  /**
   * Adds a listener for notifications to be shown.
   * @param {function} listener Listener to be invoked when a notification is
   *   to be shown.
   */
  addShowListener(listener)
  {
    this._showListeners.add(listener);
  }

  /**
   * Removes the supplied listener.
   * @param {function} listener Listener that was added via
   *   `{@link module:notifications~Notifications#addShowListener
   *           addShowListener()}`.
   */
  removeShowListener(listener)
  {
    this._showListeners.delete(listener);
  }

  /**
   * Returns whether user preferences indicate that notifications
   * should be ignored.
   * @return {boolean}
   */
  shouldIgnoreNotifications()
  {
    return this.ignored ||
      Prefs.notifications_ignoredcategories.includes("*");
  }

  /**
   * Returns all local and remote notifications.
   * @returns {Array.<object>} All local and remote notifications.
   * @private
   */
  _getNotifications()
  {
    let remoteNotifications = [];
    if (typeof Prefs.notificationdata.data == "object" &&
        Prefs.notificationdata.data.notifications instanceof Array)
      remoteNotifications = Prefs.notificationdata.data.notifications;

    return [...this._localNotifications, ...remoteNotifications];
  }

  /**
   * Determines which notification is to be shown next.
   * @returns {?object} The notification to be shown, or `null` if there is
   *   none.
   * @private
   */
  _getNextToShow()
  {
    let notifications = this._getNotifications();
    if (notifications.length == 0)
      return null;

    const {addonName, addonVersion, application, applicationVersion,
           platform, platformVersion} = __webpack_require__(7);

    let targetChecks = {
      extension: v => v == addonName,
      extensionMinVersion:
        v => compareVersions(addonVersion, v) >= 0,
      extensionMaxVersion:
        v => compareVersions(addonVersion, v) <= 0,
      application: v => v == application,
      applicationMinVersion:
        v => compareVersions(applicationVersion, v) >= 0,
      applicationMaxVersion:
        v => compareVersions(applicationVersion, v) <= 0,
      platform: v => v == platform,
      platformMinVersion:
        v => compareVersions(platformVersion, v) >= 0,
      platformMaxVersion:
        v => compareVersions(platformVersion, v) <= 0,
      blockedTotalMin: v => Prefs.show_statsinpopup &&
        Prefs.blocked_total >= v,
      blockedTotalMax: v => Prefs.show_statsinpopup &&
        Prefs.blocked_total <= v,
      locales: v => v.includes(this.locale)
    };

    let notificationToShow = null;
    for (let notification of notifications)
    {
      if (notification.type != "critical")
      {
        let shown;
        if (typeof Prefs.notificationdata.shown == "object")
          shown = Prefs.notificationdata.shown[notification.id];

        if (typeof shown != "undefined")
        {
          if (typeof notification.interval == "number")
          {
            if (shown + notification.interval > Date.now())
              continue;
          }
          else if (shown)
          {
            continue;
          }
        }

        if (notification.type != "relentless" &&
            this.shouldIgnoreNotifications())
          continue;
      }

      if (notification.targets instanceof Array)
      {
        let match = false;

        for (let target of notification.targets)
        {
          let keys = Object.keys(target);
          if (keys.every(
            key => Object.prototype.hasOwnProperty.call(targetChecks, key) &&
                   targetChecks[key](target[key]))
          )
          {
            match = true;
            break;
          }
        }

        if (!match)
          continue;
      }

      if (!notificationToShow || getNumericalSeverity(notification) >
                                 getNumericalSeverity(notificationToShow))
        notificationToShow = notification;
    }

    return notificationToShow;
  }

  /**
   * Shows a notification once.
   * @param {object} notification The notification to show.
   * @param {object} [options]
   * @param {boolean} [options.ignorable=false] If true, user preference will
   *   be considered to determine whether notification should be shown.
   */
  showNotification(notification, options = {})
  {
    if (options.ignorable && this.shouldIgnoreNotifications())
      return;

    for (let showListener of this._showListeners)
      showListener(notification);
  }

  /**
   * Invokes the listeners added via
   * `{@link module:notifications~Notifications#addShowListener
   *         addShowListener()}` with the next notification to be shown.
   */
  showNext()
  {
    let notification = this._getNextToShow();
    if (notification)
    {
      for (let showListener of this._showListeners)
        showListener(notification);
    }
  }

  /**
   * Marks a notification as shown.
   * @param {string} id The ID of the notification to be marked as shown.
   */
  markAsShown(id)
  {
    let notifications = this._getNotifications();

    // Ignore if there's no notification with the given ID.
    if (!notifications.some(notification => notification.id == id))
      return;

    let now = Date.now();
    let data = Prefs.notificationdata;

    if (data.shown instanceof Array)
    {
      let newShown = {};
      for (let oldId of data.shown)
        newShown[oldId] = now;
      data.shown = newShown;
    }

    if (typeof data.shown != "object")
      data.shown = {};

    data.shown[id] = now;

    saveNotificationData();
  }

  /**
   * Localizes the texts of the given notification based on the
   * {@link module:notifications~Notifications#locale locale}.
   * @param {object} notification The notification.
   * @returns {object} The localized texts.
   */
  getLocalizedTexts(notification)
  {
    let textKeys = ["title", "message"];
    let localizedTexts = {};

    for (let key of textKeys)
    {
      if (key in notification)
      {
        if (typeof notification[key] == "string")
          localizedTexts[key] = notification[key];
        else
          localizedTexts[key] = localize(notification[key], this.locale);
      }
    }

    return localizedTexts;
  }

  /**
   * Adds a local notification.
   * @param {object} notification The notification to add.
   */
  addNotification(notification)
  {
    if (!isValidNotification(notification))
      throw new Error(`Invalid notification with ID "${notification.id}"`);

    this._localNotifications.add(notification);
  }

  /**
   * Removes an existing local notification.
   * @param {object} notification The notification to remove.
   */
  removeNotification(notification)
  {
    this._localNotifications.delete(notification);
  }

  /**
   * Toggles whether notifications of a specific category should be ignored.
   * @param {string} category The notification category identifier.
   * @param {boolean} [forceValue] Whether to force the specified value.
   */
  toggleIgnoreCategory(category, forceValue)
  {
    let categories = Prefs.notifications_ignoredcategories;
    let index = categories.indexOf(category);
    if (index == -1 && forceValue != false)
      categories.push(category);
    else if (index != -1 && forceValue != true)
      categories.splice(index, 1);

    saveNotificationData("notifications_ignoredcategories");
  }
}

/**
 * Regularly fetches notifications and decides which notification to show.
 * @type {module:notifications~Notifications}
 */
exports.notifications = new Notifications();


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * A `Recommendation` object represents a recommended filter subscription.
 */
class Recommendation
{
  /**
   * Creates a `Recommendation` object from the given source object.
   * @param {object} source The source object.
   * @private
   */
  constructor(source)
  {
    this._source = source;
  }

  /**
   * The type of the recommended filter subscription.
   * @type {string}
   */
  get type()
  {
    return this._source.type;
  }

  /**
   * The languages of the recommended filter subscription.
   * @type {Array.<string>}
   */
  get languages()
  {
    return this._source.languages ? [...this._source.languages] : [];
  }

  /**
   * The title of the recommended filter subscription.
   * @type {string}
   */
  get title()
  {
    return this._source.title;
  }

  /**
   * The URL of the recommended filter subscription.
   * @type {string}
   */
  get url()
  {
    return this._source.url;
  }

  /**
   * The home page of the recommended filter subscription.
   * @type {string}
   */
  get homepage()
  {
    return this._source.homepage;
  }
}

/**
 * Yields `{@link module:recommendations~Recommendation Recommendation}` objects
 * representing recommended filter subscriptions.
 *
 * @generator
 * @yields {module:recommendations~Recommendation} An object representing a
 *   recommended filter subscription.
 */
exports.recommendations = function* recommendations()
{
  for (let source of __webpack_require__(65))
    yield new Recommendation(source);
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * A `Cache` object represents a cache of arbitrary data.
 * @package
 */
exports.Cache = class Cache extends Map
{
  /**
   * Creates a cache.
   * @param {number} capacity The maximum number of entries that can exist in
   *   the cache.
   */
  constructor(capacity)
  {
    // Note: This check works for non-number values.
    if (!(capacity >= 1))
      throw new Error("capacity must be a positive number.");

    super();
    this._capacity = capacity;
  }

  /**
   * Writes an entry to the cache.
   *
   * If the cache has reached the specified maximum number of entries, all the
   * old entries are cleared first.
   *
   * @param {?*} key The key for the entry.
   * @param {?*} value The value of the entry.
   */
  set(key, value)
  {
    // To prevent logical errors, neither key nor value is allowed to be
    // undefined.
    if (typeof key == "undefined")
      throw new Error("key must not be undefined.");

    if (typeof value == "undefined")
      throw new Error("value must not be undefined.");

    if (this.size == this._capacity && !this.has(key))
      this.clear();

    super.set(key, value);
  }
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Downloads a set of URLs in regular time intervals.
 */

const {MILLIS_IN_DAY} = __webpack_require__(20);
const {isLocalhost} = __webpack_require__(9);

/**
 * A type of function that yields `{@link module:downloader.Downloadable}`
 * objects to a `{@link module:downloader.Downloader}`.
 *
 * **Note**: The implementation must yield a new
 * `{@link module:downloader.Downloadable}` instance on each call with
 * up-to-date values for properties like
 * `{@link module:downloader.Downloadable#lastCheck}`,
 * `{@link module:downloader.Downloadable#lastVersion}`,
 * `{@link module:downloader.Downloadable#downloadCount}`, and others. If a
 * value is outdated, it may result in unexpected behavior.
 *
 * @callback DataSource
 *
 * @yields {module:downloader.Downloadable}
 * @generator
 *
 * @see module:downloader.Downloader
 * @see module:downloader.Downloader#dataSource
 */

/**
 * Use a `Downloader` object to download a set of URLs at regular time
 * intervals.
 *
 * This class is used by `{@link module:synchronizer.synchronizer}` and
 * `{@link module:notifications.notifications}`.
 *
 * @example
 *
 * function* dataSource()
 * {
 *   yield new Downloadable("https://example.com/filters.txt");
 * }
 *
 * let initialDelay = 1000;
 * let checkInterval = 60000;
 *
 * let downloader = new Downloader(dataSource);
 * downloader.scheduleChecks(checkInterval, initialDelay);
 *
 * downloader.onDownloadStarted = function(downloadable)
 * {
 *   console.log(`Downloading ${downloadable.url} ...`);
 * }
 *
 * @package
 */
exports.Downloader = class Downloader
{
  /**
   * Creates a new downloader instance.
   * @param {module:downloader~DataSource} dataSource
   *   A function that yields `{@link module:downloader.Downloadable}` objects
   *   on each {@link module:downloader.Downloader#scheduleChecks check}.
   */
  constructor(dataSource)
  {
    /**
     * Maximal time interval that the checks can be left out until the soft
     * expiration interval increases.
     * @type {number}
     */
    this.maxAbsenceInterval = 1 * MILLIS_IN_DAY;

    /**
     * Minimal time interval before retrying a download after an error.
     * @type {number}
     */
    this.minRetryInterval = 1 * MILLIS_IN_DAY;

    /**
     * Maximal allowed expiration interval; larger expiration intervals will be
     * corrected.
     * @type {number}
     */
    this.maxExpirationInterval = 14 * MILLIS_IN_DAY;

    /**
     * Maximal number of redirects before the download is considered as failed.
     * @type {number}
     */
    this.maxRedirects = 5;

    /**
     * Called whenever expiration intervals for an object need to be adapted.
     * @type {function?}
     */
    this.onExpirationChange = null;

    /**
     * Callback to be triggered whenever a download starts.
     * @type {function?}
     */
    this.onDownloadStarted = null;

    /**
     * Callback to be triggered whenever a download finishes successfully.
     *
     * The callback can return an error code to indicate that the data is
     * wrong.
     *
     * @type {function?}
     */
    this.onDownloadSuccess = null;

    /**
     * Callback to be triggered whenever a download fails.
     * @type {function?}
     */
    this.onDownloadError = null;

    /**
     * A function that yields `{@link module:downloader.Downloadable}` objects
     * on each {@link module:downloader.Downloader#scheduleChecks check}.
     * @type {module:downloader~DataSource}
     */
    this.dataSource = dataSource;

    /**
     * Set containing the URLs of objects currently being downloaded.
     * @type {Set.<string>}
     */
    this._downloading = new Set();

    /**
     * Store the timeout ID for scheduled checks.
     * @type {number}
     */
    this._timeout = 0;
  }

  /**
   * Schedules checks at regular time intervals.
   *
   * @param {number} interval The interval between checks in milliseconds.
   * @param {number} delay The delay before the initial check in milliseconds.
   */
  scheduleChecks(interval, delay)
  {
    // clear previous timeouts if called too many times
    this.unscheduleChecks();

    let check = () =>
    {
      try
      {
        this._doCheck();
      }
      finally
      {
        // Schedule the next check only after the callback has finished with
        // the current check.
        this._timeout =
          setTimeout(check, interval); // eslint-disable-line no-undef
      }
    };

    // Note: test/_common.js overrides setTimeout() for the tests; if this
    // global function is used anywhere else, it may give incorrect results.
    // This is why we disable ESLint's no-undef rule locally.
    // https://gitlab.com/eyeo/adblockplus/adblockpluscore/issues/43
    this._timeout = setTimeout(check, delay); // eslint-disable-line no-undef
  }

  /**
   * Clear previously scheduled checks, if any.
   */
  unscheduleChecks()
  {
    if (this._timeout)
    {
      clearTimeout(this._timeout); // eslint-disable-line no-undef
      this._timeout = 0;
    }
  }

  /**
   * Checks whether anything needs downloading.
   */
  _doCheck()
  {
    let now = Date.now();
    for (let downloadable of this.dataSource())
    {
      if (downloadable.lastCheck &&
          now - downloadable.lastCheck > this.maxAbsenceInterval)
      {
        // No checks for a long time interval - user must have been offline,
        // e.g.  during a weekend. Increase soft expiration to prevent load
        // peaks on the server.
        downloadable.softExpiration += now - downloadable.lastCheck;
      }
      downloadable.lastCheck = now;

      // Sanity check: do expiration times make sense? Make sure people changing
      // system clock don't get stuck with outdated subscriptions.
      if (downloadable.hardExpiration - now > this.maxExpirationInterval)
        downloadable.hardExpiration = now + this.maxExpirationInterval;
      if (downloadable.softExpiration - now > this.maxExpirationInterval)
        downloadable.softExpiration = now + this.maxExpirationInterval;

      // Notify the caller about changes to expiration parameters
      if (this.onExpirationChange)
        this.onExpirationChange(downloadable);

      // Does that object need downloading?
      if (downloadable.softExpiration > now &&
          downloadable.hardExpiration > now)
        continue;

      // Do not retry downloads too often
      if (downloadable.lastError &&
          now - downloadable.lastError < this.minRetryInterval)
        continue;

      this._download(downloadable, 0);
    }
  }

  /**
   * Checks whether an address is currently being downloaded.
   * @param {string} url
   * @returns {boolean}
   */
  isDownloading(url)
  {
    return this._downloading.has(url);
  }

  /**
   * Starts downloading for an object.
   * @param {Downloadable} downloadable
   */
  download(downloadable)
  {
    this._download(downloadable, 0);
  }

  /**
   * Generates the real download URL for an object by appending various
   * parameters.
   * @param {Downloadable} downloadable
   * @returns {string}
   */
  getDownloadUrl(downloadable)
  {
    const {addonName, addonVersion, application, applicationVersion,
           platform, platformVersion} = __webpack_require__(7);

    let url = downloadable.redirectURL || downloadable.url;
    if (url.includes("?"))
      url += "&";
    else
      url += "?";

    // We limit the download count to 4+ to keep the request anonymized.
    let {downloadCount, method} = downloadable;
    if (downloadCount > 4)
      downloadCount = "4+";

    url += "addonName=" + encodeURIComponent(addonName) +
           "&addonVersion=" + encodeURIComponent(addonVersion) +
           "&application=" + encodeURIComponent(application) +
           "&applicationVersion=" + encodeURIComponent(applicationVersion) +
           "&platform=" + encodeURIComponent(platform) +
           "&platformVersion=" + encodeURIComponent(platformVersion) +
           "&lastVersion=" + encodeURIComponent(downloadable.lastVersion) +
           "&downloadCount=" + encodeURIComponent(downloadCount) +
           "&disabled=" + String(method === "HEAD");

    if (downloadable.firstVersion && !downloadable.redirectURL)
      url += "&firstVersion=" + encodeURIComponent(downloadable.firstVersion);

    return url;
  }

  _download(downloadable, redirects)
  {
    if (this.isDownloading(downloadable.url))
      return;

    let downloadUrl = this.getDownloadUrl(downloadable);
    let responseStatus = 0;

    let errorCallback = error =>
    {
      console.warn("Adblock Plus: Downloading URL " + downloadable.url +
                   " failed (" + error + ")\n" +
                   "Download address: " + downloadUrl + "\n" +
                   "Server response: " + responseStatus);

      if (this.onDownloadError)
      {
        // Allow one extra redirect if the error handler gives us a redirect URL
        let redirectCallback = null;
        if (redirects <= this.maxRedirects)
        {
          redirectCallback = url =>
          {
            downloadable.redirectURL = url;
            this._download(downloadable, redirects + 1);
          };
        }

        this.onDownloadError(downloadable, downloadUrl, error, responseStatus,
                             redirectCallback);
      }
    };

    if (!Downloader.isValidURL(downloadUrl))
    {
      errorCallback("synchronize_invalid_url");
      return;
    }

    let requestURL = new URL(downloadUrl);

    let initObj = {
      cache: "no-store",
      credentials: "omit",
      referrer: "no-referrer",
      method: downloadable.method
    };

    let handleError = () =>
    {
      this._downloading.delete(downloadable.url);
      errorCallback("synchronize_connection_error");
    };

    let handleResponse = response =>
    {
      this._downloading.delete(downloadable.url);

      // If the Response.url property is available [1], disallow redirection
      // from HTTPS to any other protocol.
      // [1]: https://developer.mozilla.org/en-US/docs/Web/API/Response/url#Browser_compatibility
      if (typeof response.url == "string" && requestURL.protocol == "https:" &&
          new URL(response.url).protocol != requestURL.protocol)
      {
        errorCallback("synchronize_connection_error");
        return;
      }

      responseStatus = response.status;

      if (responseStatus != 200)
      {
        errorCallback("synchronize_connection_error");
        return;
      }

      // We need to keep updated the subscription version even via HEAD.
      if (downloadable.method === "HEAD")
      {
        // However, as we don't know if the server would respond with such
        // detail, we need to be sure there is such `Date` or `date` field.
        let date = response.headers.get("Date") || response.headers.get("date");
        if (date)
        {
          // if that's the case, we want it to be formatted as YYYYMMDDHHMM.
          downloadable.lastVersion =
            new Date(date).toISOString().replace(/\D/g, "").slice(0, 12);
        }
      }
      else
      {
        downloadable.downloadCount++;
      }

      response.text().then(
        responseText =>
        {
          this.onDownloadSuccess(
            downloadable, responseText, errorCallback, url =>
            {
              if (redirects >= this.maxRedirects)
              {
                errorCallback("synchronize_connection_error");
                return;
              }

              downloadable.redirectURL = url;
              this._download(downloadable, redirects + 1);
            }
          );
        },
        () =>
        {
          errorCallback("synchronize_connection_error");
        }
      );
    };

    fetch(requestURL.href, initObj).then(handleResponse, handleError);

    this._downloading.add(downloadable.url);

    if (this.onDownloadStarted)
      this.onDownloadStarted(downloadable);
  }

  /**
   * Produces a soft and a hard expiration interval for a given supplied
   * expiration interval.
   * @param {number} interval
   * @returns {Array.<number>} soft and hard expiration interval
   */
  processExpirationInterval(interval)
  {
    interval = Math.min(Math.max(interval, 0), this.maxExpirationInterval);
    let soft = Math.round(interval * (Math.random() * 0.4 + 0.8));
    let hard = interval * 2;
    let now = Date.now();
    return [now + soft, now + hard];
  }
};

/**
 * Checks whether a URL is a valid download URL.
 *
 * For a URL to be a valid download URL, its scheme must be `https` or `data`.
 * If the host component of the URL is `localhost`, `127.0.0.1`, or `[::1]`,
 * however, but its scheme is not `https` or `data`, the URL is still
 * considered to be a valid download URL.
 *
 * `https://example.com/`, `data:,Hello%2C%20World!`, and
 * `http://127.0.0.1/example.txt` are all examples of valid download URLs.
 *
 * @param {string} url The URL.
 *
 * @returns {boolean} Whether the URL is a valid download URL.
 *
 * @package
 */
exports.Downloader.isValidURL = function isValidURL(url)
{
  try
  {
    url = new URL(url);
  }
  catch (error)
  {
    return false;
  }

  if (!["https:", "data:"].includes(url.protocol) &&
      !isLocalhost(url.hostname))
    return false;

  return true;
};

/**
 * A `Downloadable` object represents a downloadable resource.
 * @package
 */
exports.Downloadable = class Downloadable
{
  /**
   * Creates an object that can be downloaded by the downloader.
   * @param {string} url  URL that has to be requested for the object
   */
  constructor(url)
  {
    /**
     * URL that the download was redirected to if any.
     * @type {string?}
     */
    this.redirectURL = null;

    /**
     * Time of last download error or 0 if the last download was successful.
     * @type {number}
     */
    this.lastError = 0;

    /**
     * Time of last check whether the object needs downloading.
     * @type {number}
     */
    this.lastCheck = 0;

    /**
     * Object version corresponding to the last successful download.
     * @type {number}
     */
    this.lastVersion = 0;

    /**
     * A string indicating the version of the first ever downloaded resource,
     * in `YYYY[MM[DD]][-E]` format or just `"0"` or `"0-E"`.
     *
     * Note that unlike `{@link module:downloader.Downloadable#lastVersion}`
     * this property is related to analytics and its value is common across all
     * downloadable resources.
     *
     * If `{@link module:downloader.Downloadable#url}` is not a trusted URL,
     * the value of this property should be set to `null`.
     *
     * @see module:analytics~Analytics#getFirstVersion
     * @see module:analytics~Analytics#isTrusted
     *
     * @type {?string}
     *
     * @package
     */
    this.firstVersion = null;

    /**
     * Soft expiration interval; will increase if no checks are performed for a
     * while.
     * @type {number}
     */
    this.softExpiration = 0;

    /**
     * Hard expiration interval; this is fixed.
     * @type {number}
     */
    this.hardExpiration = 0;

    /**
     * Number indicating how often the object was downloaded.
     * @type {number}
     */
    this.downloadCount = 0;

    /**
     * Request method to use, which is either "GET" or "HEAD".
     * @type {string}
     */
    this.method = "GET";

    /**
     * URL that has to be requested for the object.
     * @type {string}
     */
    this.url = url;
  }
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Element hiding implementation.
 */

const {elemHideExceptions} = __webpack_require__(27);
const {domainSuffixes} = __webpack_require__(9);
const {FiltersByDomain, FilterMap} = __webpack_require__(37);
const {Cache} = __webpack_require__(24);

/**
 * The maximum number of selectors in a CSS rule.
 *
 * This is used by
 * `{@link module:elemHide.createStyleSheet createStyleSheet()}` to split up a
 * long list of selectors into multiple rules.
 *
 * @const {number}
 * @default
 */
const SELECTOR_GROUP_SIZE = 1024;

/**
 * `{@link module:elemHide.elemHide elemHide}` implementation.
 */
class ElemHide
{
  /**
   * @hideconstructor
   */
  constructor()
  {
    /**
     * Lookup table, active flag, by filter by domain.
     *
     * (Only contains filters that aren't unconditionally matched for all
     * domains.)
     *
     * @type {FiltersByDomain}
     *
     * @private
     */
    this._filtersByDomain = new FiltersByDomain();

    /**
     * Lookup table, filter by selector.
     *
     * (Only used for selectors that are unconditionally matched for all
     * domains.)
     *
     * @type {Map.<string, Filter>}
     *
     * @private
     */
    this._filterBySelector = new Map();

    /**
     * This array caches the keys of
     * `{@link module:elemHide~ElemHide#_filterBySelector _filterBySelector}`
     * (selectors which unconditionally apply on all domains).
     *
     * It will be `null` if the cache needs to be rebuilt.
     *
     * @type {?Array.<string>}
     *
     * @private
     */
    this._unconditionalSelectors = null;

    /**
     * The default style sheet that applies on all domains.
     *
     * This is based on the value of
     * `{@link module:elemHide~ElemHide#_unconditionalSelectors
     *         _unconditionalSelectors}`.
     *
     * @type {?string}
     *
     * @private
     */
    this._defaultStyleSheet = null;

    /**
     * The common style sheet that applies on all unknown domains.
     *
     * This is a concatenation of the default style sheet and an additional
     * style sheet based on selectors from all generic filters that are not in
     * the `{@link module:elemHide~ElemHide#_unconditionalSelectors
     *             _unconditionalSelectors}` list.
     *
     * @type {?string}
     *
     * @private
     */
    this._commonStyleSheet = null;

    /**
     * Cache of generated domain-specific style sheets.
     *
     * This contains entries for only known domains. If a domain is unknown, it
     * gets `{@link module:elemHide~ElemHide#_commonStyleSheet
     *              _commonStyleSheet}`.
     *
     * @type {Cache.<string, string>}
     *
     * @private
     */
    this._styleSheetCache = new Cache(100);

    /**
     * Set containing known element hiding filters
     * @type {Set.<module:filterClasses.ElemHideFilter>}
     * @private
     */
    this._filters = new Set();

    /**
     * All domains known to occur in exceptions
     * @type {Set.<string>}
     * @private
     */
    this._exceptionDomains = new Set();

    elemHideExceptions.on("added", this._onExceptionAdded.bind(this));
  }

  /**
   * Removes all known element hiding filters.
   */
  clear()
  {
    this._commonStyleSheet = null;

    for (let collection of [this._styleSheetCache, this._filtersByDomain,
                            this._filterBySelector, this._filters,
                            this._exceptionDomains])
      collection.clear();

    this._unconditionalSelectors = null;
    this._defaultStyleSheet = null;
  }

  /**
   * Add a new element hiding filter.
   * @param {module:filterClasses.ElemHideFilter} filter
   */
  add(filter)
  {
    if (this._filters.has(filter))
      return;

    this._styleSheetCache.clear();
    this._commonStyleSheet = null;

    let {domains, selector} = filter;

    if (!(domains || elemHideExceptions.hasExceptions(selector)))
    {
      // The new filter's selector is unconditionally applied to all domains
      this._filterBySelector.set(selector, filter);
      this._unconditionalSelectors = null;
      this._defaultStyleSheet = null;
    }
    else
    {
      // The new filter's selector only applies to some domains
      this._filtersByDomain.add(filter, domains);
    }

    this._filters.add(filter);
  }

  /**
   * Removes an existing element hiding filter.
   * @param {module:filterClasses.ElemHideFilter} filter
   */
  remove(filter)
  {
    if (!this._filters.has(filter))
      return;

    this._styleSheetCache.clear();
    this._commonStyleSheet = null;

    let {selector} = filter;

    // Unconditially applied element hiding filters
    if (this._filterBySelector.get(selector) == filter)
    {
      this._filterBySelector.delete(selector);
      this._unconditionalSelectors = null;
      this._defaultStyleSheet = null;
    }
    // Conditionally applied element hiding filters
    else
    {
      this._filtersByDomain.remove(filter);
    }

    this._filters.delete(filter);
  }

  /**
   * Checks whether an element hiding filter exists.
   * @param {module:filterClasses.ElemHideFilter} filter
   * @returns {boolean}
   */
  has(filter)
  {
    return this._filters.has(filter);
  }

  /**
   * @typedef {object} ElemHideStyleSheet
   * @property {string} code CSS code.
   * @property {?Array.<string>} selectors List of selectors.
   * @property {?Array.<string>} exceptions List of exceptions.
   */

  /**
   * Returns a style sheet for a given domain based on the current set of
   * filters.
   *
   * @param {string} domain The domain.
   * @param {boolean} [specificOnly=false] Whether selectors from generic
   *   filters should be included.
   * @param {boolean} [includeSelectors=false] Whether the return value should
   *   include a separate list of selectors.
   * @param {boolean} [includeExceptions=false] Whether the return value should
   *   include a separate list of exceptions.
   *
   * @returns {module:elemHide~ElemHideStyleSheet} An object containing the CSS
   *   code and the list of selectors.
   */
  getStyleSheet(domain, specificOnly = false, includeSelectors = false,
                includeExceptions = false)
  {
    let code = null;
    let selectors = null;
    let exceptions = null;

    if (specificOnly)
    {
      if (includeExceptions)
      {
        let selectorsAndExceptions =
          this._getConditionalSelectorsWithExceptions(domain, true);

        selectors = selectorsAndExceptions.selectors;
        exceptions = selectorsAndExceptions.exceptions;
      }
      else
      {
        selectors = this._getConditionalSelectors(domain, true);
      }

      code = createStyleSheet(selectors);
    }
    else
    {
      let knownSuffix = this._getKnownSuffix(domain);

      if (includeSelectors || includeExceptions)
      {
        let selectorsAndExceptions =
          this._getConditionalSelectorsWithExceptions(knownSuffix, false);

        selectors = selectorsAndExceptions.selectors;
        exceptions = selectorsAndExceptions.exceptions;
        code = knownSuffix == "" ? this._getCommonStyleSheet() :
                 this._getDefaultStyleSheet() + createStyleSheet(selectors);

        selectors = this._getUnconditionalSelectors().concat(selectors);
      }
      else
      {
        code = knownSuffix == "" ? this._getCommonStyleSheet() :
                 this._getDefaultStyleSheet() +
                 this._getDomainSpecificStyleSheet(knownSuffix);
      }
    }

    return {
      code,
      selectors: includeSelectors ? selectors : null,
      exceptions: includeExceptions ? exceptions : null
    };
  }

  /**
   * Returns a style sheet for a given domain based on the current set of
   * filters.
   *
   * @param {string} domain The domain.
   * @param {boolean} [specificOnly=false] Whether selectors from generic
   *   filters should be included.
   * @param {boolean} [includeSelectors=false] Whether the return value should
   *   include a separate list of selectors.
   * @param {boolean} [includeExceptions=false] Whether the return value should
   *   include a separate list of exceptions.
   *
   * @returns {module:elemHide~ElemHideStyleSheet} An object containing the CSS
   *   code and the list of selectors.
   *
   * @deprecated Use
   *   <code>{@link module:elemHide~ElemHide#getStyleSheet}</code> instead.
   * @see module:elemHide~ElemHide#getStyleSheet
   */
  generateStyleSheetForDomain(domain, specificOnly = false,
                              includeSelectors = false,
                              includeExceptions = false)
  {
    return this.getStyleSheet(domain, specificOnly, includeSelectors,
                              includeExceptions);
  }

  /**
   * Returns the suffix of the given domain that is known.
   *
   * If no suffix is known, an empty string is returned.
   *
   * @param {?string} domain
   *
   * @returns {string}
   *
   * @private
   */
  _getKnownSuffix(domain)
  {
    for (let suffix of domainSuffixes(domain))
    {
      if (this._filtersByDomain.has(suffix) ||
          this._exceptionDomains.has(suffix))
        return suffix;
    }

    return "";
  }

  /**
   * Returns a list of selectors that apply on each website unconditionally.
   * @returns {string[]}
   * @private
   */
  _getUnconditionalSelectors()
  {
    if (!this._unconditionalSelectors)
      this._unconditionalSelectors = [...this._filterBySelector.keys()];

    return this._unconditionalSelectors;
  }

  /**
   * Returns the list of selectors that apply on a given domain from the subset
   * of filters that do not apply unconditionally on all domains.
   *
   * @param {string} domain The domain.
   * @param {boolean} specificOnly Whether selectors from generic filters should
   *   be included.
   *
   * @returns {Array.<string>} The list of selectors.
   *
   * @private
   */
  _getConditionalSelectors(domain, specificOnly)
  {
    let selectors = [];

    let excluded = new Set();

    for (let currentDomain of domainSuffixes(domain, !specificOnly))
    {
      let map = this._filtersByDomain.get(currentDomain);
      if (map)
      {
        for (let [filter, include] of (map instanceof FilterMap ?
                                         map.entries() : [[map, true]]))
        {
          if (!include)
          {
            excluded.add(filter);
          }
          else
          {
            let {selector} = filter;
            if ((excluded.size == 0 || !excluded.has(filter)) &&
                !elemHideExceptions.getException(selector, domain))
              selectors.push(selector);
          }
        }
      }
    }

    return selectors;
  }

  /**
   * Returns the list of selectors and the list of exceptions that apply on a
   * given domain from the subset of filters that do not apply unconditionally
   * on all domains.
   *
   * @param {string} domain The domain.
   * @param {boolean} specificOnly Whether selectors from generic filters should
   *   be included.
   *
   * @returns {{selectors: Array.<string>,
   *            exceptions: Array.<module:filterClasses.ElemHideException>}}
   *   An object containing the lists of selectors and exceptions.
   *
   * @private
   */
  _getConditionalSelectorsWithExceptions(domain, specificOnly)
  {
    let selectors = [];
    let exceptions = [];

    let excluded = new Set();

    for (let currentDomain of domainSuffixes(domain, !specificOnly))
    {
      let map = this._filtersByDomain.get(currentDomain);
      if (map)
      {
        for (let [filter, include] of (map instanceof FilterMap ?
                                         map.entries() : [[map, true]]))
        {
          if (!include)
          {
            excluded.add(filter);
          }
          else if (excluded.size == 0 || !excluded.has(filter))
          {
            let {selector} = filter;
            let exception = elemHideExceptions.getException(selector, domain);

            if (exception)
              exceptions.push(exception);
            else
              selectors.push(selector);
          }
        }
      }
    }

    return {selectors, exceptions};
  }

  /**
   * Returns the default style sheet that applies on all domains.
   * @returns {string}
   * @private
   */
  _getDefaultStyleSheet()
  {
    if (!this._defaultStyleSheet)
    {
      this._defaultStyleSheet =
        createStyleSheet(this._getUnconditionalSelectors());
    }

    return this._defaultStyleSheet;
  }

  /**
   * Returns the common style sheet that applies on all unknown domains.
   * @returns {string}
   * @private
   */
  _getCommonStyleSheet()
  {
    if (!this._commonStyleSheet)
    {
      this._commonStyleSheet =
        this._getDefaultStyleSheet() +
        createStyleSheet(this._getConditionalSelectors("", false));
    }

    return this._commonStyleSheet;
  }

  /**
   * Returns the domain-specific style sheet that applies on a given domain.
   * @param {string} domain
   * @returns {string}
   * @private
   */
  _getDomainSpecificStyleSheet(domain)
  {
    let styleSheet = this._styleSheetCache.get(domain);

    if (typeof styleSheet == "undefined")
    {
      styleSheet =
        createStyleSheet(this._getConditionalSelectors(domain, false));
      this._styleSheetCache.set(domain, styleSheet);
    }

    return styleSheet;
  }

  _onExceptionAdded(exception)
  {
    let {domains, selector} = exception;

    this._styleSheetCache.clear();
    this._commonStyleSheet = null;

    if (domains)
    {
      for (let domain of domains.keys())
      {
        // Note: Once an exception domain is known it never becomes unknown,
        // even when all the exceptions containing that domain are removed.
        // This is a best-case optimization.
        if (domain != "")
          this._exceptionDomains.add(domain);
      }
    }

    // If this is the first exception for a previously unconditionally applied
    // element hiding selector we need to take care to update the lookups.
    let unconditionalFilterForSelector = this._filterBySelector.get(selector);
    if (unconditionalFilterForSelector)
    {
      this._filtersByDomain.add(unconditionalFilterForSelector);
      this._filterBySelector.delete(selector);
      this._unconditionalSelectors = null;
      this._defaultStyleSheet = null;
    }
  }
}

/**
 * Container for element hiding filters.
 * @type {module:elemHide~ElemHide}
 */
exports.elemHide = new ElemHide();

/**
 * Yields rules from a style sheet returned by
 * `{@link module:elemHide.createStyleSheet createStyleSheet()}`.
 *
 * @param {string} styleSheet A style sheet returned by
 *   `{@link module:elemHide.createStyleSheet createStyleSheet()}`. If the
 *   given style sheet is *not* a value previously returned by a call to
 *   `{@link module:elemHide.createStyleSheet createStyleSheet()}`, the
 *   behavior is undefined.
 *
 * @generator
 * @yields {string} A rule from the given style sheet.
 */
exports.rulesFromStyleSheet = function* rulesFromStyleSheet(styleSheet)
{
  let startIndex = 0;
  while (startIndex < styleSheet.length)
  {
    let ruleTerminatorIndex = styleSheet.indexOf("\n", startIndex);
    yield styleSheet.substring(startIndex, ruleTerminatorIndex);
    startIndex = ruleTerminatorIndex + 1;
  }
};

/**
 * Splits a list of selectors into groups determined by the value of
 * `{@link module:elemHide~SELECTOR_GROUP_SIZE}`.
 *
 * @param {Array.<string>} selectors
 *
 * @yields {Array.<string>}
 */
function* splitSelectors(selectors)
{
  // Chromium's Blink engine supports only up to 8,192 simple selectors, and
  // even fewer compound selectors, in a rule. The exact number of selectors
  // that would work depends on their sizes (e.g. "#foo .bar" has a size of 2).
  // Since we don't know the sizes of the selectors here, we simply split them
  // into groups of 1,024, based on the reasonable assumption that the average
  // selector won't have a size greater than 8. The alternative would be to
  // calculate the sizes of the selectors and divide them up accordingly, but
  // this approach is more efficient and has worked well in practice. In theory
  // this could still lead to some selectors not working on Chromium, but it is
  // highly unlikely.
  // See issue #6298 and https://crbug.com/804179
  for (let i = 0; i < selectors.length; i += SELECTOR_GROUP_SIZE)
    yield selectors.slice(i, i + SELECTOR_GROUP_SIZE);
}

/**
 * Escapes curly braces to prevent CSS rule injection.
 *
 * @param {string} selector
 *
 * @returns {string}
 */
function escapeSelector(selector)
{
  return selector.replace("{", "\\7B ").replace("}", "\\7D ");
}

/**
 * Creates an element hiding CSS rule for a given list of selectors.
 *
 * @param {Array.<string>} selectors The list of selectors.
 * @param {string} [declarationBlock] Optional CSS code to use as the
 *   declaration block. By default, the code `{display: none !important;}` is
 *   used. If specified, the value is injected as-is into the rule.
 *
 * @returns {string} A CSS rule.
 */
function createRule(selectors, declarationBlock = "{display: none !important;}")
{
  let rule = "";

  for (let i = 0; i < selectors.length - 1; i++)
    rule += escapeSelector(selectors[i]) + ", ";

  rule += escapeSelector(selectors[selectors.length - 1]) + " " +
          declarationBlock + "\n";

  return rule;
}

let createStyleSheet =
/**
 * Creates an element hiding CSS style sheet from a given list of selectors.
 *
 * @param {Array.<string>} selectors The list of selectors.
 * @param {string} [declarationBlock] Optional CSS code to use as the
 *   declaration block. By default, the code `{display: none !important;}` is
 *   used. If specified, the value is injected as-is into the style sheet.
 *
 * @returns {string} A CSS style sheet.
 */
exports.createStyleSheet = function createStyleSheet(selectors,
                                                     declarationBlock)
{
  let styleSheet = "";

  for (let selectorGroup of splitSelectors(selectors))
    styleSheet += createRule(selectorGroup, declarationBlock);

  return styleSheet;
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Element hiding exceptions implementation.
 */

const {EventEmitter} = __webpack_require__(12);

/**
 * `{@link module:elemHideExceptions.elemHideExceptions elemHideExceptions}`
 * implementation.
 */
class ElemHideExceptions extends EventEmitter
{
  /**
   * @hideconstructor
   */
  constructor()
  {
    super();

    /**
     * Lookup table, lists of element hiding exceptions by selector
     * @type {Map.<string, Set.<module:filterClasses.ElemHideException>>}
     * @private
     */
    this._exceptionsBySelector = new Map();

    /**
     * Set containing known element hiding exceptions
     * @type {Set.<module:filterClasses.ElemHideException>}
     * @private
     */
    this._exceptions = new Set();
  }

  /**
   * Removes all known element hiding exceptions.
   */
  clear()
  {
    this._exceptionsBySelector.clear();
    this._exceptions.clear();
  }

  /**
   * Adds a new element hiding exception.
   * @param {module:filterClasses.ElemHideException} exception
   */
  add(exception)
  {
    if (this._exceptions.has(exception))
      return;

    let {selector} = exception;
    let set = this._exceptionsBySelector.get(selector);
    if (set)
      set.add(exception);
    else
      this._exceptionsBySelector.set(selector, new Set([exception]));

    this._exceptions.add(exception);

    this.emit("added", exception);
  }

  /**
   * Removes an existing element hiding exception.
   * @param {module:filterClasses.ElemHideException} exception
   */
  remove(exception)
  {
    if (!this._exceptions.has(exception))
      return;

    let {selector} = exception;
    let set = this._exceptionsBySelector.get(selector);
    set.delete(exception);
    if (set.size == 0)
      this._exceptionsBySelector.delete(selector);

    this._exceptions.delete(exception);

    this.emit("removed", exception);
  }

  /**
   * Checks whether an element hiding exception exists.
   * @param {module:filterClasses.ElemHideException} exception
   * @returns {boolean}
   */
  has(exception)
  {
    return this._exceptions.has(exception);
  }

  /**
   * Checks whether any exception rules are registered for a selector.
   * @param {string} selector
   * @returns {boolean}
   */
  hasExceptions(selector)
  {
    return this._exceptionsBySelector.has(selector);
  }

  /**
   * Checks whether an exception rule is registered for a selector on a
   * particular domain.
   * @param {string} selector
   * @param {?string} [domain]
   * @returns {?module:filterClasses.ElemHideException}
   */
  getException(selector, domain)
  {
    let exceptions = this._exceptionsBySelector.get(selector);
    if (exceptions)
    {
      for (let exception of exceptions)
      {
        if (exception.isActiveOnDomain(domain))
          return exception;
      }
    }

    return null;
  }
}

/**
 * Container for element hiding exceptions.
 * @type {module:elemHideExceptions~ElemHideExceptions}
 */
exports.elemHideExceptions = new ElemHideExceptions();


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Element hiding emulation implementation.
 */

const {elemHideExceptions} = __webpack_require__(27);

/**
 * `{@link module:elemHideEmulation.elemHideEmulation elemHideEmulation}`
 * implementation.
 */
class ElemHideEmulation extends Set
{
  /**
   * Removes an existing element hiding emulation filter.
   * @param {module:filterClasses.ElemHideEmulationFilter} filter
   *
   * @deprecated Use
   *   <code>ElemHideEmulation#delete</code>
   *   instead.
   */
  remove(filter)
  {
    this.delete(filter);
  }

  /**
   * Returns a list of all element hiding emulation filters active on the given
   * domain.
   * @param {string} domain The domain.
   * @returns {Array.<module:filterClasses.ElemHideEmulationFilter>} A list of
   *   element hiding emulation filters.
   */
  getFilters(domain)
  {
    let result = [];

    for (let filter of this)
    {
      if (filter.isActiveOnDomain(domain) &&
          !elemHideExceptions.getException(filter.selector, domain))
        result.push(filter);
    }

    return result;
  }

  /**
   * Returns a list of all element hiding emulation filters active on the given
   * domain.
   * @param {string} domain The domain.
   * @returns {Array.<module:filterClasses.ElemHideEmulationFilter>} A list of
   *   element hiding emulation filters.
   *
   * @deprecated Use
   *   <code>{@link
   *          module:elemHideEmulation~ElemHideEmulation#getFilters}</code>
   *   instead.
   * @see module:elemHideEmulation~ElemHideEmulation#getFilters
   */
  getRulesForDomain(domain)
  {
    return this.getFilters(domain);
  }
}

/**
 * Container for element hiding emulation filters.
 * @type {module:elemHideEmulation~ElemHideEmulation}
 */
exports.elemHideEmulation = new ElemHideEmulation();


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

var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */
!function(e,t){"use strict"; true&&"object"==typeof module.exports?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)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.5.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.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||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+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]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(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},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.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=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),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("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(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 de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){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[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.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},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.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 l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(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?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,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(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===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]||se.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]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(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(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!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!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.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:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(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 Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(D).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var j,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(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},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(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[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(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(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.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&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.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=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.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 ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={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,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);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"===w(o))S.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]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^key/,we=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\.(.+)|)/;function Ce(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function ke(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)ke(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=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Ae(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,Ce)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.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,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.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&&1<=e.button))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?-1<S(i,this).index(l):S.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(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click",Ce),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Ae(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ce:Ee,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&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ce,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ce,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ce,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.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,code:!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&&be.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&we.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Ae(this,e,Se),!1},trigger:function(){return Ae(this,e),!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return ke(this,e,t,n,r)},one:function(e,t,n,r){return ke(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(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=Ee),this.each(function(){S.event.remove(this,e,n,t)})}});var Ne=/<script|<style|<link/i,De=/checked\s*(?:[^=]|=\s*.checked.)/i,je=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function qe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function Le(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function He(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function Pe(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&De.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Pe(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),Le)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,He),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(je,""),u,l))}return n}function Re(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Oe(o[r],a[r]);else Oe(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.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 Pe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Pe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Pe(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&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(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&&!Ne.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Pe(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Me=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},We=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Fe=new RegExp(ne.join("|"),"i");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||Ie(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Me.test(a)&&Fe.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}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px",t.style.height="1px",n.style.height="9px",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=3<parseInt(r.height),re.removeChild(e)),a}}))}();var _e=["Webkit","Moz","ms"],ze=E.createElement("div").style,Ue={};function Xe(e){var t=S.cssProps[e]||Ue[e];return t||(e in ze?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_e.length;while(n--)if((e=_e[n]+t)in ze)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Ge=/^--/,Ye={position:"absolute",visibility:"hidden",display:"block"},Qe={letterSpacing:"0",fontWeight:"400"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Ke(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+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=Be(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?"border":"content"),o,r,a)+"px"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!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=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=S.cssHooks[t]||S.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=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.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=X(t);return Ge.test(t)||(t=Xe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),"normal"===i&&t in Qe&&(i=Qe[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,u,n):We(e,Ye,function(){return Ze(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Je(0,t,s)}}}),S.cssHooks.marginLeft=$e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,"marginLeft"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Je)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=et).prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=S.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):et.propHooks._default.set(this),this}}).init.prototype=et.prototype,(et.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=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=et.prototype.init,S.fx.step={};var tt,nt,rt,it,ot=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function st(){nt&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(st):C.setTimeout(st,S.fx.interval),S.fx.tick())}function ut(){return C.setTimeout(function(){tt=void 0}),tt=Date.now()}function lt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ct(e,t,n){for(var r,i=(ft.tweeners[t]||[]).concat(ft.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ft(o,e,t){var n,a,r=0,i=ft.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=tt||ut(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:tt||ut(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=ft.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ct,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(ft,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],ft.tweeners[n]=ft.tweeners[n]||[],ft.tweeners[n].unshift(t)},prefilters:[function(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),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._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--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ot.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.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,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ct(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ft.prefilters.unshift(e):ft.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.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(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=ft(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&at.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),S.each({slideDown:lt("show"),slideUp:lt("hide"),slideToggle:lt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),tt=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){nt||(nt=!0,st())},S.fx.stop=function(){nt=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},rt=E.createElement("input"),it=E.createElement("select").appendChild(E.createElement("option")),rt.type="checkbox",y.checkOn=""!==rt.value,y.optSelected=it.selected,(rt=E.createElement("input")).value="t",rt.type="radio",y.radioValue="t"===rt.value;var pt,dt=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void S.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=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(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(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=dt[t]||S.find.attr;dt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=dt[o],dt[o]=r,r=null!=a(e,t,n)?o:null,dt[o]=i),r}});var ht=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function mt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.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=S.find.attr(e,"tabindex");return t?parseInt(t,10):ht.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.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)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,yt(this)))});if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr("class","");if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=mt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=yt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+vt(yt(n))+" ").indexOf(t))return!0;return!1}});var xt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(xt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:vt(S.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||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var bt=/^(?:focusinfocus|focusoutblur)$/,wt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!bt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,bt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,wt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,wt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var Tt=C.location,Ct={guid:Date.now()},Et=/\?/;S.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||S.error("Invalid XML: "+e),t};var St=/\[\]$/,kt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Nt=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||St.test(n)?i(n,t):Dt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)Dt(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&Nt.test(this.nodeName)&&!At.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(kt,"\r\n")}}):{name:t.name,value:n.replace(kt,"\r\n")}}).get()}});var jt=/%20/g,qt=/#.*$/,Lt=/([?&])_=[^&]*/,Ht=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ot=/^(?:GET|HEAD)$/,Pt=/^\/\//,Rt={},Mt={},It="*/".concat("*"),Wt=E.createElement("a");function Ft(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Bt(t,i,o,a){var s={},u=t===Mt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function $t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Wt.href=Tt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":It,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":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,S.ajaxSettings),t):$t(S.ajaxSettings,e)},ajaxPrefilter:Ft(Rt),ajaxTransport:Ft(Mt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Ht.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Tt.href)+"").replace(Pt,Tt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Wt.protocol+"//"+Wt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Bt(Rt,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ot.test(v.type),f=v.url.replace(qt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(jt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Et.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Lt,"$1"),o=(Et.test(f)?"&":"?")+"_="+Ct.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+It+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Bt(Mt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(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]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&(v.converters["text script"]=function(){}),s=function(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}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(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(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var _t={0:200,1223:204},zt=S.ajaxSettings.xhr();y.cors=!!zt&&"withCredentials"in zt,y.ajax=zt=!!zt,S.ajaxTransport(function(i){var o,a;if(y.cors||zt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(_t[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.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 S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.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"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.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)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.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,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Gt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Gt,"")}, true&&!(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function(){return S}).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, exports, STATS, log, getSettings, Prefs, openTab,
   License
 */

// if the ping response indicates a survey (tab or overlay)
// gracefully processes the request
const stats = __webpack_require__(16);
const { OnPageIconManager } = __webpack_require__(68);
const { domainSuffixes, parseDomains } = __webpack_require__(9);
const { recordGeneralMessage, recordErrorMessage } = __webpack_require__(19).ServerMessages;

const SURVEY = (function getSurvey() {
  // Only allow one survey per browser startup, to make sure users don't get
  // spammed due to bugs in AdBlock / the ping server / the browser.
  let surveyAllowed = true;

  // True if we are willing to show an overlay on this tab.
  const validTab = function (tab) {
    if (tab.incognito || tab.status !== 'complete') {
      return false;
    }
    return /^http/.test(tab.url);
  };

  /**
   * Checks whether the tab URL is a match to the domain(s)
   * @param {?string} [tabDomain]
   * @return {boolean}
   */
  const isActiveOnDomain = function (tabDomain, domains) {
    // If no domains are set the rule matches everywhere
    if (!domains) {
      return true;
    }
    let docDomain = tabDomain;
    if (docDomain === null) {
      docDomain = '';
    } else if (docDomain[docDomain.length - 1] === '.') {
      docDomain = docDomain.substring(0, docDomain.length - 1);
    }

    // If the document has no host name, match only if the filter
    // isn't restricted to specific domains
    if (!docDomain) {
      return domains.get('');
    }

    for (docDomain of domainSuffixes(docDomain)) {
      const isDomainIncluded = domains.get(docDomain);
      if (typeof isDomainIncluded !== 'undefined') {
        return isDomainIncluded;
      }
    }

    return domains.get('');
  };

  // functions below are used by both Tab Surveys

  // Double check that the survey should be shown
  // Inputs:
  //   surveyData: JSON survey information from ping server
  //   callback(): called with no arguments if the survey should be shown
  const shouldShowSurvey = function (surveyData, callback) {
    // Check if we should show survey only if it can actually be shown
    // based on surveyAllowed.
    log('shouldShowSurvey::surveyAllowed: ', surveyAllowed);
    if (surveyAllowed) {
      let data = { cmd: 'survey', u: STATS.userId(), sid: surveyData.survey_id };
      if (STATS.flavor === 'E' && Prefs.blocked_total) {
        data.b = Prefs.blocked_total;
      }
      $.post(STATS.statsUrl, data, (responseData) => {
        try {
          data = JSON.parse(responseData);
        } catch (e) {
          log('Error parsing JSON: ', responseData, ' Error: ', e);
        }
        if (data && data.should_survey === 'true' && surveyAllowed) {
          // for icon surveys, the surveyAllowed is set to false when
          // the user engages / mouse's over the icon
          if (surveyData.type !== 'icon') {
            surveyAllowed = false;
          }
          callback(data);
        }
      });
    }
  };

  // Process a request to show the 'on page / tab AdBlock icon'
  // Inputs:
  //         surveyData : object - with the following:
  //             survey_id : string - A unique string
  //             domains : string - A separate list of domains, and subdomain to show the icon on
  //             block_count : integer - The minimum block count to show the icon (can be zero)
  //             user_state : string - one of the three values: 'all', 'free', 'active'
  // step 1 verify the user allows on page messages
  // step 2 verify the initial survey data (ping response)
  // step 3 verify license type is a match
  // step 4 add a onTab update listener to watch for user navigation
  // step 5 when a tab/site is done loading, check the tab's domain to the survey's list of domains
  // step 6 compare the current block count on the tab to survey's minimum block count
  // step 7 if the tab meets all of the survey critieria, then check with the ping server again
  // step 8 validate shouldShow response data
  // step 9 show the adblock icon on the tab
  // step 10 when the user interacts with the icon, remove tab listener
  const processIcon = function (surveyData) {
    const validateIconSurveyData = function () {
      if (!surveyData) {
        return false;
      }
      if (!surveyData.survey_id) {
        return false;
      }
      if (!surveyData.domains || typeof surveyData.domains !== 'string') {
        return false;
      }
      if (surveyData.block_count && typeof surveyData.block_count !== 'number') {
        return false;
      }
      if (!Object.prototype.hasOwnProperty.call(surveyData, 'block_count')) {
        return false;
      }
      if (!surveyData.user_state || typeof surveyData.user_state !== 'string') {
        return false;
      }
      return true;
    };

    const doesLicenseMatch = function () {
      if (surveyData.user_state === 'all') {
        return true;
      }
      if (License && License.get() && License.get().status === 'active' && surveyData.user_state === 'active') {
        return true;
      }
      if (License && License.get() && !License.get().status && surveyData.user_state === 'free') {
        return true;
      }
      return false;
    };

    const parsedDomains = parseDomains(surveyData.domains, ',');

    const tabListener = function (updatedTabId, changeInfo, tab) {
      const shouldShowOnPageIcon = function () {
        shouldShowSurvey(surveyData, (responseData) => {
          log('shouldShowSurvey::responseData:', responseData);
          if (
            responseData.survey_id === surveyData.survey_id
            && responseData.should_survey === 'true'
          ) {
            OnPageIconManager.showOnPageIcon(tab.id, tab.url, {
              titleText: responseData.titleText,
              msgText: responseData.msgText,
              buttonText: responseData.buttonText,
              buttonURL: responseData.buttonURL,
              surveyId: responseData.survey_id,
            });
          }
        });
      };

      if (changeInfo.status === 'complete' && tab.status === 'complete' && validTab(tab)) {
        const myURL = new URL(tab.url);
        const cleanDomain = myURL.hostname.replace(/^www\./, ''); // remove lead 'www.'
        log('processIcon:: checking if isActiveOnDomain', cleanDomain, isActiveOnDomain(cleanDomain, parsedDomains));
        if (isActiveOnDomain(cleanDomain, parsedDomains)) {
          log('processIcon:: block count check', stats.getBlockedPerPage(tab), surveyData.block_count);
          if (surveyData.block_count <= stats.getBlockedPerPage(tab)) {
            shouldShowOnPageIcon();
          }
        }
      }
    };

    const surveyMsgListener = function (message, sender, sendResponse) {
      if (message.onpageiconevent === 'mouseenter') {
        surveyAllowed = false;
        browser.runtime.onMessage.removeListener(surveyMsgListener);
        browser.tabs.onUpdated.removeListener(tabListener);
        browser.tabs.query({ url: '*://*/*' }).then((tabs) => {
          for (const theTab of tabs) {
            if (theTab.id !== sender.tab.id && theTab.url && theTab.url.startsWith('http')) {
              browser.tabs.sendMessage(theTab.id, { command: 'removeIcon' }).catch(() => {
                // ignore error
              });
            }
          }
        });
        sendResponse({});
      }
    };

    log('processIcon:: is survey data valid? ', validateIconSurveyData());
    log('processIcon:: is license status match? ', doesLicenseMatch());
    log('processIcon:: is settting enabled? ', getSettings().onpageMessages);
    if (getSettings().onpageMessages && validateIconSurveyData() && doesLicenseMatch()) {
      browser.runtime.onMessage.removeListener(surveyMsgListener);
      browser.runtime.onMessage.addListener(surveyMsgListener);
      browser.tabs.onUpdated.addListener(tabListener);
    }
  };

  // Check the response from a ping to see if it contains valid survey instructions.
  // If so, return an object containing data about the survey to show.
  // Otherwise, return null.
  // Inputs:
  //   responseData: string response from a ping
  const surveyDataFrom = function (responseData) {
    let surveyData;

    if (responseData.length === 0 || responseData.trim().length === 0) {
      return null;
    }
    try {
      surveyData = JSON.parse(responseData);
      if (!surveyData) {
        return null;
      }
    } catch (e) {
      // eslint-disable-next-line no-console
      console.log('Something went wrong with parsing survey data.');
      // eslint-disable-next-line no-console
      console.log('error', e);
      // eslint-disable-next-line no-console
      console.log('response data', responseData);
      return null;
    }
    return surveyData;
  };

  // open a Tab for a full page survey
  const processTab = function (surveyData) {
    const openTabIfAllowed = function () {
      setTimeout(() => {
        shouldShowSurvey(surveyData, (responseData) => {
          browser.tabs.create({ url: `https://getadblock.com/${responseData.open_this_url}` });
        });
      }, 10000); // 10 seconds
    };

    const waitForUserAction = function () {
      browser.tabs.onCreated.removeListener(waitForUserAction);
      openTabIfAllowed();
    };

    browser.idle.queryState(60, (state) => {
      if (state === 'active') {
        openTabIfAllowed();
      } else {
        browser.tabs.onCreated.removeListener(waitForUserAction);
        browser.tabs.onCreated.addListener(waitForUserAction);
      }
    });
  }; // end of processTab()

  return {
    maybeSurvey(responseData) {
      if (getSettings().show_survey === false) {
        return;
      }
      if (getSettings().suppress_surveys) {
        return;
      }

      const surveyData = surveyDataFrom(responseData);
      if (!surveyData) {
        return;
      }
      if (surveyData.type === 'tab') {
        processTab(surveyData);
      } else if (surveyData.type === 'icon') {
        processIcon(surveyData);
      }
    }, // end of maybeSurvey
    types(callback) {
      // 'T' = Tab Surveys
      callback('TI');
    },
  };
}());

exports.SURVEY = SURVEY;


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



function parseVersionComponent(comp)
{
  if (comp == "*")
    return Infinity;
  return parseInt(comp, 10) || 0;
}

/**
 * Compares two versions.
 *
 * @param {string} v1 The first version.
 * @param {string} v2 The second version.
 *
 * @returns {number} `-1` if `v1` is older than `v2`; `1` if `v1` is newer than
 *   `v2`; otherwise `0`.
 *
 * @package
 */
exports.compareVersions = function compareVersions(v1, v2)
{
  let regexp = /^(.*?)([a-z].*)?$/i;
  let [, head1, tail1] = regexp.exec(v1);
  let [, head2, tail2] = regexp.exec(v2);
  let components1 = head1.split(".");
  let components2 = head2.split(".");

  for (let i = 0; i < components1.length ||
                  i < components2.length; i++)
  {
    let result = parseVersionComponent(components1[i]) -
                 parseVersionComponent(components2[i]) || 0;

    if (result < 0)
      return -1;
    else if (result > 0)
      return 1;
  }

  // Compare version suffix (e.g. 0.1alpha < 0.1b1 < 01.b2 < 0.1).
  // However, note that this is a simple string comparision, meaning: b10 < b2
  if (tail1 == tail2)
    return 0;
  if (!tail1 || tail2 && tail1 > tail2)
    return 1;
  return -1;
};


/***/ }),
/* 32 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filterTypes", function() { return filterTypes; });
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(14);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(9);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _adblockplusui_adblockpluschrome_lib_allowlisting_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(8);
/* harmony import */ var _adblockplusui_adblockpluschrome_lib_url_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(13);
/* harmony import */ var _adblockplusui_adblockpluschrome_lib_messaging_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(1);
/* harmony import */ var _adblockplusui_adblockpluschrome_lib_hitLogger_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(11);
/* harmony import */ var _adblockplusui_adblockpluschrome_lib_stats_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(16);
/*
 * Same as the original source adblockpluschrome/lib/requestBlocker.js
 * except:
 * - updated the `require` path to other modules
 * - updated the logRequest function to emit the "filter.hitCount" event
 */
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module requestBlocker */














const extensionProtocol = new URL(browser.runtime.getURL("")).protocol;

// Map of content types reported by the browser to the respecitve content types
// used by Adblock Plus. Other content types are simply mapped to OTHER.
let resourceTypes = new Map(function*()
{
  for (let type in _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__["contentTypes"])
    yield [type.toLowerCase(), type];

  yield ["sub_frame", "SUBDOCUMENT"];

  // Treat navigator.sendBeacon() the same as <a ping>, it's essentially the
  // same concept - merely generalized.
  yield ["beacon", "PING"];

  // Treat <img srcset> and <picture> the same as other images.
  yield ["imageset", "IMAGE"];

  // Treat requests sent by plugins the same as <object> or <embed>.
  yield ["object_subrequest", "OBJECT"];
}());

let typeSelectors = new Map([
  ["IMAGE", "img,input"],
  ["MEDIA", "audio,video"],
  ["SUBDOCUMENT", "frame,iframe,object,embed"],
  ["OBJECT", "object,embed"]
]);

let filterTypes = new Set(function*()
{
  for (let type in browser.webRequest.ResourceType)
    yield resourceTypes.get(browser.webRequest.ResourceType[type]) || "OTHER";

  // WEBRTC gets addressed through a workaround, even if the webRequest API is
  // lacking support to block this kind of a request.
  yield "WEBRTC";

  // POPUP, CSP and ELEMHIDE filters aren't mapped to resource types.
  yield "POPUP";
  yield "ELEMHIDE";
  yield "SNIPPET";
  yield "CSP";
}());

function getDocumentInfo(page, frame, originUrl)
{
  return [
    Object(_adblockplusui_adblockpluschrome_lib_url_js__WEBPACK_IMPORTED_MODULE_8__["extractHostFromFrame"])(frame, originUrl),
    Object(_adblockplusui_adblockpluschrome_lib_allowlisting_js__WEBPACK_IMPORTED_MODULE_7__["getKey"])(page, frame, originUrl),
    !!Object(_adblockplusui_adblockpluschrome_lib_allowlisting_js__WEBPACK_IMPORTED_MODULE_7__["checkAllowlisted"])(page, frame, originUrl, _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__["contentTypes"].GENERICBLOCK)
  ];
}

async function getRelatedTabIds(details)
{
  // This is the common case, the request is associated with a single tab.
  // If tabId is -1, its not (e.g. the request was sent by
  // a Service/Shared Worker) and we have to identify the related tabs.
  if (details.tabId != -1)
    return [details.tabId];

  let url;
  if (details.originUrl)
    // Firefox provides "originUrl" indicating the URL of the tab that caused
    // this request. In case of Service/Shared Worker, this is the URL of the
    // tab that caused the worker to spawn.
    url = details.originUrl;
  else if (details.initiator && details.initiator != "null")
    // Chromium >=63 provides "intiator" which is equivalent to "originUrl" on
    // Firefox except that its not a full URL but just an origin (proto + host).
    url = details.initiator + "/*";
  else
    return [];

  let tabs = await browser.tabs.query({url});
  return tabs.map(tab => tab.id);
}

function logRequest(tabIds, request, filter)
{
  if (filter) {
    _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].emit("filter.hitCount", filter, 0, 0, tabIds);
    Object(_adblockplusui_adblockpluschrome_lib_stats_js__WEBPACK_IMPORTED_MODULE_11__["recordBlockedRequest"])(filter, tabIds);
  }

  Object(_adblockplusui_adblockpluschrome_lib_hitLogger_js__WEBPACK_IMPORTED_MODULE_10__["logRequest"])(tabIds, request, filter);
}

async function collapse(tabId, frameId, type, url)
{
  let selector = typeSelectors.get(type);
  if (selector && frameId != -1)
  {
    try
    {
      await browser.tabs.sendMessage(
        tabId, {type: "filters.collapse", selector, url}, {frameId}
      );
    }
    catch (e) {}
  }
}

/**
 * @typedef {object} MatchingResult
 * @property {?webRequest.BlockingResponse} result The blocking response.
 * @property {?Filter} filter The matched filter.
 */

/**
 * Listener for the webRequest
 * @param {function} matchFunction Function that will match the request and
 *  returns a {@link MatchingResult}.
 * @param {object} details The details of the webRequest.
 * @return {?webRequest.BlockingResponse} The blocking response or undefined.
 */
function listener(matchFunction, details)
{
  // Filter out requests from non web protocols. Ideally, we'd explicitly
  // specify the protocols we are interested in (i.e. http://, https://,
  // ws:// and wss://) with the url patterns, given below, when adding this
  // listener. But unfortunately, Chrome <=57 doesn't support the WebSocket
  // protocol and is causing an error if it is given.
  let url = Object(_adblockplusui_adblockpluschrome_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_6__["parseURL"])(details.url);
  if (url.protocol != "http:" && url.protocol != "https:" &&
      url.protocol != "ws:" && url.protocol != "wss:")
    return;

  // Firefox provides us with the full origin URL, while Chromium (>=63)
  // provides only the protocol + host of the (top-level) document which
  // the request originates from through the "initiator" property.
  let originUrl = null;
  if (details.originUrl)
    originUrl = Object(_adblockplusui_adblockpluschrome_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_6__["parseURL"])(details.originUrl);
  else if (details.initiator && details.initiator != "null")
    originUrl = Object(_adblockplusui_adblockpluschrome_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_6__["parseURL"])(details.initiator);

  // Ignore requests sent by extensions or by Firefox itself:
  // * Firefox intercepts requests sent by any extensions, indicated with
  //   an "originURL" starting with "moz-extension:".
  // * Chromium intercepts requests sent by this extension only, indicated
  //   on Chromium >=63 with an "initiator" starting with "chrome-extension:".
  // * On Firefox, requests that don't relate to any document or extension are
  //   indicated with an "originUrl" starting with "chrome:".
  if (originUrl && (originUrl.protocol == extensionProtocol ||
                    originUrl.protocol == "chrome:"))
    return;

  let page = new ext.Page({id: details.tabId});

  // We are looking for the frame that contains the element which
  // has triggered this request. For most requests (e.g. images) we
  // can just use the request's frame ID, but for subdocument requests
  // (e.g. iframes) we must instead use the request's parent frame ID.
  let frameId = details.type == "sub_frame" ? details.parentFrameId :
                                              details.frameId;

  // On Chromium >= 63, if both the frame is unknown and we haven't get
  // an "initiator", this implies a request sent by the browser itself
  // (on older versions of Chromium, due to the lack of "initiator",
  // this can also indicate a request sent by a Shared/Service Worker).
  let frame = ext.getFrame(details.tabId, frameId);
  if (!frame && !originUrl)
    return;

  if (Object(_adblockplusui_adblockpluschrome_lib_allowlisting_js__WEBPACK_IMPORTED_MODULE_7__["checkAllowlisted"])(page, frame, originUrl))
    return;

  let type = resourceTypes.get(details.type) || "OTHER";
  let [docDomain, sitekey, specificOnly] = getDocumentInfo(page, frame,
                                                           originUrl);

  let {result, filter} = matchFunction(
    details, url, frameId, docDomain, sitekey, type, specificOnly);

  if (result && result.cancel)
    collapse(details.tabId, frameId, type, details.url);

  getRelatedTabIds(details).then(tabIds =>
  {
    logRequest(
      tabIds,
      {
        url: details.url, type, docDomain,
        sitekey, specificOnly,
        rewrittenUrl: result ? result.redirectUrl : void 0
      },
      filter
    );
  });

  return result;
}

function urlMatch(details, url, frameId, docDomain, sitekey, type, specificOnly)
{
  let filter = _adblockplusui_adblockpluschrome_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_3__["defaultMatcher"].match(url, _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__["contentTypes"][type],
                                    docDomain, sitekey, specificOnly);

  let result;
  if (filter instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["BlockingFilter"])
  {
    if (typeof filter.rewrite == "string")
    {
      let redirectUrl = filter.rewriteUrl(details.url);
      // If no rewrite happened (error, different origin), we'll
      // return undefined in order to avoid an "infinite" loop.
      if (redirectUrl != details.url)
        result = {redirectUrl};
    }
    else
    {
      result = {cancel: true};
    }
  }
  return {result, filter};
}

browser.webRequest.onBeforeRequest.addListener(
  listener.bind(null, urlMatch),
  {
    types: Object.values(browser.webRequest.ResourceType)
                 .filter(type => type != "main_frame"),
    urls: ["<all_urls>"]
  }, ["blocking"]);

function headerMatch(details, url, frameId, docDomain, sitekey, type,
                     specificOnly)
{
  let match = _adblockplusui_adblockpluschrome_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_3__["defaultMatcher"].match(url,
                                   _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__["contentTypes"].HEADER | _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__["contentTypes"][type],
                                   docDomain, sitekey, specificOnly);

  // The presence of an exception filter is enough.
  if (!(match instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["BlockingFilter"]))
    return {filter: match};

  let {blocking} = _adblockplusui_adblockpluschrome_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_3__["defaultMatcher"].search(url, _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__["contentTypes"].HEADER,
                                         docDomain, sitekey, specificOnly,
                                         "blocking");

  for (let filter of blocking)
  {
    if (filter.filterHeaders(details.responseHeaders))
      return {result: {cancel: true}, filter};
  }

  return {};
}

browser.webRequest.onHeadersReceived.addListener(
  listener.bind(null, headerMatch),
  {
    types: Object.values(browser.webRequest.ResourceType)
                 .filter(type => type != "main_frame"),
    urls: ["<all_urls>"]
  }, ["blocking", "responseHeaders"]);

/**
 * Returns true if the given WebRTC request should be blocked, false otherwise.
 * Used by our injected RTCPeerConnection wrapper to decide which requests to
 * block.
 *
 * @event "request.blockedByRTCWrapper"
 * @property {string} url - The URL of the WebRTC request.
 * @returns {boolean}
 */
_adblockplusui_adblockpluschrome_lib_messaging_js__WEBPACK_IMPORTED_MODULE_9__["port"].on("request.blockedByRTCWrapper", (msg, sender) =>
{
  let {page, frame} = sender;

  if (Object(_adblockplusui_adblockpluschrome_lib_allowlisting_js__WEBPACK_IMPORTED_MODULE_7__["checkAllowlisted"])(page, frame))
    return false;

  let {url} = msg;
  let [docDomain, sitekey, specificOnly] = getDocumentInfo(page, frame);
  let filter = _adblockplusui_adblockpluschrome_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_3__["defaultMatcher"].match(new URL(url), _adblockplusui_adblockpluschrome_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_1__["contentTypes"].WEBRTC,
                                    docDomain, sitekey, specificOnly);
  logRequest(
    [sender.page.id],
    {url, type: "WEBRTC", docDomain, sitekey, specificOnly},
    filter
  );

  return filter instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["BlockingFilter"];
});

let ignoreFilterNotifications = false;

function onNavigateAfterFilterChange()
{
  browser.webNavigation.onBeforeNavigate.removeListener(
    onNavigateAfterFilterChange
  );
  browser.webRequest.handlerBehaviorChanged();
}

function onFilterChange(arg, isDisabledAction)
{
  // Avoid triggering filters.behaviorChanged multiple times
  // when multiple filter changes happen at the same time.
  if (ignoreFilterNotifications)
    return;

  // Convert filter text into a filter object.
  if (typeof arg == "string")
    arg = _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["Filter"].fromText(arg);

  // Ignore disabled subscriptions and filters, unless they just got
  // disabled, otherwise they have no effect on the handler behavior.
  if (!isDisabledAction &&
      ((arg instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_2__["Subscription"] && arg.disabled) ||
       (arg instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["Filter"] && !_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterState_js__WEBPACK_IMPORTED_MODULE_5__["filterState"].isEnabled(arg.text))))
    return;

  // Ignore empty subscriptions. This includes subscriptions
  // that have just been added, but not downloaded yet.
  if (arg instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_2__["Subscription"] && arg.filterCount == 0)
    return;

  // Ignore all types of filters but request filters,
  // only these have an effect on the handler behavior.
  if (arg instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["Filter"] && !(arg instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["URLFilter"]))
    return;

  ignoreFilterNotifications = true;
  setTimeout(() =>
  {
    // Defer handlerBehaviorChanged() until navigation occurs.
    // There wouldn't be any visible effect when calling it earlier,
    // but it's an expensive operation and that way we avoid to call
    // it multiple times, if multiple filters are added/removed.
    let {onBeforeNavigate} = browser.webNavigation;
    if (!onBeforeNavigate.hasListener(onNavigateAfterFilterChange))
      onBeforeNavigate.addListener(onNavigateAfterFilterChange);

    ignoreFilterNotifications = false;
    _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].emit("filter.behaviorChanged");
  });
}

_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("subscription.added", onFilterChange);
_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("subscription.removed", arg => onFilterChange(arg, false));
_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("subscription.updated", arg => onFilterChange(arg, false));
_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("subscription.disabled", arg => onFilterChange(arg, true));
_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("filter.added", onFilterChange);
_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("filter.removed", onFilterChange);
_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("filterState.enabled", arg => onFilterChange(arg, true));
_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_4__["filterNotifier"].on("ready", onFilterChange);


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

"use strict";
// Allows interaction with the server to track install rate
// and log messages.



/* For ESLint: List any global identifiers used in this file below */
/* global browser, exports, require, log, getSettings, determineUserLanguage,
   replacedCounts, chromeStorageSetHelper, getAllSubscriptionsMinusText,
   License, channels, LocalCDN, Filter, SpecialSubscription, filterStorage,
   getSubscriptionsChecksum, BigInt */


const { Prefs } = __webpack_require__(5);
const { SURVEY } = __webpack_require__(30);
const { CtaABManager } = __webpack_require__(41);
const { recordGeneralMessage, recordErrorMessage } = __webpack_require__(19).ServerMessages;

const STATS = (function exportStats() {
  const userIDStorageKey = 'userid';
  const totalPingStorageKey = 'total_pings';
  const nextPingTimeStorageKey = 'next_ping_time';
  const statsUrl = 'https://ping.getadblock.com/stats/';
  const FiftyFiveMinutes = 3300000;
  let dataCorrupt = false;

  // Get some information about the version, os, and browser
  const { version } = browser.runtime.getManifest();
  let match = navigator.userAgent.match(/(CrOS \w+|Windows NT|Mac OS X|Linux) ([\d._]+)?/);
  const os = (match || [])[1] || 'Unknown';
  const osVersion = (match || [])[2] || 'Unknown';
  let flavor = 'E'; // Chrome
  match = navigator.userAgent.match(/(?:Chrome|Version)\/([\d.]+)/);
  const edgeMatch = navigator.userAgent.match(/(?:Edg|Version)\/([\d.]+)/);
  const firefoxMatch = navigator.userAgent.match(/(?:Firefox)\/([\d.]+)/);
  if (edgeMatch) {
    flavor = 'CM'; // MS - Chromium Edge
    match = edgeMatch;
  } else if (firefoxMatch) {
    flavor = 'F'; // Firefox
    match = firefoxMatch;
  }
  const browserVersion = (match || [])[1] || 'Unknown';

  const firstRun = false;

  let userID;

  // Inputs: key:string.
  // Returns value if key exists, else undefined.
  // Note: "_alt" is appended to the key to make it the key different
  // from the previous items stored in localstorage
  const storageGet = function (key) {
    const storageKey = `${key}_alt`;
    const store = localStorage;
    if (store === undefined) {
      return undefined;
    }
    const json = store.getItem(storageKey);
    if (json == null) {
      return undefined;
    }
    try {
      return JSON.parse(json);
    } catch (ex) {
      if (ex && ex.message) {
        recordErrorMessage('storage_get_error ', undefined, { errorMessage: ex.message });
      }
      return undefined;
    }
  };

  // Inputs: key:string, value:object.
  // Note: "_alt" is appended to the key to make it the key different
  // from the previous items stored in localstorage
  // If value === undefined, removes key from storage.
  // Returns undefined.
  const storageSet = function (key, value) {
    const storageKey = `${key}_alt`;
    const store = localStorage;

    if (value === undefined) {
      store.removeItem(storageKey);
      return;
    }
    try {
      store.setItem(storageKey, JSON.stringify(value));
    } catch (ex) {
      dataCorrupt = true;
    }
  };

  // Give the user a userid if they don't have one yet.
  function readUserIDPromisified() {
    return new Promise(
      ((resolve) => {
        browser.storage.local.get(STATS.userIDStorageKey).then((response) => {
          const localuserid = storageGet(STATS.userIDStorageKey);
          if (!response[STATS.userIDStorageKey] && !localuserid) {
            STATS.firstRun = true;
            const timeSuffix = (Date.now()) % 1e8; // 8 digits from end of
            // timestamp
            const alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789';
            const result = [];
            for (let i = 0; i < 8; i++) {
              const choice = Math.floor(Math.random() * alphabet.length);
              result.push(alphabet[choice]);
            }
            userID = result.join('') + timeSuffix;
            // store in redundant locations
            chromeStorageSetHelper(STATS.userIDStorageKey, userID);
            storageSet(STATS.userIDStorageKey, userID);
          } else {
            userID = response[STATS.userIDStorageKey] || localuserid;
            if (!response[STATS.userIDStorageKey] && localuserid) {
              chromeStorageSetHelper(STATS.userIDStorageKey, userID);
            }
            if (response[STATS.userIDStorageKey] && !localuserid) {
              storageSet(STATS.userIDStorageKey, userID);
            }
          }
          resolve(userID);
        });
      }),
    );
  }

  browser.runtime.onMessage.addListener((message, _sender, sendResponse) => {
    if (message.command !== 'get_adblock_user_id') {
      return undefined;
    }
    readUserIDPromisified().then((resolvedUserID) => {
      sendResponse(resolvedUserID);
    });
    return true;
  });

  const getPingData = function (callbackFN) {
    if (!callbackFN && (typeof callbackFN !== 'function')) {
      return;
    }
    browser.storage.local.get(STATS.totalPingStorageKey).then((response) => {
      const settingsObj = getSettings();
      const localTotalPings = storageGet(STATS.totalPingStorageKey);
      const totalPings = response[STATS.totalPingStorageKey] || localTotalPings || 0;
      const themeOptionsPage = settingsObj.color_themes.options_page.replace('_theme', '');
      const themePopupMenu = settingsObj.color_themes.popup_menu.replace('_theme', '');
      let subsStr = '-1';
      if (typeof BigInt === 'function') {
        subsStr = BigInt(`0b${getSubscriptionsChecksum()}`).toString();
      }

      const data = {
        u: userID,
        v: version,
        f: flavor,
        o: os,
        bv: browserVersion,
        ov: osVersion,
        ad: settingsObj.show_advanced_options ? '1' : '0',
        yt: settingsObj.youtube_channel_whitelist ? '1' : '0',
        l: determineUserLanguage(),
        pc: totalPings,
        dcv2: settingsObj.data_collection_v2 ? '1' : '0',
        ldc: settingsObj.local_data_collection ? '1' : '0',
        cdn: settingsObj.local_cdn ? '1' : '0',
        rc: replacedCounts.getTotalAdsReplaced(),
        to: themeOptionsPage,
        tm: themePopupMenu,
        sy: settingsObj.sync_settings ? '1' : '0',
        ir: channels.isAnyEnabled() ? '1' : '0',
        cir: channels.channelGuide[channels.getIdByName('CustomChannel')].enabled ? '1' : '0',
        tca: settingsObj.twitch_channel_allowlist ? '1' : '0',
        sup: settingsObj.suppress_update_page ? '1' : '0',
        ss: settingsObj.suppress_surveys ? '1' : '0',
        sfrp: settingsObj.suppress_first_run_page ? '1' : '0',
        opm: settingsObj.onpageMessages ? '1' : '0',
        subs: subsStr,
      };

      if (typeof LocalCDN !== 'undefined') {
        data.cdnr = LocalCDN.getRedirectCount();
        data.cdnd = LocalCDN.getDataCount();
      } else {
        data.cdnr = 0;
        data.cdnd = 0;
      }

      // only on Chrome, Edge, or Firefox
      if ((flavor === 'E' || flavor === 'CM' || flavor === 'F') && Prefs.blocked_total) {
        data.b = Prefs.blocked_total;
      }
      if (browser.runtime.id) {
        data.extid = browser.runtime.id;
      }
      const subs = getAllSubscriptionsMinusText();
      if (subs) {
        const aa = subs.acceptable_ads;
        const aaPrivacy = subs.acceptable_ads_privacy;

        if (!aa && !aaPrivacy) {
          data.aa = 'u'; // Both filter lists unavailable
        } else if (aa.subscribed) {
          data.aa = '1';
        } else if (aaPrivacy.subscribed) {
          data.aa = '2';
        } else if (!aa.subscribed && !aaPrivacy.subscribed) {
          data.aa = '0'; // Both filter lists unsubscribed
        }
        data.dcv = subs['distraction-control-video'].subscribed ? '1' : '0';
        data.dcs = subs['distraction-control-survey'].subscribed ? '1' : '0';
        data.dcn = subs['distraction-control-newsletter'].subscribed ? '1' : '0';
        data.dcp = subs['distraction-control-push'].subscribed ? '1' : '0';
      }

      data.crctotal = 0;
      data.crcsnippet = 0;
      data.crcelemhideemulation = 0;
      data.crcelemhideexception = 0;
      data.crcelemhide = 0;
      data.crcallowing = 0;
      data.crcblocking = 0;
      data.crccomment = 0;
      data.crcinvalid = 0;

      for (const subscription of filterStorage.subscriptions()) {
        if ((subscription instanceof SpecialSubscription)) {
          for (let j = 0; j < subscription._filterText.length; j++) {
            const filter = Filter.fromText(subscription._filterText[j]);
            data[`crc${filter.type}`] += 1;
            data.crctotal += 1;
          }
        }
      }

      data.dc = dataCorrupt ? '1' : '0';
      SURVEY.types((res) => {
        data.st = res + CtaABManager.types();
        if (browser.permissions && browser.permissions.getAll) {
          browser.permissions.getAll((allPermissions) => {
            data.dhp = allPermissions.origins && allPermissions.origins.includes('<all_urls>') ? '1' : '0';
            callbackFN(data);
          });
        } else {
          data.dhp = '1';
          callbackFN(data);
        }
      });
    });
  };
  // Tell the server we exist.
  const pingNow = function () {
    let pingData = {};
    return new Promise((resolve, reject) => {
      const handlePingResponse = function (responseData) {
        SURVEY.maybeSurvey(responseData);
        CtaABManager.maybeCtaAB(responseData);
        resolve(pingData);
      };

      getPingData((data) => {
        pingData = data;

        if (!pingData.u) {
          return;
        }
        // attempt to stop users that are pinging us 'alot'
        // by checking the current ping count,
        // if the ping count is above a theshold,
        // then only ping 'occasionally'
        if (pingData.pc > 5000) {
          if (pingData.pc > 5000 && pingData.pc < 100000 && ((pingData.pc % 5000) !== 0)) {
            return;
          }
          if (pingData.pc >= 100000 && ((pingData.pc % 50000) !== 0)) {
            return;
          }
        }
        pingData.cmd = 'ping';
        const ajaxOptions = {
          type: 'POST',
          url: statsUrl,
          data: pingData,
          success: handlePingResponse, // TODO: Remove when we no longer do a/b
          // tests
          error(e) {
            // eslint-disable-next-line no-console
            console.log('Ping returned error: ', e.status);
            reject(e);
          },
        };

        if (browser.management && browser.management.getSelf) {
          browser.management.getSelf().then((info) => {
            pingData.it = info.installType.charAt(0);
            $.ajax(ajaxOptions);
          });
        } else {
          $.ajax(ajaxOptions);
        }

        if (typeof LocalCDN !== 'undefined') {
          const missedVersions = LocalCDN.getMissedVersions();
          if (missedVersions) {
            recordGeneralMessage('cdn_miss_stats', undefined, { cdnm: missedVersions });
          }
        }
      });
    });
  };

  // Called just after we ping the server, to schedule our next ping.
  const scheduleNextPing = function () {
    browser.storage.local.get(STATS.totalPingStorageKey).then((response) => {
      let localTotalPings = storageGet(totalPingStorageKey);
      if (typeof localTotalPings !== 'number' || Number.isNaN(localTotalPings)) {
        localTotalPings = 0;
      }
      let totalPings = response[STATS.totalPingStorageKey];
      if (typeof totalPings !== 'number' || Number.isNaN(totalPings)) {
        totalPings = 0;
      }
      totalPings = Math.max(localTotalPings, totalPings);
      totalPings += 1;
      // store in redundant locations
      chromeStorageSetHelper(STATS.totalPingStorageKey, totalPings);
      storageSet(STATS.totalPingStorageKey, totalPings);

      let delayHours;
      if (totalPings === 1) { // Ping one hour after install
        delayHours = 1;
      } else if (totalPings < 9) { // Then every day for a week
        delayHours = 24;
      } else { // Then weekly forever
        delayHours = 24 * 7;
      }

      const millis = 1000 * 60 * 60 * delayHours;
      const nextPingTime = Date.now() + millis;

      // store in redundant location
      chromeStorageSetHelper(STATS.nextPingTimeStorageKey, nextPingTime, (error) => {
        if (error) {
          dataCorrupt = true;
        } else {
          dataCorrupt = false;
        }
      });
      storageSet(STATS.nextPingTimeStorageKey, nextPingTime);
    });
  };

  // Return the number of milliseconds until the next scheduled ping.
  const millisTillNextPing = function (callbackFN) {
    if (!callbackFN || (typeof callbackFN !== 'function')) {
      return;
    }
    // If we've detected data corruption issues,
    // then default to a 55 minute ping interval
    if (dataCorrupt) {
      callbackFN(FiftyFiveMinutes);
      return;
    }
    // Wait 10 seconds to allow the previous 'set' to finish
    window.setTimeout(() => {
      browser.storage.local.get(STATS.nextPingTimeStorageKey).then((response) => {
        let localNextPingTime = storageGet(STATS.nextPingTimeStorageKey);
        if (typeof localNextPingTime !== 'number' || Number.isNaN(localNextPingTime)) {
          localNextPingTime = 0;
        }
        let nextPingTimeStored = response[STATS.nextPingTimeStorageKey];
        if (typeof nextPingTimeStored !== 'number' || Number.isNaN(nextPingTimeStored)) {
          nextPingTimeStored = 0;
        }
        const nextPingTime = Math.max(localNextPingTime, nextPingTimeStored);
        // if this is the first time we've run (just installed), millisTillNextPing is 0
        if (nextPingTime === 0 && STATS.firstRun) {
          callbackFN(0);
          return;
        }
        // if we don't have a 'next ping time', or it's not a valid number,
        // default to 55 minute ping interval
        if (
          typeof nextPingTime !== 'number'
          || nextPingTime === 0
          || Number.isNaN(nextPingTime)
        ) {
          callbackFN(FiftyFiveMinutes);
          return;
        }
        callbackFN(nextPingTime - Date.now());
      }); // end of get
    }, 10000);
  };

  // Used to rate limit .message()s. Rate limits reset at startup.
  const throttle = {
    // A small initial amount in case the server is bogged down.
    // The server will tell us the correct amount.
    maxEventsPerHour: 3, // null if no limit
    // Called when attempting an event. If not rate limited, returns
    // true and records the event.
    attempt() {
      const now = Date.now();
      const oneHour = 1000 * 60 * 60;
      const times = this.eventTimes;
      const mph = this.maxEventsPerHour;
      // Discard old or irrelevant events
      while (times[0] && (times[0] + oneHour < now || mph === null)) {
        times.shift();
      }
      if (mph === null) {
        return true;
      } // no limit
      if (times.length >= mph) {
        return false;
      } // used our quota this hour
      times.push(now);
      return true;
    },
    eventTimes: [],
  };

  return {
    userIDStorageKey,
    totalPingStorageKey,
    nextPingTimeStorageKey,
    firstRun, // True if AdBlock was just installed.
    userId() {
      return userID;
    },
    version,
    flavor,
    browser: ({
      E: 'Chrome',
      CM: 'Edge',
      F: 'Firefox',
    })[flavor],
    browserVersion,
    os,
    osVersion,
    pingNow,
    statsUrl,
    untilLoaded(callback) {
      readUserIDPromisified().then((resUserId) => {
        if (typeof callback === 'function') {
          callback(resUserId);
        }
      });
    },
    // Ping the server when necessary.
    startPinging() {
      function sleepThenPing() {
        millisTillNextPing((delay) => {
          window.setTimeout(() => {
            pingNow();
            scheduleNextPing();
            sleepThenPing();
          }, delay);
        });
      }

      readUserIDPromisified().then(() => {
        // Do 'stuff' when we're first installed...
        // - send a message
        browser.storage.local.get(STATS.totalPingStorageKey).then((response) => {
          if (!response[STATS.totalPingStorageKey]) {
            if (browser.management && browser.management.getSelf) {
              browser.management.getSelf().then((info) => {
                if (info) {
                  recordGeneralMessage(`new_install_${info.installType}`);
                } else {
                  recordGeneralMessage('new_install');
                }
              });
            } else {
              recordGeneralMessage('new_install');
            }
          }
        });
      });
      // This will sleep, then ping, then schedule a new ping, then
      // call itself to start the process over again.
      sleepThenPing();
    },

    // Record some data, if we are not rate limited.
    msg(message) {
      if (!throttle.attempt()) {
        log('Rate limited:', message);
        return;
      }
      const data = {
        cmd: 'msg2',
        m: message,
        u: userID,
        v: version,
        fr: firstRun,
        f: flavor,
        bv: browserVersion,
        o: os,
        ov: osVersion,
      };
      if (browser.runtime.id) {
        data.extid = browser.runtime.id;
      }
      $.ajax(statsUrl, {
        type: 'POST',
        data,
        complete(xhr) {
          let mph = parseInt(xhr.getResponseHeader('X-RateLimit-MPH'), 10);
          if (typeof mph !== 'number' || Number.isNaN(mph) || mph < -1) { // Server is sick
            mph = 1;
          }
          if (mph === -1) {
            mph = null;
          } // no rate limit
          throttle.maxEventsPerHour = mph;
        },
      });
    },
  };
}());

exports.STATS = STATS;


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * Converts raw text into a regular expression string
 * @param {string} text the string to convert
 * @return {string} regular expression representation of the text
 * @package
 */
exports.textToRegExp = function textToRegExp(text)
{
  return text.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
};

/**
 * Converts filter text into regular expression string
 * @param {string} text as in Filter()
 * @return {string} regular expression representation of filter text
 * @package
 */
exports.filterToRegExp = function filterToRegExp(text)
{
  // remove multiple wildcards
  text = text.replace(/\*+/g, "*");

  // remove leading wildcard
  if (text[0] == "*")
    text = text.substring(1);

  // remove trailing wildcard
  if (text[text.length - 1] == "*")
    text = text.substring(0, text.length - 1);

  return text
    // remove anchors following separator placeholder
    .replace(/\^\|$/, "^")
    // escape special symbols
    .replace(/\W/g, "\\$&")
    // replace wildcards by .*
    .replace(/\\\*/g, ".*")
    // process separator placeholders (all ANSI characters but alphanumeric
    // characters and _%.-)
    .replace(/\\\^/g, "(?:[\\x00-\\x24\\x26-\\x2C\\x2F\\x3A-\\x40\\x5B-\\x5E\\x60\\x7B-\\x7F]|$)")
    // process extended anchor at expression start
    .replace(/^\\\|\\\|/, "^[\\w\\-]+:\\/+(?!\\/)(?:[^\\/]+\\.)?")
    // process anchor at expression start
    .replace(/^\\\|/, "^")
    // process anchor at expression end
    .replace(/\\\|$/, "$");
};

let splitSelector = exports.splitSelector = function splitSelector(selector)
{
  if (!selector.includes(","))
    return [selector];

  let selectors = [];
  let start = 0;
  let level = 0;
  let sep = "";

  for (let i = 0; i < selector.length; i++)
  {
    let chr = selector[i];

    if (chr == "\\")        // ignore escaped characters
    {
      i++;
    }
    else if (chr == sep)    // don't split within quoted text
    {
      sep = "";             // e.g. [attr=","]
    }
    else if (sep == "")
    {
      if (chr == '"' || chr == "'")
      {
        sep = chr;
      }
      else if (chr == "(")  // don't split between parentheses
      {
        level++;            // e.g. :matches(div,span)
      }
      else if (chr == ")")
      {
        level = Math.max(0, level - 1);
      }
      else if (chr == "," && level == 0)
      {
        selectors.push(selector.substring(start, i));
        start = i + 1;
      }
    }
  }

  selectors.push(selector.substring(start));
  return selectors;
};

function findTargetSelectorIndex(selector)
{
  let index = 0;
  let whitespace = 0;
  let scope = [];

  // Start from the end of the string and go character by character, where each
  // character is a Unicode code point.
  for (let character of [...selector].reverse())
  {
    let currentScope = scope[scope.length - 1];

    if (character == "'" || character == "\"")
    {
      // If we're already within the same type of quote, close the scope;
      // otherwise open a new scope.
      if (currentScope == character)
        scope.pop();
      else
        scope.push(character);
    }
    else if (character == "]" || character == ")")
    {
      // For closing brackets and parentheses, open a new scope only if we're
      // not within a quote. Within quotes these characters should have no
      // meaning.
      if (currentScope != "'" && currentScope != "\"")
        scope.push(character);
    }
    else if (character == "[")
    {
      // If we're already within a bracket, close the scope.
      if (currentScope == "]")
        scope.pop();
    }
    else if (character == "(")
    {
      // If we're already within a parenthesis, close the scope.
      if (currentScope == ")")
        scope.pop();
    }
    else if (!currentScope)
    {
      // At the top level (not within any scope), count the whitespace if we've
      // encountered it. Otherwise if we've hit one of the combinators,
      // terminate here; otherwise if we've hit a non-colon character,
      // terminate here.
      if (/\s/.test(character))
        whitespace++;
      else if ((character == ">" || character == "+" || character == "~") ||
               (whitespace > 0 && character != ":"))
        break;
    }

    // Zero out the whitespace count if we've entered a scope.
    if (scope.length > 0)
      whitespace = 0;

    // Increment the index by the size of the character. Note that for Unicode
    // composite characters (like emoji) this will be more than one.
    index += character.length;
  }

  return selector.length - index + whitespace;
}

/**
 * Qualifies a CSS selector with a qualifier, which may be another CSS selector
 * or an empty string. For example, given the selector "div.bar" and the
 * qualifier "#foo", this function returns "div#foo.bar".
 * @param {string} selector The selector to qualify.
 * @param {string} qualifier The qualifier with which to qualify the selector.
 * @returns {string} The qualified selector.
 * @package
 */
exports.qualifySelector = function qualifySelector(selector, qualifier)
{
  let qualifiedSelector = "";

  let qualifierTargetSelectorIndex = findTargetSelectorIndex(qualifier);
  let [, qualifierType = ""] =
    /^([a-z][a-z-]*)?/i.exec(qualifier.substring(qualifierTargetSelectorIndex));

  for (let sub of splitSelector(selector))
  {
    sub = sub.trim();

    qualifiedSelector += ", ";

    let index = findTargetSelectorIndex(sub);

    // Note that the first group in the regular expression is optional. If it
    // doesn't match (e.g. "#foo::nth-child(1)"), type will be an empty string.
    let [, type = "", rest] =
      /^([a-z][a-z-]*)?\*?(.*)/i.exec(sub.substring(index));

    if (type == qualifierType)
      type = "";

    // If the qualifier ends in a combinator (e.g. "body #foo>"), we put the
    // type and the rest of the selector after the qualifier
    // (e.g. "body #foo>div.bar"); otherwise (e.g. "body #foo") we merge the
    // type into the qualifier (e.g. "body div#foo.bar").
    if (/[\s>+~]$/.test(qualifier))
      qualifiedSelector += sub.substring(0, index) + qualifier + type + rest;
    else
      qualifiedSelector += sub.substring(0, index) + type + qualifier + rest;
  }

  // Remove the initial comma and space.
  return qualifiedSelector.substring(2);
};


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

"use strict";
/** @module adblock-betafish/alias/recommendations */

/*
 * Same as the original source adblockpluschrome\adblockpluscore\lib
 * except:
 * - added AdBlock specific filter lists
 * - added language, id & hidden attribute
 */

/** @module */



/**
 * A `Recommendation` object represents a recommended filter subscription.
 */
class Recommendation
{
  /**
   * Creates a `Recommendation` object from the given source object.
   * @param {object} source The source object.
   * @private
   */
  constructor(source)
  {
    this._source = source;
  }

  /**
   * The type of the recommended filter subscription.
   * @type {string}
   */
  get type()
  {
    return this._source.type;
  }

  /**
   * The languages of the recommended filter subscription.
   * @type {Array.<string>}
   */
  get languages()
  {
    return this._source.languages ? [...this._source.languages] : [];
  }

  /**
   * The language indicator of the recommended filter subscription.
   * @type {boolean}
   */
  get language()
  {
    return this._source.language || (this._source.languages && this._source.languages.length > 0) || false;
  }

  /**
   * The title of the recommended filter subscription.
   * @type {string}
   */
  get title()
  {
    return this._source.title;
  }

  /**
   * The URL of the recommended filter subscription.
   * @type {string}
   */
  get url()
  {
    return this._source.url;
  }

  /**
   * The home page of the recommended filter subscription.
   * @type {string}
   */
  get homepage()
  {
    return this._source.homepage;
  }

  /**
   * The id of the recommended filter subscription.
   * @type {string}
   */
  get id()
  {
    return this._source.id;
  }

  /**
   * The hidden indicator of the recommended filter subscription.
   * @type {boolean}
   */
  get hidden()
  {
    return this._source.hidden || false;
  }

  /**
   * The unique index of the recommended filter subscription.
   * @type {Integer}
   */
   get index()
   {
    return this._source.index;
   }
}

/**
 * Yields <code>{@link Recommendation}</code> objects representing recommended
 * filter subscriptions.
 *
 * @yields {Recommendation} An object representing a recommended filter
 *   subscription.
 */
 exports.recommendations = function* recommendations()
{
  for (let source of __webpack_require__(54))
    yield new Recommendation(source);
}


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/* eslint no-console: "off" */
/* global self */

/** @module */



const {performance, PerformanceObserver} = __webpack_require__(55);

/**
 * Default profiler("...") returned object when profile mode is disabled.
 * @type {Profiler}
 * @private
 */
let noopProfiler = {
  start() {},
  mark() {},
  end() {},
  toString()
  {
    return "{start(){},mark(){},end(){}}";
  }
};

let inactiveProfiling = true;
let obs = null;

/** Enable or disable profiling
 *
 * @param {bool} enable the profiling is enabled. If true it will
 * create a PerformanceObserver and start observing, profiler() will then
 * create a proper profiler object. If false, observing is cancelled and
 * the profiler object will be a noop.
 * @param {?Function} reporter The reporter function called by the observer.
 * If falsy, the default reporter will be used.
 * @param {boolean} isAsyncCallback reporter callback behaviour.
 * If true, the notification callback will be called using setImmediate()
 * and multiple instance notifications will be buffered internally.
 * If false, notifications will be immediate and synchronous.
 */
function enableProfiling(enable, reporter, isAsyncCallback = true)
{
  inactiveProfiling = !enable;
  if (enable)
  {
    performance.mark("start_profile");
    if (!reporter)
    {
      reporter = list =>
      {
        for (let entry of list.getEntriesByType("measure"))
          console.log(`${entry.name}: ${entry.duration}ms`);
      };
    }
    obs = new PerformanceObserver(reporter);

    obs.observe({entryTypes: ["measure"], buffered: isAsyncCallback});
  }
  else if (obs)
  {
    obs.disconnect();
    obs = null;
  }
}

/**
 * Create a profiler object with `start()` `mark()` and `end()` methods to
 * either start, keep marking a specific profiled name, or ending it.
 *
 * @example
 * let {mark, end} = profiler('console.log');
 * mark();
 * console.log(1, 2, 3);
 * end();
 *
 * @param {string} id the unique ID to profile.
 * @returns {Profiler} The profiler with `start()`, `mark()` and
 * `end(clear = false)` methods.
 * @private
 */
function profiler(id)
{
  if (inactiveProfiling)
    return noopProfiler;

  return {
    id,
    start()
    {
      performance.mark(`${id}:start`);
      performance.measure(`${id}:startup`, "start_profile",
                          `${id}:start`);
    },
    mark(event)
    {
      performance.mark(`${id}:${event}`);
      performance.measure(`${id}:${event}_measure`, "start_profile",
                          `${id}:${event}`);
    },
    end()
    {
      performance.mark(`${id}:end`);
      performance.measure(id, "start_profile", `${id}:end`);
    }
  };
}

function isProfilingEnabled()
{
  return !inactiveProfiling;
}

exports.profiler = profiler;
exports.enable = enableProfiling;
exports.isEnabled = isProfilingEnabled;


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * Map to be used instead when a filter has a blank `domains` property.
 * @type {Map.<string, boolean>}
 */
let defaultDomains = new Map([["", true]]);

let FilterMap =
/**
 * A `FilterMap` object contains a set of filters, each mapped to a boolean
 * value indicating whether the filter should be applied.
 *
 * It is used by
 * `{@link module:filtersByDomain.FiltersByDomain FiltersByDomain}`.
 *
 * @package
 */
exports.FilterMap = class FilterMap extends Map {};

/**
 * A `FiltersByDomain` object contains a set of domains, each mapped to a set
 * of filters along with a boolean value for each filter indicating whether the
 * filter should be applied to the domain.
 *
 * @package
 */
exports.FiltersByDomain = class FiltersByDomain extends Map
{
  /**
   * Adds a filter and all of its domains to the object.
   *
   * @param {module:filterClasses.ActiveFilter} filter The filter.
   * @param {Map.<string, boolean>} [domains] The filter's domains. If not
   *   given, the `{@link module:filterClasses.ActiveFilter#domains domains}`
   *   property of `filter` is used.
   */
  add(filter, domains = filter.domains)
  {
    for (let [domain, include] of domains || defaultDomains)
    {
      if (!include && domain == "")
        continue;

      let map = this.get(domain);
      if (!map)
      {
        this.set(domain, include ? filter : new FilterMap([[filter, false]]));
      }
      else if (map.size == 1 && !(map instanceof FilterMap))
      {
        if (filter != map)
          this.set(domain, new FilterMap([[map, true], [filter, include]]));
      }
      else
      {
        map.set(filter, include);
      }
    }
  }

  /**
   * Removes a filter and all of its domains from the object.
   *
   * @param {module:filterClasses.ActiveFilter} filter The filter.
   * @param {Map.<string, boolean>} [domains] The filter's domains. If not
   *   given, the `{@link module:filterClasses.ActiveFilter#domains domains}`
   *   property of `filter` is used.
   */
  remove(filter, domains = filter.domains)
  {
    for (let domain of (domains || defaultDomains).keys())
    {
      let map = this.get(domain);
      if (map)
      {
        if (map.size > 1 || map instanceof FilterMap)
        {
          map.delete(filter);

          if (map.size == 0)
          {
            this.delete(domain);
          }
          else if (map.size == 1)
          {
            for (let [lastFilter, include] of map.entries())
            {
              // Reduce Map { "example.com" => Map { filter => true } } to
              // Map { "example.com" => filter }
              if (include)
                this.set(domain, lastFilter);

              break;
            }
          }
        }
        else if (filter == map)
        {
          this.delete(domain);
        }
      }
    }
  }
};


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

"use strict";
/*
 * Same as the original source adblockpluschrome/lib/contentFiltering.js
 * except:
 * - updated require paths
 * - added fetch() of second snippet library
 */
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module contentFiltering */



const { contentTypes } = __webpack_require__(6);
const {
  elemHide,
  createStyleSheet,
  rulesFromStyleSheet
} = __webpack_require__(26);
const {
  elemHideEmulation
} = __webpack_require__(28);
const { filterNotifier } = __webpack_require__(4);
const { snippets, compileScript } = __webpack_require__(39);
const { checkAllowlisted } = __webpack_require__(8);
const { extractHostFromFrame } = __webpack_require__(13);
const { port } = __webpack_require__(1);
const { HitLogger, logRequest } = __webpack_require__(11);
const { recordBlockedRequest } = __webpack_require__(16);
const { Prefs } = __webpack_require__(5);
const info = __webpack_require__(17);

const DEBUG_CSS_PROPERTIES = [["background", "#e67370"], ["outline", "solid red"]];

const DEBUG_CSS_PROPERTIES_SNIPPETS = [
  [
    "background",
    "repeating-linear-gradient(to bottom, " + "#e67370 0, #e67370 9px, white 9px, white 10px)"
  ],
  ["outline", "solid red"]
];

// Chromium's support for tabs.removeCSS is still a work in progress and the
// API is likely to be different from Firefox's; for now we just don't use it
// at all, even if it's available.
// See https://crbug.com/608854
const styleSheetRemovalSupported = info.platform == "gecko";

let userStyleSheetsSupported = true;

let snippetsSource = {};

function addStyleSheet(tabId, frameId, styleSheet) {
  try {
    let promise = browser.tabs.insertCSS(tabId, {
      code: styleSheet,
      cssOrigin: "user",
      frameId,
      matchAboutBlank: true,
      runAt: "document_start"
    });

    // See error handling notes in the catch block.
    promise.catch(() => { });
  } catch (error) {
    // If the error is about the "cssOrigin" option, this is an older version
    // of Chromium (65 and below) or Firefox (52 and below) that does not
    // support user style sheets.
    if (/\bcssOrigin\b/.test(error.message)) userStyleSheetsSupported = false;

    // For other errors, we simply return false to indicate failure.
    //
    // One common error that occurs frequently is when a frame is not found
    // (e.g. "Error: No frame with id 574 in tab 266"), which can happen when
    // the code in the parent document has removed the frame before the
    // background page has had a chance to respond to the content script's
    // "content.applyFilters" message. We simply ignore such errors, because
    // otherwise they show up in the log too often and make debugging
    // difficult.
    //
    // Also note that the missing frame error is thrown synchronously on
    // Firefox, while on Chromium it is an asychronous promise rejection. In
    // the latter case, we cannot indicate failure to the caller, but we still
    // explicitly ignore the error.
    return false;
  }

  return true;
}

function removeStyleSheet(tabId, frameId, styleSheet) {
  if (!styleSheetRemovalSupported) return;

  browser.tabs.removeCSS(tabId, {
    code: styleSheet,
    cssOrigin: "user",
    frameId,
    matchAboutBlank: true
  });
}

function updateFrameStyles(tabId, frameId, styleSheet, groupName = "standard", appendOnly = false) {
  let frame = ext.getFrame(tabId, frameId);
  if (!frame) return false;

  if (!frame.state.injectedStyleSheets) frame.state.injectedStyleSheets = new Map();

  let oldStyleSheet = frame.state.injectedStyleSheets.get(groupName);

  if (appendOnly && oldStyleSheet) styleSheet = oldStyleSheet + styleSheet;

  // Ideally we would compare the old and new style sheets and skip this code
  // if they're the same. But first we need to ensure that there are no edge
  // cases that would cause the old style sheet to be a leftover from a
  // previous instance of the frame (see issue #7180). For now, we add the new
  // style sheet regardless.

  // Add the new style sheet first to keep previously hidden elements from
  // reappearing momentarily.
  if (styleSheet && !addStyleSheet(tabId, frameId, styleSheet)) return false;

  // Sometimes the old and new style sheets can be exactly the same. In such a
  // case, do not remove the "old" style sheet, because it is in fact the new
  // style sheet now.
  if (oldStyleSheet && oldStyleSheet != styleSheet) removeStyleSheet(tabId, frameId, oldStyleSheet);

  // The standard style sheet is ~660 KB per frame (as of Adblock Plus 3.3.2).
  // Keeping it in memory would only really be useful on Firefox, which allows
  // us to remove it via the tabs.removeCSS API. By choosing not to hold on to
  // it, we save potentially several megabytes per tab (#6967).
  if (groupName != "standard") frame.state.injectedStyleSheets.set(groupName, styleSheet);
  return true;
}

function executeScripts(scripts, tabId, frameId) {
  try {
    let environment = {};
    if (Prefs.elemhide_debug) environment.debugCSSProperties = DEBUG_CSS_PROPERTIES_SNIPPETS;

    let details = {
      frameId,
      code: compileScript(
        scripts,
        snippetsSource.isolatedCode,
        snippetsSource.injectedCode,
        snippetsSource.injectedList,
        environment),
      matchAboutBlank: true,
      runAt: "document_start"
    };

    return browser.tabs.executeScript(tabId, details).catch(error => {
      // Sometimes a frame is added and removed very quickly, in such cases we
      // simply ignore the error.
      if (error.message == "The frame was removed.") return;

      // Sometimes the frame in question is just not found. We don't know why
      // this is exactly, but we simply ignore the error.
      if (/^No frame with id \d+ in tab \d+\.$/.test(error.message)) return;

      throw error;
    });
  } catch (error) {
    // See the comment in the catch block associated with the call to
    // tabs.insertCSS for why we catch any error here and simply
    // return a rejected promise.
    return Promise.reject(error);
  }
}

/**
 * @typedef {object} contentApplyFiltersResult
 * @property {boolean} trace
 *   true if we're logging requests (our developer tools pane is open).
 * @property {boolean} inline
 *   true if user stylesheets aren't supported but there is CSS to inject.
 * @property {string[]} [rules]
 *   Array of CSS rules, included if the "inline" property is true.
 * @property {string[]} [selectors]
 *   Array of selectors, included if "trace" property is true.
 * @property {string[]} [exceptions]
 *   Array of exceptions, included if "trace" property is true.
 */

/**
 * Apply content (snippet and element hiding) filters to the page.
 *
 * @event "content.applyFilters"
 * @property {object} filterTypes - which filter types to apply, either
 *                                  "elemhide, "snippets" or both.
 * @returns {contentApplyFiltersResult}
 */
port.on("content.applyFilters", (message, sender) => {
  let styleSheet = { code: "", selectors: [] };
  let emulatedPatterns = [];
  let trace = HitLogger.hasListener(sender.page.id);
  let debug = Prefs.elemhide_debug;
  let inline = !userStyleSheetsSupported;

  let filterTypes = message.filterTypes || { elemhide: true, snippets: true };

  if (!checkAllowlisted(sender.page, sender.frame, null, contentTypes.DOCUMENT)) {
    let docDomain = extractHostFromFrame(sender.frame);

    // If snippetsSource is an empty object,
    // then the snippets library was not bundled with the extension.
    // For compatibility reasons with `compileScript` we avoid
    // injecting anything into the page.
    if (filterTypes.snippets && Object.keys(snippetsSource).length > 0) {
      let filters = snippets.getFilters(docDomain);
      if (filters.length) {
        let scripts = filters.filter(ok => ok).map(({ script }) => script);
        executeScripts(scripts, sender.page.id, sender.frame.id).then(() => {
          for (let filter of filters) {
            let tabIds = [sender.page.id];
            if (filter) recordBlockedRequest(filter, tabIds);

            logRequest(tabIds, {
              url: sender.frame.url.href,
              type: "SNIPPET",
              docDomain
            }, filter);
          }
        });
      }
    }

    if (
      filterTypes.elemhide &&
      !checkAllowlisted(sender.page, sender.frame, null, contentTypes.ELEMHIDE)
    ) {
      let specificOnly = checkAllowlisted(
        sender.page,
        sender.frame,
        null,
        contentTypes.GENERICHIDE
      );
      styleSheet = elemHide.getStyleSheet(docDomain, specificOnly, trace || debug, trace);

      if (debug) {
        let declarationBlock = "{";
        for (let [property, value] of DEBUG_CSS_PROPERTIES)
          declarationBlock += `${property}: ${value} !important;`;
        declarationBlock += "}";

        styleSheet.code = createStyleSheet(styleSheet.selectors, declarationBlock);
      }

      for (let filter of elemHideEmulation.getFilters(docDomain))
        emulatedPatterns.push({ selector: filter.selector, text: filter.text });
    }
  }

  if (!inline && !updateFrameStyles(sender.page.id, sender.frame.id, styleSheet.code))
    inline = true;

  let response = { trace, inline, emulatedPatterns };

  if (inline) response.rules = [...rulesFromStyleSheet(styleSheet.code)];

  if (trace) {
    response.selectors = styleSheet.selectors;
    response.exceptions = styleSheet.exceptions.map(({ text, selector }) => ({ text, selector }));
  }

  if (debug) response.cssProperties = DEBUG_CSS_PROPERTIES;

  return response;
});

/**
 * Inject the given CSS selectors into the page.
 * @event "content.injectSelectors"
 * @property {string[]} selectors - The CSS selectors to inject
 * @property {string} groupName - The group name, e.g. "standard" or
 *                                "collapsing".
 * @property {boolean} appendOnly - true if given selectors should never be
 *                                  removed, for example element collapsing
 *                                  selectors.
 * @returns {?string[]} Array of CSS rules which were injected, if any.
 */
port.on("content.injectSelectors", (message, sender) => {
  let styleSheet = createStyleSheet(message.selectors);
  if (
    !userStyleSheetsSupported ||
    !updateFrameStyles(
      sender.page.id,
      sender.frame.id,
      styleSheet,
      message.groupName,
      message.appendOnly
    )
  )
    return [...rulesFromStyleSheet(styleSheet)];
});

async function loadSnippets() {
  try {
    let response =
      await fetch(browser.runtime.getURL("/snippets.json"),
        { cache: "no-cache" });
    snippetsSource = response.ok ? (await response.json()) : {};
  }
  catch (e) {
    // If the request fails, the snippets library is not
    // bundled with the extension, so we silently ignore this error.
  }
};
loadSnippets();

async function loadAdBlockSnippets() {
  try {
    let response =
      await fetch(browser.runtime.getURL("/adblock-snippets.json"),
        { cache: "no-cache" });
    let ABsnippetsSource = response.ok ? (await response.json()) : {};

    if (ABsnippetsSource.injectedCode) {
      snippetsSource.injectedCode = snippetsSource.injectedCode + ABsnippetsSource.injectedCode;
    }
    if (ABsnippetsSource.injectedList) {
      snippetsSource.injectedList = snippetsSource.injectedList.concat(ABsnippetsSource.injectedList);
    }
    if (ABsnippetsSource.isolatedCode) {
      snippetsSource.isolatedCode = snippetsSource.isolatedCode + ABsnippetsSource.isolatedCode;
    }
  }
  catch (e) {
    // If the request fails, the snippets library is not
    // bundled with the extension, so we silently ignore this error.
  }
};
exports.loadAdBlockSnippets = loadAdBlockSnippets;




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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Snippets implementation.
 */

const {EventEmitter} = __webpack_require__(12);

let singleCharacterEscapes = new Map([
  ["n", "\n"], ["r", "\r"], ["t", "\t"]
]);

/**
 * `{@link module:snippets.snippets snippets}` implementation.
 */
class Snippets extends EventEmitter
{
  /**
   * @hideconstructor
   */
  constructor()
  {
    super();

    /**
     * All known snippet filters.
     * @type {Set.<module:filterClasses.SnippetFilter>}
     * @private
     */
    this._filters = new Set();
  }

  /**
   * Removes all known snippet filters.
   */
  clear()
  {
    let {_filters} = this;

    if (_filters.size == 0)
      return;

    _filters.clear();

    this.emit("snippets.filtersCleared");
  }

  /**
   * Adds a new snippet filter.
   * @param {module:filterClasses.SnippetFilter} filter
   */
  add(filter)
  {
    let {_filters} = this;
    let {size} = _filters;

    _filters.add(filter);

    if (size != _filters.size)
      this.emit("snippets.filterAdded", filter);
  }

  /**
   * Removes an existing snippet filter.
   * @param {module:filterClasses.SnippetFilter} filter
   */
  remove(filter)
  {
    let {_filters} = this;
    let {size} = _filters;

    _filters.delete(filter);

    if (size != _filters.size)
      this.emit("snippets.filterRemoved", filter);
  }

  /**
   * Checks whether a snippet filter exists.
   * @param {module:filterClasses.SnippetFilter} filter
   * @returns {boolean}
   */
  has(filter)
  {
    return this._filters.has(filter);
  }

  /**
   * Returns a list of all snippet filters active on the given domain.
   * @param {string} domain The domain.
   * @returns {Array.<module:filterClasses.SnippetFilter>} A list of snippet
   *   filters.
   */
  getFilters(domain)
  {
    let result = [];

    for (let filter of this._filters)
    {
      if (filter.isActiveOnDomain(domain))
        result.push(filter);
    }

    return result;
  }

  /**
   * Returns a list of all snippet filters active on the given domain.
   * @param {string} domain The domain.
   * @returns {Array.<module:filterClasses.SnippetFilter>} A list of snippet
   *   filters.
   *
   * @deprecated Use <code>{@link module:snippets~Snippets#getFilters}</code>
   *   instead.
   * @see module:snippets~Snippets#getFilters
   */
  getFiltersForDomain(domain)
  {
    return this.getFilters(domain);
  }
}

/**
 * Container for snippet filters.
 * @type {module:snippets~Snippets}
 */
exports.snippets = new Snippets();

let parseScript =
/**
 * Parses a script and returns a list of all its commands and their arguments.
 * @param {string} script The script.
 * @returns {Array.<string[]>} A list of commands and their arguments.
 * @package
 */
exports.parseScript = function parseScript(script)
{
  let tree = [];

  let escape = false;
  let withinQuotes = false;

  let unicodeEscape = null;

  let quotesClosed = false;

  let call = [];
  let argument = "";

  for (let character of script.trim() + ";")
  {
    let afterQuotesClosed = quotesClosed;
    quotesClosed = false;

    if (unicodeEscape != null)
    {
      unicodeEscape += character;

      if (unicodeEscape.length == 4)
      {
        let codePoint = parseInt(unicodeEscape, 16);
        if (!isNaN(codePoint))
          argument += String.fromCodePoint(codePoint);

        unicodeEscape = null;
      }
    }
    else if (escape)
    {
      escape = false;

      if (character == "u")
        unicodeEscape = "";
      else
        argument += singleCharacterEscapes.get(character) || character;
    }
    else if (character == "\\")
    {
      escape = true;
    }
    else if (character == "'")
    {
      withinQuotes = !withinQuotes;

      if (!withinQuotes)
        quotesClosed = true;
    }
    else if (withinQuotes || character != ";" && !/\s/.test(character))
    {
      argument += character;
    }
    else
    {
      if (argument || afterQuotesClosed)
      {
        call.push(argument);
        argument = "";
      }

      if (character == ";" && call.length > 0)
      {
        tree.push(call);
        call = [];
      }
    }
  }

  return tree;
};

/**
 * Compiles a script against a given list of libraries into executable code.
 * @param {string|Array.<string>} scripts One or more scripts to convert into
 *  executable code.
 * @param {string} isolatedSnippetsLibrary The stringified bundle to be executed
 * in the isolated content script context.
 * @param {string} injectedSnippetsLibrary The stringified bundle to be injected
 * and executed in the main context.
 * @param {string|Array.<string>} injectedSnippetsList An array containing the
 * available injectable snippets.
 * @param {object} [environment] An object containing environment variables.
 * @returns {string} Executable code.
 */
exports.compileScript = function compileScript(scripts,
                                               isolatedSnippetsLibrary,
                                               injectedSnippetsLibrary,
                                               injectedSnippetsList,
                                               environment = {})
{
  let isolatedLib = JSON.stringify(isolatedSnippetsLibrary);
  let injectedLib = JSON.stringify(injectedSnippetsLibrary);
  let jsonEnv = JSON.stringify(environment);
  return `
    "use strict";
    (() =>
    {
      let scripts = ${JSON.stringify([].concat(scripts).map(parseScript))};

      let isolatedLib = ${isolatedLib};
      let imports = Object.create(null);
      let injectedSnippetsCount = 0;
      let loadLibrary = new Function("exports", "environment", isolatedLib);
      loadLibrary(imports, ${jsonEnv});
      const isolatedSnippets = imports.snippets;

      let injectedLib = ${injectedLib};
      let injectedSnippetsList = ${JSON.stringify(injectedSnippetsList)};
      let executable = "(() => {";
      executable += "let environment = ${jsonEnv.replace(/[\\"]/g, "\\$&")};";
      executable += injectedLib;

      let {hasOwnProperty} = Object.prototype;
      for (let script of scripts)
      {
        for (let [name, ...args] of script)
        {
          if (hasOwnProperty.call(isolatedSnippets, name))
          {
            let value = isolatedSnippets[name];
            if (typeof value == "function")
              value(...args);
          }
          if (injectedSnippetsList.includes(name))
          {
            executable += stringifyFunctionCall(name, ...args);
            injectedSnippetsCount++;
          }
        }
      }

      executable += "})();";

      if (injectedSnippetsCount > 0)
        injectSnippetsInMainContext(executable);

      function stringifyFunctionCall(func, ...params)
      {
        // Call JSON.stringify on the arguments to avoid any arbitrary code
        // execution.
        const f = "snippets['" + func + "']";
        const parameters = params.map(JSON.stringify).join(",");
        return f + "(" + parameters + ");";
      }

      function injectSnippetsInMainContext(exec)
      {
        // injecting phase
        let script = document.createElement("script");
        script.type = "application/javascript";
        script.async = false;

        // Firefox 58 only bypasses site CSPs when assigning to 'src',
        // while Chrome 67 and Microsoft Edge (tested on 44.17763.1.0)
        // only bypass site CSPs when using 'textContent'.
        if (typeof netscape != "undefined" && typeof browser != "undefined")
        {
          let url = URL.createObjectURL(new Blob([executable]));
          script.src = url;
          document.documentElement.appendChild(script);
          URL.revokeObjectURL(url);
        }
        else
        {
          script.textContent = executable;
          document.documentElement.appendChild(script);
        }

        document.documentElement.removeChild(script);
      }
    })();
  `;
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



const {Prefs} = __webpack_require__(5);

const {MILLIS_IN_DAY} = __webpack_require__(20);

/**
 * Converts a version string into a `Date` object with minute-level precision.
 *
 * @param {string} version The version string in `YYYYMMDD[HH[MM]]` format or
 *   just the value `"0"`.
 *
 * @returns {Date} A `Date` object. If the value of `version` is `"0"`, the
 *   returned value represents the Unix epoch.
 */
function versionToDate(version)
{
  if (version == "0")
    return new Date(0);

  let year = version.substring(0, 4);
  let month = version.substring(4, 6);
  let date = version.substring(6, 8);

  let hours = version.substring(8, 10) || "00";
  let minutes = version.substring(10, 12) || "00";

  // The input is nearly a valid ISO 8601 timestamp, except for the hyphens,
  // the colon, and the special characters T and Z. We can use the timestamp
  // string version of the Date constructor directly. Alternatively, we could
  // use Date.UTC(), but that would require some adjustment to the values
  // (e.g. the month must be 0-based).
  return new Date(`${year}-${month}-${date}T${hours}:${minutes}Z`);
}

/**
 * Strips the value of the `firstVersion` parameter down to either `YYYYMMDD`,
 * `YYYYMM`, or `YYYY` depending on its distance from the value of the
 * `currentVersion` parameter.
 *
 * @param {string} firstVersion A version string in `YYYYMMDD[HH[MM]]` format
 *   with an optional `"-E"` suffix or just `"0"` or `"0-E"`.
 * @param {string} currentVersion A version string in `YYYYMMDD[HH[MM]]` format
 *   or just `"0"`.
 *
 * @returns {?string}
 */
function stripFirstVersion(firstVersion, currentVersion)
{
  let eFlag = firstVersion.endsWith("-E");
  if (eFlag)
    firstVersion = firstVersion.slice(0, -2);

  try
  {
    let firstDate = versionToDate(firstVersion);
    let currentDate = versionToDate(currentVersion);

    if (currentDate - firstDate > 365 * MILLIS_IN_DAY)
      firstVersion = firstVersion.substring(0, 4);
    else if (currentDate - firstDate > 30 * MILLIS_IN_DAY)
      firstVersion = firstVersion.substring(0, 6);
    else
      firstVersion = firstVersion.substring(0, 8);
  }
  catch (error)
  {
    return null;
  }

  if (eFlag)
    firstVersion += "-E";

  return firstVersion;
}

/**
 * Checks whether this is a fresh installation.
 * @returns {boolean}
 */
function isFreshInstall()
{
  return !("data" in Prefs.notificationdata);
}

/**
 * `{@link module:analytics.analytics analytics}` implementation.
 */
class Analytics
{
  /**
   * @hideconstructor
   */
  constructor()
  {
  }

  /**
   * Checks whether the given URL is trusted for analytics purposes based on
   * the value of the `analytics.trustedHosts` preference.
   *
   * @param {string} url The URL.
   *
   * @returns {boolean} Whether the URL is trusted.
   */
  isTrusted(url)
  {
    let {trustedHosts} = Prefs.analytics || {};
    if (Array.isArray(trustedHosts))
    {
      try
      {
        return trustedHosts.includes(new URL(url).host);
      }
      catch (error)
      {
      }
    }

    return false;
  }

  /**
   * Returns a string indicating the version of the first ever downloaded
   * resource (as recorded by
   * `{@link module:analytics~Analytics#recordVersion recordVersion()}`), for
   * the purpose of cohort analysis.
   *
   * For privacy reasons, the original value is stripped down to either
   * `YYYYMMDD`, `YYYYMM`, or `YYYY` depending on its age. An `-E` suffix is
   * appended to the original value if it was recorded on an existing
   * installation.
   *
   * @returns {?string} A string indicating the version of the first ever
   *   downloaded resource, or `"0"` or `"0-E"` if there is no data, or `null`
   *   in case of a parsing error.
   */
  getFirstVersion()
  {
    let {analytics} = Prefs;
    if (analytics)
    {
      let {firstVersion = "0", currentVersion = "0"} = analytics.data || {};
      let strippedFirstVersion = stripFirstVersion(firstVersion,
                                                   currentVersion);
      if (strippedFirstVersion)
      {
        if (strippedFirstVersion == "0" && !isFreshInstall())
          strippedFirstVersion = "0-E";

        return strippedFirstVersion;
      }
    }

    return null;
  }

  /**
   * Records the version of a downloaded resource for the purpose of cohort
   * analysis.
   *
   * The value of the `analytics` preference must be set at least to an
   * empty object, otherwise nothing is ever recorded and
   * `{@link module:analytics~Analytics#getFirstVersion getFirstVersion()}`
   * always returns `null`.
   *
   * @param {string} version The version, in `YYYYMMDD[HH[MM]]` format.
   */
  recordVersion(version)
  {
    if (!/^(\d{8}|\d{10}|\d{12})$/.test(version))
      return;

    let {analytics} = Prefs;
    if (analytics)
    {
      if (!analytics.data)
        analytics.data = {};

      let {data} = analytics;

      data.currentVersion = version;

      if (typeof data.firstVersion == "undefined")
      {
        // If this is not a new installation, set the -E flag.
        if (!isFreshInstall())
          version += "-E";

        data.firstVersion = version;
      }

      // JSON values aren't saved unless they are assigned a different object.
      Prefs.analytics = JSON.parse(JSON.stringify(analytics));
    }
  }
}

/**
 * Implements data analytics functions.
 * @type {module:analytics~Analytics}
 */
exports.analytics = new Analytics();


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, exports, STATS, log, getSettings, Prefs, openTab,
   License, settings,
 */

const { showIconBadgeCTA, NEW_BADGE_REASONS } = __webpack_require__(21);


const CtaABManager = (function get() {
  let ctaData = {
    enrollment: false,
  };
  const ctaDataStorageKey = 'ctaData';
  // Load the CTA A/B data from persistent storage
  // Should only be called during startup / initialization
  browser.storage.local.get(ctaDataStorageKey).then((response) => {
    if (response[ctaDataStorageKey]) {
      ctaData = response[ctaDataStorageKey];
    }
  });

  // Check the response from a ping to see if it contains valid CTA A/B instructions.
  // If so, return an object containing data about the CTA A/B data.
  // Otherwise, return null.
  // Inputs:
  //   responseData: string response from a ping
  const dataFrom = function (responseData) {
    if (!responseData || responseData.length === 0 || responseData.trim().length === 0) {
      return null;
    }
    let pingData = {};
    try {
      pingData = JSON.parse(responseData);
      if (!pingData) {
        return null;
      }
    } catch (e) {
      // eslint-disable-next-line no-console
      console.log('Something went wrong with parsing data.');
      // eslint-disable-next-line no-console
      console.log('error', e);
      // eslint-disable-next-line no-console
      console.log('response data', responseData);
      return null;
    }
    return pingData;
  };

  return {
    get() {
      return ctaData;
    },
    isEnrolled() {
      return (ctaData.enrollment === true);
    },
    getVar() {
      return ctaData.var;
    },
    getExp() {
      return ctaData.exp;
    },
    maybeCtaAB(responseData) {
      if (!License.shouldShowPremiumCTA()) {
        return;
      }
      const pingData = dataFrom(responseData);
      if (!pingData) {
        return;
      }
      ctaData.enrollment = true;
      ctaData.var = pingData.var;
      ctaData.exp = pingData.exp;
      browser.storage.local.set({ ctaData });
      showIconBadgeCTA(true, NEW_BADGE_REASONS.VPN_CTA);
    }, // end of maybeCtaAB
    types() {
      // 'C' = A/B Test of CTAs
      return 'C';
    },
  };
}());

exports.CtaABManager = CtaABManager;


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, settings, getSettings, setSetting, License, STATS, channels, exports, require,
   getSubscriptionsMinusText, chromeStorageSetHelper, getUserFilters, Prefs, abpPrefPropertyNames,
   Subscription, adblockIsDomainPaused, PubNub, adblockIsPaused, filterStorage, parseFilter,
   synchronizer, pausedFilterText1, pausedFilterText2, getUrlFromId, channelsNotifier,
   settingsNotifier, filterNotifier, isWhitelistFilter, recordGeneralMessage */

const { EventEmitter } = __webpack_require__(12);

const SyncService = (function getSyncService() {
  let storedSyncDomainPauses = [];
  let syncCommitVersion = 0;
  let currentExtensionName = '';
  let pubnub;
  const syncSchemaVersion = 1;
  const syncCommitVersionKey = 'SyncCommitKey';
  const syncLogMessageKey = 'SyncLogMessageKey';
  const syncPreviousDataKey = 'SyncPreviousDataKey';
  const syncExtensionNameKey = 'SyncExtensionNameKey';
  const syncPendingPostDataKey = 'syncPendingPostDataKey';
  const syncNotifier = new EventEmitter();
  let lastPostStatusCode = 200;
  let pendingPostData = false;
  let lastGetStatusCode = 200;
  let lastGetErrorResponse = {};
  const debounceWaitTime = 3000; // time in ms before posting data
  // Below is a list of filter list ids that have been added since the
  // sync feature was added to AdBlock, therefore these filter lists should be sent
  // with an ID of 'url:...' instead of the id in the betafish-subscriptions.json file
  // any adds to the the betafish-subscriptions.json file should be added here as well.
  const sendFilterListByURL = ['nordic', 'annoyances',
    'fb_notifications', 'easylist_plus_romanian', 'idcac'];

  function setCommitVersion(newVersionNum) {
    syncCommitVersion = newVersionNum;
  }

  function getLastPostStatusCode() {
    return lastPostStatusCode;
  }

  function resetLastPostStatusCode() {
    lastPostStatusCode = 200;
  }

  function setLastPostStatusCode(newCode) {
    lastPostStatusCode = newCode;
  }

  function getLastGetStatusCode() {
    return lastGetStatusCode;
  }

  function resetLastGetStatusCode() {
    lastGetStatusCode = 200;
  }

  function setLastGetStatusCode(newCode) {
    lastGetStatusCode = newCode;
  }

  function getLastGetErrorResponse() {
    return lastGetErrorResponse;
  }

  function resetLastGetErrorResponse() {
    lastGetErrorResponse = {};
  }

  function setLastGetErrorResponse(newObject) {
    lastGetErrorResponse = newObject;
  }

  function resetAllErrors() {
    resetLastGetErrorResponse();
    resetLastGetStatusCode();
    resetLastPostStatusCode();
  }

  const getCurrentExtensionName = function () {
    return currentExtensionName;
  };

  const getSyncLog = function () {
    const storedLog = JSON.parse(localStorage.getItem(syncLogMessageKey) || '[]');
    const theReturnObj = {};
    Object.assign(theReturnObj, storedLog);
    return theReturnObj;
  };

  // TODO - when should we delete the log file???
  const deleteSyncLog = function () {
    localStorage.removeItem(syncLogMessageKey);
  };

  function debounced(delay, fn) {
    let timerId;
    return function debouncedAgain(...args) {
      if (timerId) {
        clearTimeout(timerId);
      }
      timerId = setTimeout(() => {
        fn(...args);
        timerId = null;
      }, delay);
    };
  }

  // return meta data about the extension installation
  const getExtensionInfo = function () {
    return {
      flavor: STATS.flavor,
      browserVersion: STATS.browserVersion,
      os: STATS.os,
      osVersion: STATS.osVersion,
      extVersion: STATS.version,
      syncSchemaVersion,
    };
  };

  /*
  ** @param a, b        - values (Object, Date, etc.)
  ** @returns {boolean} - true if a and b are the same object or
  **                      same primitive value or
  **                      have the same properties with the same values
  **                      otherwise false
  */
  function objectComparison(a, b) {
    // Helper to return a value's internal object [[Class]]
    // That this returns [object Type] even for primitives
    function getClass(obj) {
      return Object.prototype.toString.call(obj);
    }

    // If a and b reference the same value, return true
    if (a === b) {
      return true;
    }

    // If a and b aren't the same type, return false
    if (typeof a !== typeof b) {
      return false;
    }

    // Already know types are the same, so if type is number
    // and both NaN, return true
    if (typeof a === 'number' && Number.isNaN(a) && Number.isNaN(b)) {
      return true;
    }

    // Get internal [[Class]]
    const aClass = getClass(a);
    const bClass = getClass(b);

    // Return false if not same class
    if (aClass !== bClass) {
      return false;
    }

    // If they're Boolean, String or Number objects, check values
    if (
      aClass === '[object Boolean]'
      || aClass === '[object String]'
      || aClass === '[object Number]'
    ) {
      if (a.valueOf() !== b.valueOf()) {
        return false;
      }
    }

    // If they're RegExps, Dates or Error objects, check stringified values
    if (aClass === '[object RegExp]' || aClass === '[object Date]' || aClass === '[object Error]') {
      if (a.toString() !== b.toString()) {
        return false;
      }
    }

    // For functions, check stringigied values are the same
    // Almost impossible to be equal if a and b aren't trivial
    // and are different functions
    if (aClass === '[object Function]' && a.toString() !== b.toString()) {
      return false;
    }

    // For all objects, (including Objects, Functions, Arrays and host objects),
    // check the properties
    const aKeys = Object.keys(a);
    const bKeys = Object.keys(b);

    // If they don't have the same number of keys, return false
    if (aKeys.length !== bKeys.length) {
      return false;
    }

    // Check they have the same keys
    if (!aKeys.every(key => Object.prototype.hasOwnProperty.call(b, key))) {
      return false;
    }

    // Check key values - uses ES5 Object.keys
    return aKeys.every(key => objectComparison(a[key], b[key]));
  }

  const isDomainPauseFilter = function (filterText) {
    if (isWhitelistFilter(filterText)) {
      const domains = adblockIsDomainPaused();
      for (const domain in domains) {
        if (`@@${domain}$document` === filterText) {
          return true;
        }
      }
    }
    return false;
  };

  const isPauseFilter = function (filterText) {
    return (
      isWhitelistFilter(filterText) && ((pausedFilterText1 === filterText)
        || (pausedFilterText2 === filterText))
    );
  };

  function getCommitVersion() {
    return syncCommitVersion;
  }

  // Sync log message processing

  const addSyncLogText = function (msg) {
    const storedLog = JSON.parse(localStorage.getItem(syncLogMessageKey) || '[]');
    storedLog.push(`${new Date().toUTCString()} , ${msg}`);
    while (storedLog.length > 500) { // only keep the last 500 log entries
      storedLog.shift();
    }
    localStorage.setItem(syncLogMessageKey, JSON.stringify(storedLog));
  };

  const onExtensionNamesDownloadingAddLogEntry = function () {
    addSyncLogText('extension.names.downloading');
  };

  const onExtensionNamesDownloadedAddLogEntry = function () {
    addSyncLogText('extension.names.downloaded');
  };

  const onExtensionNamesDownloadingErrorAddLogEntry = function (errorCode) {
    addSyncLogText(`extension.names.downloading.error: ${errorCode}`);
  };

  const onExtensionNameUpdatingAddLogEntry = function () {
    addSyncLogText('extension.name.updating');
  };

  const onExtensionNameUpdatedAddLogEntry = function () {
    addSyncLogText('extension.name.updated');
  };

  const onExtensionNameUpdatedErrorAddLogEntry = function (errorCode) {
    addSyncLogText(`extension.names.updated.error: ${errorCode}`);
  };

  const onExtensionNameRemoveAddLogEntry = function () {
    addSyncLogText('extension.name.remove');
  };

  const onExtensionNameRemovedAddLogEntry = function () {
    addSyncLogText('extension.name.removed');
  };

  const onExtensionNamesRemoveErrorAddLogEntry = function (errorCode) {
    addSyncLogText(`extension.name.remove.error: ${errorCode}`);
  };

  const onPostDataSendingAddLogEntry = function () {
    addSyncLogText('post.data.sending');
  };

  const onPostDataSentAddLogEntry = function () {
    addSyncLogText(`post.data.sent, commit version: ${getCommitVersion()}`);
  };

  const onPostDataSentErrorAddLogEntry = function (errorCode) {
    addSyncLogText(`post.data.sent.error: ${errorCode}`);
  };

  const onSyncDataGettingAddLogEntry = function () {
    addSyncLogText('sync.data.getting');
  };

  const onSyncDataReceievedAddLogEntry = function () {
    addSyncLogText(`sync.data.receieved, commit version: ${getCommitVersion()}`);
  };

  const onSyncDataGettingErrorAddLogEntry = function (errorCode) {
    addSyncLogText(`sync.data.getting.error: ${errorCode}`);
  };

  const onSyncDataGettingErrorInitialFailAddLogEntry = function (errorCode) {
    addSyncLogText(`sync.data.getting.error.initial.fail: ${errorCode}`);
  };

  function cleanCustomFilter(filters) {
    // Remove the global pause white-list item if adblock is paused
    if (adblockIsPaused()) {
      let index = filters.indexOf(pausedFilterText1);
      if (index >= 0) {
        filters.splice(index, 1);
      }
      index = filters.indexOf(pausedFilterText2);
      if (index >= 0) {
        filters.splice(index, 1);
      }
    }

    // Remove the domain pause white-list items
    const domainPauses = adblockIsDomainPaused();
    for (const aDomain in domainPauses) {
      const index = filters.indexOf(`@@${aDomain}$document`);
      if (index >= 0) {
        filters.splice(index, 1);
      }
    }
    return filters;
  }

  const processSyncUpdate = function (payload) {
    // do we need a check or comparison of payload.version vs. syncSchemaVersion ?
    if (payload.settings) {
      const keywords = Object.keys(payload.settings);
      // Use a Promise to wait until the previous 'set' is complete because
      // calling 'setSetting' several times in a row in a loop prevents some
      // settings from being saved to storage
      for (let inx = 0, p = Promise.resolve(); inx < keywords.length; inx++) {
        const id = keywords[inx];
        p = p.then(() => new Promise((resolve) => {
          setSetting(id, payload.settings[id], () => {
            resolve();
          });
        }));
      }
    }
    if (payload.subscriptions) {
      const currentSubs = getSubscriptionsMinusText();
      for (const id in currentSubs) {
        const tempId = `url:${currentSubs[id].url}`;
        if (
          !payload.subscriptions[id]
          && !payload.subscriptions[tempId]
          && currentSubs[id].subscribed
          && currentSubs[id].url
        ) {
          const subscription = Subscription.fromURL(currentSubs[id].url);
          setTimeout(() => {
            filterStorage.removeSubscription(subscription);
          }, 1);
        }
      }
      for (const id in payload.subscriptions) {
        if (!currentSubs[id] || !currentSubs[id].subscribed) {
          let url = getUrlFromId(id);
          let subscription = Subscription.fromURL(url);
          if (!url && id.startsWith('url:')) {
            url = id.slice(4);
            subscription = Subscription.fromURL(url);
          }
          filterStorage.addSubscription(subscription);
          synchronizer.execute(subscription);
        }
      }
    }

    if (payload.customFilterRules) {
      // capture, then remove all current custom filters, account for pause filters in
      // current processing
      let currentUserFilters = getUserFilters();
      for (const inx in payload.customFilterRules) {
        const result = parseFilter(payload.customFilterRules[inx]);
        if (result.filter) {
          filterStorage.addFilter(result.filter);
        }
      }
      if (currentUserFilters && currentUserFilters.length) {
        currentUserFilters = cleanCustomFilter(currentUserFilters);
        // Delete / remove filters the user removed...
        if (currentUserFilters) {
          for (let i = 0; (i < currentUserFilters.length); i++) {
            let filter = currentUserFilters[i];
            if (payload.customFilterRules.indexOf(filter) === -1) {
              filter = filter.trim();
              if (filter.length > 0) {
                const result = parseFilter(filter);
                if (result.filter) {
                  filterStorage.removeFilter(result.filter);
                }
              }
            }
          }
        }
      }
    }
    if (payload.prefs) {
      for (const key in payload.prefs) {
        Prefs[key] = payload.prefs[key];
        // add any new Prefs to the array of Preferences we're tracking for sync
        if (abpPrefPropertyNames.indexOf(key) < 0) {
          abpPrefPropertyNames.push(key);
        }
      }
    }
    if (payload.channels) {
      for (const name in payload.channels) {
        const channelId = channels.getIdByName(name);
        if (channelId) {
          channels.setEnabled(channelId, payload.channels[name]);
        } else {
          // create a new channel to save the channel name and the enabled indicator
          channels.add({ name, param: undefined, enabled: payload.channels[name] });
        }
      }
    }
  };

  const process403ErrorCode = function () {
    // eslint-disable-next-line no-use-before-define
    disableSync(false);
  };

  // Retreive or 'get' the sync data from the sync server
  // Input: initialGet:boolean - if true, and the server returns a 404 error code,
  //                             then a 'post' is invoked
  //        disableEmitMsg:boolean - if true, then no sync notifier message will be emitted
  //                                 (usually used for post error processing)
  //        callback:function - function that will be called when success or failure occurs
  //        shouldForce:boolean - optional, force a response from the server (even if the commit
  //                              versions match), defaults to false
  const getSyncData = function (initialGet, disableEmitMsg, callback, shouldForce) {
    const getSuccess = function (text, statusCode) {
      let responseObj = {};
      if (text && typeof text === 'object') {
        responseObj = text;
      } else if (text && typeof text === 'string') {
        try {
          responseObj = JSON.parse(text);
        } catch (e) {
          // eslint-disable-next-line no-console
          console.log('Something went wrong with parsing license data.');
          // eslint-disable-next-line no-console
          console.log('error', e);
          // eslint-disable-next-line no-console
          console.log(text);
          return;
        }
      }
      if (responseObj && ((responseObj.commitVersion > syncCommitVersion) || shouldForce)) {
        if (responseObj.data) {
          try {
            processSyncUpdate(JSON.parse(responseObj.data));
          } catch (e) {
            // eslint-disable-next-line no-console
            console.log('failed to parse response data from server', responseObj.data);
            // eslint-disable-next-line no-console
            console.log(e);
          }
        }
        syncCommitVersion = responseObj.commitVersion;
        chromeStorageSetHelper(syncCommitVersionKey, responseObj.commitVersion);
        chromeStorageSetHelper(syncPreviousDataKey, responseObj.data);
        pendingPostData = false; // reset in case an update is received from another extension
        chromeStorageSetHelper(syncPendingPostDataKey, pendingPostData);
      }
      if (!disableEmitMsg) {
        syncNotifier.emit('sync.data.receieved');
      }
      if (typeof callback === 'function') {
        callback(statusCode);
      }
    };

    const getFailure = function (statusCode, textStatus, errorThrown, responseJSON) {
      lastGetStatusCode = statusCode;
      lastGetErrorResponse = responseJSON;
      if (initialGet && statusCode === 404) {
        // eslint-disable-next-line no-use-before-define
        postDataSync(callback, initialGet);
        // now that the initial post is complete, enable Sync (add listeners, etc.)
        // with 'initialGet' now set to false
        // eslint-disable-next-line no-use-before-define
        enableSync();
        return;
      }
      if (initialGet && !disableEmitMsg) {
        syncNotifier.emit('sync.data.getting.error.initial.fail', statusCode);
      } else if (!disableEmitMsg) {
        syncNotifier.emit('sync.data.getting.error', statusCode, responseJSON);
        if (statusCode === 403) {
          process403ErrorCode();
        }
      }
      if (typeof callback === 'function') {
        callback(statusCode);
      }
    };

    if (!disableEmitMsg) {
      syncNotifier.emit('sync.data.getting');
    }
    lastGetStatusCode = 200;
    lastGetErrorResponse = {};
    // eslint-disable-next-line no-use-before-define
    requestSyncData(getSuccess, getFailure, undefined, shouldForce);
  };

  const getAllExtensionNames = function (callback) {
    syncNotifier.emit('extension.names.downloading');
    $.ajax({
      jsonp: false,
      cache: false,
      headers: {
        'X-GABSYNC-PARAMS': JSON.stringify({
          extensionGUID: STATS.userId(),
          licenseId: License.get().licenseId,
          extInfo: getExtensionInfo(),
        }),
      },
      url: `${License.MAB_CONFIG.syncURL}/devices/list`,
      type: 'GET',
      success(text) {
        let responseObj = {};
        if (typeof text === 'object') {
          responseObj = text;
        } else if (typeof text === 'string') {
          try {
            responseObj = JSON.parse(text);
          } catch (e) {
            // eslint-disable-next-line no-console
            console.log('Something went wrong with parsing license data.');
            // eslint-disable-next-line no-console
            console.log('error', e);
            // eslint-disable-next-line no-console
            console.log(text);
            return;
          }
        }
        syncNotifier.emit('extension.names.downloaded', responseObj);
        if (typeof callback === 'function') {
          callback(responseObj);
        }
      },
      error(xhr) {
        if (xhr.status === 404 && typeof callback === 'function' && xhr.responseText) {
          callback(xhr.responseText);
        }
        syncNotifier.emit('extension.names.downloading.error', xhr.status);
      },
    });
  };

  const setCurrentExtensionName = function (newName) {
    if (newName && newName.trim().length >= 1 && newName.trim().length <= 50) {
      currentExtensionName = newName.trim();
      chromeStorageSetHelper(syncExtensionNameKey, currentExtensionName);
      const thedata = {
        deviceName: currentExtensionName,
        extensionGUID: STATS.userId(),
        licenseId: License.get().licenseId,
        extInfo: getExtensionInfo(),
      };
      syncNotifier.emit('extension.name.updating');
      $.ajax({
        jsonp: false,
        url: `${License.MAB_CONFIG.syncURL}/devices/add`,
        type: 'post',
        success() {
          syncNotifier.emit('extension.name.updated');
        },
        error(xhr) {
          syncNotifier.emit('extension.name.updated.error', xhr.status);
        },
        data: thedata,
      });
    }
  };
  const removeExtensionName = function (extensionName, extensionGUID) {
    const thedata = {
      deviceName: extensionName,
      extensionGUID,
      licenseId: License.get().licenseId,
      extInfo: getExtensionInfo(),
    };
    syncNotifier.emit('extension.name.remove');
    $.ajax({
      jsonp: false,
      url: `${License.MAB_CONFIG.syncURL}/devices/remove`,
      type: 'post',
      success() {
        if (extensionName === currentExtensionName) {
          currentExtensionName = '';
          chromeStorageSetHelper(syncExtensionNameKey, currentExtensionName);
        }
        syncNotifier.emit('extension.name.removed');
      },
      error(xhr) {
        syncNotifier.emit('extension.name.remove.error', xhr.status);
      },
      data: thedata,
    });
  };


  const removeCurrentExtensionName = function () {
    removeExtensionName(currentExtensionName, STATS.userId());
  };

  // return all of the current user configurable extension options (settings, Prefs, filter list
  // sub, custom rules, themes, etc. Since a comparison will be done in this, and other sync'd
  // extensions, the payload should only contain settings, Prefs, etc and not data that can change
  // from browser to brower, version to version, etc.
  const getSyncInformation = function () {
    const payload = {};
    payload.settings = getSettings();
    payload.subscriptions = {};
    const subscriptions = getSubscriptionsMinusText();

    for (const id in subscriptions) {
      if (subscriptions[id].subscribed && subscriptions[id].url) {
        if (sendFilterListByURL.includes(id)) {
          payload.subscriptions[`url:${subscriptions[id].url}`] = subscriptions[id].url;
        } else {
          payload.subscriptions[id] = subscriptions[id].url;
        }
      }
    }
    payload.customFilterRules = cleanCustomFilter(getUserFilters());
    payload.prefs = {};
    for (const inx in abpPrefPropertyNames) {
      const name = abpPrefPropertyNames[inx];
      payload.prefs[name] = Prefs[name];
    }
    payload.channels = {};
    const guide = channels.getGuide();
    for (const id in guide) {
      payload.channels[guide[id].name] = guide[id].enabled;
    }
    return payload;
  };

  const postDataSync = function (callback, initialGet) {
    if (!getSettings().sync_settings) {
      return;
    }
    const payload = getSyncInformation();
    const thedata = {
      data: JSON.stringify(payload),
      commitVersion: syncCommitVersion,
      extensionGUID: STATS.userId(),
      licenseId: License.get().licenseId,
      extInfo: getExtensionInfo(),
    };

    browser.storage.local.get(syncPreviousDataKey).then((response) => {
      const previousData = response[syncPreviousDataKey] || '{}';
      if (objectComparison(payload, JSON.parse(previousData))) {
        return;
      }
      syncNotifier.emit('post.data.sending');
      lastPostStatusCode = 200;
      pendingPostData = false;
      chromeStorageSetHelper(syncPendingPostDataKey, pendingPostData);
      $.ajax({
        jsonp: false,
        url: License.MAB_CONFIG.syncURL,
        type: 'post',
        success(text, status, xhr) {
          lastPostStatusCode = xhr.status;
          let responseObj = {};
          if (typeof text === 'object') {
            responseObj = text;
          } else if (typeof text === 'string') {
            try {
              responseObj = JSON.parse(text);
            } catch (e) {
              // eslint-disable-next-line no-console
              console.log('Something went wrong with parsing license data.');
              // eslint-disable-next-line no-console
              console.log('error', e);
              // eslint-disable-next-line no-console
              console.log(text);
              return;
            }
          }
          if (responseObj && responseObj.commitVersion > syncCommitVersion) {
            syncCommitVersion = text.commitVersion;
            chromeStorageSetHelper(syncCommitVersionKey, responseObj.commitVersion);
          }
          chromeStorageSetHelper(syncPreviousDataKey, thedata.data);
          if (typeof callback === 'function') {
            callback();
          }
          syncNotifier.emit('post.data.sent');
        },
        error(xhr) {
          syncNotifier.emit('post.data.sent.error', xhr.status, initialGet);
          lastPostStatusCode = xhr.status;
          if (xhr.status === 409) {
            // this extension probably had an version of the sync data
            // aka - the sync commit version was behind the sync server
            // so, undo / revert all of the user changes that were just posted
            // by doing a 'GET'
            // because we want the above error to be persisted, will set the
            // 'disableEmitMsg' to true
            getSyncData(false, true);
            return;
          }
          if (xhr.status === 403) {
            process403ErrorCode();
          }
          // all other currently known errors (0, 401, 404, 500).
          pendingPostData = true;
          chromeStorageSetHelper(syncPendingPostDataKey, pendingPostData);
        },
        data: thedata,
      });
    });
  };

  const processUserSyncRequest = function () {
    if (pendingPostData) {
      postDataSync();
    } else {
      getSyncData(false, false, undefined, true);
    }
  };

  const processEventChangeRequest = function () {
    if (pendingPostData) {
      postDataSync();
    } else {
      getSyncData();
    }
  };

  const postDataSyncHandler = debounced(debounceWaitTime, postDataSync);

  // Sync Listeners
  function onFilterAdded(filter, subscription, position, calledPreviously) {
    // a delay is added to allow the domain pause filters time to be saved to storage
    // otherwise the domain pause filter check below would always fail
    if (calledPreviously === undefined) {
      setTimeout(() => {
        onFilterAdded(filter, subscription, position, true);
      }, 500);
      return;
    }
    if (isPauseFilter(filter.text)) {
      return;
    }
    if (isDomainPauseFilter(filter.text)) {
      storedSyncDomainPauses.push(filter.text);
      return;
    }
    postDataSyncHandler();
  }

  function onFilterRemoved(filter) {
    if (isPauseFilter(filter.text)) {
      return;
    }
    if (isDomainPauseFilter(filter.text)) {
      const filterTextIndex = storedSyncDomainPauses.indexOf(filter.text);
      storedSyncDomainPauses = storedSyncDomainPauses.slice(filterTextIndex);
      return;
    }
    postDataSyncHandler();
  }

  // a delay is added to allow the domain pause filters time to be saved to storage
  // otherwise the domain pause filter check below would always fail
  const onFilterListsSubAdded = function (sub, calledPreviously) {
    if (calledPreviously === undefined) {
      setTimeout(() => {
        onFilterListsSubAdded(sub, true);
      }, 500);
      return;
    }
    let containsPauseFilter = false;
    if (sub.url && sub.url.startsWith('~user~') && sub._filterText.length) {
      const arrayLength = sub._filterText.length;
      for (let i = 0; i < arrayLength; i++) {
        const filter = sub._filterText[i];
        containsPauseFilter = isPauseFilter(filter);
        if (!containsPauseFilter && isDomainPauseFilter(filter)) {
          containsPauseFilter = true;
          storedSyncDomainPauses.push(filter.text);
        }
      }
    }
    if (containsPauseFilter) {
      return;
    }
    postDataSyncHandler();
  };

  const onFilterListsSubRemoved = function (sub) {
    let containsPauseFilter = false;
    if (sub.url && sub.url.startsWith('~user~') && sub._filterText.length) {
      const arrayLength = sub._filterText.length;
      for (let i = 0; i < arrayLength; i++) {
        const filter = sub._filterText[i];
        containsPauseFilter = isPauseFilter(filter);
        if (!containsPauseFilter && isDomainPauseFilter(filter.text)) {
          containsPauseFilter = true;
          const filterTextIndex = storedSyncDomainPauses.indexOf(filter.text);
          storedSyncDomainPauses = storedSyncDomainPauses.slice(filterTextIndex);
          return;
        }
      }
    }
    if (containsPauseFilter) {
      return;
    }
    postDataSyncHandler();
  };

  const onSettingsChanged = function (name) {
    if (name === 'sync_settings') {
      return; // don't process any sync setting changes
    }
    postDataSyncHandler();
  };

  const updateNetworkStatus = function () {
    if (navigator.onLine) {
      processEventChangeRequest();
    }
  };

  function processFetchRequest(commitVersion) {
    let fetchCommitVersion = commitVersion;
    if (!fetchCommitVersion) {
      return;
    }
    if (typeof fetchCommitVersion === 'string') {
      fetchCommitVersion = Number.parseInt(fetchCommitVersion, 10);
    }
    if (fetchCommitVersion === syncCommitVersion) {
      return;
    }
    getSyncData();
  }

  function enablePubNub() {
    pubnub = new PubNub({
      subscribeKey: License.MAB_CONFIG.subscribeKey,
      authKey: `${License.get().licenseId}_${STATS.userId()}`,
      ssl: true,
    });

    pubnub.addListener({
      message(response) {
        if (response.message && response.message && response.message.commitVersion) {
          processFetchRequest(response.message.commitVersion);
        }
      },
      status(msg) {
        if (msg.category === 'PNNetworkUpCategory') {
          pubnub.subscribe({
            channels: [License.get().licenseId],
          });
        }
        if (msg.error === true && msg.category && msg.operation) {
          recordGeneralMessage('pubnub_error', undefined, { licenseId: License.get().licenseId, category: msg.category, operation: msg.operation });
        }
      },
    });

    pubnub.subscribe({
      channels: [License.get().licenseId],
    });
  }

  const enableSync = function (initialGet) {
    setSetting('sync_settings', true);
    const addListeners = function () {
      syncNotifier.on('sync.data.getting.error', onSyncDataGettingErrorAddLogEntry);
      syncNotifier.on('sync.data.getting.error.initial.fail', onSyncDataGettingErrorInitialFailAddLogEntry);
      syncNotifier.on('extension.names.downloading', onExtensionNamesDownloadingAddLogEntry);
      syncNotifier.on('sync.data.receieved', onSyncDataReceievedAddLogEntry);
      syncNotifier.on('sync.data.getting', onSyncDataGettingAddLogEntry);
      syncNotifier.on('post.data.sent.error', onPostDataSentErrorAddLogEntry);
      syncNotifier.on('post.data.sending', onPostDataSendingAddLogEntry);
      syncNotifier.on('post.data.sent', onPostDataSentAddLogEntry);
      syncNotifier.on('extension.name.remove.error', onExtensionNamesRemoveErrorAddLogEntry);
      syncNotifier.on('extension.name.removed', onExtensionNameRemovedAddLogEntry);
      syncNotifier.on('extension.name.remove', onExtensionNameRemoveAddLogEntry);
      syncNotifier.on('extension.name.updated.error', onExtensionNameUpdatedErrorAddLogEntry);
      syncNotifier.on('extension.name.updated', onExtensionNameUpdatedAddLogEntry);
      syncNotifier.on('extension.name.updating', onExtensionNameUpdatingAddLogEntry);
      syncNotifier.on('extension.names.downloaded', onExtensionNamesDownloadedAddLogEntry);
      syncNotifier.on('extension.names.downloading.error', onExtensionNamesDownloadingErrorAddLogEntry);

      filterNotifier.on('subscription.removed', onFilterListsSubRemoved);
      filterNotifier.on('subscription.added', onFilterListsSubAdded);

      filterNotifier.on('filter.added', onFilterAdded);
      filterNotifier.on('filter.removed', onFilterRemoved);

      settingsNotifier.on('settings.changed', onSettingsChanged);
      channelsNotifier.on('channels.changed', postDataSyncHandler);

      for (const inx in abpPrefPropertyNames) {
        const name = abpPrefPropertyNames[inx];
        Prefs.on(name, postDataSyncHandler);
      }
      // wait a moment at start to allow all of the backgound scripts to load
      setTimeout(() => {
        enablePubNub();
      }, 1000);

      window.addEventListener('online', updateNetworkStatus);
      window.addEventListener('offline', updateNetworkStatus);
    };

    if (initialGet) {
      SyncService.getSyncData(initialGet, false, (response) => {
        if (response === 200 || response === 304) {
          addListeners();
        }
      });
      return;
    }

    addListeners();
  };

  function disablePubNub() {
    if (!pubnub) {
      return;
    }

    pubnub.removeAllListeners();
    pubnub.unsubscribeAll();
    pubnub = undefined;
  }

  const disableSync = function (removeName) {
    setSetting('sync_settings', false);
    syncCommitVersion = 0;
    disablePubNub();

    filterNotifier.off('subscription.added', onFilterListsSubAdded);
    filterNotifier.off('subscription.removed', onFilterListsSubRemoved);

    filterNotifier.off('filter.added', onFilterAdded);
    filterNotifier.off('filter.removed', onFilterRemoved);

    settingsNotifier.off('settings.changed', onSettingsChanged);
    channelsNotifier.off('channels.changed', postDataSyncHandler);

    for (const inx in abpPrefPropertyNames) {
      const name = abpPrefPropertyNames[inx];
      Prefs.off(name, postDataSyncHandler);
    }

    storedSyncDomainPauses = [];
    if (removeName) {
      removeCurrentExtensionName();

      currentExtensionName = '';
      chromeStorageSetHelper(syncExtensionNameKey, currentExtensionName);
    }

    syncNotifier.off('sync.data.getting.error', onSyncDataGettingErrorAddLogEntry);
    syncNotifier.off('sync.data.getting.error.initial.fail', onSyncDataGettingErrorInitialFailAddLogEntry);
    syncNotifier.off('extension.names.downloading', onExtensionNamesDownloadingAddLogEntry);
    syncNotifier.off('sync.data.receieved', onSyncDataReceievedAddLogEntry);
    syncNotifier.off('sync.data.getting', onSyncDataGettingAddLogEntry);
    syncNotifier.off('post.data.sent.error', onPostDataSentErrorAddLogEntry);
    syncNotifier.off('post.data.sending', onPostDataSendingAddLogEntry);
    syncNotifier.off('post.data.sent', onPostDataSentAddLogEntry);
    syncNotifier.off('extension.name.remove.error', onExtensionNamesRemoveErrorAddLogEntry);
    syncNotifier.off('extension.name.removed', onExtensionNameRemovedAddLogEntry);
    syncNotifier.off('extension.name.remove', onExtensionNameRemoveAddLogEntry);
    syncNotifier.off('extension.name.updated.error', onExtensionNameUpdatedErrorAddLogEntry);
    syncNotifier.off('extension.name.updated', onExtensionNameUpdatedAddLogEntry);
    syncNotifier.off('extension.name.updating', onExtensionNameUpdatingAddLogEntry);
    syncNotifier.off('extension.names.downloaded', onExtensionNamesDownloadedAddLogEntry);
    syncNotifier.off('extension.names.downloading.error', onExtensionNamesDownloadingErrorAddLogEntry);

    window.removeEventListener('online', updateNetworkStatus);
    window.removeEventListener('offline', updateNetworkStatus);
  };

  // Retreive the sync data from the sync server
  // Input: successCallback:function - function that will be called when success occurs, the
  //                                   callback will be provided the response data
  //        errorCallback:function - function that will be called when  failure occurs, the
  //                                 callback will be provided the error code
  //        totalAttempts:integer - the number of 'get' attempts made (only used internally by
  //                               the retry logic)
  //        shouldForce:boolean - optional, force a response from the server (even if the commit
  //                              versions match), defaults to false
  const requestSyncData = function (successCallback, errorCallback, totalAttempts, shouldForce) {
    let attemptCount = totalAttempts;
    if (!attemptCount) {
      attemptCount = 1;
    } else {
      attemptCount += 1;
    }
    const forceParam = shouldForce || false;

    $.ajax({
      jsonp: false,
      cache: false,
      headers: {
        'X-GABSYNC-PARAMS': JSON.stringify({
          extensionGUID: STATS.userId(),
          licenseId: License.get().licenseId,
          commitVersion: syncCommitVersion,
          force: forceParam,
          extInfo: getExtensionInfo(),
        }),
      },
      url: License.MAB_CONFIG.syncURL,
      type: 'GET',
      success(text, textStatus, xhr) {
        if (typeof successCallback === 'function') {
          successCallback(text, xhr.status);
        }
      },
      error(xhr, textStatus, errorThrown) {
        if ((xhr.status !== 404 || xhr.status !== 403) && attemptCount < 3) {
          setTimeout(() => {
            requestSyncData(successCallback, errorCallback, attemptCount, shouldForce);
          }, 1000); // wait 1 second for retry
          return;
        }
        if (typeof errorCallback === 'function') {
          errorCallback(xhr.status, textStatus, errorThrown, xhr.responseJSON);
        }
      },
    });
  };

  settings.onload().then(() => {
    License.ready().then(() => {
      if (getSettings().sync_settings) {
        browser.storage.local.get(syncCommitVersionKey).then((response) => {
          syncCommitVersion = response[syncCommitVersionKey] || 0;
          browser.storage.local.get(syncPendingPostDataKey).then((postDataResponse) => {
            pendingPostData = postDataResponse[syncPendingPostDataKey] || false;
            processEventChangeRequest();
            enableSync();
          });
        });
      }

      browser.storage.local.get(syncExtensionNameKey).then((response) => {
        currentExtensionName = response[syncExtensionNameKey] || '';
      });

      browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.command === 'resetLastGetStatusCode') {
          resetLastGetStatusCode();
          sendResponse({});
        }
      });

      browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.command === 'resetLastGetErrorResponse') {
          resetLastGetErrorResponse();
          sendResponse({});
        }
      });

      browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.command === 'resetLastPostStatusCode') {
          resetLastPostStatusCode();
          sendResponse({});
        }
      });

      browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
        if (request.command === 'resetAllSyncErrors') {
          resetAllErrors();
          sendResponse({});
        }
      });
    });
  });

  return {
    enableSync,
    disableSync,
    getSyncData,
    processFetchRequest,
    getCurrentExtensionName,
    getAllExtensionNames,
    setCurrentExtensionName,
    removeCurrentExtensionName,
    removeExtensionName,
    syncNotifier,
    getCommitVersion,
    setCommitVersion,
    getLastPostStatusCode,
    resetLastPostStatusCode,
    setLastPostStatusCode,
    getLastGetStatusCode,
    resetLastGetStatusCode,
    setLastGetStatusCode,
    getLastGetErrorResponse,
    resetLastGetErrorResponse,
    setLastGetErrorResponse,
    resetAllErrors,
    getSyncLog,
    deleteSyncLog,
    processUserSyncRequest,
    processEventChangeRequest,
  };
}());

exports.SyncService = SyncService;


/***/ }),
/* 43 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setUninstallURL", function() { return setUninstallURL; });
/* harmony import */ var filterStorage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3);
/* harmony import */ var filterStorage__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(filterStorage__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _stats__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(33);
/* harmony import */ var _stats__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_stats__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var prefs_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5);
/** @module uninstall */
/** similar to adblockpluschrome\lib\uninstall.js */





function setUninstallURL() {
  if (browser.runtime.setUninstallURL) {
    _stats__WEBPACK_IMPORTED_MODULE_1__["STATS"].untilLoaded(function(userID) {
      let uninstallURL = "https://getadblock.com/uninstall/?u=" + userID;
      // if the start property of blockCount exists (which is the AdBlock
      // installation timestamp)
      // use it to calculate the approximate length of time that user has
      // AdBlock installed
      if (prefs_js__WEBPACK_IMPORTED_MODULE_2__["Prefs"] && prefs_js__WEBPACK_IMPORTED_MODULE_2__["Prefs"].blocked_total !== undefined) {
        let twoMinutes = 2 * 60 * 1000;
        let getABCLastUpdateTime = function() {
          for (let subscription of filterStorage__WEBPACK_IMPORTED_MODULE_0__["filterStorage"].subscriptions()) {
            if (subscription.url === getUrlFromId("adblock_custom")) {
              return subscription._lastDownload;
            }
          }
          return null;
        };
        let updateUninstallURL = function() {
          browser.storage.local.get("blockage_stats").then(data => {
            let url = uninstallURL;
            if (data && data.blockage_stats && data.blockage_stats.start) {
              let installedDuration = Date.now() - data.blockage_stats.start;
              url = url + "&t=" + installedDuration;
            }
            let bc = prefs_js__WEBPACK_IMPORTED_MODULE_2__["Prefs"].blocked_total;
            url = url + "&bc=" + bc;
            let lastUpdateTime = getABCLastUpdateTime();
            if (lastUpdateTime !== null) {
              url = url + "&abc-lt=" + lastUpdateTime;
            } else {
              url = url + "&abc-lt=-1";
            }
            browser.runtime.setUninstallURL(url);
          });
        };
        // start an interval timer that will update the Uninstall URL every 2
        // minutes
        setInterval(updateUninstallURL, twoMinutes);
        updateUninstallURL();
      } else {
        browser.runtime.setUninstallURL(uninstallURL + "&t=-1");
      }
    }); // end of STATS.then
  }
};



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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, exports, parseFilter, chromeStorageSetHelper */

// Module for removing individual filters from filter lists
// An 'advance' feature, used on the Customize tab, titled "disabled filters"

const { filterNotifier } = __webpack_require__(4);
const { filterStorage } = __webpack_require__(3);

const ExcludeFilter = (function excludeFilter() {
  const ABRemoveFilter = function (filter) {
    for (const currentSubscription of filterStorage.subscriptions()) {
      const positions = [];
      let index = -1;
      do {
        index = currentSubscription.findFilterIndex(filter, index + 1);
        if (index >= 0) {
          positions.push(index);
        }
      } while (index >= 0);

      for (let j = positions.length - 1; j >= 0; j--) {
        const currentPosition = positions[j];
        const currentFilter = currentSubscription.filterTextAt(currentPosition);
        if (currentFilter === filter.text) {
          currentSubscription.deleteFilterAt(currentPosition);
          filterNotifier.emit('filter.removed', filter, currentSubscription,
            currentPosition);
        }
      }
    }


    for (const subscription of filterStorage.subscriptions()) {
      const positions = [];
      let index = -1;
      do {
        index = subscription._filterText.indexOf(filter, index + 1);
        if (index >= 0) {
          positions.push(index);
        }
      }
      while (index >= 0);

      for (let j = positions.length - 1; j >= 0; j--) {
        const position = positions[j];
        if (subscription._filterText[position] === filter) {
          subscription._filterText.splice(position, 1);
          if (subscription._filterText.indexOf(filter) < 0) {
            index = filter._subscriptions.indexOf(subscription);
            if (index >= 0) {
              filter._subscriptions.splice(index, 1);
            }
          }
          filterNotifier.emit('filter.removed', filter, subscription, position);
        }
      }
    }
  };

  // Removes the valid filters from any / all filter lists and
  // saves the valid entries
  // Note:  any invalid filters are ignored
  // Inputs: filters:string the new filters.
  const setExcludeFilters = function (filtersToExclude) {
    const excludeFilters = filtersToExclude.trim();
    const excludeFiltersArray = excludeFilters.split('\n');
    const validExcludeFiltersArray = [];
    for (let i = 0; i < excludeFiltersArray.length; i++) {
      let filter = excludeFiltersArray[i];
      filter = filter.trim();
      if (filter.length > 0) {
        const result = parseFilter(filter);
        if (result.filter) {
          validExcludeFiltersArray.push(result.filter);
          ABRemoveFilter(result.filter);
        }
      }
    }

    if (validExcludeFiltersArray.length > 0) {
      chromeStorageSetHelper('exclude_filters', validExcludeFiltersArray.join('\n'));
    } else {
      browser.storage.local.remove('exclude_filters');
    }
  };

  function excludeFilterChangeListener() {
    const excludeFiltersKey = 'exclude_filters';
    browser.storage.local.get(excludeFiltersKey).then((response) => {
      if (response[excludeFiltersKey]) {
        const excludeFiltersArray = response[excludeFiltersKey].split('\n');
        for (let i = 0; i < excludeFiltersArray.length; i++) {
          const filter = excludeFiltersArray[i];
          if (filter.length > 0) {
            const result = parseFilter(filter);
            if (result.filter) {
              ABRemoveFilter(result.filter);
            }
          }
        }
      } else {
        filterNotifier.off('save', excludeFilterChangeListener);
      }
    });
  }

  // At startup, add a listener to so that the exclude filters
  // can be removed if the filter lists are updated
  filterNotifier.on('save', excludeFilterChangeListener);

  return {
    setExcludeFilters,
  };
}());

exports.ExcludeFilter = ExcludeFilter;


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global exports:true */

// Used by both channels.js and picreplacement.js
// Since this file is conditional loaded, and not part of the content script web pack,
// 'exports' may not be defined, so we use this hack
if (false) {}

const imageSizesMap = new Map([
  ['NONE', 0],
  ['wide', 1],
  ['tall', 2],
  ['skinnywide', 4],
  ['skinnytall', 8],
  ['big', 16],
  ['small', 32],
]);

exports.imageSizesMap = imageSizesMap;
exports.WIDE = imageSizesMap.get('wide');
exports.TALL = imageSizesMap.get('tall');
exports.BIG = imageSizesMap.get('big');
exports.SMALL = imageSizesMap.get('small');
exports.SKINNYWIDE = imageSizesMap.get('skinnywide');
exports.SKINNYTALL = imageSizesMap.get('skinnytall');


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview This is a specialized RSA library meant only to
 * verify SHA1-based signatures.
 */

const {BigInteger} = __webpack_require__(59);
const Rusha = __webpack_require__(60);

let rusha = new Rusha();

// Define ASN.1 templates for the data structures used
function seq(...args)
{
  return {type: 0x30, children: args};
}
function obj(id)
{
  return {type: 0x06, content: id};
}
function bitStr(contents)
{
  return {type: 0x03, encapsulates: contents};
}
function intResult(id)
{
  return {type: 0x02, out: id};
}
function octetResult(id)
{
  return {type: 0x04, out: id};
}

// See http://www.cryptopp.com/wiki/Keys_and_Formats#RSA_PublicKey
// 2A 86 48 86 F7 0D 01 01 01 means 1.2.840.113549.1.1.1
let publicKeyTemplate = seq(
  seq(obj("\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01"), {}),
  bitStr(seq(intResult("n"), intResult("e")))
);

// See http://tools.ietf.org/html/rfc3447#section-9.2 step 2
// 2B 0E 03 02 1A means 1.3.14.3.2.26
let signatureTemplate = seq(
  seq(obj("\x2B\x0E\x03\x02\x1A"), {}),
  octetResult("sha1")
);

/**
 * Reads ASN.1 data matching the template passed in. This will throw an
 * exception if the data format doesn't match the template. On success an
 * object containing result properties is returned.
 * @see http://luca.ntop.org/Teaching/Appunti/asn1.html for info on the format.
 * @param {string} data
 * @param {Object} templ
 * @returns {Object}
 */
function readASN1(data, templ)
{
  let pos = 0;
  function next()
  {
    return data.charCodeAt(pos++);
  }

  function readLength()
  {
    let len = next();
    if (len & 0x80)
    {
      let cnt = len & 0x7F;
      if (cnt > 2 || cnt == 0)
        throw "Unsupported length";

      len = 0;
      for (let i = 0; i < cnt; i++)
        len += next() << (cnt - 1 - i) * 8;
      return len;
    }
    return len;
  }

  function readNode(curTempl)
  {
    let type = next();
    let len = readLength();
    if ("type" in curTempl && curTempl.type != type)
      throw "Unexpected type";
    if ("content" in curTempl &&
        curTempl.content != data.substring(pos, pos + len))
      throw "Unexpected content";
    if ("out" in curTempl)
      out[curTempl.out] = new BigInteger(data.substring(pos, pos + len), 256);
    if ("children" in curTempl)
    {
      let i;
      let end;
      for (i = 0, end = pos + len; pos < end; i++)
      {
        if (i >= curTempl.children.length)
          throw "Too many children";
        readNode(curTempl.children[i]);
      }
      if (i < curTempl.children.length)
        throw "Too few children";
      if (pos > end)
        throw "Children too large";
    }
    else if ("encapsulates" in curTempl)
    {
      if (next() != 0)
        throw "Encapsulation expected";
      readNode(curTempl.encapsulates);
    }
    else
    {
      pos += len;
    }
  }

  let out = {};
  readNode(templ);
  if (pos != data.length)
    throw "Too much data";
  return out;
}

/**
 * Reads a BER-encoded RSA public key. On success returns an object with the
 * properties n and e (the components of the key), otherwise null.
 * @param {string} key
 * @return {?Object}
 */
function readPublicKey(key)
{
  try
  {
    return readASN1(atob(key), publicKeyTemplate);
  }
  catch (e)
  {
    console.warn("Invalid RSA public key: " + e);
    return null;
  }
}

/**
 * Checks whether the signature is valid for the given public key and data.
 * @param {string} key
 * @param {string} signature
 * @param {string} data
 * @returns {boolean}
 */
exports.verifySignature = function verifySignature(key, signature, data)
{
  let keyData = readPublicKey(key);
  if (!keyData)
    return false;

  // We need the exponent as regular number
  keyData.e = parseInt(keyData.e.toString(16), 16);

  // Decrypt signature data using RSA algorithm
  let sigInt = new BigInteger(atob(signature), 256);
  let digest = sigInt.modPowInt(keyData.e, keyData.n).toString(256);

  try
  {
    let pos = 0;
    let next = () => digest.charCodeAt(pos++);

    // Skip padding, see http://tools.ietf.org/html/rfc3447#section-9.2 step 5
    if (next() != 1)
      throw "Wrong padding in signature digest";
    while (next() == 255) {}
    if (digest.charCodeAt(pos - 1) != 0)
      throw "Wrong padding in signature digest";

    // Rest is an ASN.1 structure, get the SHA1 hash from it and compare to
    // the real one
    let {sha1} = readASN1(digest.substring(pos), signatureTemplate);
    let expected = new BigInteger(rusha.digest(data), 16);
    return (sha1.compareTo(expected) == 0);
  }
  catch (e)
  {
    console.warn("Invalid encrypted signature: " + e);
    return false;
  }
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



__webpack_require__(78);
const {parseURL} = __webpack_require__(9);
const {Filter} = __webpack_require__(0);
const {defaultMatcher} = __webpack_require__(10);
const {elemHide} = __webpack_require__(26);
const {elemHideEmulation} = __webpack_require__(28);
const {elemHideExceptions} = __webpack_require__(27);
const {snippets} = __webpack_require__(39);
const {profiler} = __webpack_require__(36);

/**
 * Selects the appropriate module for the given filter type.
 *
 * @param {string} type The type of a filter. This must be one of
 *   `"blocking"`, `"allowing"`, `"elemhide"`, `"elemhideemulation"`,
 *   `"elemhideexception"`, and `"snippet"`; otherwise the function returns
 *   `null`.
 *
 * @returns {?object} The appropriate module for the given filter type.
 */
function selectModule(type)
{
  switch (type)
  {
    case "blocking":
    case "allowing":
      return defaultMatcher;
    case "elemhide":
      return elemHide;
    case "elemhideemulation":
      return elemHideEmulation;
    case "elemhideexception":
      return elemHideExceptions;
    case "snippet":
      return snippets;
  }

  return null;
}

/**
 * `{@link module:filterEngine.filterEngine filterEngine}` implementation.
 */
class FilterEngine
{
  /**
   * Creates the `{@link module:filterEngine.filterEngine filterEngine}`
   * object.
   * @private
   */
  constructor()
  {
    this.p = profiler("FilterEngine");
    this.p.start();
    /**
     * The promise returned by
     * `{@link module:filterEngine~FilterEngine#initialize}`.
     * @type {?Promise}
     * @private
     */
    this._initializationPromise = null;
  }

  /**
   * Initializes the `{@link module:filterEngine.filterEngine filterEngine}`
   * object with the given filters or filters loaded from disk.
   *
   * @param {Iterable.<string>} [filterSource] An iterable object that yields
   *   the text of the filters with which to initialize the
   *   `{@link module:filterEngine.filterEngine filterEngine}` object. If
   *   omitted, filters are loaded from disk.
   *
   * @returns {Promise} A promise that is fulfilled when the initialization is
   *   complete.
   *
   * @public
   */
  initialize(filterSource)
  {
    this.p.mark("initialize");
    if (!this._initializationPromise)
    {
      if (typeof filterSource == "undefined")
      {
        // Note: filterListener.js must be loaded conditionally here in local
        // scope in order for the engine to be able to work in standalone mode
        // with no disk and network I/O.
        const {filterListener} = __webpack_require__(79);
        this._initializationPromise = filterListener.initialize(this);
      }
      else
      {
        this._initializationPromise = Promise.resolve().then(() =>
        {
          for (let text of filterSource)
            this.add(Filter.fromText(Filter.normalize(text)));
        }).finally(() =>
        {
          this.p.mark("download_done");
        });
      }
    }

    return this._initializationPromise;
  }

  /**
   * Adds a new filter.
   * @param {module:filterClasses.ActiveFilter} filter
   * @package
   */
  add(filter)
  {
    let module = selectModule(filter.type);
    if (module)
      module.add(filter);
  }

  /**
   * Removes an existing filter.
   * @param {module:filterClasses.ActiveFilter} filter
   * @package
   */
  remove(filter)
  {
    let module = selectModule(filter.type);
    if (module)
      module.remove(filter);
  }

  /**
   * Checks whether a filter exists.
   * @param {module:filterClasses.ActiveFilter} filter
   * @returns {boolean}
   * @package
   */
  has(filter)
  {
    let module = selectModule(filter.type);
    if (module)
      return module.has(filter);
    return false;
  }

  /**
   * Clears all filters.
   * @package
   */
  clear()
  {
    defaultMatcher.clear();
    elemHide.clear();
    elemHideEmulation.clear();
    elemHideExceptions.clear();
    snippets.clear();
  }

  /**
   * Matches existing URL filters against a web resource
   * (HTML document, CSS style sheet, PNG image, etc.) and returns the matching
   * filter if there's a match.
   *
   * @param {string|URL|module:url~URLInfo} url The URL of the resource.
   * @param {number} typeMask The
   *   {@link module:contentTypes.contentTypes content types} associated with
   *   the resource.
   * @param {string} documentHostname The hostname of the document of the
   *   resource.
   * @param {?string} [sitekey] An optional public key associated with the
   *   document of the resource.
   * @param {boolean} [specificOnly] Whether to ignore any generic filters.
   *
   * @returns {?string} A URL filter if there's a match; otherwise `null`.
   *
   * @public
   */
  match(url, typeMask, documentHostname, sitekey = null, specificOnly = false)
  {
    if (typeof url == "string")
      url = parseURL(url);

    let filter = defaultMatcher.match(url, typeMask, documentHostname, sitekey,
                                      specificOnly);
    return filter ? filter.text : null;
  }
}

/**
 * The `filterEngine` object maintains filters for request blocking, element
 * hiding, and snippets.
 *
 * @type {module:filterEngine~FilterEngine}
 *
 * @public
 *
 * @example
 *
 * let {contentTypes, filterEngine} = require("adblockpluscore");
 *
 * await filterEngine.initialize(
 *   [
 *     "/annoying-ad^$image",
 *     "||example.com/social-widget.html^"
 *   ]
 * );
 *
 * let resource = {
 *   url: "https://ad-server.example.net/annoying-ad.png",
 *   documentURL: "https://news.example.com/world.html"
 * };
 *
 * let filter = filterEngine.match(resource.url, contentTypes.IMAGE,
 *                                 new URL(resource.documentURL).hostname);
 * console.log(filter); // prints "/annoying-ad^$image"
 */
exports.filterEngine = new FilterEngine();


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

"use strict";
/** @module notificationHelper */
/* For ESLint: List any global identifiers used in this file below */
/* global browser */

/** original file adblockpluschrome\lib\notificationHelper.js
 * except:
 * Most of the logic has been removed to prevent users from seeing notifications
 * Only exported functions remain, which are no-op
 *
 */



/**
 * Initializes the notification system.
 *
 * @param {bool} firstRun
 */
 exports.initNotifications = firstRun =>
 {

 };

 let isOptional =
 /**
  * If the given notification type is of vital importance return false,
  * true otherwise.
  *
  * @param {string} notificationType
  * @return {boolean}
  */
 exports.isOptional = notificationType =>
 {
   return true;
 };


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

"use strict";


// ref: https://github.com/tc39/proposal-global
var getGlobal = function () {
	// the only reliable means to get the global object is
	// `Function('return this')()`
	// However, this causes CSP violations in Chrome apps.
	if (typeof self !== 'undefined') { return self; }
	if (typeof window !== 'undefined') { return window; }
	if (typeof global !== 'undefined') { return global; }
	throw new Error('unable to locate global object');
}

var global = getGlobal();

module.exports = exports = global.fetch;

// Needed for TypeScript and Webpack.
if (global.fetch) {
	exports.default = global.fetch.bind(global);
}

exports.Headers = global.Headers;
exports.Request = global.Request;
exports.Response = global.Response;

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

__webpack_require__(51);
__webpack_require__(61);
__webpack_require__(32);
__webpack_require__(62);
__webpack_require__(16);
__webpack_require__(63);
__webpack_require__(38);
__webpack_require__(64);
__webpack_require__(106);
__webpack_require__(29);
__webpack_require__(66);
__webpack_require__(67);
__webpack_require__(30);
__webpack_require__(69);
__webpack_require__(70);
__webpack_require__(71);
__webpack_require__(76);
__webpack_require__(77);
__webpack_require__(21);
__webpack_require__(44);
__webpack_require__(45);
__webpack_require__(80);
__webpack_require__(81);
__webpack_require__(83);
__webpack_require__(85);
__webpack_require__(87);
__webpack_require__(88);
__webpack_require__(90);
__webpack_require__(92);
__webpack_require__(94);
__webpack_require__(96);
__webpack_require__(97);
__webpack_require__(42);
__webpack_require__(98);
__webpack_require__(99);
__webpack_require__(100);
__webpack_require__(101);
__webpack_require__(102);
__webpack_require__(103);
module.exports = __webpack_require__(104);


/***/ }),
/* 51 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
/* harmony import */ var _adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
/* harmony import */ var _adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
/* harmony import */ var _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10);
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4);
/* harmony import */ var _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _messaging_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(1);
/* harmony import */ var _hitLogger_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(11);
/* harmony import */ var info__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(7);
/* harmony import */ var _adblockpluscore_lib_versions_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(31);
/* harmony import */ var _adblockpluscore_lib_versions_js__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_versions_js__WEBPACK_IMPORTED_MODULE_10__);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module devtools */













let panels = new Map();

function getFilterInfo(filter)
{
  if (!filter)
    return null;

  let userDefined = false;
  let subscriptionTitle = null;

  for (let subscription of _adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_4__["filterStorage"].subscriptions(filter.text))
  {
    if (!subscription.disabled)
    {
      if (subscription instanceof _adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_1__["SpecialSubscription"])
        userDefined = true;
      else
        subscriptionTitle = subscription.title;
    }
  }

  return {
    text: filter.text,
    whitelisted: filter instanceof _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["AllowingFilter"] ||
                 filter instanceof _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_0__["ElemHideException"],
    userDefined,
    subscription: subscriptionTitle
  };
}

function hasRecord(request, filter, record)
{
  return record.request.url == request.url &&
    record.request.docDomain == request.docDomain &&

    // Ignore partial (e.g. ELEMHIDE) allowlisting if there is already
    // a DOCUMENT exception which disables all means of blocking.
    (record.request.type == "DOCUMENT" ?
       _hitLogger_js__WEBPACK_IMPORTED_MODULE_8__["nonRequestTypes"].includes(request.type) :
       record.request.type == request.type) &&

    // Matched element hiding filters don't relate to a particular request,
    // so we have to compare the selector in order to avoid duplicates.
    (record.filter && record.filter.selector) == (filter && filter.selector) &&

    // We apply multiple CSP filters to a document, but we must still remove
    // any duplicates. Two CSP filters are duplicates if both have identical
    // text.
    (record.filter && record.filter.csp && record.filter.text) ==
    (filter && filter.csp && filter.text);
}

function addRecord(panel, request, filter)
{
  let matchesAny = false;

  for (let i = 0; i < panel.records.length; i++)
  {
    let record = panel.records[i];

    let matches = hasRecord(request, filter, record);
    if (!matches)
      continue;

    matchesAny = true;

    // Update record without filters, if filter matches on later checks
    if (!filter)
      break;

    if (record.filter)
      continue;

    record.filter = filter;

    panel.port.postMessage({
      type: "update-record",
      initialize: true,
      index: i,
      request: record.request,
      filter: getFilterInfo(record.filter)
    });
  }

  if (matchesAny)
    return;

  panel.port.postMessage({
    type: "add-record",
    request,
    filter: getFilterInfo(filter)
  });

  panel.records.push({request, filter});
}

function matchRequest(request)
{
  return _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_5__["defaultMatcher"].match(
    Object(_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__["parseURL"])(request.url),
    _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"][request.type],
    request.docDomain,
    request.sitekey,
    request.specificOnly
  );
}

function onBeforeRequest(details)
{
  let panel = panels.get(details.tabId);

  // Clear the devtools panel and reload the inspected tab without caching
  // when a new request is issued. However, make sure that we don't end up
  // in an infinite recursion if we already triggered a reload.
  if (panel.reloading)
  {
    panel.reloading = false;
  }
  else
  {
    panel.records = [];
    panel.port.postMessage({type: "reset"});

    // We can't repeat the request if it isn't a GET request. Chrome would
    // prompt the user to confirm reloading the page, and POST requests are
    // known to cause issues on many websites if repeated.
    if (details.method == "GET")
      panel.reload = true;
  }
}

function onLoading(page)
{
  let tabId = page.id;
  let panel = panels.get(tabId);

  // Reloading the tab is the only way that allows bypassing all caches, in
  // order to see all requests in the devtools panel. Reloading must not be
  // performed before the tab changes to "loading", otherwise it will load the
  // previous URL.
  if (panel && panel.reload)
  {
    browser.tabs.reload(tabId, {bypassCache: true});

    panel.reload = false;
    panel.reloading = true;
  }
}

function updateFilters(subscription, filters, added)
{
  let includes = subscription ?
    filter => filter && subscription.findFilterIndex(filter) != -1 :
    filters.includes.bind(filters);

  for (let panel of panels.values())
  {
    for (let i = 0; i < panel.records.length; i++)
    {
      let record = panel.records[i];

      // If an added filter matches a request shown in the devtools panel,
      // update that record to show the new filter. Ignore filters that aren't
      // associated with any sub-resource request. There is no record for these
      // if they don't already match. In particular, in case of element hiding
      // filters, we also wouldn't know if any new element matches.
      if (added)
      {
        if (_hitLogger_js__WEBPACK_IMPORTED_MODULE_8__["nonRequestTypes"].includes(record.request.type))
          continue;

        let filter = matchRequest(record.request);

        if (!includes(filter))
          continue;

        record.filter = filter;
      }

      // If a filter shown in the devtools panel got removed, update that
      // record to show the filter that matches now, or none, instead.
      // For filters that aren't associated with any sub-resource request,
      // just remove the record. We wouldn't know whether another filter
      // matches instead until the page is reloaded.
      else
      {
        if (!includes(record.filter))
          continue;

        if (_hitLogger_js__WEBPACK_IMPORTED_MODULE_8__["nonRequestTypes"].includes(record.request.type))
        {
          panel.port.postMessage({
            type: "remove-record",
            index: i
          });
          panel.records.splice(i--, 1);
          continue;
        }

        record.filter = matchRequest(record.request);
      }

      panel.port.postMessage({
        type: "update-record",
        index: i,
        request: record.request,
        filter: getFilterInfo(record.filter)
      });
    }
  }
}

function onFilterAdded(filter)
{
  updateFilters(null, [filter], true);
}

function onFilterRemoved(filter)
{
  updateFilters(null, [filter], false);
}

function onSubscriptionAdded(subscription)
{
  if (subscription instanceof _adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_1__["SpecialSubscription"])
    updateFilters(subscription, null, true);
}

browser.runtime.onConnect.addListener(newPort =>
{
  let match = newPort.name.match(/^devtools-(\d+)$/);
  if (!match)
    return;

  let inspectedTabId = parseInt(match[1], 10);
  let localOnBeforeRequest = onBeforeRequest.bind();
  let panel = {port: newPort, records: []};
  let hitListener = addRecord.bind(null, panel);

  browser.webRequest.onBeforeRequest.addListener(
    localOnBeforeRequest,
    {
      urls: ["http://*/*", "https://*/*"],
      types: ["main_frame"],
      tabId: inspectedTabId
    }
  );

  if (panels.size == 0)
  {
    ext.pages.onLoading.addListener(onLoading);
    _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__["filterNotifier"].on("filter.added", onFilterAdded);
    _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__["filterNotifier"].on("filter.removed", onFilterRemoved);
    _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__["filterNotifier"].on("subscription.added", onSubscriptionAdded);
  }

  newPort.onDisconnect.addListener(() =>
  {
    _hitLogger_js__WEBPACK_IMPORTED_MODULE_8__["HitLogger"].removeListener(inspectedTabId, hitListener);
    panels.delete(inspectedTabId);
    browser.webRequest.onBeforeRequest.removeListener(localOnBeforeRequest);

    if (panels.size == 0)
    {
      ext.pages.onLoading.removeListener(onLoading);
      _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__["filterNotifier"].off("filter.added", onFilterAdded);
      _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__["filterNotifier"].off("filter.removed", onFilterRemoved);
      _adblockpluscore_lib_filterNotifier_js__WEBPACK_IMPORTED_MODULE_6__["filterNotifier"].off("subscription.added", onSubscriptionAdded);
    }
  });

  _hitLogger_js__WEBPACK_IMPORTED_MODULE_8__["HitLogger"].addListener(inspectedTabId, hitListener);
  panels.set(inspectedTabId, panel);
});

/**
 * Returns true if our devtools panel is supported by the browser.
 *
 * @event "devtools.supported"
 * @returns {boolean}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_7__["port"].on("devtools.supported", (message, sender) =>
  info__WEBPACK_IMPORTED_MODULE_9__["platform"] == "chromium" ||
  info__WEBPACK_IMPORTED_MODULE_9__["application"] == "firefox" &&
  Object(_adblockpluscore_lib_versions_js__WEBPACK_IMPORTED_MODULE_10__["compareVersions"])(info__WEBPACK_IMPORTED_MODULE_9__["applicationVersion"], "54") >= 0
);


/***/ }),
/* 52 */
/***/ (function(module) {

module.exports = JSON.parse("{\"0.bg\":1,\"001www.com\":1,\"0e.vc\":1,\"0emm.com\":2,\"1.bg\":1,\"12hp.at\":1,\"12hp.ch\":1,\"12hp.de\":1,\"1337.pictures\":1,\"16-b.it\":1,\"1kapp.com\":1,\"2.bg\":1,\"2000.hu\":1,\"2038.io\":1,\"2ix.at\":1,\"2ix.ch\":1,\"2ix.de\":1,\"3.bg\":1,\"32-b.it\":1,\"3utilities.com\":1,\"4.bg\":1,\"4lima.at\":1,\"4lima.ch\":1,\"4lima.de\":1,\"4u.com\":1,\"5.bg\":1,\"6.bg\":1,\"611.to\":1,\"64-b.it\":1,\"7.bg\":1,\"8.bg\":1,\"9.bg\":1,\"9guacu.br\":1,\"a.bg\":1,\"a.prod.fastly.net\":1,\"a.run.app\":1,\"a.se\":1,\"a.ssl.fastly.net\":1,\"aa.no\":1,\"aaa.pro\":1,\"aarborte.no\":1,\"ab.ca\":1,\"abashiri.hokkaido.jp\":1,\"abc.br\":1,\"abeno.osaka.jp\":1,\"abiko.chiba.jp\":1,\"abira.hokkaido.jp\":1,\"abkhazia.su\":1,\"abo.pa\":1,\"abr.it\":1,\"abruzzo.it\":1,\"abu.yamaguchi.jp\":1,\"ac.ae\":1,\"ac.at\":1,\"ac.be\":1,\"ac.ci\":1,\"ac.cn\":1,\"ac.cr\":1,\"ac.cy\":1,\"ac.fj\":1,\"ac.gn\":1,\"ac.gov.br\":1,\"ac.id\":1,\"ac.il\":1,\"ac.im\":1,\"ac.in\":1,\"ac.ir\":1,\"ac.jp\":1,\"ac.ke\":1,\"ac.kr\":1,\"ac.leg.br\":1,\"ac.lk\":1,\"ac.ls\":1,\"ac.ma\":1,\"ac.me\":1,\"ac.mu\":1,\"ac.mw\":1,\"ac.mz\":1,\"ac.ni\":1,\"ac.nz\":1,\"ac.pa\":1,\"ac.pr\":1,\"ac.rs\":1,\"ac.ru\":1,\"ac.rw\":1,\"ac.se\":1,\"ac.sz\":1,\"ac.th\":1,\"ac.tj\":1,\"ac.tz\":1,\"ac.ug\":1,\"ac.uk\":1,\"ac.vn\":1,\"ac.za\":1,\"ac.zm\":1,\"ac.zw\":1,\"aca.pro\":1,\"academia.bo\":1,\"academy.museum\":1,\"accesscam.org\":1,\"accident-investigation.aero\":1,\"accident-prevention.aero\":1,\"acct.pro\":1,\"achi.nagano.jp\":1,\"act.au\":1,\"act.edu.au\":1,\"ad.jp\":1,\"adachi.tokyo.jp\":1,\"adm.br\":1,\"adobeaemcloud.com\":1,\"adobeaemcloud.net\":1,\"adult.ht\":1,\"adv.br\":1,\"adv.mz\":1,\"advisor.ws\":2,\"adygeya.ru\":1,\"adygeya.su\":1,\"ae.org\":1,\"aejrie.no\":1,\"aero.mv\":1,\"aero.tt\":1,\"aerobatic.aero\":1,\"aeroclub.aero\":1,\"aerodrome.aero\":1,\"aeroport.fr\":1,\"afjord.no\":1,\"africa.com\":1,\"ag.it\":1,\"aga.niigata.jp\":1,\"agano.niigata.jp\":1,\"agdenes.no\":1,\"agematsu.nagano.jp\":1,\"agents.aero\":1,\"agr.br\":1,\"agrar.hu\":1,\"agric.za\":1,\"agriculture.museum\":1,\"agrigento.it\":1,\"agrinet.tn\":1,\"agro.bo\":1,\"agro.pl\":1,\"aguni.okinawa.jp\":1,\"ah.cn\":1,\"ah.no\":1,\"aibetsu.hokkaido.jp\":1,\"aichi.jp\":1,\"aid.pl\":1,\"aikawa.kanagawa.jp\":1,\"ainan.ehime.jp\":1,\"aioi.hyogo.jp\":1,\"aip.ee\":1,\"air-surveillance.aero\":1,\"air-traffic-control.aero\":1,\"air.museum\":1,\"aircraft.aero\":1,\"airguard.museum\":1,\"airline.aero\":1,\"airport.aero\":1,\"airtraffic.aero\":1,\"aisai.aichi.jp\":1,\"aisho.shiga.jp\":1,\"aizubange.fukushima.jp\":1,\"aizumi.tokushima.jp\":1,\"aizumisato.fukushima.jp\":1,\"aizuwakamatsu.fukushima.jp\":1,\"aju.br\":1,\"ak.us\":1,\"akabira.hokkaido.jp\":1,\"akagi.shimane.jp\":1,\"akaiwa.okayama.jp\":1,\"akashi.hyogo.jp\":1,\"aki.kochi.jp\":1,\"akiruno.tokyo.jp\":1,\"akishima.tokyo.jp\":1,\"akita.akita.jp\":1,\"akita.jp\":1,\"akkeshi.hokkaido.jp\":1,\"aknoluokta.no\":1,\"ako.hyogo.jp\":1,\"akrehamn.no\":1,\"aktyubinsk.su\":1,\"akune.kagoshima.jp\":1,\"al.eu.org\":1,\"al.gov.br\":1,\"al.it\":1,\"al.leg.br\":1,\"al.no\":1,\"al.us\":1,\"alabama.museum\":1,\"alaheadju.no\":1,\"aland.fi\":1,\"alaska.museum\":1,\"alces.network\":2,\"alessandria.it\":1,\"alesund.no\":1,\"algard.no\":1,\"algorithmia.com\":2,\"alpha-myqnapcloud.com\":1,\"alpha.bounty-full.com\":1,\"alstahaug.no\":1,\"alt.za\":1,\"alta.no\":1,\"altervista.org\":1,\"alto-adige.it\":1,\"altoadige.it\":1,\"alvdal.no\":1,\"alwaysdata.net\":1,\"am.br\":1,\"am.gov.br\":1,\"am.leg.br\":1,\"ama.aichi.jp\":1,\"ama.shimane.jp\":1,\"amagasaki.hyogo.jp\":1,\"amakusa.kumamoto.jp\":1,\"amami.kagoshima.jp\":1,\"amber.museum\":1,\"ambulance.aero\":1,\"ambulance.museum\":1,\"american.museum\":1,\"americana.museum\":1,\"americanantiques.museum\":1,\"americanart.museum\":1,\"ami.ibaraki.jp\":1,\"amli.no\":1,\"amot.no\":1,\"amsterdam.museum\":1,\"amsw.nl\":1,\"amusement.aero\":1,\"an.it\":1,\"anamizu.ishikawa.jp\":1,\"anan.nagano.jp\":1,\"anan.tokushima.jp\":1,\"anani.br\":1,\"ancona.it\":1,\"and.mom\":1,\"and.museum\":1,\"andasuolo.no\":1,\"andebu.no\":1,\"ando.nara.jp\":1,\"andoy.no\":1,\"andria-barletta-trani.it\":1,\"andria-trani-barletta.it\":1,\"andriabarlettatrani.it\":1,\"andriatranibarletta.it\":1,\"anjo.aichi.jp\":1,\"ann-arbor.mi.us\":1,\"annaka.gunma.jp\":1,\"annefrank.museum\":1,\"anpachi.gifu.jp\":1,\"anthro.museum\":1,\"anthropology.museum\":1,\"antiques.museum\":1,\"ao.it\":1,\"aogaki.hyogo.jp\":1,\"aogashima.tokyo.jp\":1,\"aoki.nagano.jp\":1,\"aomori.aomori.jp\":1,\"aomori.jp\":1,\"aosta-valley.it\":1,\"aosta.it\":1,\"aostavalley.it\":1,\"aoste.it\":1,\"ap-northeast-1.elasticbeanstalk.com\":1,\"ap-northeast-2.elasticbeanstalk.com\":1,\"ap-northeast-3.elasticbeanstalk.com\":1,\"ap-south-1.elasticbeanstalk.com\":1,\"ap-southeast-1.elasticbeanstalk.com\":1,\"ap-southeast-2.elasticbeanstalk.com\":1,\"ap.gov.br\":1,\"ap.gov.pl\":1,\"ap.it\":1,\"ap.leg.br\":1,\"aparecida.br\":1,\"api.stdlib.com\":1,\"apigee.io\":1,\"app.banzaicloud.io\":1,\"app.br\":1,\"app.gp\":1,\"app.lmpm.com\":1,\"app.os.fedoraproject.org\":1,\"app.os.stg.fedoraproject.org\":1,\"app.render.com\":1,\"appchizi.com\":1,\"appengine.flow.ch\":1,\"applicationcloud.io\":1,\"applinzi.com\":1,\"apps.fbsbx.com\":1,\"apps.lair.io\":1,\"appspot.com\":1,\"aprendemas.cl\":1,\"aq.it\":1,\"aquarium.museum\":1,\"aquila.it\":1,\"ar.com\":1,\"ar.it\":1,\"ar.us\":1,\"arai.shizuoka.jp\":1,\"arakawa.saitama.jp\":1,\"arakawa.tokyo.jp\":1,\"arao.kumamoto.jp\":1,\"arboretum.museum\":1,\"archaeological.museum\":1,\"archaeology.museum\":1,\"architecture.museum\":1,\"ardal.no\":1,\"aremark.no\":1,\"arendal.no\":1,\"arezzo.it\":1,\"ariake.saga.jp\":1,\"arida.wakayama.jp\":1,\"aridagawa.wakayama.jp\":1,\"arita.saga.jp\":1,\"arkhangelsk.su\":1,\"armenia.su\":1,\"arna.no\":1,\"arq.br\":1,\"art.br\":1,\"art.do\":1,\"art.dz\":1,\"art.ht\":1,\"art.museum\":1,\"art.pl\":1,\"art.sn\":1,\"artanddesign.museum\":1,\"artcenter.museum\":1,\"artdeco.museum\":1,\"arte.bo\":1,\"arteducation.museum\":1,\"artgallery.museum\":1,\"arts.co\":1,\"arts.museum\":1,\"arts.nf\":1,\"arts.ro\":1,\"arts.ve\":1,\"artsandcrafts.museum\":1,\"arvo.network\":1,\"as.us\":1,\"asago.hyogo.jp\":1,\"asahi.chiba.jp\":1,\"asahi.ibaraki.jp\":1,\"asahi.mie.jp\":1,\"asahi.nagano.jp\":1,\"asahi.toyama.jp\":1,\"asahi.yamagata.jp\":1,\"asahikawa.hokkaido.jp\":1,\"asaka.saitama.jp\":1,\"asakawa.fukushima.jp\":1,\"asakuchi.okayama.jp\":1,\"asaminami.hiroshima.jp\":1,\"ascoli-piceno.it\":1,\"ascolipiceno.it\":1,\"aseral.no\":1,\"ashgabad.su\":1,\"ashibetsu.hokkaido.jp\":1,\"ashikaga.tochigi.jp\":1,\"ashiya.fukuoka.jp\":1,\"ashiya.hyogo.jp\":1,\"ashoro.hokkaido.jp\":1,\"asker.no\":1,\"askim.no\":1,\"askoy.no\":1,\"askvoll.no\":1,\"asmatart.museum\":1,\"asn.au\":1,\"asn.lv\":1,\"asnes.no\":1,\"aso.kumamoto.jp\":1,\"ass.km\":1,\"assabu.hokkaido.jp\":1,\"assassination.museum\":1,\"assisi.museum\":1,\"assn.lk\":1,\"asso.bj\":1,\"asso.ci\":1,\"asso.dz\":1,\"asso.eu.org\":1,\"asso.fr\":1,\"asso.gp\":1,\"asso.ht\":1,\"asso.km\":1,\"asso.mc\":1,\"asso.nc\":1,\"asso.re\":1,\"association.aero\":1,\"association.museum\":1,\"asti.it\":1,\"astronomy.museum\":1,\"asuke.aichi.jp\":1,\"at-band-camp.net\":1,\"at.eu.org\":1,\"at.it\":1,\"at.md\":1,\"at.vg\":1,\"atami.shizuoka.jp\":1,\"ath.cx\":1,\"atlanta.museum\":1,\"atm.pl\":1,\"ato.br\":1,\"atsugi.kanagawa.jp\":1,\"atsuma.hokkaido.jp\":1,\"au.eu.org\":1,\"audnedaln.no\":1,\"augustow.pl\":1,\"aukra.no\":1,\"aure.no\":1,\"aurland.no\":1,\"aurskog-holand.no\":1,\"aus.basketball\":1,\"austevoll.no\":1,\"austin.museum\":1,\"australia.museum\":1,\"austrheim.no\":1,\"author.aero\":1,\"auto.pl\":1,\"automotive.museum\":1,\"av.it\":1,\"av.tr\":1,\"avellino.it\":1,\"averoy.no\":1,\"aviation.museum\":1,\"avocat.fr\":1,\"avocat.pro\":1,\"avoues.fr\":1,\"awaji.hyogo.jp\":1,\"awdev.ca\":2,\"awsmppl.com\":1,\"axis.museum\":1,\"aya.miyazaki.jp\":1,\"ayabe.kyoto.jp\":1,\"ayagawa.kagawa.jp\":1,\"ayase.kanagawa.jp\":1,\"az.us\":1,\"azerbaijan.su\":1,\"azimuth.network\":1,\"azumino.nagano.jp\":1,\"azure-mobile.net\":1,\"azurecontainer.io\":2,\"azurewebsites.net\":1,\"b-data.io\":1,\"b.bg\":1,\"b.br\":1,\"b.se\":1,\"b.ssl.fastly.net\":1,\"ba.gov.br\":1,\"ba.it\":1,\"ba.leg.br\":1,\"babia-gora.pl\":1,\"backplaneapp.io\":1,\"backyards.banzaicloud.io\":2,\"badaddja.no\":1,\"badajoz.museum\":1,\"baghdad.museum\":1,\"bahcavuotna.no\":1,\"bahccavuotna.no\":1,\"bahn.museum\":1,\"baidar.no\":1,\"bajddar.no\":1,\"balashov.su\":1,\"balat.no\":1,\"bale.museum\":1,\"balena-devices.com\":1,\"balestrand.no\":1,\"ballangen.no\":1,\"ballooning.aero\":1,\"balsan-sudtirol.it\":1,\"balsan-suedtirol.it\":1,\"balsan.it\":1,\"balsfjord.no\":1,\"baltimore.museum\":1,\"bamble.no\":1,\"bandai.fukushima.jp\":1,\"bando.ibaraki.jp\":1,\"banzai.cloud\":2,\"bar.pro\":1,\"bar0.net\":1,\"bar1.net\":1,\"bar2.net\":1,\"barcelona.museum\":1,\"bardu.no\":1,\"bari.it\":1,\"barletta-trani-andria.it\":1,\"barlettatraniandria.it\":1,\"barreau.bj\":1,\"barrel-of-knowledge.info\":1,\"barrell-of-knowledge.info\":1,\"barsy.bg\":1,\"barsy.ca\":1,\"barsy.club\":1,\"barsy.co.uk\":1,\"barsy.de\":1,\"barsy.eu\":1,\"barsy.in\":1,\"barsy.info\":1,\"barsy.io\":1,\"barsy.me\":1,\"barsy.menu\":1,\"barsy.mobi\":1,\"barsy.net\":1,\"barsy.online\":1,\"barsy.org\":1,\"barsy.pro\":1,\"barsy.pub\":1,\"barsy.shop\":1,\"barsy.site\":1,\"barsy.support\":1,\"barsy.uk\":1,\"barsycenter.com\":1,\"barsyonline.co.uk\":1,\"barsyonline.com\":1,\"barueri.br\":1,\"barum.no\":1,\"bas.it\":1,\"baseball.museum\":1,\"basel.museum\":1,\"bashkiria.ru\":1,\"bashkiria.su\":1,\"basicserver.io\":1,\"basilicata.it\":1,\"baths.museum\":1,\"bato.tochigi.jp\":1,\"batsfjord.no\":1,\"bauern.museum\":1,\"bbs.tr\":1,\"bc.ca\":1,\"bc.platform.sh\":1,\"bci.dnstrace.pro\":1,\"bd\":2,\"bd.se\":1,\"be.ax\":1,\"be.eu.org\":1,\"be.gy\":1,\"bearalvahki.no\":1,\"beardu.no\":1,\"beauxarts.museum\":1,\"bedzin.pl\":1,\"beeldengeluid.museum\":1,\"beep.pl\":1,\"beiarn.no\":1,\"bel.tr\":1,\"belau.pw\":1,\"belem.br\":1,\"bellevue.museum\":1,\"belluno.it\":1,\"benevento.it\":1,\"beppu.oita.jp\":1,\"berg.no\":1,\"bergamo.it\":1,\"bergbau.museum\":1,\"bergen.no\":1,\"berkeley.museum\":1,\"berlevag.no\":1,\"berlin.museum\":1,\"bern.museum\":1,\"beskidy.pl\":1,\"beta.bounty-full.com\":1,\"betainabox.com\":1,\"better-than.tv\":1,\"bg.eu.org\":1,\"bg.it\":1,\"bhz.br\":1,\"bi.it\":1,\"bialowieza.pl\":1,\"bialystok.pl\":1,\"bib.br\":1,\"bibai.hokkaido.jp\":1,\"bible.museum\":1,\"biei.hokkaido.jp\":1,\"bielawa.pl\":1,\"biella.it\":1,\"bieszczady.pl\":1,\"bievat.no\":1,\"bifuka.hokkaido.jp\":1,\"bihoro.hokkaido.jp\":1,\"bilbao.museum\":1,\"bill.museum\":1,\"bindal.no\":1,\"bio.br\":1,\"bir.ru\":1,\"biratori.hokkaido.jp\":1,\"birdart.museum\":1,\"birkenes.no\":1,\"birthplace.museum\":1,\"bitbridge.net\":1,\"biz.at\":1,\"biz.az\":1,\"biz.bb\":1,\"biz.cy\":1,\"biz.dk\":1,\"biz.et\":1,\"biz.fj\":1,\"biz.gl\":1,\"biz.id\":1,\"biz.ki\":1,\"biz.ls\":1,\"biz.mv\":1,\"biz.mw\":1,\"biz.ni\":1,\"biz.nr\":1,\"biz.pk\":1,\"biz.pl\":1,\"biz.pr\":1,\"biz.ss\":1,\"biz.tj\":1,\"biz.tr\":1,\"biz.tt\":1,\"biz.ua\":1,\"biz.vn\":1,\"biz.zm\":1,\"bizen.okayama.jp\":1,\"bj.cn\":1,\"bjarkoy.no\":1,\"bjerkreim.no\":1,\"bjugn.no\":1,\"bl.it\":1,\"blackbaudcdn.net\":1,\"blog.bo\":1,\"blog.br\":1,\"blog.gt\":1,\"blog.kg\":1,\"blog.vu\":1,\"blogdns.com\":1,\"blogdns.net\":1,\"blogdns.org\":1,\"blogsite.org\":1,\"blogsite.xyz\":1,\"blogspot.ae\":1,\"blogspot.al\":1,\"blogspot.am\":1,\"blogspot.ba\":1,\"blogspot.be\":1,\"blogspot.bg\":1,\"blogspot.bj\":1,\"blogspot.ca\":1,\"blogspot.cf\":1,\"blogspot.ch\":1,\"blogspot.cl\":1,\"blogspot.co.at\":1,\"blogspot.co.id\":1,\"blogspot.co.il\":1,\"blogspot.co.ke\":1,\"blogspot.co.nz\":1,\"blogspot.co.uk\":1,\"blogspot.co.za\":1,\"blogspot.com\":1,\"blogspot.com.ar\":1,\"blogspot.com.au\":1,\"blogspot.com.br\":1,\"blogspot.com.by\":1,\"blogspot.com.co\":1,\"blogspot.com.cy\":1,\"blogspot.com.ee\":1,\"blogspot.com.eg\":1,\"blogspot.com.es\":1,\"blogspot.com.mt\":1,\"blogspot.com.ng\":1,\"blogspot.com.tr\":1,\"blogspot.com.uy\":1,\"blogspot.cv\":1,\"blogspot.cz\":1,\"blogspot.de\":1,\"blogspot.dk\":1,\"blogspot.fi\":1,\"blogspot.fr\":1,\"blogspot.gr\":1,\"blogspot.hk\":1,\"blogspot.hr\":1,\"blogspot.hu\":1,\"blogspot.ie\":1,\"blogspot.in\":1,\"blogspot.is\":1,\"blogspot.it\":1,\"blogspot.jp\":1,\"blogspot.kr\":1,\"blogspot.li\":1,\"blogspot.lt\":1,\"blogspot.lu\":1,\"blogspot.md\":1,\"blogspot.mk\":1,\"blogspot.mr\":1,\"blogspot.mx\":1,\"blogspot.my\":1,\"blogspot.nl\":1,\"blogspot.no\":1,\"blogspot.pe\":1,\"blogspot.pt\":1,\"blogspot.qa\":1,\"blogspot.re\":1,\"blogspot.ro\":1,\"blogspot.rs\":1,\"blogspot.ru\":1,\"blogspot.se\":1,\"blogspot.sg\":1,\"blogspot.si\":1,\"blogspot.sk\":1,\"blogspot.sn\":1,\"blogspot.td\":1,\"blogspot.tw\":1,\"blogspot.ug\":1,\"blogspot.vn\":1,\"blogsyte.com\":1,\"bloxcms.com\":1,\"bmd.br\":1,\"bmoattachments.org\":1,\"bn.it\":1,\"bnr.la\":1,\"bo.it\":1,\"bo.nordland.no\":1,\"bo.telemark.no\":1,\"boavista.br\":1,\"bodo.no\":1,\"bokn.no\":1,\"boldlygoingnowhere.org\":1,\"boleslawiec.pl\":1,\"bolivia.bo\":1,\"bologna.it\":1,\"bolt.hu\":1,\"bolzano-altoadige.it\":1,\"bolzano.it\":1,\"bomlo.no\":1,\"bonn.museum\":1,\"boomla.net\":1,\"boston.museum\":1,\"botanical.museum\":1,\"botanicalgarden.museum\":1,\"botanicgarden.museum\":1,\"botany.museum\":1,\"bounceme.net\":1,\"bounty-full.com\":1,\"boxfuse.io\":1,\"bozen-sudtirol.it\":1,\"bozen-suedtirol.it\":1,\"bozen.it\":1,\"bpl.biz\":1,\"bplaced.com\":1,\"bplaced.de\":1,\"bplaced.net\":1,\"br.com\":1,\"br.it\":1,\"brand.se\":1,\"brandywinevalley.museum\":1,\"brasil.museum\":1,\"brasilia.me\":1,\"bremanger.no\":1,\"brescia.it\":1,\"brindisi.it\":1,\"bristol.museum\":1,\"british.museum\":1,\"britishcolumbia.museum\":1,\"broadcast.museum\":1,\"broke-it.net\":1,\"broker.aero\":1,\"bronnoy.no\":1,\"bronnoysund.no\":1,\"browsersafetymark.io\":1,\"brumunddal.no\":1,\"brunel.museum\":1,\"brussel.museum\":1,\"brussels.museum\":1,\"bruxelles.museum\":1,\"bryansk.su\":1,\"bryne.no\":1,\"bs.it\":1,\"bsb.br\":1,\"bss.design\":1,\"bt.it\":1,\"bu.no\":1,\"budejju.no\":1,\"building.museum\":1,\"builtwithdark.com\":1,\"bukhara.su\":1,\"bulsan-sudtirol.it\":1,\"bulsan-suedtirol.it\":1,\"bulsan.it\":1,\"bungoono.oita.jp\":1,\"bungotakada.oita.jp\":1,\"bunkyo.tokyo.jp\":1,\"burghof.museum\":1,\"bus.museum\":1,\"busan.kr\":1,\"bushey.museum\":1,\"buyshouses.net\":1,\"buzen.fukuoka.jp\":1,\"bydgoszcz.pl\":1,\"byen.site\":1,\"bygland.no\":1,\"bykle.no\":1,\"bytom.pl\":1,\"bz.it\":1,\"bzz.dapps.earth\":2,\"c.bg\":1,\"c.cdn77.org\":1,\"c.la\":1,\"c.se\":1,\"c66.me\":1,\"ca-central-1.elasticbeanstalk.com\":1,\"ca.eu.org\":1,\"ca.it\":1,\"ca.na\":1,\"ca.us\":1,\"caa.aero\":1,\"caa.li\":1,\"cable-modem.org\":1,\"cadaques.museum\":1,\"cagliari.it\":1,\"cahcesuolo.no\":1,\"cal.it\":1,\"calabria.it\":1,\"california.museum\":1,\"caltanissetta.it\":1,\"cam.it\":1,\"cambridge.museum\":1,\"camdvr.org\":1,\"campania.it\":1,\"campidano-medio.it\":1,\"campidanomedio.it\":1,\"campinagrande.br\":1,\"campinas.br\":1,\"campobasso.it\":1,\"can.museum\":1,\"canada.museum\":1,\"capebreton.museum\":1,\"carbonia-iglesias.it\":1,\"carboniaiglesias.it\":1,\"cargo.aero\":1,\"carrara-massa.it\":1,\"carraramassa.it\":1,\"carrd.co\":1,\"carrier.museum\":1,\"cartoonart.museum\":1,\"casacam.net\":1,\"casadelamoneda.museum\":1,\"caserta.it\":1,\"casino.hu\":1,\"castle.museum\":1,\"castres.museum\":1,\"cat.ax\":1,\"catania.it\":1,\"catanzaro.it\":1,\"catering.aero\":1,\"catholic.edu.au\":1,\"caxias.br\":1,\"cb.it\":1,\"cbg.ru\":1,\"cc.ak.us\":1,\"cc.al.us\":1,\"cc.ar.us\":1,\"cc.as.us\":1,\"cc.az.us\":1,\"cc.ca.us\":1,\"cc.co.us\":1,\"cc.ct.us\":1,\"cc.dc.us\":1,\"cc.de.us\":1,\"cc.fl.us\":1,\"cc.ga.us\":1,\"cc.gu.us\":1,\"cc.hi.us\":1,\"cc.hn\":1,\"cc.ia.us\":1,\"cc.id.us\":1,\"cc.il.us\":1,\"cc.in.us\":1,\"cc.ks.us\":1,\"cc.ky.us\":1,\"cc.la.us\":1,\"cc.ma.us\":1,\"cc.md.us\":1,\"cc.me.us\":1,\"cc.mi.us\":1,\"cc.mn.us\":1,\"cc.mo.us\":1,\"cc.ms.us\":1,\"cc.mt.us\":1,\"cc.na\":1,\"cc.nc.us\":1,\"cc.nd.us\":1,\"cc.ne.us\":1,\"cc.nh.us\":1,\"cc.nj.us\":1,\"cc.nm.us\":1,\"cc.nv.us\":1,\"cc.ny.us\":1,\"cc.oh.us\":1,\"cc.ok.us\":1,\"cc.or.us\":1,\"cc.pa.us\":1,\"cc.pr.us\":1,\"cc.ri.us\":1,\"cc.sc.us\":1,\"cc.sd.us\":1,\"cc.tn.us\":1,\"cc.tx.us\":1,\"cc.ua\":1,\"cc.ut.us\":1,\"cc.va.us\":1,\"cc.vi.us\":1,\"cc.vt.us\":1,\"cc.wa.us\":1,\"cc.wi.us\":1,\"cc.wv.us\":1,\"cc.wy.us\":1,\"cci.fr\":1,\"cd.eu.org\":1,\"cdn77-ssl.net\":1,\"ce.gov.br\":1,\"ce.it\":1,\"ce.leg.br\":1,\"cechire.com\":1,\"celtic.museum\":1,\"center.museum\":1,\"certification.aero\":1,\"certmgr.org\":1,\"cesena-forli.it\":1,\"cesenaforli.it\":1,\"ch.eu.org\":1,\"ch.it\":1,\"ch.tc\":1,\"chambagri.fr\":1,\"championship.aero\":1,\"channelsdvr.net\":1,\"charter.aero\":1,\"chattanooga.museum\":1,\"cheltenham.museum\":1,\"cherkassy.ua\":1,\"cherkasy.ua\":1,\"chernigov.ua\":1,\"chernihiv.ua\":1,\"chernivtsi.ua\":1,\"chernovtsy.ua\":1,\"chesapeakebay.museum\":1,\"chiba.jp\":1,\"chicago.museum\":1,\"chichibu.saitama.jp\":1,\"chieti.it\":1,\"chigasaki.kanagawa.jp\":1,\"chihayaakasaka.osaka.jp\":1,\"chijiwa.nagasaki.jp\":1,\"chikugo.fukuoka.jp\":1,\"chikuho.fukuoka.jp\":1,\"chikuhoku.nagano.jp\":1,\"chikujo.fukuoka.jp\":1,\"chikuma.nagano.jp\":1,\"chikusei.ibaraki.jp\":1,\"chikushino.fukuoka.jp\":1,\"chikuzen.fukuoka.jp\":1,\"children.museum\":1,\"childrens.museum\":1,\"childrensgarden.museum\":1,\"chimkent.su\":1,\"chino.nagano.jp\":1,\"chippubetsu.hokkaido.jp\":1,\"chiropractic.museum\":1,\"chirurgiens-dentistes-en-france.fr\":1,\"chirurgiens-dentistes.fr\":1,\"chiryu.aichi.jp\":1,\"chita.aichi.jp\":1,\"chitose.hokkaido.jp\":1,\"chiyoda.gunma.jp\":1,\"chiyoda.tokyo.jp\":1,\"chizu.tottori.jp\":1,\"chocolate.museum\":1,\"chofu.tokyo.jp\":1,\"chonan.chiba.jp\":1,\"chosei.chiba.jp\":1,\"choshi.chiba.jp\":1,\"choyo.kumamoto.jp\":1,\"christiansburg.museum\":1,\"chtr.k12.ma.us\":1,\"chungbuk.kr\":1,\"chungnam.kr\":1,\"chuo.chiba.jp\":1,\"chuo.fukuoka.jp\":1,\"chuo.osaka.jp\":1,\"chuo.tokyo.jp\":1,\"chuo.yamanashi.jp\":1,\"ci.it\":1,\"ciencia.bo\":1,\"cieszyn.pl\":1,\"cim.br\":1,\"cincinnati.museum\":1,\"cinema.museum\":1,\"circus.museum\":1,\"ciscofreak.com\":1,\"cistron.nl\":1,\"city.hu\":1,\"city.kawasaki.jp\":0,\"city.kitakyushu.jp\":0,\"city.kobe.jp\":0,\"city.nagoya.jp\":0,\"city.sapporo.jp\":0,\"city.sendai.jp\":0,\"city.yokohama.jp\":0,\"civilaviation.aero\":1,\"civilisation.museum\":1,\"civilization.museum\":1,\"civilwar.museum\":1,\"ck\":2,\"ck.ua\":1,\"cl.it\":1,\"clan.rip\":1,\"cleverapps.io\":1,\"clic2000.net\":1,\"clinton.museum\":1,\"clock.museum\":1,\"cloud.fedoraproject.org\":1,\"cloud.goog\":1,\"cloud.metacentrum.cz\":2,\"cloud66.ws\":1,\"cloud66.zone\":1,\"cloudaccess.host\":1,\"cloudaccess.net\":1,\"cloudapp.net\":1,\"cloudapps.digital\":1,\"cloudcontrolapp.com\":1,\"cloudcontrolled.com\":1,\"cloudeity.net\":1,\"cloudera.site\":1,\"cloudfront.net\":1,\"cloudfunctions.net\":1,\"cloudjiffy.net\":1,\"cloudns.asia\":1,\"cloudns.biz\":1,\"cloudns.cc\":1,\"cloudns.club\":1,\"cloudns.eu\":1,\"cloudns.in\":1,\"cloudns.info\":1,\"cloudns.org\":1,\"cloudns.pro\":1,\"cloudns.pw\":1,\"cloudns.us\":1,\"cloudycluster.net\":1,\"club.aero\":1,\"club.tw\":1,\"cn-north-1.eb.amazonaws.com.cn\":1,\"cn-northwest-1.eb.amazonaws.com.cn\":1,\"cn.com\":1,\"cn.eu.org\":1,\"cn.it\":1,\"cn.ua\":1,\"cn.vu\":1,\"cng.br\":1,\"cnpy.gdn\":1,\"cns.joyent.com\":2,\"cnt.br\":1,\"co.ae\":1,\"co.ag\":1,\"co.am\":1,\"co.ao\":1,\"co.at\":1,\"co.bb\":1,\"co.bi\":1,\"co.bn\":1,\"co.business\":1,\"co.bw\":1,\"co.ca\":1,\"co.ci\":1,\"co.cl\":1,\"co.cm\":1,\"co.com\":1,\"co.cr\":1,\"co.cz\":1,\"co.dk\":1,\"co.education\":1,\"co.events\":1,\"co.financial\":1,\"co.gg\":1,\"co.gl\":1,\"co.gy\":1,\"co.hu\":1,\"co.id\":1,\"co.il\":1,\"co.im\":1,\"co.in\":1,\"co.ir\":1,\"co.it\":1,\"co.je\":1,\"co.jp\":1,\"co.ke\":1,\"co.kr\":1,\"co.krd\":1,\"co.lc\":1,\"co.ls\":1,\"co.ma\":1,\"co.me\":1,\"co.mg\":1,\"co.mu\":1,\"co.mw\":1,\"co.mz\":1,\"co.na\":1,\"co.network\":1,\"co.ni\":1,\"co.nl\":1,\"co.no\":1,\"co.nz\":1,\"co.om\":1,\"co.pl\":1,\"co.place\":1,\"co.pn\":1,\"co.pw\":1,\"co.ro\":1,\"co.rs\":1,\"co.rw\":1,\"co.st\":1,\"co.sz\":1,\"co.technology\":1,\"co.th\":1,\"co.tj\":1,\"co.tm\":1,\"co.tt\":1,\"co.tz\":1,\"co.ua\":1,\"co.ug\":1,\"co.uk\":1,\"co.us\":1,\"co.uz\":1,\"co.ve\":1,\"co.vi\":1,\"co.za\":1,\"co.zm\":1,\"co.zw\":1,\"coal.museum\":1,\"coastaldefence.museum\":1,\"codespot.com\":1,\"cody.museum\":1,\"cog.mi.us\":1,\"col.ng\":1,\"coldwar.museum\":1,\"collection.museum\":1,\"collegefan.org\":1,\"colonialwilliamsburg.museum\":1,\"coloradoplateau.museum\":1,\"columbia.museum\":1,\"columbus.museum\":1,\"com.ac\":1,\"com.af\":1,\"com.ag\":1,\"com.ai\":1,\"com.al\":1,\"com.am\":1,\"com.ar\":1,\"com.au\":1,\"com.aw\":1,\"com.az\":1,\"com.ba\":1,\"com.bb\":1,\"com.bh\":1,\"com.bi\":1,\"com.bm\":1,\"com.bn\":1,\"com.bo\":1,\"com.br\":1,\"com.bs\":1,\"com.bt\":1,\"com.by\":1,\"com.bz\":1,\"com.ci\":1,\"com.cm\":1,\"com.cn\":1,\"com.co\":1,\"com.cu\":1,\"com.cw\":1,\"com.cy\":1,\"com.de\":1,\"com.dm\":1,\"com.do\":1,\"com.dz\":1,\"com.ec\":1,\"com.ee\":1,\"com.eg\":1,\"com.es\":1,\"com.et\":1,\"com.fj\":1,\"com.fm\":1,\"com.fr\":1,\"com.ge\":1,\"com.gh\":1,\"com.gi\":1,\"com.gl\":1,\"com.gn\":1,\"com.gp\":1,\"com.gr\":1,\"com.gt\":1,\"com.gu\":1,\"com.gy\":1,\"com.hk\":1,\"com.hn\":1,\"com.hr\":1,\"com.ht\":1,\"com.im\":1,\"com.io\":1,\"com.iq\":1,\"com.is\":1,\"com.jo\":1,\"com.kg\":1,\"com.ki\":1,\"com.km\":1,\"com.kp\":1,\"com.kw\":1,\"com.ky\":1,\"com.kz\":1,\"com.la\":1,\"com.lb\":1,\"com.lc\":1,\"com.lk\":1,\"com.lr\":1,\"com.lv\":1,\"com.ly\":1,\"com.mg\":1,\"com.mk\":1,\"com.ml\":1,\"com.mo\":1,\"com.ms\":1,\"com.mt\":1,\"com.mu\":1,\"com.mv\":1,\"com.mw\":1,\"com.mx\":1,\"com.my\":1,\"com.na\":1,\"com.nf\":1,\"com.ng\":1,\"com.ni\":1,\"com.nr\":1,\"com.om\":1,\"com.pa\":1,\"com.pe\":1,\"com.pf\":1,\"com.ph\":1,\"com.pk\":1,\"com.pl\":1,\"com.pr\":1,\"com.ps\":1,\"com.pt\":1,\"com.py\":1,\"com.qa\":1,\"com.re\":1,\"com.ro\":1,\"com.ru\":1,\"com.sa\":1,\"com.sb\":1,\"com.sc\":1,\"com.sd\":1,\"com.se\":1,\"com.sg\":1,\"com.sh\":1,\"com.sl\":1,\"com.sn\":1,\"com.so\":1,\"com.ss\":1,\"com.st\":1,\"com.sv\":1,\"com.sy\":1,\"com.tj\":1,\"com.tm\":1,\"com.tn\":1,\"com.to\":1,\"com.tr\":1,\"com.tt\":1,\"com.tw\":1,\"com.ua\":1,\"com.ug\":1,\"com.uy\":1,\"com.uz\":1,\"com.vc\":1,\"com.ve\":1,\"com.vi\":1,\"com.vn\":1,\"com.vu\":1,\"com.ws\":1,\"com.zm\":1,\"commune.am\":1,\"communication.museum\":1,\"communications.museum\":1,\"community-pro.de\":1,\"community-pro.net\":1,\"community.museum\":1,\"como.it\":1,\"compute-1.amazonaws.com\":2,\"compute.amazonaws.com\":2,\"compute.amazonaws.com.cn\":2,\"compute.estate\":2,\"computer.museum\":1,\"computerhistory.museum\":1,\"conf.au\":1,\"conf.lv\":1,\"conf.se\":1,\"conference.aero\":1,\"conn.uk\":1,\"consulado.st\":1,\"consultant.aero\":1,\"consulting.aero\":1,\"contagem.br\":1,\"contemporary.museum\":1,\"contemporaryart.museum\":1,\"control.aero\":1,\"convent.museum\":1,\"coop.br\":1,\"coop.ht\":1,\"coop.km\":1,\"coop.mv\":1,\"coop.mw\":1,\"coop.py\":1,\"coop.rw\":1,\"coop.tt\":1,\"cooperativa.bo\":1,\"copenhagen.museum\":1,\"copro.uk\":1,\"corporation.museum\":1,\"corvette.museum\":1,\"cosenza.it\":1,\"costume.museum\":1,\"couchpotatofries.org\":1,\"couk.me\":1,\"council.aero\":1,\"countryestate.museum\":1,\"county.museum\":1,\"coz.br\":1,\"cpa.pro\":1,\"cq.cn\":1,\"cr.it\":1,\"cr.ua\":1,\"crafting.xyz\":1,\"crafts.museum\":1,\"cranbrook.museum\":1,\"crd.co\":1,\"creation.museum\":1,\"cremona.it\":1,\"crew.aero\":1,\"cri.br\":1,\"cri.nz\":1,\"crimea.ua\":1,\"crotone.it\":1,\"cryptonomic.net\":2,\"cs.it\":1,\"csx.cc\":1,\"ct.it\":1,\"ct.us\":1,\"cuiaba.br\":1,\"cultural.museum\":1,\"culturalcenter.museum\":1,\"culture.museum\":1,\"cuneo.it\":1,\"cupcake.is\":1,\"curitiba.br\":1,\"curv.dev\":1,\"cust.dev.thingdust.io\":1,\"cust.disrec.thingdust.io\":1,\"cust.prod.thingdust.io\":1,\"cust.retrosnub.co.uk\":1,\"cust.testing.thingdust.io\":1,\"custom.metacentrum.cz\":1,\"customer-oci.com\":2,\"customer.enonic.io\":1,\"customer.mythic-beasts.com\":1,\"customer.speedpartner.de\":1,\"cv.ua\":1,\"cx.ua\":1,\"cy.eu.org\":1,\"cya.gg\":1,\"cyber.museum\":1,\"cymru.museum\":1,\"cyon.link\":1,\"cyon.site\":1,\"cz.eu.org\":1,\"cz.it\":1,\"czeladz.pl\":1,\"czest.pl\":1,\"d.bg\":1,\"d.gv.vc\":1,\"d.se\":1,\"daegu.kr\":1,\"daejeon.kr\":1,\"daemon.panel.gg\":1,\"dagestan.ru\":1,\"dagestan.su\":1,\"daigo.ibaraki.jp\":1,\"daisen.akita.jp\":1,\"daito.osaka.jp\":1,\"daiwa.hiroshima.jp\":1,\"dali.museum\":1,\"dallas.museum\":1,\"damnserver.com\":1,\"daplie.me\":1,\"dapps.earth\":2,\"database.museum\":1,\"date.fukushima.jp\":1,\"date.hokkaido.jp\":1,\"dattolocal.com\":1,\"dattolocal.net\":1,\"dattorelay.com\":1,\"dattoweb.com\":1,\"davvenjarga.no\":1,\"davvesiida.no\":1,\"dazaifu.fukuoka.jp\":1,\"dc.us\":1,\"dd-dns.de\":1,\"ddns.me\":1,\"ddns.net\":1,\"ddnsfree.com\":1,\"ddnsgeek.com\":1,\"ddnsking.com\":1,\"ddnslive.com\":1,\"ddnss.de\":1,\"ddnss.org\":1,\"ddr.museum\":1,\"de.com\":1,\"de.cool\":1,\"de.eu.org\":1,\"de.gt\":1,\"de.ls\":1,\"de.md\":1,\"de.us\":1,\"deatnu.no\":1,\"debian.net\":1,\"decorativearts.museum\":1,\"dedyn.io\":1,\"def.br\":1,\"defense.tn\":1,\"definima.io\":1,\"definima.net\":1,\"delaware.museum\":1,\"dell-ogliastra.it\":1,\"dellogliastra.it\":1,\"delmenhorst.museum\":1,\"demo.jelastic.com\":1,\"democracia.bo\":1,\"demon.nl\":1,\"denmark.museum\":1,\"dep.no\":1,\"deporte.bo\":1,\"depot.museum\":1,\"des.br\":1,\"desa.id\":1,\"design.aero\":1,\"design.museum\":1,\"det.br\":1,\"detroit.museum\":1,\"dev-myqnapcloud.com\":1,\"dev.adobeaemcloud.com\":2,\"dev.br\":1,\"dev.static.land\":1,\"dev.vu\":1,\"development.run\":1,\"devices.resinstaging.io\":1,\"df.gov.br\":1,\"df.leg.br\":1,\"dgca.aero\":1,\"dh.bytemark.co.uk\":1,\"dielddanuorri.no\":1,\"dinosaur.museum\":1,\"direct.quickconnect.to\":1,\"discourse.group\":1,\"discourse.team\":1,\"discovery.museum\":1,\"diskstation.eu\":1,\"diskstation.me\":1,\"diskstation.org\":1,\"diskussionsbereich.de\":1,\"ditchyourip.com\":1,\"divtasvuodna.no\":1,\"divttasvuotna.no\":1,\"dk.eu.org\":1,\"dlugoleka.pl\":1,\"dn.ua\":1,\"dnepropetrovsk.ua\":1,\"dni.us\":1,\"dnipropetrovsk.ua\":1,\"dnsalias.com\":1,\"dnsalias.net\":1,\"dnsalias.org\":1,\"dnsdojo.com\":1,\"dnsdojo.net\":1,\"dnsdojo.org\":1,\"dnsfor.me\":1,\"dnshome.de\":1,\"dnsiskinky.com\":1,\"dnsking.ch\":1,\"dnsup.net\":1,\"dnsupdate.info\":1,\"dnsupdater.de\":1,\"does-it.net\":1,\"doesntexist.com\":1,\"doesntexist.org\":1,\"dolls.museum\":1,\"donetsk.ua\":1,\"donna.no\":1,\"donostia.museum\":1,\"dontexist.com\":1,\"dontexist.net\":1,\"dontexist.org\":1,\"doomdns.com\":1,\"doomdns.org\":1,\"dopaas.com\":1,\"doshi.yamanashi.jp\":1,\"dovre.no\":1,\"dp.ua\":1,\"dr.na\":1,\"dr.tr\":1,\"drammen.no\":1,\"drangedal.no\":1,\"dray-dns.de\":1,\"drayddns.com\":1,\"draydns.de\":1,\"dreamhosters.com\":1,\"drobak.no\":1,\"drud.io\":1,\"drud.us\":1,\"dscloud.biz\":1,\"dscloud.me\":1,\"dscloud.mobi\":1,\"dsmynas.com\":1,\"dsmynas.net\":1,\"dsmynas.org\":1,\"dst.mi.us\":1,\"duckdns.org\":1,\"durham.museum\":1,\"dvrcam.info\":1,\"dvrdns.org\":1,\"dweb.link\":2,\"dy.fi\":1,\"dyn-berlin.de\":1,\"dyn-ip24.de\":1,\"dyn-o-saur.com\":1,\"dyn-vpn.de\":1,\"dyn.cosidns.de\":1,\"dyn.ddnss.de\":1,\"dyn.home-webserver.de\":1,\"dyn53.io\":1,\"dynalias.com\":1,\"dynalias.net\":1,\"dynalias.org\":1,\"dynamic-dns.info\":1,\"dynamisches-dns.de\":1,\"dynathome.net\":1,\"dyndns-at-home.com\":1,\"dyndns-at-work.com\":1,\"dyndns-blog.com\":1,\"dyndns-free.com\":1,\"dyndns-home.com\":1,\"dyndns-ip.com\":1,\"dyndns-mail.com\":1,\"dyndns-office.com\":1,\"dyndns-pics.com\":1,\"dyndns-remote.com\":1,\"dyndns-server.com\":1,\"dyndns-web.com\":1,\"dyndns-wiki.com\":1,\"dyndns-work.com\":1,\"dyndns.biz\":1,\"dyndns.dappnode.io\":1,\"dyndns.ddnss.de\":1,\"dyndns.info\":1,\"dyndns.org\":1,\"dyndns.tv\":1,\"dyndns.ws\":1,\"dyndns1.de\":1,\"dynns.com\":1,\"dynserv.org\":1,\"dynu.net\":1,\"dynv6.net\":1,\"dynvpn.de\":1,\"dyroy.no\":1,\"e.bg\":1,\"e.se\":1,\"e12.ve\":1,\"e164.arpa\":1,\"e4.cz\":1,\"east-kazakhstan.su\":1,\"eastafrica.museum\":1,\"eastcoast.museum\":1,\"eating-organic.net\":1,\"eaton.mi.us\":1,\"ebetsu.hokkaido.jp\":1,\"ebina.kanagawa.jp\":1,\"ebino.miyazaki.jp\":1,\"ebiz.tw\":1,\"echizen.fukui.jp\":1,\"ecn.br\":1,\"eco.br\":1,\"ecologia.bo\":1,\"economia.bo\":1,\"ed.ao\":1,\"ed.ci\":1,\"ed.cr\":1,\"ed.jp\":1,\"ed.pw\":1,\"edgeapp.net\":1,\"edgestack.me\":1,\"edogawa.tokyo.jp\":1,\"edu.ac\":1,\"edu.af\":1,\"edu.al\":1,\"edu.ar\":1,\"edu.au\":1,\"edu.az\":1,\"edu.ba\":1,\"edu.bb\":1,\"edu.bh\":1,\"edu.bi\":1,\"edu.bm\":1,\"edu.bn\":1,\"edu.bo\":1,\"edu.br\":1,\"edu.bs\":1,\"edu.bt\":1,\"edu.bz\":1,\"edu.ci\":1,\"edu.cn\":1,\"edu.co\":1,\"edu.cu\":1,\"edu.cw\":1,\"edu.dm\":1,\"edu.do\":1,\"edu.dz\":1,\"edu.ec\":1,\"edu.ee\":1,\"edu.eg\":1,\"edu.es\":1,\"edu.et\":1,\"edu.eu.org\":1,\"edu.fm\":1,\"edu.gd\":1,\"edu.ge\":1,\"edu.gh\":1,\"edu.gi\":1,\"edu.gl\":1,\"edu.gn\":1,\"edu.gp\":1,\"edu.gr\":1,\"edu.gt\":1,\"edu.gu\":1,\"edu.gy\":1,\"edu.hk\":1,\"edu.hn\":1,\"edu.ht\":1,\"edu.in\":1,\"edu.iq\":1,\"edu.is\":1,\"edu.it\":1,\"edu.jo\":1,\"edu.kg\":1,\"edu.ki\":1,\"edu.km\":1,\"edu.kn\":1,\"edu.kp\":1,\"edu.krd\":1,\"edu.kw\":1,\"edu.ky\":1,\"edu.kz\":1,\"edu.la\":1,\"edu.lb\":1,\"edu.lc\":1,\"edu.lk\":1,\"edu.lr\":1,\"edu.ls\":1,\"edu.lv\":1,\"edu.ly\":1,\"edu.me\":1,\"edu.mg\":1,\"edu.mk\":1,\"edu.ml\":1,\"edu.mn\":1,\"edu.mo\":1,\"edu.ms\":1,\"edu.mt\":1,\"edu.mv\":1,\"edu.mw\":1,\"edu.mx\":1,\"edu.my\":1,\"edu.mz\":1,\"edu.ng\":1,\"edu.ni\":1,\"edu.nr\":1,\"edu.om\":1,\"edu.pa\":1,\"edu.pe\":1,\"edu.pf\":1,\"edu.ph\":1,\"edu.pk\":1,\"edu.pl\":1,\"edu.pn\":1,\"edu.pr\":1,\"edu.ps\":1,\"edu.pt\":1,\"edu.py\":1,\"edu.qa\":1,\"edu.rs\":1,\"edu.ru\":1,\"edu.sa\":1,\"edu.sb\":1,\"edu.sc\":1,\"edu.sd\":1,\"edu.sg\":1,\"edu.sl\":1,\"edu.sn\":1,\"edu.so\":1,\"edu.ss\":1,\"edu.st\":1,\"edu.sv\":1,\"edu.sy\":1,\"edu.tj\":1,\"edu.tm\":1,\"edu.to\":1,\"edu.tr\":1,\"edu.tt\":1,\"edu.tw\":1,\"edu.ua\":1,\"edu.uy\":1,\"edu.vc\":1,\"edu.ve\":1,\"edu.vn\":1,\"edu.vu\":1,\"edu.ws\":1,\"edu.za\":1,\"edu.zm\":1,\"education.museum\":1,\"educational.museum\":1,\"educator.aero\":1,\"edugit.org\":1,\"edunet.tn\":1,\"ee.eu.org\":1,\"egersund.no\":1,\"egyptian.museum\":1,\"ehime.jp\":1,\"eid.no\":1,\"eidfjord.no\":1,\"eidsberg.no\":1,\"eidskog.no\":1,\"eidsvoll.no\":1,\"eigersund.no\":1,\"eiheiji.fukui.jp\":1,\"eisenbahn.museum\":1,\"ekloges.cy\":1,\"elasticbeanstalk.com\":1,\"elb.amazonaws.com\":2,\"elb.amazonaws.com.cn\":2,\"elblag.pl\":1,\"elburg.museum\":1,\"elk.pl\":1,\"elvendrell.museum\":1,\"elverum.no\":1,\"emb.kw\":1,\"embaixada.st\":1,\"embetsu.hokkaido.jp\":1,\"embroidery.museum\":1,\"emergency.aero\":1,\"emilia-romagna.it\":1,\"emiliaromagna.it\":1,\"emp.br\":1,\"empresa.bo\":1,\"emr.it\":1,\"en-root.fr\":1,\"en.it\":1,\"ena.gifu.jp\":1,\"encyclopedic.museum\":1,\"endofinternet.net\":1,\"endofinternet.org\":1,\"endoftheinternet.org\":1,\"enebakk.no\":1,\"enf.br\":1,\"eng.br\":1,\"eng.pro\":1,\"engerdal.no\":1,\"engine.aero\":1,\"engineer.aero\":1,\"england.museum\":1,\"eniwa.hokkaido.jp\":1,\"enna.it\":1,\"enonic.io\":1,\"ens.tn\":1,\"ent.platform.sh\":1,\"enterprisecloud.nu\":1,\"entertainment.aero\":1,\"entomology.museum\":1,\"environment.museum\":1,\"environmentalconservation.museum\":1,\"epilepsy.museum\":1,\"equipment.aero\":1,\"er\":2,\"erimo.hokkaido.jp\":1,\"erotica.hu\":1,\"erotika.hu\":1,\"es.ax\":1,\"es.eu.org\":1,\"es.gov.br\":1,\"es.kr\":1,\"es.leg.br\":1,\"esan.hokkaido.jp\":1,\"esashi.hokkaido.jp\":1,\"esp.br\":1,\"essex.museum\":1,\"est-a-la-maison.com\":1,\"est-a-la-masion.com\":1,\"est-le-patron.com\":1,\"est-mon-blogueur.com\":1,\"est.pr\":1,\"estate.museum\":1,\"etajima.hiroshima.jp\":1,\"etc.br\":1,\"ethnology.museum\":1,\"eti.br\":1,\"etne.no\":1,\"etnedal.no\":1,\"eu-1.evennode.com\":1,\"eu-2.evennode.com\":1,\"eu-3.evennode.com\":1,\"eu-4.evennode.com\":1,\"eu-central-1.elasticbeanstalk.com\":1,\"eu-west-1.elasticbeanstalk.com\":1,\"eu-west-2.elasticbeanstalk.com\":1,\"eu-west-3.elasticbeanstalk.com\":1,\"eu.ax\":1,\"eu.com\":1,\"eu.int\":1,\"eu.meteorapp.com\":1,\"eu.org\":1,\"eu.platform.sh\":1,\"eun.eg\":1,\"evenassi.no\":1,\"evenes.no\":1,\"evje-og-hornnes.no\":1,\"ex.futurecms.at\":2,\"ex.ortsinfo.at\":2,\"exchange.aero\":1,\"exeter.museum\":1,\"exhibition.museum\":1,\"exnet.su\":1,\"experts-comptables.fr\":1,\"express.aero\":1,\"f.bg\":1,\"f.se\":1,\"fam.pk\":1,\"family.museum\":1,\"familyds.com\":1,\"familyds.net\":1,\"familyds.org\":1,\"fantasyleague.cc\":1,\"far.br\":1,\"farm.museum\":1,\"farmequipment.museum\":1,\"farmers.museum\":1,\"farmstead.museum\":1,\"farsund.no\":1,\"fastly-terrarium.com\":1,\"fastlylb.net\":1,\"fastvps-server.com\":1,\"fastvps.host\":1,\"fastvps.site\":1,\"fauske.no\":1,\"fbx-os.fr\":1,\"fbxos.fr\":1,\"fc.it\":1,\"fe.it\":1,\"fed.us\":1,\"federation.aero\":1,\"fedje.no\":1,\"fedorainfracloud.org\":1,\"fedorapeople.org\":1,\"feira.br\":1,\"fermo.it\":1,\"ferrara.it\":1,\"feste-ip.net\":1,\"fet.no\":1,\"fetsund.no\":1,\"fg.it\":1,\"fh.se\":1,\"fhapp.xyz\":1,\"fhs.no\":1,\"fhsk.se\":1,\"fhv.se\":1,\"fi.cloudplatform.fi\":1,\"fi.cr\":1,\"fi.eu.org\":1,\"fi.it\":1,\"fie.ee\":1,\"field.museum\":1,\"figueres.museum\":1,\"filatelia.museum\":1,\"filegear-au.me\":1,\"filegear-de.me\":1,\"filegear-gb.me\":1,\"filegear-ie.me\":1,\"filegear-jp.me\":1,\"filegear-sg.me\":1,\"filegear.me\":1,\"film.hu\":1,\"film.museum\":1,\"fin.ci\":1,\"fin.ec\":1,\"fin.tn\":1,\"fineart.museum\":1,\"finearts.museum\":1,\"finland.museum\":1,\"finnoy.no\":1,\"firebaseapp.com\":1,\"firenet.ch\":2,\"firenze.it\":1,\"firewall-gateway.com\":1,\"firewall-gateway.de\":1,\"firewall-gateway.net\":1,\"firm.co\":1,\"firm.dk\":1,\"firm.ht\":1,\"firm.in\":1,\"firm.nf\":1,\"firm.ng\":1,\"firm.ro\":1,\"firm.ve\":1,\"fitjar.no\":1,\"fj.cn\":1,\"fjaler.no\":1,\"fjell.no\":1,\"fk\":2,\"fl.us\":1,\"fla.no\":1,\"flakstad.no\":1,\"flanders.museum\":1,\"flatanger.no\":1,\"flekkefjord.no\":1,\"flesberg.no\":1,\"flight.aero\":1,\"flog.br\":1,\"flora.no\":1,\"florence.it\":1,\"florida.museum\":1,\"floripa.br\":1,\"floro.no\":1,\"flt.cloud.muni.cz\":1,\"fly.dev\":1,\"flynnhosting.net\":1,\"fm.br\":1,\"fm.it\":1,\"fm.no\":1,\"fnd.br\":1,\"fnwk.site\":1,\"foggia.it\":1,\"folionetwork.site\":1,\"folkebibl.no\":1,\"folldal.no\":1,\"for-better.biz\":1,\"for-more.biz\":1,\"for-our.info\":1,\"for-some.biz\":1,\"for-the.biz\":1,\"for.men\":1,\"for.mom\":1,\"for.one\":1,\"for.sale\":1,\"force.museum\":1,\"forde.no\":1,\"forgot.her.name\":1,\"forgot.his.name\":1,\"forli-cesena.it\":1,\"forlicesena.it\":1,\"forsand.no\":1,\"fortal.br\":1,\"forte.id\":1,\"fortmissoula.museum\":1,\"fortworth.museum\":1,\"forum.hu\":1,\"forumz.info\":1,\"fosnes.no\":1,\"fot.br\":1,\"foundation.museum\":1,\"foz.br\":1,\"fr.eu.org\":1,\"fr.it\":1,\"frana.no\":1,\"francaise.museum\":1,\"frankfurt.museum\":1,\"franziskaner.museum\":1,\"fredrikstad.no\":1,\"free.hr\":1,\"freebox-os.com\":1,\"freebox-os.fr\":1,\"freeboxos.com\":1,\"freeboxos.fr\":1,\"freeddns.org\":1,\"freeddns.us\":1,\"freedesktop.org\":1,\"freemasonry.museum\":1,\"freesite.host\":1,\"freetls.fastly.net\":1,\"frei.no\":1,\"freiburg.museum\":1,\"fribourg.museum\":1,\"friuli-v-giulia.it\":1,\"friuli-ve-giulia.it\":1,\"friuli-vegiulia.it\":1,\"friuli-venezia-giulia.it\":1,\"friuli-veneziagiulia.it\":1,\"friuli-vgiulia.it\":1,\"friuliv-giulia.it\":1,\"friulive-giulia.it\":1,\"friulivegiulia.it\":1,\"friulivenezia-giulia.it\":1,\"friuliveneziagiulia.it\":1,\"friulivgiulia.it\":1,\"frog.museum\":1,\"frogn.no\":1,\"froland.no\":1,\"from-ak.com\":1,\"from-al.com\":1,\"from-ar.com\":1,\"from-az.net\":1,\"from-ca.com\":1,\"from-co.net\":1,\"from-ct.com\":1,\"from-dc.com\":1,\"from-de.com\":1,\"from-fl.com\":1,\"from-ga.com\":1,\"from-hi.com\":1,\"from-ia.com\":1,\"from-id.com\":1,\"from-il.com\":1,\"from-in.com\":1,\"from-ks.com\":1,\"from-ky.com\":1,\"from-la.net\":1,\"from-ma.com\":1,\"from-md.com\":1,\"from-me.org\":1,\"from-mi.com\":1,\"from-mn.com\":1,\"from-mo.com\":1,\"from-ms.com\":1,\"from-mt.com\":1,\"from-nc.com\":1,\"from-nd.com\":1,\"from-ne.com\":1,\"from-nh.com\":1,\"from-nj.com\":1,\"from-nm.com\":1,\"from-nv.com\":1,\"from-ny.net\":1,\"from-oh.com\":1,\"from-ok.com\":1,\"from-or.com\":1,\"from-pa.com\":1,\"from-pr.com\":1,\"from-ri.com\":1,\"from-sc.com\":1,\"from-sd.com\":1,\"from-tn.com\":1,\"from-tx.com\":1,\"from-ut.com\":1,\"from-va.com\":1,\"from-vt.com\":1,\"from-wa.com\":1,\"from-wi.com\":1,\"from-wv.com\":1,\"from-wy.com\":1,\"from.hr\":1,\"frosinone.it\":1,\"frosta.no\":1,\"froya.no\":1,\"fst.br\":1,\"ftpaccess.cc\":1,\"fuchu.hiroshima.jp\":1,\"fuchu.tokyo.jp\":1,\"fuchu.toyama.jp\":1,\"fudai.iwate.jp\":1,\"fuefuki.yamanashi.jp\":1,\"fuel.aero\":1,\"fuettertdasnetz.de\":1,\"fuji.shizuoka.jp\":1,\"fujieda.shizuoka.jp\":1,\"fujiidera.osaka.jp\":1,\"fujikawa.shizuoka.jp\":1,\"fujikawa.yamanashi.jp\":1,\"fujikawaguchiko.yamanashi.jp\":1,\"fujimi.nagano.jp\":1,\"fujimi.saitama.jp\":1,\"fujimino.saitama.jp\":1,\"fujinomiya.shizuoka.jp\":1,\"fujioka.gunma.jp\":1,\"fujisato.akita.jp\":1,\"fujisawa.iwate.jp\":1,\"fujisawa.kanagawa.jp\":1,\"fujishiro.ibaraki.jp\":1,\"fujiyoshida.yamanashi.jp\":1,\"fukagawa.hokkaido.jp\":1,\"fukaya.saitama.jp\":1,\"fukuchi.fukuoka.jp\":1,\"fukuchiyama.kyoto.jp\":1,\"fukudomi.saga.jp\":1,\"fukui.fukui.jp\":1,\"fukui.jp\":1,\"fukumitsu.toyama.jp\":1,\"fukuoka.jp\":1,\"fukuroi.shizuoka.jp\":1,\"fukusaki.hyogo.jp\":1,\"fukushima.fukushima.jp\":1,\"fukushima.hokkaido.jp\":1,\"fukushima.jp\":1,\"fukuyama.hiroshima.jp\":1,\"funabashi.chiba.jp\":1,\"funagata.yamagata.jp\":1,\"funahashi.toyama.jp\":1,\"fundacio.museum\":1,\"fuoisku.no\":1,\"fuossko.no\":1,\"furano.hokkaido.jp\":1,\"furniture.museum\":1,\"furubira.hokkaido.jp\":1,\"furudono.fukushima.jp\":1,\"furukawa.miyagi.jp\":1,\"fusa.no\":1,\"fuso.aichi.jp\":1,\"fussa.tokyo.jp\":1,\"futaba.fukushima.jp\":1,\"futsu.nagasaki.jp\":1,\"futtsu.chiba.jp\":1,\"futurecms.at\":2,\"futurehosting.at\":1,\"futuremailing.at\":1,\"fvg.it\":1,\"fylkesbibl.no\":1,\"fyresdal.no\":1,\"g.bg\":1,\"g.se\":1,\"g.vbrplsbx.io\":1,\"g12.br\":1,\"ga.us\":1,\"gaivuotna.no\":1,\"gallery.museum\":1,\"galsa.no\":1,\"gamagori.aichi.jp\":1,\"game-host.org\":1,\"game-server.cc\":1,\"game.tw\":1,\"games.hu\":1,\"gamo.shiga.jp\":1,\"gamvik.no\":1,\"gangaviika.no\":1,\"gangwon.kr\":1,\"garden.museum\":1,\"gateway.museum\":1,\"gaular.no\":1,\"gausdal.no\":1,\"gb.com\":1,\"gb.net\":1,\"gc.ca\":1,\"gd.cn\":1,\"gda.pl\":1,\"gdansk.pl\":1,\"gdynia.pl\":1,\"ge.it\":1,\"geek.nz\":1,\"geekgalaxy.com\":1,\"geelvinck.museum\":1,\"gehirn.ne.jp\":1,\"geisei.kochi.jp\":1,\"gemological.museum\":1,\"gen.in\":1,\"gen.mi.us\":1,\"gen.ng\":1,\"gen.nz\":1,\"gen.tr\":1,\"genkai.saga.jp\":1,\"genoa.it\":1,\"genova.it\":1,\"gentapps.com\":1,\"gentlentapis.com\":1,\"geo.br\":1,\"geology.museum\":1,\"geometre-expert.fr\":1,\"georgia.museum\":1,\"georgia.su\":1,\"getmyip.com\":1,\"gets-it.net\":1,\"gg.ax\":1,\"ggf.br\":1,\"giehtavuoatna.no\":1,\"giessen.museum\":1,\"gifu.gifu.jp\":1,\"gifu.jp\":1,\"giize.com\":1,\"gildeskal.no\":1,\"ginan.gifu.jp\":1,\"ginowan.okinawa.jp\":1,\"ginoza.okinawa.jp\":1,\"giske.no\":1,\"git-pages.rit.edu\":1,\"git-repos.de\":1,\"gitapp.si\":1,\"github.io\":1,\"githubusercontent.com\":1,\"gitlab.io\":1,\"gitpage.si\":1,\"gjemnes.no\":1,\"gjerdrum.no\":1,\"gjerstad.no\":1,\"gjesdal.no\":1,\"gjovik.no\":1,\"glas.museum\":1,\"glass.museum\":1,\"gleeze.com\":1,\"gliding.aero\":1,\"glitch.me\":1,\"gliwice.pl\":1,\"global.prod.fastly.net\":1,\"global.ssl.fastly.net\":1,\"glogow.pl\":1,\"gloppen.no\":1,\"glug.org.uk\":1,\"gmina.pl\":1,\"gniezno.pl\":1,\"go.ci\":1,\"go.cr\":1,\"go.dyndns.org\":1,\"go.gov.br\":1,\"go.id\":1,\"go.it\":1,\"go.jp\":1,\"go.ke\":1,\"go.kr\":1,\"go.leg.br\":1,\"go.pw\":1,\"go.th\":1,\"go.tj\":1,\"go.tz\":1,\"go.ug\":1,\"gob.ar\":1,\"gob.bo\":1,\"gob.cl\":1,\"gob.do\":1,\"gob.ec\":1,\"gob.es\":1,\"gob.gt\":1,\"gob.hn\":1,\"gob.mx\":1,\"gob.ni\":1,\"gob.pa\":1,\"gob.pe\":1,\"gob.pk\":1,\"gob.sv\":1,\"gob.ve\":1,\"gobo.wakayama.jp\":1,\"godo.gifu.jp\":1,\"goiania.br\":1,\"goip.de\":1,\"gojome.akita.jp\":1,\"gok.pk\":1,\"gokase.miyazaki.jp\":1,\"gol.no\":1,\"golffan.us\":1,\"gon.pk\":1,\"gonohe.aomori.jp\":1,\"googleapis.com\":1,\"googlecode.com\":1,\"gop.pk\":1,\"gorge.museum\":1,\"gorizia.it\":1,\"gorlice.pl\":1,\"gos.pk\":1,\"gose.nara.jp\":1,\"gosen.niigata.jp\":1,\"goshiki.hyogo.jp\":1,\"gotdns.ch\":1,\"gotdns.com\":1,\"gotdns.org\":1,\"gotemba.shizuoka.jp\":1,\"goto.nagasaki.jp\":1,\"gotpantheon.com\":1,\"gotsu.shimane.jp\":1,\"gouv.bj\":1,\"gouv.ci\":1,\"gouv.fr\":1,\"gouv.ht\":1,\"gouv.km\":1,\"gouv.ml\":1,\"gouv.sn\":1,\"gov.ac\":1,\"gov.ae\":1,\"gov.af\":1,\"gov.al\":1,\"gov.ar\":1,\"gov.as\":1,\"gov.au\":1,\"gov.az\":1,\"gov.ba\":1,\"gov.bb\":1,\"gov.bf\":1,\"gov.bh\":1,\"gov.bm\":1,\"gov.bn\":1,\"gov.br\":1,\"gov.bs\":1,\"gov.bt\":1,\"gov.by\":1,\"gov.bz\":1,\"gov.cd\":1,\"gov.cl\":1,\"gov.cm\":1,\"gov.cn\":1,\"gov.co\":1,\"gov.cu\":1,\"gov.cx\":1,\"gov.cy\":1,\"gov.dm\":1,\"gov.do\":1,\"gov.dz\":1,\"gov.ec\":1,\"gov.ee\":1,\"gov.eg\":1,\"gov.et\":1,\"gov.fj\":1,\"gov.gd\":1,\"gov.ge\":1,\"gov.gh\":1,\"gov.gi\":1,\"gov.gn\":1,\"gov.gr\":1,\"gov.gu\":1,\"gov.gy\":1,\"gov.hk\":1,\"gov.ie\":1,\"gov.il\":1,\"gov.in\":1,\"gov.iq\":1,\"gov.ir\":1,\"gov.is\":1,\"gov.it\":1,\"gov.jo\":1,\"gov.kg\":1,\"gov.ki\":1,\"gov.km\":1,\"gov.kn\":1,\"gov.kp\":1,\"gov.kw\":1,\"gov.ky\":1,\"gov.kz\":1,\"gov.la\":1,\"gov.lb\":1,\"gov.lc\":1,\"gov.lk\":1,\"gov.lr\":1,\"gov.ls\":1,\"gov.lt\":1,\"gov.lv\":1,\"gov.ly\":1,\"gov.ma\":1,\"gov.me\":1,\"gov.mg\":1,\"gov.mk\":1,\"gov.ml\":1,\"gov.mn\":1,\"gov.mo\":1,\"gov.mr\":1,\"gov.ms\":1,\"gov.mu\":1,\"gov.mv\":1,\"gov.mw\":1,\"gov.my\":1,\"gov.mz\":1,\"gov.nc.tr\":1,\"gov.ng\":1,\"gov.nr\":1,\"gov.om\":1,\"gov.ph\":1,\"gov.pk\":1,\"gov.pl\":1,\"gov.pn\":1,\"gov.pr\":1,\"gov.ps\":1,\"gov.pt\":1,\"gov.py\":1,\"gov.qa\":1,\"gov.rs\":1,\"gov.ru\":1,\"gov.rw\":1,\"gov.sa\":1,\"gov.sb\":1,\"gov.sc\":1,\"gov.scot\":1,\"gov.sd\":1,\"gov.sg\":1,\"gov.sh\":1,\"gov.sl\":1,\"gov.so\":1,\"gov.ss\":1,\"gov.st\":1,\"gov.sx\":1,\"gov.sy\":1,\"gov.tj\":1,\"gov.tl\":1,\"gov.tm\":1,\"gov.tn\":1,\"gov.to\":1,\"gov.tr\":1,\"gov.tt\":1,\"gov.tw\":1,\"gov.ua\":1,\"gov.uk\":1,\"gov.vc\":1,\"gov.ve\":1,\"gov.vn\":1,\"gov.ws\":1,\"gov.za\":1,\"gov.zm\":1,\"gov.zw\":1,\"government.aero\":1,\"govt.nz\":1,\"gr.com\":1,\"gr.eu.org\":1,\"gr.it\":1,\"gr.jp\":1,\"grajewo.pl\":1,\"gran.no\":1,\"grandrapids.museum\":1,\"grane.no\":1,\"granvin.no\":1,\"graphox.us\":1,\"gratangen.no\":1,\"graz.museum\":1,\"greta.fr\":1,\"grimstad.no\":1,\"griw.gov.pl\":1,\"groks-the.info\":1,\"groks-this.info\":1,\"grondar.za\":1,\"grong.no\":1,\"grosseto.it\":1,\"groundhandling.aero\":1,\"group.aero\":1,\"grozny.ru\":1,\"grozny.su\":1,\"grp.lk\":1,\"gru.br\":1,\"grue.no\":1,\"gs.aa.no\":1,\"gs.ah.no\":1,\"gs.bu.no\":1,\"gs.cn\":1,\"gs.fm.no\":1,\"gs.hl.no\":1,\"gs.hm.no\":1,\"gs.jan-mayen.no\":1,\"gs.mr.no\":1,\"gs.nl.no\":1,\"gs.nt.no\":1,\"gs.of.no\":1,\"gs.ol.no\":1,\"gs.oslo.no\":1,\"gs.rl.no\":1,\"gs.sf.no\":1,\"gs.st.no\":1,\"gs.svalbard.no\":1,\"gs.tm.no\":1,\"gs.tr.no\":1,\"gs.va.no\":1,\"gs.vf.no\":1,\"gsj.bz\":1,\"gsm.pl\":1,\"gu.us\":1,\"guam.gu\":1,\"gub.uy\":1,\"guernsey.museum\":1,\"gujo.gifu.jp\":1,\"gulen.no\":1,\"gunma.jp\":1,\"guovdageaidnu.no\":1,\"gushikami.okinawa.jp\":1,\"gv.ao\":1,\"gv.at\":1,\"gv.vc\":1,\"gwangju.kr\":1,\"gwiddle.co.uk\":1,\"gx.cn\":1,\"gyeongbuk.kr\":1,\"gyeonggi.kr\":1,\"gyeongnam.kr\":1,\"gyokuto.kumamoto.jp\":1,\"gz.cn\":1,\"h.bg\":1,\"h.se\":1,\"ha.cn\":1,\"ha.no\":1,\"habikino.osaka.jp\":1,\"habmer.no\":1,\"haboro.hokkaido.jp\":1,\"hachijo.tokyo.jp\":1,\"hachinohe.aomori.jp\":1,\"hachioji.tokyo.jp\":1,\"hachirogata.akita.jp\":1,\"hadano.kanagawa.jp\":1,\"hadsel.no\":1,\"haebaru.okinawa.jp\":1,\"haga.tochigi.jp\":1,\"hagebostad.no\":1,\"hagi.yamaguchi.jp\":1,\"haibara.shizuoka.jp\":1,\"hakata.fukuoka.jp\":1,\"hakodate.hokkaido.jp\":1,\"hakone.kanagawa.jp\":1,\"hakuba.nagano.jp\":1,\"hakui.ishikawa.jp\":1,\"hakusan.ishikawa.jp\":1,\"halden.no\":1,\"half.host\":1,\"halloffame.museum\":1,\"halsa.no\":1,\"ham-radio-op.net\":1,\"hamada.shimane.jp\":1,\"hamamatsu.shizuoka.jp\":1,\"hamar.no\":1,\"hamaroy.no\":1,\"hamatama.saga.jp\":1,\"hamatonbetsu.hokkaido.jp\":1,\"hamburg.museum\":1,\"hammarfeasta.no\":1,\"hammerfest.no\":1,\"hamura.tokyo.jp\":1,\"hanamaki.iwate.jp\":1,\"hanamigawa.chiba.jp\":1,\"hanawa.fukushima.jp\":1,\"handa.aichi.jp\":1,\"handson.museum\":1,\"hanggliding.aero\":1,\"hannan.osaka.jp\":1,\"hanno.saitama.jp\":1,\"hanyu.saitama.jp\":1,\"hapmir.no\":1,\"happou.akita.jp\":1,\"hara.nagano.jp\":1,\"haram.no\":1,\"hareid.no\":1,\"harima.hyogo.jp\":1,\"harstad.no\":1,\"harvestcelebration.museum\":1,\"hasama.oita.jp\":1,\"hasami.nagasaki.jp\":1,\"hashbang.sh\":1,\"hashikami.aomori.jp\":1,\"hashima.gifu.jp\":1,\"hashimoto.wakayama.jp\":1,\"hasuda.saitama.jp\":1,\"hasura-app.io\":1,\"hasura.app\":1,\"hasvik.no\":1,\"hatogaya.saitama.jp\":1,\"hatoyama.saitama.jp\":1,\"hatsukaichi.hiroshima.jp\":1,\"hattfjelldal.no\":1,\"haugesund.no\":1,\"hawaii.museum\":1,\"hayakawa.yamanashi.jp\":1,\"hayashima.okayama.jp\":1,\"hazu.aichi.jp\":1,\"hb.cldmail.ru\":1,\"hb.cn\":1,\"he.cn\":1,\"health-carereform.com\":1,\"health.museum\":1,\"health.nz\":1,\"health.vn\":1,\"heguri.nara.jp\":1,\"heimatunduhren.museum\":1,\"hekinan.aichi.jp\":1,\"hellas.museum\":1,\"helsinki.museum\":1,\"hembygdsforbund.museum\":1,\"hemne.no\":1,\"hemnes.no\":1,\"hemsedal.no\":1,\"hepforge.org\":1,\"herad.no\":1,\"here-for-more.info\":1,\"heritage.museum\":1,\"herokuapp.com\":1,\"herokussl.com\":1,\"heroy.more-og-romsdal.no\":1,\"heroy.nordland.no\":1,\"hi.cn\":1,\"hi.us\":1,\"hicam.net\":1,\"hichiso.gifu.jp\":1,\"hida.gifu.jp\":1,\"hidaka.hokkaido.jp\":1,\"hidaka.kochi.jp\":1,\"hidaka.saitama.jp\":1,\"hidaka.wakayama.jp\":1,\"hidora.com\":1,\"higashi.fukuoka.jp\":1,\"higashi.fukushima.jp\":1,\"higashi.okinawa.jp\":1,\"higashiagatsuma.gunma.jp\":1,\"higashichichibu.saitama.jp\":1,\"higashihiroshima.hiroshima.jp\":1,\"higashiizu.shizuoka.jp\":1,\"higashiizumo.shimane.jp\":1,\"higashikagawa.kagawa.jp\":1,\"higashikagura.hokkaido.jp\":1,\"higashikawa.hokkaido.jp\":1,\"higashikurume.tokyo.jp\":1,\"higashimatsushima.miyagi.jp\":1,\"higashimatsuyama.saitama.jp\":1,\"higashimurayama.tokyo.jp\":1,\"higashinaruse.akita.jp\":1,\"higashine.yamagata.jp\":1,\"higashiomi.shiga.jp\":1,\"higashiosaka.osaka.jp\":1,\"higashishirakawa.gifu.jp\":1,\"higashisumiyoshi.osaka.jp\":1,\"higashitsuno.kochi.jp\":1,\"higashiura.aichi.jp\":1,\"higashiyama.kyoto.jp\":1,\"higashiyamato.tokyo.jp\":1,\"higashiyodogawa.osaka.jp\":1,\"higashiyoshino.nara.jp\":1,\"hiji.oita.jp\":1,\"hikari.yamaguchi.jp\":1,\"hikawa.shimane.jp\":1,\"hikimi.shimane.jp\":1,\"hikone.shiga.jp\":1,\"himeji.hyogo.jp\":1,\"himeshima.oita.jp\":1,\"himi.toyama.jp\":1,\"hino.tokyo.jp\":1,\"hino.tottori.jp\":1,\"hinode.tokyo.jp\":1,\"hinohara.tokyo.jp\":1,\"hioki.kagoshima.jp\":1,\"hirado.nagasaki.jp\":1,\"hiraizumi.iwate.jp\":1,\"hirakata.osaka.jp\":1,\"hiranai.aomori.jp\":1,\"hirara.okinawa.jp\":1,\"hirata.fukushima.jp\":1,\"hiratsuka.kanagawa.jp\":1,\"hiraya.nagano.jp\":1,\"hirogawa.wakayama.jp\":1,\"hirokawa.fukuoka.jp\":1,\"hirono.fukushima.jp\":1,\"hirono.iwate.jp\":1,\"hiroo.hokkaido.jp\":1,\"hirosaki.aomori.jp\":1,\"hiroshima.jp\":1,\"hisayama.fukuoka.jp\":1,\"histoire.museum\":1,\"historical.museum\":1,\"historicalsociety.museum\":1,\"historichouses.museum\":1,\"historisch.museum\":1,\"historisches.museum\":1,\"history.museum\":1,\"historyofscience.museum\":1,\"hita.oita.jp\":1,\"hitachi.ibaraki.jp\":1,\"hitachinaka.ibaraki.jp\":1,\"hitachiomiya.ibaraki.jp\":1,\"hitachiota.ibaraki.jp\":1,\"hitra.no\":1,\"hizen.saga.jp\":1,\"hjartdal.no\":1,\"hjelmeland.no\":1,\"hk.cn\":1,\"hk.com\":1,\"hk.org\":1,\"hl.cn\":1,\"hl.no\":1,\"hm.no\":1,\"hn.cn\":1,\"hobby-site.com\":1,\"hobby-site.org\":1,\"hobol.no\":1,\"hof.no\":1,\"hofu.yamaguchi.jp\":1,\"hokkaido.jp\":1,\"hokksund.no\":1,\"hokuryu.hokkaido.jp\":1,\"hokuto.hokkaido.jp\":1,\"hokuto.yamanashi.jp\":1,\"hol.no\":1,\"hole.no\":1,\"holmestrand.no\":1,\"holtalen.no\":1,\"home-webserver.de\":1,\"home.dyndns.org\":1,\"homebuilt.aero\":1,\"homedns.org\":1,\"homeftp.net\":1,\"homeftp.org\":1,\"homeip.net\":1,\"homelink.one\":1,\"homelinux.com\":1,\"homelinux.net\":1,\"homelinux.org\":1,\"homeoffice.gov.uk\":1,\"homesecuritymac.com\":1,\"homesecuritypc.com\":1,\"homeunix.com\":1,\"homeunix.net\":1,\"homeunix.org\":1,\"honai.ehime.jp\":1,\"honbetsu.hokkaido.jp\":1,\"honefoss.no\":1,\"hongo.hiroshima.jp\":1,\"honjo.akita.jp\":1,\"honjo.saitama.jp\":1,\"honjyo.akita.jp\":1,\"hopto.me\":1,\"hopto.org\":1,\"hornindal.no\":1,\"horokanai.hokkaido.jp\":1,\"horology.museum\":1,\"horonobe.hokkaido.jp\":1,\"horten.no\":1,\"hostedpi.com\":1,\"hosting-cluster.nl\":1,\"hosting.myjino.ru\":2,\"hostyhosting.io\":1,\"hotel.hu\":1,\"hotel.lk\":1,\"hotel.tz\":1,\"house.museum\":1,\"hoyanger.no\":1,\"hoylandet.no\":1,\"hr.eu.org\":1,\"hs.kr\":1,\"hs.run\":1,\"hs.zone\":1,\"hu.com\":1,\"hu.eu.org\":1,\"hu.net\":1,\"huissier-justice.fr\":1,\"humanities.museum\":1,\"hurdal.no\":1,\"hurum.no\":1,\"hvaler.no\":1,\"hyllestad.no\":1,\"hyogo.jp\":1,\"hyuga.miyazaki.jp\":1,\"hzc.io\":1,\"i.bg\":1,\"i.ng\":1,\"i.ph\":1,\"i.se\":1,\"i234.me\":1,\"ia.us\":1,\"iamallama.com\":1,\"ibara.okayama.jp\":1,\"ibaraki.ibaraki.jp\":1,\"ibaraki.jp\":1,\"ibaraki.osaka.jp\":1,\"ibestad.no\":1,\"ibigawa.gifu.jp\":1,\"ic.gov.pl\":1,\"ichiba.tokushima.jp\":1,\"ichihara.chiba.jp\":1,\"ichikai.tochigi.jp\":1,\"ichikawa.chiba.jp\":1,\"ichikawa.hyogo.jp\":1,\"ichikawamisato.yamanashi.jp\":1,\"ichinohe.iwate.jp\":1,\"ichinomiya.aichi.jp\":1,\"ichinomiya.chiba.jp\":1,\"ichinoseki.iwate.jp\":1,\"id.au\":1,\"id.ir\":1,\"id.lv\":1,\"id.ly\":1,\"id.us\":1,\"ide.kyoto.jp\":1,\"idf.il\":1,\"idrett.no\":1,\"idv.hk\":1,\"idv.tw\":1,\"ie.eu.org\":1,\"if.ua\":1,\"iglesias-carbonia.it\":1,\"iglesiascarbonia.it\":1,\"iheya.okinawa.jp\":1,\"iida.nagano.jp\":1,\"iide.yamagata.jp\":1,\"iijima.nagano.jp\":1,\"iitate.fukushima.jp\":1,\"iiyama.nagano.jp\":1,\"iizuka.fukuoka.jp\":1,\"iizuna.nagano.jp\":1,\"ikaruga.nara.jp\":1,\"ikata.ehime.jp\":1,\"ikawa.akita.jp\":1,\"ikeda.fukui.jp\":1,\"ikeda.gifu.jp\":1,\"ikeda.hokkaido.jp\":1,\"ikeda.nagano.jp\":1,\"ikeda.osaka.jp\":1,\"iki.fi\":1,\"iki.nagasaki.jp\":1,\"ikoma.nara.jp\":1,\"ikusaka.nagano.jp\":1,\"il.eu.org\":1,\"il.us\":1,\"ilawa.pl\":1,\"illustration.museum\":1,\"ilovecollege.info\":1,\"im.it\":1,\"imabari.ehime.jp\":1,\"imageandsound.museum\":1,\"imakane.hokkaido.jp\":1,\"imari.saga.jp\":1,\"imb.br\":1,\"imizu.toyama.jp\":1,\"imperia.it\":1,\"impertrix.com\":1,\"impertrixcdn.com\":1,\"in-addr.arpa\":1,\"in-berlin.de\":1,\"in-brb.de\":1,\"in-butter.de\":1,\"in-dsl.de\":1,\"in-dsl.net\":1,\"in-dsl.org\":1,\"in-the-band.net\":1,\"in-vpn.de\":1,\"in-vpn.net\":1,\"in-vpn.org\":1,\"in.eu.org\":1,\"in.futurecms.at\":2,\"in.london\":1,\"in.na\":1,\"in.net\":1,\"in.ni\":1,\"in.rs\":1,\"in.th\":1,\"in.ua\":1,\"in.us\":1,\"ina.ibaraki.jp\":1,\"ina.nagano.jp\":1,\"ina.saitama.jp\":1,\"inabe.mie.jp\":1,\"inagawa.hyogo.jp\":1,\"inagi.tokyo.jp\":1,\"inami.toyama.jp\":1,\"inami.wakayama.jp\":1,\"inashiki.ibaraki.jp\":1,\"inatsuki.fukuoka.jp\":1,\"inawashiro.fukushima.jp\":1,\"inazawa.aichi.jp\":1,\"inc.hk\":1,\"incheon.kr\":1,\"ind.br\":1,\"ind.gt\":1,\"ind.in\":1,\"ind.kw\":1,\"ind.tn\":1,\"inderoy.no\":1,\"indian.museum\":1,\"indiana.museum\":1,\"indianapolis.museum\":1,\"indianmarket.museum\":1,\"indie.porn\":1,\"indigena.bo\":1,\"industria.bo\":1,\"ine.kyoto.jp\":1,\"inf.br\":1,\"inf.cu\":1,\"inf.mk\":1,\"inf.ua\":1,\"info.at\":1,\"info.au\":1,\"info.az\":1,\"info.bb\":1,\"info.bo\":1,\"info.co\":1,\"info.cx\":1,\"info.ec\":1,\"info.et\":1,\"info.fj\":1,\"info.gu\":1,\"info.ht\":1,\"info.hu\":1,\"info.ke\":1,\"info.ki\":1,\"info.la\":1,\"info.ls\":1,\"info.mv\":1,\"info.na\":1,\"info.nf\":1,\"info.ni\":1,\"info.nr\":1,\"info.pk\":1,\"info.pl\":1,\"info.pr\":1,\"info.ro\":1,\"info.sd\":1,\"info.tn\":1,\"info.tr\":1,\"info.tt\":1,\"info.tz\":1,\"info.ve\":1,\"info.vn\":1,\"info.zm\":1,\"ing.pa\":1,\"ingatlan.hu\":1,\"ino.kochi.jp\":1,\"instantcloud.cn\":1,\"insurance.aero\":1,\"int.ar\":1,\"int.az\":1,\"int.bo\":1,\"int.ci\":1,\"int.co\":1,\"int.eu.org\":1,\"int.is\":1,\"int.la\":1,\"int.lk\":1,\"int.mv\":1,\"int.mw\":1,\"int.ni\":1,\"int.pt\":1,\"int.ru\":1,\"int.tj\":1,\"int.tt\":1,\"int.ve\":1,\"int.vn\":1,\"intelligence.museum\":1,\"interactive.museum\":1,\"internet-dns.de\":1,\"intl.tn\":1,\"inuyama.aichi.jp\":1,\"inzai.chiba.jp\":1,\"io.kg\":1,\"iobb.net\":1,\"ip6.arpa\":1,\"ipifony.net\":1,\"iraq.museum\":1,\"iris.arpa\":1,\"iron.museum\":1,\"iruma.saitama.jp\":1,\"is-a-anarchist.com\":1,\"is-a-blogger.com\":1,\"is-a-bookkeeper.com\":1,\"is-a-bruinsfan.org\":1,\"is-a-bulls-fan.com\":1,\"is-a-candidate.org\":1,\"is-a-caterer.com\":1,\"is-a-celticsfan.org\":1,\"is-a-chef.com\":1,\"is-a-chef.net\":1,\"is-a-chef.org\":1,\"is-a-conservative.com\":1,\"is-a-cpa.com\":1,\"is-a-cubicle-slave.com\":1,\"is-a-democrat.com\":1,\"is-a-designer.com\":1,\"is-a-doctor.com\":1,\"is-a-financialadvisor.com\":1,\"is-a-geek.com\":1,\"is-a-geek.net\":1,\"is-a-geek.org\":1,\"is-a-green.com\":1,\"is-a-guru.com\":1,\"is-a-hard-worker.com\":1,\"is-a-hunter.com\":1,\"is-a-knight.org\":1,\"is-a-landscaper.com\":1,\"is-a-lawyer.com\":1,\"is-a-liberal.com\":1,\"is-a-libertarian.com\":1,\"is-a-linux-user.org\":1,\"is-a-llama.com\":1,\"is-a-musician.com\":1,\"is-a-nascarfan.com\":1,\"is-a-nurse.com\":1,\"is-a-painter.com\":1,\"is-a-patsfan.org\":1,\"is-a-personaltrainer.com\":1,\"is-a-photographer.com\":1,\"is-a-player.com\":1,\"is-a-republican.com\":1,\"is-a-rockstar.com\":1,\"is-a-socialist.com\":1,\"is-a-soxfan.org\":1,\"is-a-student.com\":1,\"is-a-teacher.com\":1,\"is-a-techie.com\":1,\"is-a-therapist.com\":1,\"is-an-accountant.com\":1,\"is-an-actor.com\":1,\"is-an-actress.com\":1,\"is-an-anarchist.com\":1,\"is-an-artist.com\":1,\"is-an-engineer.com\":1,\"is-an-entertainer.com\":1,\"is-by.us\":1,\"is-certified.com\":1,\"is-found.org\":1,\"is-gone.com\":1,\"is-into-anime.com\":1,\"is-into-cars.com\":1,\"is-into-cartoons.com\":1,\"is-into-games.com\":1,\"is-leet.com\":1,\"is-lost.org\":1,\"is-not-certified.com\":1,\"is-saved.org\":1,\"is-slick.com\":1,\"is-uberleet.com\":1,\"is-very-bad.org\":1,\"is-very-evil.org\":1,\"is-very-good.org\":1,\"is-very-nice.org\":1,\"is-very-sweet.org\":1,\"is-with-theband.com\":1,\"is.eu.org\":1,\"is.gov.pl\":1,\"is.it\":1,\"isa-geek.com\":1,\"isa-geek.net\":1,\"isa-geek.org\":1,\"isa-hockeynut.com\":1,\"isa.kagoshima.jp\":1,\"isa.us\":1,\"isahaya.nagasaki.jp\":1,\"ise.mie.jp\":1,\"isehara.kanagawa.jp\":1,\"isen.kagoshima.jp\":1,\"isernia.it\":1,\"iserv.dev\":1,\"isesaki.gunma.jp\":1,\"ishigaki.okinawa.jp\":1,\"ishikari.hokkaido.jp\":1,\"ishikawa.fukushima.jp\":1,\"ishikawa.jp\":1,\"ishikawa.okinawa.jp\":1,\"ishinomaki.miyagi.jp\":1,\"isla.pr\":1,\"isleofman.museum\":1,\"isshiki.aichi.jp\":1,\"issmarterthanyou.com\":1,\"isteingeek.de\":1,\"istmein.de\":1,\"isumi.chiba.jp\":1,\"it.ao\":1,\"it.eu.org\":1,\"itabashi.tokyo.jp\":1,\"itako.ibaraki.jp\":1,\"itakura.gunma.jp\":1,\"itami.hyogo.jp\":1,\"itano.tokushima.jp\":1,\"itayanagi.aomori.jp\":1,\"ito.shizuoka.jp\":1,\"itoigawa.niigata.jp\":1,\"itoman.okinawa.jp\":1,\"its.me\":1,\"ivano-frankivsk.ua\":1,\"ivanovo.su\":1,\"iveland.no\":1,\"ivgu.no\":1,\"iwade.wakayama.jp\":1,\"iwafune.tochigi.jp\":1,\"iwaizumi.iwate.jp\":1,\"iwaki.fukushima.jp\":1,\"iwakuni.yamaguchi.jp\":1,\"iwakura.aichi.jp\":1,\"iwama.ibaraki.jp\":1,\"iwamizawa.hokkaido.jp\":1,\"iwanai.hokkaido.jp\":1,\"iwanuma.miyagi.jp\":1,\"iwata.shizuoka.jp\":1,\"iwate.iwate.jp\":1,\"iwate.jp\":1,\"iwatsuki.saitama.jp\":1,\"iwi.nz\":1,\"iyo.ehime.jp\":1,\"iz.hr\":1,\"izena.okinawa.jp\":1,\"izu.shizuoka.jp\":1,\"izumi.kagoshima.jp\":1,\"izumi.osaka.jp\":1,\"izumiotsu.osaka.jp\":1,\"izumisano.osaka.jp\":1,\"izumizaki.fukushima.jp\":1,\"izumo.shimane.jp\":1,\"izumozaki.niigata.jp\":1,\"izunokuni.shizuoka.jp\":1,\"j.bg\":1,\"j.layershift.co.uk\":1,\"j.scaleforce.com.cy\":1,\"jab.br\":1,\"jambyl.su\":1,\"jamison.museum\":1,\"jampa.br\":1,\"jan-mayen.no\":1,\"jaworzno.pl\":1,\"jcloud.ik-server.com\":1,\"jdevcloud.com\":1,\"jdf.br\":1,\"jefferson.museum\":1,\"jeju.kr\":1,\"jelastic.dogado.eu\":1,\"jelastic.regruhosting.ru\":1,\"jelastic.saveincloud.net\":1,\"jelastic.team\":1,\"jele.cloud\":1,\"jele.club\":1,\"jele.host\":1,\"jele.io\":1,\"jele.site\":1,\"jelenia-gora.pl\":1,\"jeonbuk.kr\":1,\"jeonnam.kr\":1,\"jerusalem.museum\":1,\"jessheim.no\":1,\"jevnaker.no\":1,\"jewelry.museum\":1,\"jewish.museum\":1,\"jewishart.museum\":1,\"jfk.museum\":1,\"jgora.pl\":1,\"jinsekikogen.hiroshima.jp\":1,\"jl.cn\":1,\"jls-sto1.elastx.net\":1,\"jm\":2,\"joboji.iwate.jp\":1,\"jobs.tt\":1,\"joetsu.niigata.jp\":1,\"jogasz.hu\":1,\"johana.toyama.jp\":1,\"joinville.br\":1,\"jolster.no\":1,\"jondal.no\":1,\"jor.br\":1,\"jorpeland.no\":1,\"joso.ibaraki.jp\":1,\"journal.aero\":1,\"journalism.museum\":1,\"journalist.aero\":1,\"joyo.kyoto.jp\":1,\"jozi.biz\":1,\"jp.eu.org\":1,\"jp.kg\":1,\"jp.md\":1,\"jp.net\":1,\"jpn.com\":1,\"js.cn\":1,\"js.org\":1,\"judaica.museum\":1,\"judygarland.museum\":1,\"juedisches.museum\":1,\"juif.museum\":1,\"jur.pro\":1,\"jus.br\":1,\"jx.cn\":1,\"k.bg\":1,\"k.se\":1,\"k12.ak.us\":1,\"k12.al.us\":1,\"k12.ar.us\":1,\"k12.as.us\":1,\"k12.az.us\":1,\"k12.ca.us\":1,\"k12.co.us\":1,\"k12.ct.us\":1,\"k12.dc.us\":1,\"k12.de.us\":1,\"k12.ec\":1,\"k12.fl.us\":1,\"k12.ga.us\":1,\"k12.gu.us\":1,\"k12.ia.us\":1,\"k12.id.us\":1,\"k12.il\":1,\"k12.il.us\":1,\"k12.in.us\":1,\"k12.ks.us\":1,\"k12.ky.us\":1,\"k12.la.us\":1,\"k12.ma.us\":1,\"k12.md.us\":1,\"k12.me.us\":1,\"k12.mi.us\":1,\"k12.mn.us\":1,\"k12.mo.us\":1,\"k12.ms.us\":1,\"k12.mt.us\":1,\"k12.nc.us\":1,\"k12.ne.us\":1,\"k12.nh.us\":1,\"k12.nj.us\":1,\"k12.nm.us\":1,\"k12.nv.us\":1,\"k12.ny.us\":1,\"k12.oh.us\":1,\"k12.ok.us\":1,\"k12.or.us\":1,\"k12.pa.us\":1,\"k12.pr.us\":1,\"k12.sc.us\":1,\"k12.tn.us\":1,\"k12.tr\":1,\"k12.tx.us\":1,\"k12.ut.us\":1,\"k12.va.us\":1,\"k12.vi\":1,\"k12.vi.us\":1,\"k12.vt.us\":1,\"k12.wa.us\":1,\"k12.wi.us\":1,\"k12.wy.us\":1,\"kaas.gg\":1,\"kadena.okinawa.jp\":1,\"kadogawa.miyazaki.jp\":1,\"kadoma.osaka.jp\":1,\"kafjord.no\":1,\"kaga.ishikawa.jp\":1,\"kagami.kochi.jp\":1,\"kagamiishi.fukushima.jp\":1,\"kagamino.okayama.jp\":1,\"kagawa.jp\":1,\"kagoshima.jp\":1,\"kagoshima.kagoshima.jp\":1,\"kaho.fukuoka.jp\":1,\"kahoku.ishikawa.jp\":1,\"kahoku.yamagata.jp\":1,\"kai.yamanashi.jp\":1,\"kainan.tokushima.jp\":1,\"kainan.wakayama.jp\":1,\"kaisei.kanagawa.jp\":1,\"kaita.hiroshima.jp\":1,\"kaizuka.osaka.jp\":1,\"kakamigahara.gifu.jp\":1,\"kakegawa.shizuoka.jp\":1,\"kakinoki.shimane.jp\":1,\"kakogawa.hyogo.jp\":1,\"kakuda.miyagi.jp\":1,\"kalisz.pl\":1,\"kalmykia.ru\":1,\"kalmykia.su\":1,\"kaluga.su\":1,\"kamagaya.chiba.jp\":1,\"kamaishi.iwate.jp\":1,\"kamakura.kanagawa.jp\":1,\"kameoka.kyoto.jp\":1,\"kameyama.mie.jp\":1,\"kami.kochi.jp\":1,\"kami.miyagi.jp\":1,\"kamiamakusa.kumamoto.jp\":1,\"kamifurano.hokkaido.jp\":1,\"kamigori.hyogo.jp\":1,\"kamiichi.toyama.jp\":1,\"kamiizumi.saitama.jp\":1,\"kamijima.ehime.jp\":1,\"kamikawa.hokkaido.jp\":1,\"kamikawa.hyogo.jp\":1,\"kamikawa.saitama.jp\":1,\"kamikitayama.nara.jp\":1,\"kamikoani.akita.jp\":1,\"kamimine.saga.jp\":1,\"kaminokawa.tochigi.jp\":1,\"kaminoyama.yamagata.jp\":1,\"kamioka.akita.jp\":1,\"kamisato.saitama.jp\":1,\"kamishihoro.hokkaido.jp\":1,\"kamisu.ibaraki.jp\":1,\"kamisunagawa.hokkaido.jp\":1,\"kamitonda.wakayama.jp\":1,\"kamitsue.oita.jp\":1,\"kamo.kyoto.jp\":1,\"kamo.niigata.jp\":1,\"kamoenai.hokkaido.jp\":1,\"kamogawa.chiba.jp\":1,\"kanagawa.jp\":1,\"kanan.osaka.jp\":1,\"kanazawa.ishikawa.jp\":1,\"kanegasaki.iwate.jp\":1,\"kaneyama.fukushima.jp\":1,\"kaneyama.yamagata.jp\":1,\"kani.gifu.jp\":1,\"kanie.aichi.jp\":1,\"kanmaki.nara.jp\":1,\"kanna.gunma.jp\":1,\"kannami.shizuoka.jp\":1,\"kanonji.kagawa.jp\":1,\"kanoya.kagoshima.jp\":1,\"kanra.gunma.jp\":1,\"kanuma.tochigi.jp\":1,\"kanzaki.saga.jp\":1,\"karacol.su\":1,\"karaganda.su\":1,\"karasjohka.no\":1,\"karasjok.no\":1,\"karasuyama.tochigi.jp\":1,\"karate.museum\":1,\"karatsu.saga.jp\":1,\"karelia.su\":1,\"karikatur.museum\":1,\"kariwa.niigata.jp\":1,\"kariya.aichi.jp\":1,\"karlsoy.no\":1,\"karmoy.no\":1,\"karpacz.pl\":1,\"kartuzy.pl\":1,\"karuizawa.nagano.jp\":1,\"karumai.iwate.jp\":1,\"kasahara.gifu.jp\":1,\"kasai.hyogo.jp\":1,\"kasama.ibaraki.jp\":1,\"kasamatsu.gifu.jp\":1,\"kasaoka.okayama.jp\":1,\"kashiba.nara.jp\":1,\"kashihara.nara.jp\":1,\"kashima.ibaraki.jp\":1,\"kashima.saga.jp\":1,\"kashiwa.chiba.jp\":1,\"kashiwara.osaka.jp\":1,\"kashiwazaki.niigata.jp\":1,\"kasserver.com\":1,\"kasuga.fukuoka.jp\":1,\"kasuga.hyogo.jp\":1,\"kasugai.aichi.jp\":1,\"kasukabe.saitama.jp\":1,\"kasumigaura.ibaraki.jp\":1,\"kasuya.fukuoka.jp\":1,\"kaszuby.pl\":1,\"katagami.akita.jp\":1,\"katano.osaka.jp\":1,\"katashina.gunma.jp\":1,\"katori.chiba.jp\":1,\"katowice.pl\":1,\"katsuragi.nara.jp\":1,\"katsuragi.wakayama.jp\":1,\"katsushika.tokyo.jp\":1,\"katsuura.chiba.jp\":1,\"katsuyama.fukui.jp\":1,\"kautokeino.no\":1,\"kawaba.gunma.jp\":1,\"kawachinagano.osaka.jp\":1,\"kawagoe.mie.jp\":1,\"kawagoe.saitama.jp\":1,\"kawaguchi.saitama.jp\":1,\"kawahara.tottori.jp\":1,\"kawai.iwate.jp\":1,\"kawai.nara.jp\":1,\"kawajima.saitama.jp\":1,\"kawakami.nagano.jp\":1,\"kawakami.nara.jp\":1,\"kawakita.ishikawa.jp\":1,\"kawamata.fukushima.jp\":1,\"kawaminami.miyazaki.jp\":1,\"kawanabe.kagoshima.jp\":1,\"kawanehon.shizuoka.jp\":1,\"kawanishi.hyogo.jp\":1,\"kawanishi.nara.jp\":1,\"kawanishi.yamagata.jp\":1,\"kawara.fukuoka.jp\":1,\"kawasaki.jp\":2,\"kawasaki.miyagi.jp\":1,\"kawatana.nagasaki.jp\":1,\"kawaue.gifu.jp\":1,\"kawazu.shizuoka.jp\":1,\"kayabe.hokkaido.jp\":1,\"kazimierz-dolny.pl\":1,\"kazo.saitama.jp\":1,\"kazuno.akita.jp\":1,\"keisen.fukuoka.jp\":1,\"kembuchi.hokkaido.jp\":1,\"kep.tr\":1,\"kepno.pl\":1,\"ketrzyn.pl\":1,\"keymachine.de\":1,\"kg.kr\":1,\"kh\":2,\"kh.ua\":1,\"khakassia.su\":1,\"kharkiv.ua\":1,\"kharkov.ua\":1,\"kherson.ua\":1,\"khmelnitskiy.ua\":1,\"khmelnytskyi.ua\":1,\"khplay.nl\":1,\"kibichuo.okayama.jp\":1,\"kicks-ass.net\":1,\"kicks-ass.org\":1,\"kids.museum\":1,\"kids.us\":1,\"kiev.ua\":1,\"kiho.mie.jp\":1,\"kihoku.ehime.jp\":1,\"kijo.miyazaki.jp\":1,\"kikonai.hokkaido.jp\":1,\"kikuchi.kumamoto.jp\":1,\"kikugawa.shizuoka.jp\":1,\"kimino.wakayama.jp\":1,\"kimitsu.chiba.jp\":1,\"kimobetsu.hokkaido.jp\":1,\"kin.okinawa.jp\":1,\"kinghost.net\":1,\"kinko.kagoshima.jp\":1,\"kinokawa.wakayama.jp\":1,\"kira.aichi.jp\":1,\"kirkenes.no\":1,\"kirovograd.ua\":1,\"kiryu.gunma.jp\":1,\"kisarazu.chiba.jp\":1,\"kishiwada.osaka.jp\":1,\"kiso.nagano.jp\":1,\"kisofukushima.nagano.jp\":1,\"kisosaki.mie.jp\":1,\"kita.kyoto.jp\":1,\"kita.osaka.jp\":1,\"kita.tokyo.jp\":1,\"kitaaiki.nagano.jp\":1,\"kitaakita.akita.jp\":1,\"kitadaito.okinawa.jp\":1,\"kitagata.gifu.jp\":1,\"kitagata.saga.jp\":1,\"kitagawa.kochi.jp\":1,\"kitagawa.miyazaki.jp\":1,\"kitahata.saga.jp\":1,\"kitahiroshima.hokkaido.jp\":1,\"kitakami.iwate.jp\":1,\"kitakata.fukushima.jp\":1,\"kitakata.miyazaki.jp\":1,\"kitakyushu.jp\":2,\"kitami.hokkaido.jp\":1,\"kitamoto.saitama.jp\":1,\"kitanakagusuku.okinawa.jp\":1,\"kitashiobara.fukushima.jp\":1,\"kitaura.miyazaki.jp\":1,\"kitayama.wakayama.jp\":1,\"kiwa.mie.jp\":1,\"kiwi.nz\":1,\"kiyama.saga.jp\":1,\"kiyokawa.kanagawa.jp\":1,\"kiyosato.hokkaido.jp\":1,\"kiyose.tokyo.jp\":1,\"kiyosu.aichi.jp\":1,\"kizu.kyoto.jp\":1,\"klabu.no\":1,\"klepp.no\":1,\"klodzko.pl\":1,\"km.ua\":1,\"kmpsp.gov.pl\":1,\"knightpoint.systems\":1,\"knowsitall.info\":1,\"knx-server.net\":1,\"kobayashi.miyazaki.jp\":1,\"kobe.jp\":2,\"kobierzyce.pl\":1,\"kochi.jp\":1,\"kochi.kochi.jp\":1,\"kodaira.tokyo.jp\":1,\"koebenhavn.museum\":1,\"koeln.museum\":1,\"kofu.yamanashi.jp\":1,\"koga.fukuoka.jp\":1,\"koga.ibaraki.jp\":1,\"koganei.tokyo.jp\":1,\"koge.tottori.jp\":1,\"koka.shiga.jp\":1,\"kokonoe.oita.jp\":1,\"kokubunji.tokyo.jp\":1,\"kolobrzeg.pl\":1,\"komae.tokyo.jp\":1,\"komagane.nagano.jp\":1,\"komaki.aichi.jp\":1,\"komatsu.ishikawa.jp\":1,\"komatsushima.tokushima.jp\":1,\"komforb.se\":1,\"kommunalforbund.se\":1,\"kommune.no\":1,\"komono.mie.jp\":1,\"komoro.nagano.jp\":1,\"komvux.se\":1,\"konan.aichi.jp\":1,\"konan.shiga.jp\":1,\"kongsberg.no\":1,\"kongsvinger.no\":1,\"konin.pl\":1,\"konskowola.pl\":1,\"konsulat.gov.pl\":1,\"konyvelo.hu\":1,\"koori.fukushima.jp\":1,\"kopervik.no\":1,\"koriyama.fukushima.jp\":1,\"koryo.nara.jp\":1,\"kosai.shizuoka.jp\":1,\"kosaka.akita.jp\":1,\"kosei.shiga.jp\":1,\"koshigaya.saitama.jp\":1,\"koshimizu.hokkaido.jp\":1,\"koshu.yamanashi.jp\":1,\"kosuge.yamanashi.jp\":1,\"kota.aichi.jp\":1,\"koto.shiga.jp\":1,\"koto.tokyo.jp\":1,\"kotohira.kagawa.jp\":1,\"kotoura.tottori.jp\":1,\"kouhoku.saga.jp\":1,\"kounosu.saitama.jp\":1,\"kouyama.kagoshima.jp\":1,\"kouzushima.tokyo.jp\":1,\"koya.wakayama.jp\":1,\"koza.wakayama.jp\":1,\"kozagawa.wakayama.jp\":1,\"kozaki.chiba.jp\":1,\"kozow.com\":1,\"kppsp.gov.pl\":1,\"kr.com\":1,\"kr.eu.org\":1,\"kr.it\":1,\"kr.ua\":1,\"kraanghke.no\":1,\"kragero.no\":1,\"krakow.pl\":1,\"krasnik.pl\":1,\"krasnodar.su\":1,\"kristiansand.no\":1,\"kristiansund.no\":1,\"krodsherad.no\":1,\"krokstadelva.no\":1,\"krym.ua\":1,\"ks.ua\":1,\"ks.us\":1,\"kuchinotsu.nagasaki.jp\":1,\"kudamatsu.yamaguchi.jp\":1,\"kudoyama.wakayama.jp\":1,\"kui.hiroshima.jp\":1,\"kuji.iwate.jp\":1,\"kuju.oita.jp\":1,\"kujukuri.chiba.jp\":1,\"kuki.saitama.jp\":1,\"kumagaya.saitama.jp\":1,\"kumakogen.ehime.jp\":1,\"kumamoto.jp\":1,\"kumamoto.kumamoto.jp\":1,\"kumano.hiroshima.jp\":1,\"kumano.mie.jp\":1,\"kumatori.osaka.jp\":1,\"kumejima.okinawa.jp\":1,\"kumenan.okayama.jp\":1,\"kumiyama.kyoto.jp\":1,\"kunden.ortsinfo.at\":2,\"kunigami.okinawa.jp\":1,\"kunimi.fukushima.jp\":1,\"kunisaki.oita.jp\":1,\"kunitachi.tokyo.jp\":1,\"kunitomi.miyazaki.jp\":1,\"kunneppu.hokkaido.jp\":1,\"kunohe.iwate.jp\":1,\"kunst.museum\":1,\"kunstsammlung.museum\":1,\"kunstunddesign.museum\":1,\"kurashiki.okayama.jp\":1,\"kurate.fukuoka.jp\":1,\"kure.hiroshima.jp\":1,\"kurgan.su\":1,\"kuriyama.hokkaido.jp\":1,\"kurobe.toyama.jp\":1,\"kurogi.fukuoka.jp\":1,\"kuroishi.aomori.jp\":1,\"kuroiso.tochigi.jp\":1,\"kuromatsunai.hokkaido.jp\":1,\"kurotaki.nara.jp\":1,\"kurume.fukuoka.jp\":1,\"kusatsu.gunma.jp\":1,\"kusatsu.shiga.jp\":1,\"kushima.miyazaki.jp\":1,\"kushimoto.wakayama.jp\":1,\"kushiro.hokkaido.jp\":1,\"kustanai.ru\":1,\"kustanai.su\":1,\"kusu.oita.jp\":1,\"kutchan.hokkaido.jp\":1,\"kutno.pl\":1,\"kuwana.mie.jp\":1,\"kuzumaki.iwate.jp\":1,\"kv.ua\":1,\"kvafjord.no\":1,\"kvalsund.no\":1,\"kvam.no\":1,\"kvanangen.no\":1,\"kvinesdal.no\":1,\"kvinnherad.no\":1,\"kviteseid.no\":1,\"kvitsoy.no\":1,\"kwp.gov.pl\":1,\"kwpsp.gov.pl\":1,\"ky.us\":1,\"kyiv.ua\":1,\"kyonan.chiba.jp\":1,\"kyotamba.kyoto.jp\":1,\"kyotanabe.kyoto.jp\":1,\"kyotango.kyoto.jp\":1,\"kyoto.jp\":1,\"kyowa.akita.jp\":1,\"kyowa.hokkaido.jp\":1,\"kyuragi.saga.jp\":1,\"l-o-g-i-n.de\":1,\"l.bg\":1,\"l.se\":1,\"la-spezia.it\":1,\"la.us\":1,\"laakesvuemie.no\":1,\"lab.ms\":1,\"labor.museum\":1,\"labour.museum\":1,\"lahppi.no\":1,\"lajolla.museum\":1,\"lakas.hu\":1,\"lanbib.se\":1,\"lancashire.museum\":1,\"land-4-sale.us\":1,\"landes.museum\":1,\"landing.myjino.ru\":2,\"langevag.no\":1,\"lans.museum\":1,\"lapy.pl\":1,\"laquila.it\":1,\"lardal.no\":1,\"larsson.museum\":1,\"larvik.no\":1,\"laspezia.it\":1,\"latina.it\":1,\"lavagis.no\":1,\"lavangen.no\":1,\"law.pro\":1,\"law.za\":1,\"laz.it\":1,\"lazio.it\":1,\"lc.it\":1,\"lcl.dev\":2,\"lcube-server.de\":1,\"le.it\":1,\"leadpages.co\":1,\"leangaviika.no\":1,\"leasing.aero\":1,\"lebesby.no\":1,\"lebork.pl\":1,\"lebtimnetz.de\":1,\"lecce.it\":1,\"lecco.it\":1,\"leczna.pl\":1,\"leg.br\":1,\"legnica.pl\":1,\"leikanger.no\":1,\"leirfjord.no\":1,\"leirvik.no\":1,\"leitungsen.de\":1,\"leka.no\":1,\"leksvik.no\":1,\"lel.br\":1,\"lelux.site\":1,\"lenug.su\":1,\"lenvik.no\":1,\"lerdal.no\":1,\"lesja.no\":1,\"levanger.no\":1,\"lewismiller.museum\":1,\"lezajsk.pl\":1,\"lg.jp\":1,\"lg.ua\":1,\"li.it\":1,\"lib.ak.us\":1,\"lib.al.us\":1,\"lib.ar.us\":1,\"lib.as.us\":1,\"lib.az.us\":1,\"lib.ca.us\":1,\"lib.co.us\":1,\"lib.ct.us\":1,\"lib.dc.us\":1,\"lib.de.us\":1,\"lib.ee\":1,\"lib.fl.us\":1,\"lib.ga.us\":1,\"lib.gu.us\":1,\"lib.hi.us\":1,\"lib.ia.us\":1,\"lib.id.us\":1,\"lib.il.us\":1,\"lib.in.us\":1,\"lib.ks.us\":1,\"lib.ky.us\":1,\"lib.la.us\":1,\"lib.ma.us\":1,\"lib.md.us\":1,\"lib.me.us\":1,\"lib.mi.us\":1,\"lib.mn.us\":1,\"lib.mo.us\":1,\"lib.ms.us\":1,\"lib.mt.us\":1,\"lib.nc.us\":1,\"lib.nd.us\":1,\"lib.ne.us\":1,\"lib.nh.us\":1,\"lib.nj.us\":1,\"lib.nm.us\":1,\"lib.nv.us\":1,\"lib.ny.us\":1,\"lib.oh.us\":1,\"lib.ok.us\":1,\"lib.or.us\":1,\"lib.pa.us\":1,\"lib.pr.us\":1,\"lib.ri.us\":1,\"lib.sc.us\":1,\"lib.sd.us\":1,\"lib.tn.us\":1,\"lib.tx.us\":1,\"lib.ut.us\":1,\"lib.va.us\":1,\"lib.vi.us\":1,\"lib.vt.us\":1,\"lib.wa.us\":1,\"lib.wi.us\":1,\"lib.wy.us\":1,\"lier.no\":1,\"lierne.no\":1,\"lig.it\":1,\"liguria.it\":1,\"likes-pie.com\":1,\"likescandy.com\":1,\"lillehammer.no\":1,\"lillesand.no\":1,\"lima-city.at\":1,\"lima-city.ch\":1,\"lima-city.de\":1,\"lima-city.rocks\":1,\"lima.zone\":1,\"limanowa.pl\":1,\"lincoln.museum\":1,\"lindas.no\":1,\"lindesnes.no\":1,\"linkitools.space\":1,\"linkyard-cloud.ch\":1,\"linkyard.cloud\":1,\"linodeobjects.com\":2,\"linz.museum\":1,\"living.museum\":1,\"livinghistory.museum\":1,\"livorno.it\":1,\"ln.cn\":1,\"lo.it\":1,\"loabat.no\":1,\"localhistory.museum\":1,\"localhost.daplie.me\":1,\"lodi.it\":1,\"lodingen.no\":1,\"log.br\":1,\"loginline.app\":1,\"loginline.dev\":1,\"loginline.io\":1,\"loginline.services\":1,\"loginline.site\":1,\"loginto.me\":1,\"logistics.aero\":1,\"logoip.com\":1,\"logoip.de\":1,\"lolipop.io\":1,\"lom.it\":1,\"lom.no\":1,\"lombardia.it\":1,\"lombardy.it\":1,\"lomza.pl\":1,\"london.cloudapps.digital\":1,\"london.museum\":1,\"londrina.br\":1,\"loppa.no\":1,\"lorenskog.no\":1,\"losangeles.museum\":1,\"loseyourip.com\":1,\"loten.no\":1,\"louvre.museum\":1,\"lowicz.pl\":1,\"loyalist.museum\":1,\"lpages.co\":1,\"lpusercontent.com\":1,\"lt.eu.org\":1,\"lt.it\":1,\"lt.ua\":1,\"ltd.co.im\":1,\"ltd.cy\":1,\"ltd.gi\":1,\"ltd.hk\":1,\"ltd.lk\":1,\"ltd.ng\":1,\"ltd.ua\":1,\"ltd.uk\":1,\"lu.eu.org\":1,\"lu.it\":1,\"lubartow.pl\":1,\"lubin.pl\":1,\"lublin.pl\":1,\"lucania.it\":1,\"lucca.it\":1,\"lucerne.museum\":1,\"lug.org.uk\":1,\"lugansk.ua\":1,\"lugs.org.uk\":1,\"lukow.pl\":1,\"lund.no\":1,\"lunner.no\":1,\"luroy.no\":1,\"luster.no\":1,\"lutsk.ua\":1,\"luxembourg.museum\":1,\"luzern.museum\":1,\"lv.eu.org\":1,\"lv.ua\":1,\"lviv.ua\":1,\"lyngdal.no\":1,\"lyngen.no\":1,\"lynx.mythic-beasts.com\":1,\"m.bg\":1,\"m.se\":1,\"ma.gov.br\":1,\"ma.leg.br\":1,\"ma.us\":1,\"macapa.br\":1,\"maceio.br\":1,\"macerata.it\":1,\"machida.tokyo.jp\":1,\"mad.museum\":1,\"madrid.museum\":1,\"maebashi.gunma.jp\":1,\"magazine.aero\":1,\"magentosite.cloud\":2,\"maibara.shiga.jp\":1,\"mail.pl\":1,\"maintenance.aero\":1,\"maizuru.kyoto.jp\":1,\"makinohara.shizuoka.jp\":1,\"makurazaki.kagoshima.jp\":1,\"malatvuopmi.no\":1,\"malbork.pl\":1,\"mallorca.museum\":1,\"malopolska.pl\":1,\"malselv.no\":1,\"malvik.no\":1,\"mamurogawa.yamagata.jp\":1,\"manaus.br\":1,\"manchester.museum\":1,\"mandal.no\":1,\"mangyshlak.su\":1,\"maniwa.okayama.jp\":1,\"manno.kagawa.jp\":1,\"mansion.museum\":1,\"mansions.museum\":1,\"mantova.it\":1,\"manx.museum\":1,\"maori.nz\":1,\"map.fastly.net\":1,\"map.fastlylb.net\":1,\"mar.it\":1,\"marburg.museum\":1,\"marche.it\":1,\"marine.ru\":1,\"maringa.br\":1,\"maritime.museum\":1,\"maritimo.museum\":1,\"marker.no\":1,\"marnardal.no\":1,\"marugame.kagawa.jp\":1,\"marumori.miyagi.jp\":1,\"maryland.museum\":1,\"marylhurst.museum\":1,\"masaki.ehime.jp\":1,\"masfjorden.no\":1,\"mashike.hokkaido.jp\":1,\"mashiki.kumamoto.jp\":1,\"mashiko.tochigi.jp\":1,\"masoy.no\":1,\"massa-carrara.it\":1,\"massacarrara.it\":1,\"masuda.shimane.jp\":1,\"mat.br\":1,\"matera.it\":1,\"matsubara.osaka.jp\":1,\"matsubushi.saitama.jp\":1,\"matsuda.kanagawa.jp\":1,\"matsudo.chiba.jp\":1,\"matsue.shimane.jp\":1,\"matsukawa.nagano.jp\":1,\"matsumae.hokkaido.jp\":1,\"matsumoto.kagoshima.jp\":1,\"matsumoto.nagano.jp\":1,\"matsuno.ehime.jp\":1,\"matsusaka.mie.jp\":1,\"matsushige.tokushima.jp\":1,\"matsushima.miyagi.jp\":1,\"matsuura.nagasaki.jp\":1,\"matsuyama.ehime.jp\":1,\"matsuzaki.shizuoka.jp\":1,\"matta-varjjat.no\":1,\"mayfirst.info\":1,\"mayfirst.org\":1,\"mazowsze.pl\":1,\"mazury.pl\":1,\"mb.ca\":1,\"mb.it\":1,\"mc.ax\":1,\"mc.eu.org\":1,\"mc.it\":1,\"mcdir.ru\":1,\"mcpe.me\":1,\"md.ci\":1,\"md.us\":1,\"me.eu.org\":1,\"me.it\":1,\"me.ke\":1,\"me.so\":1,\"me.tc\":1,\"me.tz\":1,\"me.uk\":1,\"me.us\":1,\"me.vu\":1,\"med.br\":1,\"med.ec\":1,\"med.ee\":1,\"med.ht\":1,\"med.ly\":1,\"med.om\":1,\"med.pa\":1,\"med.pl\":1,\"med.pro\":1,\"med.sa\":1,\"med.sd\":1,\"medecin.fr\":1,\"medecin.km\":1,\"media.aero\":1,\"media.hu\":1,\"media.museum\":1,\"media.pl\":1,\"medical.museum\":1,\"medicina.bo\":1,\"medio-campidano.it\":1,\"mediocampidano.it\":1,\"medizinhistorisches.museum\":1,\"meeres.museum\":1,\"meguro.tokyo.jp\":1,\"mein-iserv.de\":1,\"mein-vigor.de\":1,\"meinforum.net\":1,\"meiwa.gunma.jp\":1,\"meiwa.mie.jp\":1,\"meland.no\":1,\"meldal.no\":1,\"melhus.no\":1,\"meloy.no\":1,\"members.linode.com\":1,\"memorial.museum\":1,\"memset.net\":1,\"meraker.no\":1,\"merseine.nu\":1,\"mesaverde.museum\":1,\"messina.it\":1,\"meteorapp.com\":1,\"mex.com\":1,\"mg.gov.br\":1,\"mg.leg.br\":1,\"mi.it\":1,\"mi.th\":1,\"mi.us\":1,\"miasa.nagano.jp\":1,\"miasta.pl\":1,\"mibu.tochigi.jp\":1,\"michigan.museum\":1,\"microlight.aero\":1,\"midatlantic.museum\":1,\"midori.chiba.jp\":1,\"midori.gunma.jp\":1,\"midsund.no\":1,\"midtre-gauldal.no\":1,\"mie.jp\":1,\"mielec.pl\":1,\"mielno.pl\":1,\"mifune.kumamoto.jp\":1,\"mihama.aichi.jp\":1,\"mihama.chiba.jp\":1,\"mihama.fukui.jp\":1,\"mihama.mie.jp\":1,\"mihama.wakayama.jp\":1,\"mihara.hiroshima.jp\":1,\"mihara.kochi.jp\":1,\"miharu.fukushima.jp\":1,\"miho.ibaraki.jp\":1,\"mikasa.hokkaido.jp\":1,\"mikawa.yamagata.jp\":1,\"miki.hyogo.jp\":1,\"mil.ac\":1,\"mil.ae\":1,\"mil.al\":1,\"mil.ar\":1,\"mil.az\":1,\"mil.ba\":1,\"mil.bo\":1,\"mil.br\":1,\"mil.by\":1,\"mil.cl\":1,\"mil.cn\":1,\"mil.co\":1,\"mil.do\":1,\"mil.ec\":1,\"mil.eg\":1,\"mil.fj\":1,\"mil.ge\":1,\"mil.gh\":1,\"mil.gt\":1,\"mil.hn\":1,\"mil.id\":1,\"mil.in\":1,\"mil.iq\":1,\"mil.jo\":1,\"mil.kg\":1,\"mil.km\":1,\"mil.kr\":1,\"mil.kz\":1,\"mil.lv\":1,\"mil.mg\":1,\"mil.mv\":1,\"mil.my\":1,\"mil.mz\":1,\"mil.ng\":1,\"mil.ni\":1,\"mil.no\":1,\"mil.nz\":1,\"mil.pe\":1,\"mil.ph\":1,\"mil.pl\":1,\"mil.py\":1,\"mil.qa\":1,\"mil.ru\":1,\"mil.rw\":1,\"mil.sh\":1,\"mil.st\":1,\"mil.sy\":1,\"mil.tj\":1,\"mil.tm\":1,\"mil.to\":1,\"mil.tr\":1,\"mil.tw\":1,\"mil.tz\":1,\"mil.uy\":1,\"mil.vc\":1,\"mil.ve\":1,\"mil.za\":1,\"mil.zm\":1,\"mil.zw\":1,\"milan.it\":1,\"milano.it\":1,\"military.museum\":1,\"mill.museum\":1,\"mima.tokushima.jp\":1,\"mimata.miyazaki.jp\":1,\"minakami.gunma.jp\":1,\"minamata.kumamoto.jp\":1,\"minami-alps.yamanashi.jp\":1,\"minami.fukuoka.jp\":1,\"minami.kyoto.jp\":1,\"minami.tokushima.jp\":1,\"minamiaiki.nagano.jp\":1,\"minamiashigara.kanagawa.jp\":1,\"minamiawaji.hyogo.jp\":1,\"minamiboso.chiba.jp\":1,\"minamidaito.okinawa.jp\":1,\"minamiechizen.fukui.jp\":1,\"minamifurano.hokkaido.jp\":1,\"minamiise.mie.jp\":1,\"minamiizu.shizuoka.jp\":1,\"minamimaki.nagano.jp\":1,\"minamiminowa.nagano.jp\":1,\"minamioguni.kumamoto.jp\":1,\"minamisanriku.miyagi.jp\":1,\"minamitane.kagoshima.jp\":1,\"minamiuonuma.niigata.jp\":1,\"minamiyamashiro.kyoto.jp\":1,\"minano.saitama.jp\":1,\"minato.osaka.jp\":1,\"minato.tokyo.jp\":1,\"mincom.tn\":1,\"mine.nu\":1,\"miners.museum\":1,\"mining.museum\":1,\"miniserver.com\":1,\"minnesota.museum\":1,\"mino.gifu.jp\":1,\"minobu.yamanashi.jp\":1,\"minoh.osaka.jp\":1,\"minokamo.gifu.jp\":1,\"minowa.nagano.jp\":1,\"mintere.site\":1,\"mircloud.host\":1,\"misaki.okayama.jp\":1,\"misaki.osaka.jp\":1,\"misasa.tottori.jp\":1,\"misato.akita.jp\":1,\"misato.miyagi.jp\":1,\"misato.saitama.jp\":1,\"misato.shimane.jp\":1,\"misato.wakayama.jp\":1,\"misawa.aomori.jp\":1,\"misconfused.org\":1,\"mishima.fukushima.jp\":1,\"mishima.shizuoka.jp\":1,\"missile.museum\":1,\"missoula.museum\":1,\"misugi.mie.jp\":1,\"mitaka.tokyo.jp\":1,\"mitake.gifu.jp\":1,\"mitane.akita.jp\":1,\"mito.ibaraki.jp\":1,\"mitou.yamaguchi.jp\":1,\"mitoyo.kagawa.jp\":1,\"mitsue.nara.jp\":1,\"mitsuke.niigata.jp\":1,\"miura.kanagawa.jp\":1,\"miyada.nagano.jp\":1,\"miyagi.jp\":1,\"miyake.nara.jp\":1,\"miyako.fukuoka.jp\":1,\"miyako.iwate.jp\":1,\"miyakonojo.miyazaki.jp\":1,\"miyama.fukuoka.jp\":1,\"miyama.mie.jp\":1,\"miyashiro.saitama.jp\":1,\"miyawaka.fukuoka.jp\":1,\"miyazaki.jp\":1,\"miyazaki.miyazaki.jp\":1,\"miyazu.kyoto.jp\":1,\"miyoshi.aichi.jp\":1,\"miyoshi.hiroshima.jp\":1,\"miyoshi.saitama.jp\":1,\"miyoshi.tokushima.jp\":1,\"miyota.nagano.jp\":1,\"mizuho.tokyo.jp\":1,\"mizumaki.fukuoka.jp\":1,\"mizunami.gifu.jp\":1,\"mizusawa.iwate.jp\":1,\"mjondalen.no\":1,\"mk.eu.org\":1,\"mk.ua\":1,\"mlbfan.org\":1,\"mm\":2,\"mmafan.biz\":1,\"mn.it\":1,\"mn.us\":1,\"mo-i-rana.no\":1,\"mo-siemens.io\":1,\"mo.cn\":1,\"mo.it\":1,\"mo.us\":1,\"moareke.no\":1,\"mobara.chiba.jp\":1,\"mobi.gp\":1,\"mobi.ke\":1,\"mobi.na\":1,\"mobi.ng\":1,\"mobi.tt\":1,\"mobi.tz\":1,\"mochizuki.nagano.jp\":1,\"mod.gi\":1,\"modalen.no\":1,\"modelling.aero\":1,\"modena.it\":1,\"modern.museum\":1,\"modum.no\":1,\"moka.tochigi.jp\":1,\"mol.it\":1,\"molde.no\":1,\"molise.it\":1,\"moma.museum\":1,\"mombetsu.hokkaido.jp\":1,\"money.museum\":1,\"monmouth.museum\":1,\"monticello.museum\":1,\"montreal.museum\":1,\"monza-brianza.it\":1,\"monza-e-della-brianza.it\":1,\"monza.it\":1,\"monzabrianza.it\":1,\"monzaebrianza.it\":1,\"monzaedellabrianza.it\":1,\"moonscale.io\":2,\"moonscale.net\":1,\"mordovia.ru\":1,\"mordovia.su\":1,\"morena.br\":1,\"moriguchi.osaka.jp\":1,\"morimachi.shizuoka.jp\":1,\"morioka.iwate.jp\":1,\"moriya.ibaraki.jp\":1,\"moriyama.shiga.jp\":1,\"moriyoshi.akita.jp\":1,\"morotsuka.miyazaki.jp\":1,\"moroyama.saitama.jp\":1,\"moscow.museum\":1,\"moseushi.hokkaido.jp\":1,\"mosjoen.no\":1,\"moskenes.no\":1,\"moss.no\":1,\"mosvik.no\":1,\"motegi.tochigi.jp\":1,\"motobu.okinawa.jp\":1,\"motorcycle.museum\":1,\"motosu.gifu.jp\":1,\"motoyama.kochi.jp\":1,\"movimiento.bo\":1,\"mozilla-iot.org\":1,\"mp.br\":1,\"mr.no\":1,\"mragowo.pl\":1,\"ms.gov.br\":1,\"ms.it\":1,\"ms.kr\":1,\"ms.leg.br\":1,\"ms.us\":1,\"msk.ru\":1,\"msk.su\":1,\"mt.eu.org\":1,\"mt.gov.br\":1,\"mt.it\":1,\"mt.leg.br\":1,\"mt.us\":1,\"muenchen.museum\":1,\"muenster.museum\":1,\"mugi.tokushima.jp\":1,\"muika.niigata.jp\":1,\"mukawa.hokkaido.jp\":1,\"muko.kyoto.jp\":1,\"mulhouse.museum\":1,\"munakata.fukuoka.jp\":1,\"muncie.museum\":1,\"muni.il\":1,\"muosat.no\":1,\"mup.gov.pl\":1,\"murakami.niigata.jp\":1,\"murata.miyagi.jp\":1,\"murayama.yamagata.jp\":1,\"murmansk.su\":1,\"muroran.hokkaido.jp\":1,\"muroto.kochi.jp\":1,\"mus.br\":1,\"mus.mi.us\":1,\"musashimurayama.tokyo.jp\":1,\"musashino.tokyo.jp\":1,\"museet.museum\":1,\"museum.mv\":1,\"museum.mw\":1,\"museum.no\":1,\"museum.om\":1,\"museum.tt\":1,\"museumcenter.museum\":1,\"museumvereniging.museum\":1,\"music.museum\":1,\"musica.ar\":1,\"musica.bo\":1,\"mutsu.aomori.jp\":1,\"mutsuzawa.chiba.jp\":1,\"mw.gov.pl\":1,\"mx.na\":1,\"my-firewall.org\":1,\"my-gateway.de\":1,\"my-router.de\":1,\"my-vigor.de\":1,\"my-wan.de\":1,\"my.eu.org\":1,\"my.id\":1,\"myactivedirectory.com\":1,\"myasustor.com\":1,\"mycd.eu\":1,\"mydatto.com\":1,\"mydatto.net\":1,\"myddns.rocks\":1,\"mydissent.net\":1,\"mydobiss.com\":1,\"mydrobo.com\":1,\"myds.me\":1,\"myeffect.net\":1,\"myfast.host\":1,\"myfast.space\":1,\"myfirewall.org\":1,\"myforum.community\":1,\"myfritz.net\":1,\"myftp.biz\":1,\"myftp.org\":1,\"myhome-server.de\":1,\"myiphost.com\":1,\"myjino.ru\":1,\"mykolaiv.ua\":1,\"mymailer.com.tw\":1,\"mymediapc.net\":1,\"myoko.niigata.jp\":1,\"mypep.link\":1,\"mypets.ws\":1,\"myphotos.cc\":1,\"mypi.co\":1,\"mypsx.net\":1,\"myqnapcloud.com\":1,\"myravendb.com\":1,\"mysecuritycamera.com\":1,\"mysecuritycamera.net\":1,\"mysecuritycamera.org\":1,\"myshopblocks.com\":1,\"mytis.ru\":1,\"mytuleap.com\":1,\"myvnc.com\":1,\"mywire.org\":1,\"n.bg\":1,\"n.se\":1,\"n4t.co\":1,\"na.it\":1,\"na4u.ru\":1,\"naamesjevuemie.no\":1,\"nabari.mie.jp\":1,\"nachikatsuura.wakayama.jp\":1,\"nagahama.shiga.jp\":1,\"nagai.yamagata.jp\":1,\"nagano.jp\":1,\"nagano.nagano.jp\":1,\"naganohara.gunma.jp\":1,\"nagaoka.niigata.jp\":1,\"nagaokakyo.kyoto.jp\":1,\"nagara.chiba.jp\":1,\"nagareyama.chiba.jp\":1,\"nagasaki.jp\":1,\"nagasaki.nagasaki.jp\":1,\"nagasu.kumamoto.jp\":1,\"nagato.yamaguchi.jp\":1,\"nagatoro.saitama.jp\":1,\"nagawa.nagano.jp\":1,\"nagi.okayama.jp\":1,\"nagiso.nagano.jp\":1,\"nago.okinawa.jp\":1,\"nagoya.jp\":2,\"naha.okinawa.jp\":1,\"nahari.kochi.jp\":1,\"naie.hokkaido.jp\":1,\"naka.hiroshima.jp\":1,\"naka.ibaraki.jp\":1,\"nakadomari.aomori.jp\":1,\"nakagawa.fukuoka.jp\":1,\"nakagawa.hokkaido.jp\":1,\"nakagawa.nagano.jp\":1,\"nakagawa.tokushima.jp\":1,\"nakagusuku.okinawa.jp\":1,\"nakagyo.kyoto.jp\":1,\"nakai.kanagawa.jp\":1,\"nakama.fukuoka.jp\":1,\"nakamichi.yamanashi.jp\":1,\"nakamura.kochi.jp\":1,\"nakaniikawa.toyama.jp\":1,\"nakano.nagano.jp\":1,\"nakano.tokyo.jp\":1,\"nakanojo.gunma.jp\":1,\"nakanoto.ishikawa.jp\":1,\"nakasatsunai.hokkaido.jp\":1,\"nakatane.kagoshima.jp\":1,\"nakatombetsu.hokkaido.jp\":1,\"nakatsugawa.gifu.jp\":1,\"nakayama.yamagata.jp\":1,\"nakijin.okinawa.jp\":1,\"naklo.pl\":1,\"nalchik.ru\":1,\"nalchik.su\":1,\"namdalseid.no\":1,\"name.az\":1,\"name.cy\":1,\"name.eg\":1,\"name.et\":1,\"name.fj\":1,\"name.hr\":1,\"name.jo\":1,\"name.mk\":1,\"name.mv\":1,\"name.my\":1,\"name.na\":1,\"name.ng\":1,\"name.pr\":1,\"name.qa\":1,\"name.tj\":1,\"name.tr\":1,\"name.tt\":1,\"name.vn\":1,\"namegata.ibaraki.jp\":1,\"namegawa.saitama.jp\":1,\"namerikawa.toyama.jp\":1,\"namie.fukushima.jp\":1,\"namikata.ehime.jp\":1,\"namsos.no\":1,\"namsskogan.no\":1,\"nanae.hokkaido.jp\":1,\"nanao.ishikawa.jp\":1,\"nanbu.tottori.jp\":1,\"nanbu.yamanashi.jp\":1,\"nango.fukushima.jp\":1,\"nanjo.okinawa.jp\":1,\"nankoku.kochi.jp\":1,\"nanmoku.gunma.jp\":1,\"nannestad.no\":1,\"nanporo.hokkaido.jp\":1,\"nantan.kyoto.jp\":1,\"nanto.toyama.jp\":1,\"nanyo.yamagata.jp\":1,\"naoshima.kagawa.jp\":1,\"naples.it\":1,\"napoli.it\":1,\"nara.jp\":1,\"nara.nara.jp\":1,\"narashino.chiba.jp\":1,\"narita.chiba.jp\":1,\"naroy.no\":1,\"narusawa.yamanashi.jp\":1,\"naruto.tokushima.jp\":1,\"narviika.no\":1,\"narvik.no\":1,\"nasu.tochigi.jp\":1,\"nasushiobara.tochigi.jp\":1,\"nat.tn\":1,\"natal.br\":1,\"national.museum\":1,\"nationalfirearms.museum\":1,\"nationalheritage.museum\":1,\"nativeamerican.museum\":1,\"natori.miyagi.jp\":1,\"natural.bo\":1,\"naturalhistory.museum\":1,\"naturalhistorymuseum.museum\":1,\"naturalsciences.museum\":1,\"naturbruksgymn.se\":1,\"nature.museum\":1,\"naturhistorisches.museum\":1,\"natuurwetenschappen.museum\":1,\"naumburg.museum\":1,\"naustdal.no\":1,\"naval.museum\":1,\"navigation.aero\":1,\"navoi.su\":1,\"navuotna.no\":1,\"nayoro.hokkaido.jp\":1,\"nb.ca\":1,\"nc.tr\":1,\"nc.us\":1,\"nctu.me\":1,\"nd.us\":1,\"ne.jp\":1,\"ne.ke\":1,\"ne.kr\":1,\"ne.pw\":1,\"ne.tz\":1,\"ne.ug\":1,\"ne.us\":1,\"neat-url.com\":1,\"nebraska.museum\":1,\"nedre-eiker.no\":1,\"neko.am\":1,\"nemuro.hokkaido.jp\":1,\"nerdpol.ovh\":1,\"nerima.tokyo.jp\":1,\"nes.akershus.no\":1,\"nes.buskerud.no\":1,\"nesna.no\":1,\"nesodden.no\":1,\"nesoddtangen.no\":1,\"nesseby.no\":1,\"nesset.no\":1,\"net-freaks.com\":1,\"net.ac\":1,\"net.ae\":1,\"net.af\":1,\"net.ag\":1,\"net.ai\":1,\"net.al\":1,\"net.am\":1,\"net.ar\":1,\"net.au\":1,\"net.az\":1,\"net.ba\":1,\"net.bb\":1,\"net.bh\":1,\"net.bm\":1,\"net.bn\":1,\"net.bo\":1,\"net.br\":1,\"net.bs\":1,\"net.bt\":1,\"net.bz\":1,\"net.ci\":1,\"net.cm\":1,\"net.cn\":1,\"net.co\":1,\"net.cu\":1,\"net.cw\":1,\"net.cy\":1,\"net.dm\":1,\"net.do\":1,\"net.dz\":1,\"net.ec\":1,\"net.eg\":1,\"net.et\":1,\"net.eu.org\":1,\"net.fj\":1,\"net.fm\":1,\"net.ge\":1,\"net.gg\":1,\"net.gl\":1,\"net.gn\":1,\"net.gp\":1,\"net.gr\":1,\"net.gt\":1,\"net.gu\":1,\"net.gy\":1,\"net.hk\":1,\"net.hn\":1,\"net.ht\":1,\"net.id\":1,\"net.il\":1,\"net.im\":1,\"net.in\":1,\"net.iq\":1,\"net.ir\":1,\"net.is\":1,\"net.je\":1,\"net.jo\":1,\"net.kg\":1,\"net.ki\":1,\"net.kn\":1,\"net.kw\":1,\"net.ky\":1,\"net.kz\":1,\"net.la\":1,\"net.lb\":1,\"net.lc\":1,\"net.lk\":1,\"net.lr\":1,\"net.ls\":1,\"net.lv\":1,\"net.ly\":1,\"net.ma\":1,\"net.me\":1,\"net.mk\":1,\"net.ml\":1,\"net.mo\":1,\"net.ms\":1,\"net.mt\":1,\"net.mu\":1,\"net.mv\":1,\"net.mw\":1,\"net.mx\":1,\"net.my\":1,\"net.mz\":1,\"net.nf\":1,\"net.ng\":1,\"net.ni\":1,\"net.nr\":1,\"net.nz\":1,\"net.om\":1,\"net.pa\":1,\"net.pe\":1,\"net.ph\":1,\"net.pk\":1,\"net.pl\":1,\"net.pn\":1,\"net.pr\":1,\"net.ps\":1,\"net.pt\":1,\"net.py\":1,\"net.qa\":1,\"net.ru\":1,\"net.rw\":1,\"net.sa\":1,\"net.sb\":1,\"net.sc\":1,\"net.sd\":1,\"net.sg\":1,\"net.sh\":1,\"net.sl\":1,\"net.so\":1,\"net.ss\":1,\"net.st\":1,\"net.sy\":1,\"net.th\":1,\"net.tj\":1,\"net.tm\":1,\"net.tn\":1,\"net.to\":1,\"net.tr\":1,\"net.tt\":1,\"net.tw\":1,\"net.ua\":1,\"net.uk\":1,\"net.uy\":1,\"net.uz\":1,\"net.vc\":1,\"net.ve\":1,\"net.vi\":1,\"net.vn\":1,\"net.vu\":1,\"net.ws\":1,\"net.za\":1,\"net.zm\":1,\"netlify.app\":1,\"neues.museum\":1,\"newhampshire.museum\":1,\"newjersey.museum\":1,\"newmexico.museum\":1,\"newport.museum\":1,\"news.hu\":1,\"newspaper.museum\":1,\"newyork.museum\":1,\"neyagawa.osaka.jp\":1,\"nf.ca\":1,\"nflfan.org\":1,\"nfshost.com\":1,\"ng.city\":1,\"ng.eu.org\":1,\"ng.ink\":1,\"ng.school\":1,\"ngo.lk\":1,\"ngo.ng\":1,\"ngo.ph\":1,\"ngo.za\":1,\"ngrok.io\":1,\"nh-serv.co.uk\":1,\"nh.us\":1,\"nhlfan.net\":1,\"nhs.uk\":1,\"nic.in\":1,\"nic.tj\":1,\"nic.za\":1,\"nichinan.miyazaki.jp\":1,\"nichinan.tottori.jp\":1,\"nid.io\":1,\"niepce.museum\":1,\"nieruchomosci.pl\":1,\"niigata.jp\":1,\"niigata.niigata.jp\":1,\"niihama.ehime.jp\":1,\"niikappu.hokkaido.jp\":1,\"niimi.okayama.jp\":1,\"niiza.saitama.jp\":1,\"nikaho.akita.jp\":1,\"niki.hokkaido.jp\":1,\"nikko.tochigi.jp\":1,\"nikolaev.ua\":1,\"ninohe.iwate.jp\":1,\"ninomiya.kanagawa.jp\":1,\"nirasaki.yamanashi.jp\":1,\"nis.za\":1,\"nishi.fukuoka.jp\":1,\"nishi.osaka.jp\":1,\"nishiaizu.fukushima.jp\":1,\"nishiarita.saga.jp\":1,\"nishiawakura.okayama.jp\":1,\"nishiazai.shiga.jp\":1,\"nishigo.fukushima.jp\":1,\"nishihara.kumamoto.jp\":1,\"nishihara.okinawa.jp\":1,\"nishiizu.shizuoka.jp\":1,\"nishikata.tochigi.jp\":1,\"nishikatsura.yamanashi.jp\":1,\"nishikawa.yamagata.jp\":1,\"nishimera.miyazaki.jp\":1,\"nishinomiya.hyogo.jp\":1,\"nishinoomote.kagoshima.jp\":1,\"nishinoshima.shimane.jp\":1,\"nishio.aichi.jp\":1,\"nishiokoppe.hokkaido.jp\":1,\"nishitosa.kochi.jp\":1,\"nishiwaki.hyogo.jp\":1,\"nissedal.no\":1,\"nisshin.aichi.jp\":1,\"niteroi.br\":1,\"nittedal.no\":1,\"niyodogawa.kochi.jp\":1,\"nj.us\":1,\"nl.ca\":1,\"nl.ci\":1,\"nl.eu.org\":1,\"nl.no\":1,\"nm.cn\":1,\"nm.us\":1,\"no-ip.biz\":1,\"no-ip.ca\":1,\"no-ip.co.uk\":1,\"no-ip.info\":1,\"no-ip.net\":1,\"no-ip.org\":1,\"no.com\":1,\"no.eu.org\":1,\"no.it\":1,\"nobeoka.miyazaki.jp\":1,\"noboribetsu.hokkaido.jp\":1,\"noda.chiba.jp\":1,\"noda.iwate.jp\":1,\"nodebalancer.linode.com\":2,\"nodum.co\":1,\"nodum.io\":1,\"nogata.fukuoka.jp\":1,\"nogi.tochigi.jp\":1,\"noheji.aomori.jp\":1,\"noho.st\":1,\"nohost.me\":1,\"noip.me\":1,\"noip.us\":1,\"nom.ad\":1,\"nom.ae\":1,\"nom.af\":1,\"nom.ag\":1,\"nom.ai\":1,\"nom.al\":1,\"nom.br\":2,\"nom.bz\":1,\"nom.cl\":1,\"nom.co\":1,\"nom.es\":1,\"nom.fr\":1,\"nom.gd\":1,\"nom.ge\":1,\"nom.gl\":1,\"nom.gt\":1,\"nom.hn\":1,\"nom.im\":1,\"nom.ke\":1,\"nom.km\":1,\"nom.li\":1,\"nom.lv\":1,\"nom.mg\":1,\"nom.mk\":1,\"nom.nc\":1,\"nom.ni\":1,\"nom.nu\":1,\"nom.pa\":1,\"nom.pe\":1,\"nom.pl\":1,\"nom.pw\":1,\"nom.qa\":1,\"nom.re\":1,\"nom.ro\":1,\"nom.rs\":1,\"nom.si\":1,\"nom.st\":1,\"nom.tj\":1,\"nom.tm\":1,\"nom.ug\":1,\"nom.uy\":1,\"nom.vc\":1,\"nom.vg\":1,\"nom.za\":1,\"nombre.bo\":1,\"nome.pt\":1,\"nomi.ishikawa.jp\":1,\"nonoichi.ishikawa.jp\":1,\"nord-aurdal.no\":1,\"nord-fron.no\":1,\"nord-odal.no\":1,\"norddal.no\":1,\"nordkapp.no\":1,\"nordre-land.no\":1,\"nordreisa.no\":1,\"nore-og-uvdal.no\":1,\"norfolk.museum\":1,\"north-kazakhstan.su\":1,\"north.museum\":1,\"nose.osaka.jp\":1,\"nosegawa.nara.jp\":1,\"noshiro.akita.jp\":1,\"not.br\":1,\"notaires.fr\":1,\"notaires.km\":1,\"noticias.bo\":1,\"noto.ishikawa.jp\":1,\"notodden.no\":1,\"notogawa.shiga.jp\":1,\"notteroy.no\":1,\"nov.ru\":1,\"nov.su\":1,\"novara.it\":1,\"now-dns.net\":1,\"now-dns.org\":1,\"now-dns.top\":1,\"now.sh\":1,\"nowaruda.pl\":1,\"nozawaonsen.nagano.jp\":1,\"np\":2,\"nrw.museum\":1,\"ns.ca\":1,\"nsn.us\":1,\"nsupdate.info\":1,\"nsw.au\":1,\"nsw.edu.au\":1,\"nt.au\":1,\"nt.ca\":1,\"nt.edu.au\":1,\"nt.no\":1,\"nt.ro\":1,\"ntdll.top\":1,\"ntr.br\":1,\"nu.ca\":1,\"nu.it\":1,\"numata.gunma.jp\":1,\"numata.hokkaido.jp\":1,\"numazu.shizuoka.jp\":1,\"nuoro.it\":1,\"nv.us\":1,\"nx.cn\":1,\"ny.us\":1,\"nyaa.am\":1,\"nyan.to\":1,\"nyc.mn\":1,\"nyc.museum\":1,\"nym.by\":1,\"nym.bz\":1,\"nym.ec\":1,\"nym.gr\":1,\"nym.gy\":1,\"nym.hk\":1,\"nym.ie\":1,\"nym.kz\":1,\"nym.la\":1,\"nym.lc\":1,\"nym.li\":1,\"nym.lt\":1,\"nym.lu\":1,\"nym.me\":1,\"nym.mn\":1,\"nym.mx\":1,\"nym.nz\":1,\"nym.pe\":1,\"nym.pt\":1,\"nym.ro\":1,\"nym.sk\":1,\"nym.su\":1,\"nym.sx\":1,\"nym.tw\":1,\"nyny.museum\":1,\"nysa.pl\":1,\"nyuzen.toyama.jp\":1,\"nz.basketball\":1,\"nz.eu.org\":1,\"o.bg\":1,\"o.se\":1,\"oamishirasato.chiba.jp\":1,\"oarai.ibaraki.jp\":1,\"obama.fukui.jp\":1,\"obama.nagasaki.jp\":1,\"obanazawa.yamagata.jp\":1,\"obihiro.hokkaido.jp\":1,\"obira.hokkaido.jp\":1,\"obninsk.su\":1,\"obu.aichi.jp\":1,\"obuse.nagano.jp\":1,\"oceanographic.museum\":1,\"oceanographique.museum\":1,\"ocelot.mythic-beasts.com\":1,\"ochi.kochi.jp\":1,\"oci.customer-oci.com\":2,\"ocp.customer-oci.com\":2,\"ocs.customer-oci.com\":2,\"od.ua\":1,\"odate.akita.jp\":1,\"odawara.kanagawa.jp\":1,\"odda.no\":1,\"odesa.ua\":1,\"odessa.ua\":1,\"odo.br\":1,\"oe.yamagata.jp\":1,\"of.by\":1,\"of.fashion\":1,\"of.football\":1,\"of.london\":1,\"of.no\":1,\"of.work\":1,\"off.ai\":1,\"office-on-the.net\":1,\"official.academy\":1,\"ofunato.iwate.jp\":1,\"og.ao\":1,\"og.it\":1,\"oga.akita.jp\":1,\"ogaki.gifu.jp\":1,\"ogano.saitama.jp\":1,\"ogasawara.tokyo.jp\":1,\"ogata.akita.jp\":1,\"ogawa.ibaraki.jp\":1,\"ogawa.nagano.jp\":1,\"ogawa.saitama.jp\":1,\"ogawara.miyagi.jp\":1,\"ogi.saga.jp\":1,\"ogimi.okinawa.jp\":1,\"ogliastra.it\":1,\"ogori.fukuoka.jp\":1,\"ogose.saitama.jp\":1,\"oguchi.aichi.jp\":1,\"oguni.kumamoto.jp\":1,\"oguni.yamagata.jp\":1,\"oh.us\":1,\"oharu.aichi.jp\":1,\"ohda.shimane.jp\":1,\"ohi.fukui.jp\":1,\"ohira.miyagi.jp\":1,\"ohira.tochigi.jp\":1,\"ohkura.yamagata.jp\":1,\"ohtawara.tochigi.jp\":1,\"oi.kanagawa.jp\":1,\"oirase.aomori.jp\":1,\"oirm.gov.pl\":1,\"oishida.yamagata.jp\":1,\"oiso.kanagawa.jp\":1,\"oita.jp\":1,\"oita.oita.jp\":1,\"oizumi.gunma.jp\":1,\"oji.nara.jp\":1,\"ojiya.niigata.jp\":1,\"ok.us\":1,\"okagaki.fukuoka.jp\":1,\"okawa.fukuoka.jp\":1,\"okawa.kochi.jp\":1,\"okaya.nagano.jp\":1,\"okayama.jp\":1,\"okayama.okayama.jp\":1,\"okazaki.aichi.jp\":1,\"okegawa.saitama.jp\":1,\"oketo.hokkaido.jp\":1,\"oki.fukuoka.jp\":1,\"okinawa.jp\":1,\"okinawa.okinawa.jp\":1,\"okinoshima.shimane.jp\":1,\"okoppe.hokkaido.jp\":1,\"oksnes.no\":1,\"okuizumo.shimane.jp\":1,\"okuma.fukushima.jp\":1,\"okutama.tokyo.jp\":1,\"ol.no\":1,\"olawa.pl\":1,\"olbia-tempio.it\":1,\"olbiatempio.it\":1,\"olecko.pl\":1,\"olkusz.pl\":1,\"olsztyn.pl\":1,\"omachi.nagano.jp\":1,\"omachi.saga.jp\":1,\"omaezaki.shizuoka.jp\":1,\"omaha.museum\":1,\"omasvuotna.no\":1,\"ome.tokyo.jp\":1,\"omg.lol\":1,\"omi.nagano.jp\":1,\"omi.niigata.jp\":1,\"omigawa.chiba.jp\":1,\"omihachiman.shiga.jp\":1,\"omitama.ibaraki.jp\":1,\"omiya.saitama.jp\":1,\"omniwe.site\":1,\"omotego.fukushima.jp\":1,\"omura.nagasaki.jp\":1,\"omuta.fukuoka.jp\":1,\"on-aptible.com\":1,\"on-k3s.io\":2,\"on-rancher.cloud\":2,\"on-rio.io\":2,\"on-the-web.tv\":1,\"on-web.fr\":1,\"on.ca\":1,\"on.fashion\":1,\"onagawa.miyagi.jp\":1,\"onfabrica.com\":1,\"ong.br\":1,\"onga.fukuoka.jp\":1,\"onjuku.chiba.jp\":1,\"online.museum\":1,\"online.th\":1,\"onna.okinawa.jp\":1,\"ono.fukui.jp\":1,\"ono.fukushima.jp\":1,\"ono.hyogo.jp\":1,\"onojo.fukuoka.jp\":1,\"onomichi.hiroshima.jp\":1,\"onred.one\":1,\"onrender.com\":1,\"ontario.museum\":1,\"onthewifi.com\":1,\"onza.mythic-beasts.com\":1,\"ooguy.com\":1,\"ookuwa.nagano.jp\":1,\"ooshika.nagano.jp\":1,\"openair.museum\":1,\"opencraft.hosting\":1,\"opensocial.site\":1,\"operaunite.com\":1,\"opoczno.pl\":1,\"opole.pl\":1,\"oppdal.no\":1,\"oppegard.no\":1,\"or.at\":1,\"or.bi\":1,\"or.ci\":1,\"or.cr\":1,\"or.id\":1,\"or.it\":1,\"or.jp\":1,\"or.ke\":1,\"or.kr\":1,\"or.mu\":1,\"or.na\":1,\"or.pw\":1,\"or.th\":1,\"or.tz\":1,\"or.ug\":1,\"or.us\":1,\"ora.gunma.jp\":1,\"oregon.museum\":1,\"oregontrail.museum\":1,\"org.ac\":1,\"org.ae\":1,\"org.af\":1,\"org.ag\":1,\"org.ai\":1,\"org.al\":1,\"org.am\":1,\"org.ar\":1,\"org.au\":1,\"org.az\":1,\"org.ba\":1,\"org.bb\":1,\"org.bh\":1,\"org.bi\":1,\"org.bm\":1,\"org.bn\":1,\"org.bo\":1,\"org.br\":1,\"org.bs\":1,\"org.bt\":1,\"org.bw\":1,\"org.bz\":1,\"org.ci\":1,\"org.cn\":1,\"org.co\":1,\"org.cu\":1,\"org.cw\":1,\"org.cy\":1,\"org.dm\":1,\"org.do\":1,\"org.dz\":1,\"org.ec\":1,\"org.ee\":1,\"org.eg\":1,\"org.es\":1,\"org.et\":1,\"org.fj\":1,\"org.fm\":1,\"org.ge\":1,\"org.gg\":1,\"org.gh\":1,\"org.gi\":1,\"org.gl\":1,\"org.gn\":1,\"org.gp\":1,\"org.gr\":1,\"org.gt\":1,\"org.gu\":1,\"org.gy\":1,\"org.hk\":1,\"org.hn\":1,\"org.ht\":1,\"org.hu\":1,\"org.il\":1,\"org.im\":1,\"org.in\":1,\"org.iq\":1,\"org.ir\":1,\"org.is\":1,\"org.je\":1,\"org.jo\":1,\"org.kg\":1,\"org.ki\":1,\"org.km\":1,\"org.kn\":1,\"org.kp\":1,\"org.kw\":1,\"org.ky\":1,\"org.kz\":1,\"org.la\":1,\"org.lb\":1,\"org.lc\":1,\"org.lk\":1,\"org.lr\":1,\"org.ls\":1,\"org.lv\":1,\"org.ly\":1,\"org.ma\":1,\"org.me\":1,\"org.mg\":1,\"org.mk\":1,\"org.ml\":1,\"org.mn\":1,\"org.mo\":1,\"org.ms\":1,\"org.mt\":1,\"org.mu\":1,\"org.mv\":1,\"org.mw\":1,\"org.mx\":1,\"org.my\":1,\"org.mz\":1,\"org.na\":1,\"org.ng\":1,\"org.ni\":1,\"org.nr\":1,\"org.nz\":1,\"org.om\":1,\"org.pa\":1,\"org.pe\":1,\"org.pf\":1,\"org.ph\":1,\"org.pk\":1,\"org.pl\":1,\"org.pn\":1,\"org.pr\":1,\"org.ps\":1,\"org.pt\":1,\"org.py\":1,\"org.qa\":1,\"org.ro\":1,\"org.rs\":1,\"org.ru\":1,\"org.rw\":1,\"org.sa\":1,\"org.sb\":1,\"org.sc\":1,\"org.sd\":1,\"org.se\":1,\"org.sg\":1,\"org.sh\":1,\"org.sl\":1,\"org.sn\":1,\"org.so\":1,\"org.ss\":1,\"org.st\":1,\"org.sv\":1,\"org.sy\":1,\"org.sz\":1,\"org.tj\":1,\"org.tm\":1,\"org.tn\":1,\"org.to\":1,\"org.tr\":1,\"org.tt\":1,\"org.tw\":1,\"org.ua\":1,\"org.ug\":1,\"org.uk\":1,\"org.uy\":1,\"org.uz\":1,\"org.vc\":1,\"org.ve\":1,\"org.vi\":1,\"org.vn\":1,\"org.vu\":1,\"org.ws\":1,\"org.za\":1,\"org.zm\":1,\"org.zw\":1,\"oristano.it\":1,\"orkanger.no\":1,\"orkdal.no\":1,\"orland.no\":1,\"orskog.no\":1,\"orsta.no\":1,\"orx.biz\":1,\"os.hedmark.no\":1,\"os.hordaland.no\":1,\"osaka.jp\":1,\"osakasayama.osaka.jp\":1,\"osaki.miyagi.jp\":1,\"osakikamijima.hiroshima.jp\":1,\"osasco.br\":1,\"osen.no\":1,\"oseto.nagasaki.jp\":1,\"oshima.tokyo.jp\":1,\"oshima.yamaguchi.jp\":1,\"oshino.yamanashi.jp\":1,\"oshu.iwate.jp\":1,\"oslo.no\":1,\"osoyro.no\":1,\"osteroy.no\":1,\"ostre-toten.no\":1,\"ostroda.pl\":1,\"ostroleka.pl\":1,\"ostrowiec.pl\":1,\"ostrowwlkp.pl\":1,\"ot.it\":1,\"ota.gunma.jp\":1,\"ota.tokyo.jp\":1,\"otago.museum\":1,\"otake.hiroshima.jp\":1,\"otaki.chiba.jp\":1,\"otaki.nagano.jp\":1,\"otaki.saitama.jp\":1,\"otama.fukushima.jp\":1,\"otap.co\":2,\"otari.nagano.jp\":1,\"otaru.hokkaido.jp\":1,\"other.nf\":1,\"oto.fukuoka.jp\":1,\"otobe.hokkaido.jp\":1,\"otofuke.hokkaido.jp\":1,\"otoineppu.hokkaido.jp\":1,\"otoyo.kochi.jp\":1,\"otsu.shiga.jp\":1,\"otsuchi.iwate.jp\":1,\"otsuki.kochi.jp\":1,\"otsuki.yamanashi.jp\":1,\"ouchi.saga.jp\":1,\"ouda.nara.jp\":1,\"oum.gov.pl\":1,\"oumu.hokkaido.jp\":1,\"outsystemscloud.com\":1,\"overhalla.no\":1,\"ovre-eiker.no\":1,\"owani.aomori.jp\":1,\"owariasahi.aichi.jp\":1,\"own.pm\":1,\"ownip.net\":1,\"ownprovider.com\":1,\"owo.codes\":2,\"ox.rs\":1,\"oxford.museum\":1,\"oy.lc\":1,\"oya.to\":1,\"oyabe.toyama.jp\":1,\"oyama.tochigi.jp\":1,\"oyamazaki.kyoto.jp\":1,\"oyer.no\":1,\"oygarden.no\":1,\"oyodo.nara.jp\":1,\"oystre-slidre.no\":1,\"oz.au\":1,\"ozora.hokkaido.jp\":1,\"ozu.ehime.jp\":1,\"ozu.kumamoto.jp\":1,\"p.bg\":1,\"p.se\":1,\"pa.gov.br\":1,\"pa.gov.pl\":1,\"pa.it\":1,\"pa.leg.br\":1,\"pa.us\":1,\"paas.datacenter.fi\":1,\"paas.massivegrid.com\":1,\"pacific.museum\":1,\"paderborn.museum\":1,\"padova.it\":1,\"padua.it\":1,\"pagefrontapp.com\":1,\"pages.dev\":1,\"pages.wiardweb.com\":1,\"pagespeedmobilizer.com\":1,\"pagexl.com\":1,\"palace.museum\":1,\"paleo.museum\":1,\"palermo.it\":1,\"palmas.br\":1,\"palmsprings.museum\":1,\"panama.museum\":1,\"panel.gg\":1,\"pantheonsite.io\":1,\"parachuting.aero\":1,\"paragliding.aero\":1,\"paris.eu.org\":1,\"paris.museum\":1,\"parliament.cy\":1,\"parliament.nz\":1,\"parma.it\":1,\"paroch.k12.ma.us\":1,\"parti.se\":1,\"pasadena.museum\":1,\"passenger-association.aero\":1,\"patria.bo\":1,\"pavia.it\":1,\"pb.ao\":1,\"pb.gov.br\":1,\"pb.leg.br\":1,\"pc.it\":1,\"pc.pl\":1,\"pcloud.host\":1,\"pd.it\":1,\"pdns.page\":1,\"pe.ca\":1,\"pe.gov.br\":1,\"pe.it\":1,\"pe.kr\":1,\"pe.leg.br\":1,\"penza.su\":1,\"per.la\":1,\"per.nf\":1,\"per.sg\":1,\"perso.ht\":1,\"perso.sn\":1,\"perso.tn\":1,\"perspecta.cloud\":1,\"perugia.it\":1,\"pesaro-urbino.it\":1,\"pesarourbino.it\":1,\"pescara.it\":1,\"pg\":2,\"pg.it\":1,\"pgafan.net\":1,\"pgfog.com\":1,\"pharmacien.fr\":1,\"pharmaciens.km\":1,\"pharmacy.museum\":1,\"philadelphia.museum\":1,\"philadelphiaarea.museum\":1,\"philately.museum\":1,\"phoenix.museum\":1,\"photography.museum\":1,\"pi.gov.br\":1,\"pi.it\":1,\"pi.leg.br\":1,\"piacenza.it\":1,\"piedmont.it\":1,\"piemonte.it\":1,\"pila.pl\":1,\"pilot.aero\":1,\"pilots.museum\":1,\"pimienta.org\":1,\"pinb.gov.pl\":1,\"pippu.hokkaido.jp\":1,\"pisa.it\":1,\"pistoia.it\":1,\"pisz.pl\":1,\"pittsburgh.museum\":1,\"piw.gov.pl\":1,\"pixolino.com\":1,\"pl.eu.org\":1,\"pl.ua\":1,\"planetarium.museum\":1,\"plantation.museum\":1,\"plants.museum\":1,\"platform0.app\":1,\"platformsh.site\":2,\"platter-app.com\":1,\"platter-app.dev\":1,\"platterp.us\":1,\"playstation-cloud.com\":1,\"plaza.museum\":1,\"plc.co.im\":1,\"plc.ly\":1,\"plc.uk\":1,\"plesk.page\":1,\"pleskns.com\":1,\"plo.ps\":1,\"plurinacional.bo\":1,\"pmn.it\":1,\"pn.it\":1,\"po.gov.pl\":1,\"po.it\":1,\"poa.br\":1,\"podhale.pl\":1,\"podlasie.pl\":1,\"podzone.net\":1,\"podzone.org\":1,\"point2this.com\":1,\"pointto.us\":1,\"poivron.org\":1,\"pokrovsk.su\":1,\"pol.dz\":1,\"pol.ht\":1,\"pol.tr\":1,\"police.uk\":1,\"politica.bo\":1,\"polkowice.pl\":1,\"poltava.ua\":1,\"pomorskie.pl\":1,\"pomorze.pl\":1,\"poniatowa.pl\":1,\"ponpes.id\":1,\"pony.club\":1,\"pordenone.it\":1,\"porsanger.no\":1,\"porsangu.no\":1,\"porsgrunn.no\":1,\"port.fr\":1,\"portal.museum\":1,\"portland.museum\":1,\"portlligat.museum\":1,\"posts-and-telecommunications.museum\":1,\"potager.org\":1,\"potenza.it\":1,\"powiat.pl\":1,\"poznan.pl\":1,\"pp.az\":1,\"pp.ru\":1,\"pp.se\":1,\"pp.ua\":1,\"ppg.br\":1,\"pr.gov.br\":1,\"pr.it\":1,\"pr.leg.br\":1,\"pr.us\":1,\"prato.it\":1,\"prd.fr\":1,\"prd.km\":1,\"prd.mg\":1,\"preservation.museum\":1,\"presidio.museum\":1,\"press.aero\":1,\"press.cy\":1,\"press.ma\":1,\"press.museum\":1,\"press.se\":1,\"presse.ci\":1,\"presse.km\":1,\"presse.ml\":1,\"pri.ee\":1,\"principe.st\":1,\"priv.at\":1,\"priv.hu\":1,\"priv.me\":1,\"priv.no\":1,\"priv.pl\":1,\"privatizehealthinsurance.net\":1,\"pro.az\":1,\"pro.br\":1,\"pro.cy\":1,\"pro.ec\":1,\"pro.fj\":1,\"pro.ht\":1,\"pro.mv\":1,\"pro.na\":1,\"pro.om\":1,\"pro.pr\":1,\"pro.tt\":1,\"pro.vn\":1,\"prochowice.pl\":1,\"production.aero\":1,\"prof.pr\":1,\"profesional.bo\":1,\"project.museum\":1,\"protonet.io\":1,\"pruszkow.pl\":1,\"prvcy.page\":1,\"przeworsk.pl\":1,\"psc.br\":1,\"psi.br\":1,\"psp.gov.pl\":1,\"psse.gov.pl\":1,\"pt.eu.org\":1,\"pt.it\":1,\"ptplus.fit\":1,\"pu.it\":1,\"pub.sa\":1,\"publ.pt\":1,\"public.museum\":1,\"publishproxy.com\":1,\"pubol.museum\":1,\"pubtls.org\":1,\"pueblo.bo\":1,\"pug.it\":1,\"puglia.it\":1,\"pulawy.pl\":1,\"pup.gov.pl\":1,\"pv.it\":1,\"pvh.br\":1,\"pvt.ge\":1,\"pvt.k12.ma.us\":1,\"pyatigorsk.ru\":1,\"pymnt.uk\":1,\"pz.it\":1,\"q-a.eu.org\":1,\"q.bg\":1,\"qa2.com\":1,\"qbuser.com\":1,\"qc.ca\":1,\"qc.com\":1,\"qcx.io\":1,\"qh.cn\":1,\"qld.au\":1,\"qld.edu.au\":1,\"qld.gov.au\":1,\"qsl.br\":1,\"qualifioapp.com\":1,\"quebec.museum\":1,\"quicksytes.com\":1,\"quipelements.com\":2,\"r.appspot.com\":2,\"r.bg\":1,\"r.cdn77.net\":1,\"r.se\":1,\"ra.it\":1,\"rackmaze.com\":1,\"rackmaze.net\":1,\"rade.no\":1,\"radio.am\":1,\"radio.br\":1,\"radio.fm\":1,\"radom.pl\":1,\"radoy.no\":1,\"ragusa.it\":1,\"rahkkeravju.no\":1,\"raholt.no\":1,\"railroad.museum\":1,\"railway.museum\":1,\"raisa.no\":1,\"rakkestad.no\":1,\"ralingen.no\":1,\"rana.no\":1,\"randaberg.no\":1,\"rankoshi.hokkaido.jp\":1,\"ranzan.saitama.jp\":1,\"ras.ru\":1,\"rauma.no\":1,\"ravendb.community\":1,\"ravendb.me\":1,\"ravendb.run\":1,\"ravenna.it\":1,\"rawa-maz.pl\":1,\"rc.it\":1,\"rdv.to\":1,\"re.it\":1,\"re.kr\":1,\"read-books.org\":1,\"readmyblog.org\":1,\"readthedocs.io\":1,\"realestate.pl\":1,\"realm.cz\":1,\"rebun.hokkaido.jp\":1,\"rec.br\":1,\"rec.co\":1,\"rec.nf\":1,\"rec.ro\":1,\"rec.ve\":1,\"recht.pro\":1,\"recife.br\":1,\"recreation.aero\":1,\"red.sv\":1,\"redirectme.net\":1,\"reg.dk\":1,\"reggio-calabria.it\":1,\"reggio-emilia.it\":1,\"reggiocalabria.it\":1,\"reggioemilia.it\":1,\"reklam.hu\":1,\"rel.ht\":1,\"rel.pl\":1,\"remotewd.com\":1,\"rendalen.no\":1,\"rennebu.no\":1,\"rennesoy.no\":1,\"rep.br\":1,\"rep.kp\":1,\"repbody.aero\":1,\"repl.co\":1,\"repl.run\":1,\"res.aero\":1,\"res.in\":1,\"research.aero\":1,\"research.museum\":1,\"resindevice.io\":1,\"resistance.museum\":1,\"revista.bo\":1,\"rg.it\":1,\"rhcloud.com\":1,\"ri.it\":1,\"ri.us\":1,\"ribeirao.br\":1,\"rieti.it\":1,\"rifu.miyagi.jp\":1,\"riik.ee\":1,\"rikubetsu.hokkaido.jp\":1,\"rikuzentakata.iwate.jp\":1,\"rimini.it\":1,\"rindal.no\":1,\"ringebu.no\":1,\"ringerike.no\":1,\"ringsaker.no\":1,\"rio.br\":1,\"riobranco.br\":1,\"riodejaneiro.museum\":1,\"riopreto.br\":1,\"rishiri.hokkaido.jp\":1,\"rishirifuji.hokkaido.jp\":1,\"risor.no\":1,\"rissa.no\":1,\"ritto.shiga.jp\":1,\"rivne.ua\":1,\"rj.gov.br\":1,\"rj.leg.br\":1,\"rl.no\":1,\"rm.it\":1,\"rn.gov.br\":1,\"rn.it\":1,\"rn.leg.br\":1,\"rnrt.tn\":1,\"rns.tn\":1,\"rnu.tn\":1,\"ro.eu.org\":1,\"ro.gov.br\":1,\"ro.im\":1,\"ro.it\":1,\"ro.leg.br\":1,\"roan.no\":1,\"rochester.museum\":1,\"rockart.museum\":1,\"rodoy.no\":1,\"rokunohe.aomori.jp\":1,\"rollag.no\":1,\"roma.it\":1,\"roma.museum\":1,\"rome.it\":1,\"romsa.no\":1,\"romskog.no\":1,\"roros.no\":1,\"rost.no\":1,\"rotorcraft.aero\":1,\"router.management\":1,\"rovigo.it\":1,\"rovno.ua\":1,\"royken.no\":1,\"royrvik.no\":1,\"rr.gov.br\":1,\"rr.leg.br\":1,\"rs.gov.br\":1,\"rs.leg.br\":1,\"rsc.cdn77.org\":1,\"ru.com\":1,\"ru.eu.org\":1,\"ru.net\":1,\"run.app\":1,\"ruovat.no\":1,\"russia.museum\":1,\"rv.ua\":1,\"rybnik.pl\":1,\"rygge.no\":1,\"ryokami.saitama.jp\":1,\"ryugasaki.ibaraki.jp\":1,\"ryuoh.shiga.jp\":1,\"rzeszow.pl\":1,\"rzgw.gov.pl\":1,\"s.bg\":1,\"s.se\":1,\"s3-ap-northeast-1.amazonaws.com\":1,\"s3-ap-northeast-2.amazonaws.com\":1,\"s3-ap-south-1.amazonaws.com\":1,\"s3-ap-southeast-1.amazonaws.com\":1,\"s3-ap-southeast-2.amazonaws.com\":1,\"s3-ca-central-1.amazonaws.com\":1,\"s3-eu-central-1.amazonaws.com\":1,\"s3-eu-west-1.amazonaws.com\":1,\"s3-eu-west-2.amazonaws.com\":1,\"s3-eu-west-3.amazonaws.com\":1,\"s3-external-1.amazonaws.com\":1,\"s3-fips-us-gov-west-1.amazonaws.com\":1,\"s3-sa-east-1.amazonaws.com\":1,\"s3-us-east-2.amazonaws.com\":1,\"s3-us-gov-west-1.amazonaws.com\":1,\"s3-us-west-1.amazonaws.com\":1,\"s3-us-west-2.amazonaws.com\":1,\"s3-website-ap-northeast-1.amazonaws.com\":1,\"s3-website-ap-southeast-1.amazonaws.com\":1,\"s3-website-ap-southeast-2.amazonaws.com\":1,\"s3-website-eu-west-1.amazonaws.com\":1,\"s3-website-sa-east-1.amazonaws.com\":1,\"s3-website-us-east-1.amazonaws.com\":1,\"s3-website-us-west-1.amazonaws.com\":1,\"s3-website-us-west-2.amazonaws.com\":1,\"s3-website.ap-northeast-2.amazonaws.com\":1,\"s3-website.ap-south-1.amazonaws.com\":1,\"s3-website.ca-central-1.amazonaws.com\":1,\"s3-website.eu-central-1.amazonaws.com\":1,\"s3-website.eu-west-2.amazonaws.com\":1,\"s3-website.eu-west-3.amazonaws.com\":1,\"s3-website.us-east-2.amazonaws.com\":1,\"s3.amazonaws.com\":1,\"s3.ap-northeast-2.amazonaws.com\":1,\"s3.ap-south-1.amazonaws.com\":1,\"s3.ca-central-1.amazonaws.com\":1,\"s3.cn-north-1.amazonaws.com.cn\":1,\"s3.dualstack.ap-northeast-1.amazonaws.com\":1,\"s3.dualstack.ap-northeast-2.amazonaws.com\":1,\"s3.dualstack.ap-south-1.amazonaws.com\":1,\"s3.dualstack.ap-southeast-1.amazonaws.com\":1,\"s3.dualstack.ap-southeast-2.amazonaws.com\":1,\"s3.dualstack.ca-central-1.amazonaws.com\":1,\"s3.dualstack.eu-central-1.amazonaws.com\":1,\"s3.dualstack.eu-west-1.amazonaws.com\":1,\"s3.dualstack.eu-west-2.amazonaws.com\":1,\"s3.dualstack.eu-west-3.amazonaws.com\":1,\"s3.dualstack.sa-east-1.amazonaws.com\":1,\"s3.dualstack.us-east-1.amazonaws.com\":1,\"s3.dualstack.us-east-2.amazonaws.com\":1,\"s3.eu-central-1.amazonaws.com\":1,\"s3.eu-west-2.amazonaws.com\":1,\"s3.eu-west-3.amazonaws.com\":1,\"s3.us-east-2.amazonaws.com\":1,\"s5y.io\":2,\"sa-east-1.elasticbeanstalk.com\":1,\"sa.au\":1,\"sa.com\":1,\"sa.cr\":1,\"sa.edu.au\":1,\"sa.gov.au\":1,\"sa.gov.pl\":1,\"sa.it\":1,\"sabae.fukui.jp\":1,\"sado.niigata.jp\":1,\"safety.aero\":1,\"saga.jp\":1,\"saga.saga.jp\":1,\"sagae.yamagata.jp\":1,\"sagamihara.kanagawa.jp\":1,\"saigawa.fukuoka.jp\":1,\"saijo.ehime.jp\":1,\"saikai.nagasaki.jp\":1,\"saiki.oita.jp\":1,\"saintlouis.museum\":1,\"saitama.jp\":1,\"saitama.saitama.jp\":1,\"saito.miyazaki.jp\":1,\"saka.hiroshima.jp\":1,\"sakado.saitama.jp\":1,\"sakae.chiba.jp\":1,\"sakae.nagano.jp\":1,\"sakahogi.gifu.jp\":1,\"sakai.fukui.jp\":1,\"sakai.ibaraki.jp\":1,\"sakai.osaka.jp\":1,\"sakaiminato.tottori.jp\":1,\"sakaki.nagano.jp\":1,\"sakata.yamagata.jp\":1,\"sakawa.kochi.jp\":1,\"sakegawa.yamagata.jp\":1,\"saku.nagano.jp\":1,\"sakuho.nagano.jp\":1,\"sakura.chiba.jp\":1,\"sakura.tochigi.jp\":1,\"sakuragawa.ibaraki.jp\":1,\"sakurai.nara.jp\":1,\"sakyo.kyoto.jp\":1,\"salangen.no\":1,\"salat.no\":1,\"salem.museum\":1,\"salerno.it\":1,\"saltdal.no\":1,\"salud.bo\":1,\"salvador.br\":1,\"salvadordali.museum\":1,\"salzburg.museum\":1,\"samegawa.fukushima.jp\":1,\"samnanger.no\":1,\"sampa.br\":1,\"samukawa.kanagawa.jp\":1,\"sanagochi.tokushima.jp\":1,\"sanda.hyogo.jp\":1,\"sandcats.io\":1,\"sande.more-og-romsdal.no\":1,\"sande.vestfold.no\":1,\"sande.xn--mre-og-romsdal-qqb.no\":1,\"sandefjord.no\":1,\"sandiego.museum\":1,\"sandnes.no\":1,\"sandnessjoen.no\":1,\"sandoy.no\":1,\"sanfrancisco.museum\":1,\"sango.nara.jp\":1,\"sanjo.niigata.jp\":1,\"sannan.hyogo.jp\":1,\"sannohe.aomori.jp\":1,\"sano.tochigi.jp\":1,\"sanok.pl\":1,\"santabarbara.museum\":1,\"santacruz.museum\":1,\"santafe.museum\":1,\"santamaria.br\":1,\"santoandre.br\":1,\"sanuki.kagawa.jp\":1,\"saobernardo.br\":1,\"saogonca.br\":1,\"saotome.st\":1,\"sapporo.jp\":2,\"sar.it\":1,\"sardegna.it\":1,\"sardinia.it\":1,\"saroma.hokkaido.jp\":1,\"sarpsborg.no\":1,\"sarufutsu.hokkaido.jp\":1,\"sasaguri.fukuoka.jp\":1,\"sasayama.hyogo.jp\":1,\"sasebo.nagasaki.jp\":1,\"saskatchewan.museum\":1,\"sassari.it\":1,\"satosho.okayama.jp\":1,\"satsumasendai.kagoshima.jp\":1,\"satte.saitama.jp\":1,\"satx.museum\":1,\"sauda.no\":1,\"sauherad.no\":1,\"savannahga.museum\":1,\"saves-the-whales.com\":1,\"savona.it\":1,\"sayama.osaka.jp\":1,\"sayama.saitama.jp\":1,\"sayo.hyogo.jp\":1,\"sb.ua\":1,\"sc.cn\":1,\"sc.gov.br\":1,\"sc.ke\":1,\"sc.kr\":1,\"sc.leg.br\":1,\"sc.ls\":1,\"sc.tz\":1,\"sc.ug\":1,\"sc.us\":1,\"scapp.io\":1,\"sch.ae\":1,\"sch.id\":1,\"sch.ir\":1,\"sch.jo\":1,\"sch.lk\":1,\"sch.ly\":1,\"sch.ng\":1,\"sch.qa\":1,\"sch.sa\":1,\"sch.so\":1,\"sch.uk\":2,\"sch.zm\":1,\"schlesisches.museum\":1,\"schoenbrunn.museum\":1,\"schokokeks.net\":1,\"schokoladen.museum\":1,\"school.museum\":1,\"school.na\":1,\"school.nz\":1,\"school.za\":1,\"schools.nsw.edu.au\":1,\"schulserver.de\":1,\"schweiz.museum\":1,\"sci.eg\":1,\"science-fiction.museum\":1,\"science.museum\":1,\"scienceandhistory.museum\":1,\"scienceandindustry.museum\":1,\"sciencecenter.museum\":1,\"sciencecenters.museum\":1,\"sciencehistory.museum\":1,\"sciences.museum\":1,\"sciencesnaturelles.museum\":1,\"scientist.aero\":1,\"scotland.museum\":1,\"scrapper-site.net\":1,\"scrapping.cc\":1,\"scrysec.com\":1,\"sd.cn\":1,\"sd.us\":1,\"sdn.gov.pl\":1,\"se.eu.org\":1,\"se.gov.br\":1,\"se.leg.br\":1,\"se.net\":1,\"seaport.museum\":1,\"sebastopol.ua\":1,\"sec.ps\":1,\"securitytactics.com\":1,\"seg.br\":1,\"seidat.net\":1,\"seihi.nagasaki.jp\":1,\"seika.kyoto.jp\":1,\"seiro.niigata.jp\":1,\"seirou.niigata.jp\":1,\"seiyo.ehime.jp\":1,\"sejny.pl\":1,\"seki.gifu.jp\":1,\"sekigahara.gifu.jp\":1,\"sekikawa.niigata.jp\":1,\"sel.no\":1,\"selbu.no\":1,\"selfip.biz\":1,\"selfip.com\":1,\"selfip.info\":1,\"selfip.net\":1,\"selfip.org\":1,\"selje.no\":1,\"seljord.no\":1,\"sells-for-less.com\":1,\"sells-for-u.com\":1,\"sells-it.net\":1,\"sellsyourhome.org\":1,\"semboku.akita.jp\":1,\"semine.miyagi.jp\":1,\"sendai.jp\":2,\"sennan.osaka.jp\":1,\"senseering.net\":1,\"sensiosite.cloud\":2,\"seoul.kr\":1,\"sera.hiroshima.jp\":1,\"seranishi.hiroshima.jp\":1,\"servebbs.com\":1,\"servebbs.net\":1,\"servebbs.org\":1,\"servebeer.com\":1,\"serveblog.net\":1,\"servecounterstrike.com\":1,\"serveexchange.com\":1,\"serveftp.com\":1,\"serveftp.net\":1,\"serveftp.org\":1,\"servegame.com\":1,\"servegame.org\":1,\"servehalflife.com\":1,\"servehttp.com\":1,\"servehumour.com\":1,\"serveirc.com\":1,\"serveminecraft.net\":1,\"servemp3.com\":1,\"servep2p.com\":1,\"servepics.com\":1,\"servequake.com\":1,\"servesarcasm.com\":1,\"service.gov.uk\":1,\"services.aero\":1,\"setagaya.tokyo.jp\":1,\"seto.aichi.jp\":1,\"setouchi.okayama.jp\":1,\"settlement.museum\":1,\"settlers.museum\":1,\"settsu.osaka.jp\":1,\"sevastopol.ua\":1,\"sex.hu\":1,\"sex.pl\":1,\"sf.no\":1,\"sh.cn\":1,\"shacknet.nu\":1,\"shakotan.hokkaido.jp\":1,\"shari.hokkaido.jp\":1,\"shell.museum\":1,\"sherbrooke.museum\":1,\"shibata.miyagi.jp\":1,\"shibata.niigata.jp\":1,\"shibecha.hokkaido.jp\":1,\"shibetsu.hokkaido.jp\":1,\"shibukawa.gunma.jp\":1,\"shibuya.tokyo.jp\":1,\"shichikashuku.miyagi.jp\":1,\"shichinohe.aomori.jp\":1,\"shiftedit.io\":1,\"shiga.jp\":1,\"shiiba.miyazaki.jp\":1,\"shijonawate.osaka.jp\":1,\"shika.ishikawa.jp\":1,\"shikabe.hokkaido.jp\":1,\"shikama.miyagi.jp\":1,\"shikaoi.hokkaido.jp\":1,\"shikatsu.aichi.jp\":1,\"shiki.saitama.jp\":1,\"shikokuchuo.ehime.jp\":1,\"shima.mie.jp\":1,\"shimabara.nagasaki.jp\":1,\"shimada.shizuoka.jp\":1,\"shimamaki.hokkaido.jp\":1,\"shimamoto.osaka.jp\":1,\"shimane.jp\":1,\"shimane.shimane.jp\":1,\"shimizu.hokkaido.jp\":1,\"shimizu.shizuoka.jp\":1,\"shimoda.shizuoka.jp\":1,\"shimodate.ibaraki.jp\":1,\"shimofusa.chiba.jp\":1,\"shimogo.fukushima.jp\":1,\"shimoichi.nara.jp\":1,\"shimoji.okinawa.jp\":1,\"shimokawa.hokkaido.jp\":1,\"shimokitayama.nara.jp\":1,\"shimonita.gunma.jp\":1,\"shimonoseki.yamaguchi.jp\":1,\"shimosuwa.nagano.jp\":1,\"shimotsuke.tochigi.jp\":1,\"shimotsuma.ibaraki.jp\":1,\"shinagawa.tokyo.jp\":1,\"shinanomachi.nagano.jp\":1,\"shingo.aomori.jp\":1,\"shingu.fukuoka.jp\":1,\"shingu.hyogo.jp\":1,\"shingu.wakayama.jp\":1,\"shinichi.hiroshima.jp\":1,\"shinjo.nara.jp\":1,\"shinjo.okayama.jp\":1,\"shinjo.yamagata.jp\":1,\"shinjuku.tokyo.jp\":1,\"shinkamigoto.nagasaki.jp\":1,\"shinonsen.hyogo.jp\":1,\"shinshinotsu.hokkaido.jp\":1,\"shinshiro.aichi.jp\":1,\"shinto.gunma.jp\":1,\"shintoku.hokkaido.jp\":1,\"shintomi.miyazaki.jp\":1,\"shinyoshitomi.fukuoka.jp\":1,\"shiogama.miyagi.jp\":1,\"shiojiri.nagano.jp\":1,\"shioya.tochigi.jp\":1,\"shirahama.wakayama.jp\":1,\"shirakawa.fukushima.jp\":1,\"shirakawa.gifu.jp\":1,\"shirako.chiba.jp\":1,\"shiranuka.hokkaido.jp\":1,\"shiraoi.hokkaido.jp\":1,\"shiraoka.saitama.jp\":1,\"shirataka.yamagata.jp\":1,\"shiriuchi.hokkaido.jp\":1,\"shiroi.chiba.jp\":1,\"shiroishi.miyagi.jp\":1,\"shiroishi.saga.jp\":1,\"shirosato.ibaraki.jp\":1,\"shishikui.tokushima.jp\":1,\"shiso.hyogo.jp\":1,\"shisui.chiba.jp\":1,\"shitara.aichi.jp\":1,\"shiwa.iwate.jp\":1,\"shizukuishi.iwate.jp\":1,\"shizuoka.jp\":1,\"shizuoka.shizuoka.jp\":1,\"shobara.hiroshima.jp\":1,\"shonai.fukuoka.jp\":1,\"shonai.yamagata.jp\":1,\"shoo.okayama.jp\":1,\"shop.ht\":1,\"shop.hu\":1,\"shop.pl\":1,\"shop.ro\":1,\"shop.th\":1,\"shopitsite.com\":1,\"shopware.store\":1,\"show.aero\":1,\"showa.fukushima.jp\":1,\"showa.gunma.jp\":1,\"showa.yamanashi.jp\":1,\"shunan.yamaguchi.jp\":1,\"shw.io\":1,\"si.eu.org\":1,\"si.it\":1,\"sibenik.museum\":1,\"sic.it\":1,\"sicilia.it\":1,\"sicily.it\":1,\"siellak.no\":1,\"siena.it\":1,\"sigdal.no\":1,\"siljan.no\":1,\"silk.museum\":1,\"simple-url.com\":1,\"sinaapp.com\":1,\"siracusa.it\":1,\"sirdal.no\":1,\"siteleaf.net\":1,\"sites.static.land\":1,\"sjc.br\":1,\"sk.ca\":1,\"sk.eu.org\":1,\"skanit.no\":1,\"skanland.no\":1,\"skaun.no\":1,\"skedsmo.no\":1,\"skedsmokorset.no\":1,\"ski.museum\":1,\"ski.no\":1,\"skien.no\":1,\"skierva.no\":1,\"skiptvet.no\":1,\"skjak.no\":1,\"skjervoy.no\":1,\"sklep.pl\":1,\"sko.gov.pl\":1,\"skoczow.pl\":1,\"skodje.no\":1,\"skole.museum\":1,\"skydiving.aero\":1,\"skygearapp.com\":1,\"slask.pl\":1,\"slattum.no\":1,\"sld.do\":1,\"sld.pa\":1,\"slg.br\":1,\"slupsk.pl\":1,\"slz.br\":1,\"sm.ua\":1,\"small-web.org\":1,\"smola.no\":1,\"sn.cn\":1,\"snaase.no\":1,\"snasa.no\":1,\"snillfjord.no\":1,\"snoasa.no\":1,\"so.gov.pl\":1,\"so.it\":1,\"sobetsu.hokkaido.jp\":1,\"soc.lk\":1,\"soc.srcf.net\":1,\"sochi.su\":1,\"society.museum\":1,\"sodegaura.chiba.jp\":1,\"soeda.fukuoka.jp\":1,\"software.aero\":1,\"sogndal.no\":1,\"sogne.no\":1,\"soja.okayama.jp\":1,\"soka.saitama.jp\":1,\"sokndal.no\":1,\"sola.no\":1,\"sologne.museum\":1,\"solund.no\":1,\"soma.fukushima.jp\":1,\"somna.no\":1,\"sondre-land.no\":1,\"sondrio.it\":1,\"songdalen.no\":1,\"soni.nara.jp\":1,\"soo.kagoshima.jp\":1,\"sopot.pl\":1,\"sor-aurdal.no\":1,\"sor-fron.no\":1,\"sor-odal.no\":1,\"sor-varanger.no\":1,\"sorfold.no\":1,\"sorocaba.br\":1,\"sorreisa.no\":1,\"sortland.no\":1,\"sorum.no\":1,\"sos.pl\":1,\"sosa.chiba.jp\":1,\"sosnowiec.pl\":1,\"soundandvision.museum\":1,\"soundcast.me\":1,\"southcarolina.museum\":1,\"southwest.museum\":1,\"sowa.ibaraki.jp\":1,\"sp.gov.br\":1,\"sp.it\":1,\"sp.leg.br\":1,\"space-to-rent.com\":1,\"space.museum\":1,\"spacekit.io\":1,\"spb.ru\":1,\"spb.su\":1,\"spdns.de\":1,\"spdns.eu\":1,\"spdns.org\":1,\"spectrum.myjino.ru\":2,\"sphinx.mythic-beasts.com\":1,\"spjelkavik.no\":1,\"sport.hu\":1,\"spy.museum\":1,\"spydeberg.no\":1,\"square.museum\":1,\"square7.ch\":1,\"square7.de\":1,\"square7.net\":1,\"sr.gov.pl\":1,\"sr.it\":1,\"srv.br\":1,\"ss.it\":1,\"ssl.origin.cdn77-secure.org\":1,\"st.no\":1,\"stackhero-network.com\":1,\"stadt.museum\":1,\"stage.nodeart.io\":1,\"staging.onred.one\":1,\"stalbans.museum\":1,\"stalowa-wola.pl\":1,\"stange.no\":1,\"starachowice.pl\":1,\"stargard.pl\":1,\"starnberg.museum\":1,\"starostwo.gov.pl\":1,\"stat.no\":1,\"state.museum\":1,\"stateofdelaware.museum\":1,\"stathelle.no\":1,\"static-access.net\":1,\"static.land\":1,\"static.observableusercontent.com\":1,\"statics.cloud\":2,\"station.museum\":1,\"stavanger.no\":1,\"stavern.no\":1,\"steam.museum\":1,\"steiermark.museum\":1,\"steigen.no\":1,\"steinkjer.no\":1,\"stg.dev\":2,\"sth.ac.at\":1,\"stjohn.museum\":1,\"stjordal.no\":1,\"stjordalshalsen.no\":1,\"stockholm.museum\":1,\"stokke.no\":1,\"stolos.io\":2,\"stor-elvdal.no\":1,\"storage.yandexcloud.net\":1,\"stord.no\":1,\"stordal.no\":1,\"store.bb\":1,\"store.dk\":1,\"store.nf\":1,\"store.ro\":1,\"store.st\":1,\"store.ve\":1,\"storfjord.no\":1,\"storj.farm\":1,\"stpetersburg.museum\":1,\"strand.no\":1,\"stranda.no\":1,\"stryn.no\":1,\"student.aero\":1,\"stuff-4-sale.org\":1,\"stuff-4-sale.us\":1,\"stufftoread.com\":1,\"stuttgart.museum\":1,\"sue.fukuoka.jp\":1,\"suedtirol.it\":1,\"suginami.tokyo.jp\":1,\"sugito.saitama.jp\":1,\"suifu.ibaraki.jp\":1,\"suisse.museum\":1,\"suita.osaka.jp\":1,\"sukagawa.fukushima.jp\":1,\"sukumo.kochi.jp\":1,\"sula.no\":1,\"suldal.no\":1,\"suli.hu\":1,\"sumida.tokyo.jp\":1,\"sumita.iwate.jp\":1,\"sumoto.hyogo.jp\":1,\"sumoto.kumamoto.jp\":1,\"sumy.ua\":1,\"sunagawa.hokkaido.jp\":1,\"sund.no\":1,\"sunndal.no\":1,\"surgeonshall.museum\":1,\"surnadal.no\":1,\"surrey.museum\":1,\"susaki.kochi.jp\":1,\"susono.shizuoka.jp\":1,\"suwa.nagano.jp\":1,\"suwalki.pl\":1,\"suzaka.nagano.jp\":1,\"suzu.ishikawa.jp\":1,\"suzuka.mie.jp\":1,\"sv.it\":1,\"svalbard.no\":1,\"svc.firenet.ch\":2,\"sveio.no\":1,\"svelvik.no\":1,\"svizzera.museum\":1,\"svn-repos.de\":1,\"sweden.museum\":1,\"sweetpepper.org\":1,\"swidnica.pl\":1,\"swidnik.pl\":1,\"swiebodzin.pl\":1,\"swinoujscie.pl\":1,\"sx.cn\":1,\"sydney.museum\":1,\"sykkylven.no\":1,\"syncloud.it\":1,\"syno-ds.de\":1,\"synology-diskstation.de\":1,\"synology-ds.de\":1,\"synology.me\":1,\"sys.qcx.io\":2,\"sytes.net\":1,\"szczecin.pl\":1,\"szczytno.pl\":1,\"szex.hu\":1,\"szkola.pl\":1,\"t.bg\":1,\"t.se\":1,\"t3l3p0rt.net\":1,\"ta.it\":1,\"taa.it\":1,\"tabayama.yamanashi.jp\":1,\"tabuse.yamaguchi.jp\":1,\"tachiarai.fukuoka.jp\":1,\"tachikawa.tokyo.jp\":1,\"tadaoka.osaka.jp\":1,\"tado.mie.jp\":1,\"tadotsu.kagawa.jp\":1,\"tagajo.miyagi.jp\":1,\"tagami.niigata.jp\":1,\"tagawa.fukuoka.jp\":1,\"tahara.aichi.jp\":1,\"taifun-dns.de\":1,\"taiji.wakayama.jp\":1,\"taiki.hokkaido.jp\":1,\"taiki.mie.jp\":1,\"tainai.niigata.jp\":1,\"taira.toyama.jp\":1,\"taishi.hyogo.jp\":1,\"taishi.osaka.jp\":1,\"taishin.fukushima.jp\":1,\"taito.tokyo.jp\":1,\"taiwa.miyagi.jp\":1,\"tajimi.gifu.jp\":1,\"tajiri.osaka.jp\":1,\"taka.hyogo.jp\":1,\"takagi.nagano.jp\":1,\"takahagi.ibaraki.jp\":1,\"takahama.aichi.jp\":1,\"takahama.fukui.jp\":1,\"takaharu.miyazaki.jp\":1,\"takahashi.okayama.jp\":1,\"takahata.yamagata.jp\":1,\"takaishi.osaka.jp\":1,\"takamatsu.kagawa.jp\":1,\"takamori.kumamoto.jp\":1,\"takamori.nagano.jp\":1,\"takanabe.miyazaki.jp\":1,\"takanezawa.tochigi.jp\":1,\"takaoka.toyama.jp\":1,\"takarazuka.hyogo.jp\":1,\"takasago.hyogo.jp\":1,\"takasaki.gunma.jp\":1,\"takashima.shiga.jp\":1,\"takasu.hokkaido.jp\":1,\"takata.fukuoka.jp\":1,\"takatori.nara.jp\":1,\"takatsuki.osaka.jp\":1,\"takatsuki.shiga.jp\":1,\"takayama.gifu.jp\":1,\"takayama.gunma.jp\":1,\"takayama.nagano.jp\":1,\"takazaki.miyazaki.jp\":1,\"takehara.hiroshima.jp\":1,\"taketa.oita.jp\":1,\"taketomi.okinawa.jp\":1,\"taki.mie.jp\":1,\"takikawa.hokkaido.jp\":1,\"takino.hyogo.jp\":1,\"takinoue.hokkaido.jp\":1,\"takko.aomori.jp\":1,\"tako.chiba.jp\":1,\"taku.saga.jp\":1,\"tama.tokyo.jp\":1,\"tamakawa.fukushima.jp\":1,\"tamaki.mie.jp\":1,\"tamamura.gunma.jp\":1,\"tamano.okayama.jp\":1,\"tamatsukuri.ibaraki.jp\":1,\"tamayu.shimane.jp\":1,\"tamba.hyogo.jp\":1,\"tana.no\":1,\"tanabe.kyoto.jp\":1,\"tanabe.wakayama.jp\":1,\"tanagura.fukushima.jp\":1,\"tananger.no\":1,\"tank.museum\":1,\"tanohata.iwate.jp\":1,\"tara.saga.jp\":1,\"tarama.okinawa.jp\":1,\"taranto.it\":1,\"targi.pl\":1,\"tarnobrzeg.pl\":1,\"tarui.gifu.jp\":1,\"tarumizu.kagoshima.jp\":1,\"tas.au\":1,\"tas.edu.au\":1,\"tas.gov.au\":1,\"tashkent.su\":1,\"tatebayashi.gunma.jp\":1,\"tateshina.nagano.jp\":1,\"tateyama.chiba.jp\":1,\"tateyama.toyama.jp\":1,\"tatsuno.hyogo.jp\":1,\"tatsuno.nagano.jp\":1,\"tawaramoto.nara.jp\":1,\"taxi.br\":1,\"tc.br\":1,\"tcm.museum\":1,\"tcp4.me\":1,\"te.it\":1,\"te.ua\":1,\"teaches-yoga.com\":1,\"teams.algorithmia.com\":0,\"tec.br\":1,\"tec.mi.us\":1,\"tec.ve\":1,\"technology.museum\":1,\"tecnologia.bo\":1,\"tel.tr\":1,\"tele.amune.org\":1,\"telebit.app\":1,\"telebit.io\":1,\"telebit.xyz\":2,\"telekommunikation.museum\":1,\"television.museum\":1,\"temp-dns.com\":1,\"tempio-olbia.it\":1,\"tempioolbia.it\":1,\"tendo.yamagata.jp\":1,\"tenei.fukushima.jp\":1,\"tenkawa.nara.jp\":1,\"tenri.nara.jp\":1,\"teo.br\":1,\"teramo.it\":1,\"termez.su\":1,\"terni.it\":1,\"ternopil.ua\":1,\"teshikaga.hokkaido.jp\":1,\"test-iserv.de\":1,\"test.algorithmia.com\":0,\"test.ru\":1,\"test.tj\":1,\"texas.museum\":1,\"textile.museum\":1,\"tgory.pl\":1,\"the.br\":1,\"theater.museum\":1,\"theworkpc.com\":1,\"thingdustdata.com\":1,\"thruhere.net\":1,\"time.museum\":1,\"time.no\":1,\"timekeeping.museum\":1,\"tingvoll.no\":1,\"tinn.no\":1,\"tj.cn\":1,\"tjeldsund.no\":1,\"tjome.no\":1,\"tksat.bo\":1,\"tm.cy\":1,\"tm.fr\":1,\"tm.hu\":1,\"tm.km\":1,\"tm.mc\":1,\"tm.mg\":1,\"tm.no\":1,\"tm.pl\":1,\"tm.ro\":1,\"tm.se\":1,\"tm.za\":1,\"tmp.br\":1,\"tn.it\":1,\"tn.us\":1,\"to.gov.br\":1,\"to.gt\":1,\"to.it\":1,\"to.leg.br\":1,\"to.md\":1,\"to.work\":1,\"toba.mie.jp\":1,\"tobe.ehime.jp\":1,\"tobetsu.hokkaido.jp\":1,\"tobishima.aichi.jp\":1,\"tochigi.jp\":1,\"tochigi.tochigi.jp\":1,\"tochio.niigata.jp\":1,\"toda.saitama.jp\":1,\"toei.aichi.jp\":1,\"toga.toyama.jp\":1,\"togakushi.nagano.jp\":1,\"togane.chiba.jp\":1,\"togitsu.nagasaki.jp\":1,\"togliatti.su\":1,\"togo.aichi.jp\":1,\"togura.nagano.jp\":1,\"tohma.hokkaido.jp\":1,\"tohnosho.chiba.jp\":1,\"toho.fukuoka.jp\":1,\"tokai.aichi.jp\":1,\"tokai.ibaraki.jp\":1,\"tokamachi.niigata.jp\":1,\"tokashiki.okinawa.jp\":1,\"toki.gifu.jp\":1,\"tokigawa.saitama.jp\":1,\"tokke.no\":1,\"tokoname.aichi.jp\":1,\"tokorozawa.saitama.jp\":1,\"tokushima.jp\":1,\"tokushima.tokushima.jp\":1,\"tokuyama.yamaguchi.jp\":1,\"tokyo.jp\":1,\"tolga.no\":1,\"tomakomai.hokkaido.jp\":1,\"tomari.hokkaido.jp\":1,\"tome.miyagi.jp\":1,\"tomi.nagano.jp\":1,\"tomigusuku.okinawa.jp\":1,\"tomika.gifu.jp\":1,\"tomioka.gunma.jp\":1,\"tomisato.chiba.jp\":1,\"tomiya.miyagi.jp\":1,\"tomobe.ibaraki.jp\":1,\"tonaki.okinawa.jp\":1,\"tonami.toyama.jp\":1,\"tondabayashi.osaka.jp\":1,\"tone.ibaraki.jp\":1,\"tono.iwate.jp\":1,\"tonosho.kagawa.jp\":1,\"tonsberg.no\":1,\"toolforge.org\":1,\"toon.ehime.jp\":1,\"topology.museum\":1,\"torahime.shiga.jp\":1,\"toride.ibaraki.jp\":1,\"torino.it\":1,\"torino.museum\":1,\"torsken.no\":1,\"tos.it\":1,\"tosa.kochi.jp\":1,\"tosashimizu.kochi.jp\":1,\"toscana.it\":1,\"toshima.tokyo.jp\":1,\"tosu.saga.jp\":1,\"tottori.jp\":1,\"tottori.tottori.jp\":1,\"touch.museum\":1,\"tourism.pl\":1,\"tourism.tn\":1,\"towada.aomori.jp\":1,\"town.museum\":1,\"townnews-staging.com\":1,\"toya.hokkaido.jp\":1,\"toyako.hokkaido.jp\":1,\"toyama.jp\":1,\"toyama.toyama.jp\":1,\"toyo.kochi.jp\":1,\"toyoake.aichi.jp\":1,\"toyohashi.aichi.jp\":1,\"toyokawa.aichi.jp\":1,\"toyonaka.osaka.jp\":1,\"toyone.aichi.jp\":1,\"toyono.osaka.jp\":1,\"toyooka.hyogo.jp\":1,\"toyosato.shiga.jp\":1,\"toyota.aichi.jp\":1,\"toyota.yamaguchi.jp\":1,\"toyotomi.hokkaido.jp\":1,\"toyotsu.fukuoka.jp\":1,\"toyoura.hokkaido.jp\":1,\"tozawa.yamagata.jp\":1,\"tozsde.hu\":1,\"tp.it\":1,\"tr.eu.org\":1,\"tr.it\":1,\"tr.no\":1,\"tra.kp\":1,\"trader.aero\":1,\"trading.aero\":1,\"traeumtgerade.de\":1,\"trafficplex.cloud\":1,\"trainer.aero\":1,\"trana.no\":1,\"tranby.no\":1,\"trani-andria-barletta.it\":1,\"trani-barletta-andria.it\":1,\"traniandriabarletta.it\":1,\"tranibarlettaandria.it\":1,\"tranoy.no\":1,\"transport.museum\":1,\"transporte.bo\":1,\"transurl.be\":2,\"transurl.eu\":2,\"transurl.nl\":2,\"trapani.it\":1,\"travel.pl\":1,\"travel.tt\":1,\"trd.br\":1,\"tree.museum\":1,\"trentin-sud-tirol.it\":1,\"trentin-sudtirol.it\":1,\"trentin-sued-tirol.it\":1,\"trentin-suedtirol.it\":1,\"trentino-a-adige.it\":1,\"trentino-aadige.it\":1,\"trentino-alto-adige.it\":1,\"trentino-altoadige.it\":1,\"trentino-s-tirol.it\":1,\"trentino-stirol.it\":1,\"trentino-sud-tirol.it\":1,\"trentino-sudtirol.it\":1,\"trentino-sued-tirol.it\":1,\"trentino-suedtirol.it\":1,\"trentino.it\":1,\"trentinoa-adige.it\":1,\"trentinoaadige.it\":1,\"trentinoalto-adige.it\":1,\"trentinoaltoadige.it\":1,\"trentinos-tirol.it\":1,\"trentinostirol.it\":1,\"trentinosud-tirol.it\":1,\"trentinosudtirol.it\":1,\"trentinosued-tirol.it\":1,\"trentinosuedtirol.it\":1,\"trentinsud-tirol.it\":1,\"trentinsudtirol.it\":1,\"trentinsued-tirol.it\":1,\"trentinsuedtirol.it\":1,\"trento.it\":1,\"treviso.it\":1,\"trieste.it\":1,\"triton.zone\":2,\"troandin.no\":1,\"trogstad.no\":1,\"troitsk.su\":1,\"trolley.museum\":1,\"tromsa.no\":1,\"tromso.no\":1,\"trondheim.no\":1,\"trust.museum\":1,\"trustee.museum\":1,\"trycloudflare.com\":1,\"trysil.no\":1,\"ts.it\":1,\"tselinograd.su\":1,\"tsk.tr\":1,\"tsu.mie.jp\":1,\"tsubame.niigata.jp\":1,\"tsubata.ishikawa.jp\":1,\"tsubetsu.hokkaido.jp\":1,\"tsuchiura.ibaraki.jp\":1,\"tsuga.tochigi.jp\":1,\"tsugaru.aomori.jp\":1,\"tsuiki.fukuoka.jp\":1,\"tsukigata.hokkaido.jp\":1,\"tsukiyono.gunma.jp\":1,\"tsukuba.ibaraki.jp\":1,\"tsukui.kanagawa.jp\":1,\"tsukumi.oita.jp\":1,\"tsumagoi.gunma.jp\":1,\"tsunan.niigata.jp\":1,\"tsuno.kochi.jp\":1,\"tsuno.miyazaki.jp\":1,\"tsuru.yamanashi.jp\":1,\"tsuruga.fukui.jp\":1,\"tsurugashima.saitama.jp\":1,\"tsurugi.ishikawa.jp\":1,\"tsuruoka.yamagata.jp\":1,\"tsuruta.aomori.jp\":1,\"tsushima.aichi.jp\":1,\"tsushima.nagasaki.jp\":1,\"tsuwano.shimane.jp\":1,\"tsuyama.okayama.jp\":1,\"tt.im\":1,\"tula.su\":1,\"tunk.org\":1,\"tur.ar\":1,\"tur.br\":1,\"turek.pl\":1,\"turen.tn\":1,\"turin.it\":1,\"turystyka.pl\":1,\"tuscany.it\":1,\"tuva.su\":1,\"tuxfamily.org\":1,\"tv.bb\":1,\"tv.bo\":1,\"tv.br\":1,\"tv.im\":1,\"tv.it\":1,\"tv.kg\":1,\"tv.na\":1,\"tv.sd\":1,\"tv.tr\":1,\"tv.tz\":1,\"tvedestrand.no\":1,\"tw.cn\":1,\"twmail.cc\":1,\"twmail.net\":1,\"twmail.org\":1,\"tx.us\":1,\"tychy.pl\":1,\"tydal.no\":1,\"tynset.no\":1,\"tysfjord.no\":1,\"tysnes.no\":1,\"tysvar.no\":1,\"u.bg\":1,\"u.channelsdvr.net\":1,\"u.se\":1,\"u2-local.xnbay.com\":1,\"u2.xnbay.com\":1,\"ua.rs\":1,\"ube.yamaguchi.jp\":1,\"uber.space\":1,\"uberspace.de\":2,\"uchihara.ibaraki.jp\":1,\"uchiko.ehime.jp\":1,\"uchinada.ishikawa.jp\":1,\"uchinomi.kagawa.jp\":1,\"ud.it\":1,\"uda.nara.jp\":1,\"udi.br\":1,\"udine.it\":1,\"udono.mie.jp\":1,\"ueda.nagano.jp\":1,\"ueno.gunma.jp\":1,\"uenohara.yamanashi.jp\":1,\"ufcfan.org\":1,\"ug.gov.pl\":1,\"ugim.gov.pl\":1,\"uhren.museum\":1,\"ui.nabu.casa\":1,\"uji.kyoto.jp\":1,\"ujiie.tochigi.jp\":1,\"ujitawara.kyoto.jp\":1,\"uk.com\":1,\"uk.eu.org\":1,\"uk.kg\":1,\"uk.net\":1,\"uk0.bigv.io\":1,\"ukco.me\":1,\"uki.kumamoto.jp\":1,\"ukiha.fukuoka.jp\":1,\"uklugs.org\":1,\"ullensaker.no\":1,\"ullensvang.no\":1,\"ulm.museum\":1,\"ulsan.kr\":1,\"ulvik.no\":1,\"um.gov.pl\":1,\"umaji.kochi.jp\":1,\"umb.it\":1,\"umbria.it\":1,\"umi.fukuoka.jp\":1,\"umig.gov.pl\":1,\"unazuki.toyama.jp\":1,\"undersea.museum\":1,\"uni5.net\":1,\"union.aero\":1,\"univ.sn\":1,\"university.museum\":1,\"unjarga.no\":1,\"unnan.shimane.jp\":1,\"unusualperson.com\":1,\"unzen.nagasaki.jp\":1,\"uonuma.niigata.jp\":1,\"uozu.toyama.jp\":1,\"upow.gov.pl\":1,\"uppo.gov.pl\":1,\"urakawa.hokkaido.jp\":1,\"urasoe.okinawa.jp\":1,\"urausu.hokkaido.jp\":1,\"urawa.saitama.jp\":1,\"urayasu.chiba.jp\":1,\"urbino-pesaro.it\":1,\"urbinopesaro.it\":1,\"ureshino.mie.jp\":1,\"uri.arpa\":1,\"url.tw\":1,\"urn.arpa\":1,\"urown.cloud\":1,\"uruma.okinawa.jp\":1,\"uryu.hokkaido.jp\":1,\"us-1.evennode.com\":1,\"us-2.evennode.com\":1,\"us-3.evennode.com\":1,\"us-4.evennode.com\":1,\"us-east-1.amazonaws.com\":1,\"us-east-1.elasticbeanstalk.com\":1,\"us-east-2.elasticbeanstalk.com\":1,\"us-gov-west-1.elasticbeanstalk.com\":1,\"us-west-1.elasticbeanstalk.com\":1,\"us-west-2.elasticbeanstalk.com\":1,\"us.ax\":1,\"us.com\":1,\"us.eu.org\":1,\"us.gov.pl\":1,\"us.kg\":1,\"us.na\":1,\"us.org\":1,\"us.platform.sh\":1,\"usa.museum\":1,\"usa.oita.jp\":1,\"usantiques.museum\":1,\"usarts.museum\":1,\"uscountryestate.museum\":1,\"usculture.museum\":1,\"usdecorativearts.museum\":1,\"user.aseinet.ne.jp\":1,\"user.party.eus\":1,\"user.srcf.net\":1,\"usercontent.jp\":1,\"usgarden.museum\":1,\"ushiku.ibaraki.jp\":1,\"ushistory.museum\":1,\"ushuaia.museum\":1,\"uslivinghistory.museum\":1,\"usr.cloud.muni.cz\":1,\"ustka.pl\":1,\"usui.fukuoka.jp\":1,\"usuki.oita.jp\":1,\"ut.us\":1,\"utah.museum\":1,\"utashinai.hokkaido.jp\":1,\"utazas.hu\":1,\"utazu.kagawa.jp\":1,\"uto.kumamoto.jp\":1,\"utsira.no\":1,\"utsunomiya.tochigi.jp\":1,\"utwente.io\":1,\"uvic.museum\":1,\"uw.gov.pl\":1,\"uwajima.ehime.jp\":1,\"uwu.ai\":1,\"uwu.nu\":1,\"uy.com\":1,\"uz.ua\":1,\"uzhgorod.ua\":1,\"uzs.gov.pl\":1,\"v-info.info\":1,\"v.bg\":1,\"v.ua\":1,\"va.it\":1,\"va.no\":1,\"va.us\":1,\"vaapste.no\":1,\"vadso.no\":1,\"vaga.no\":1,\"vagan.no\":1,\"vagsoy.no\":1,\"vaksdal.no\":1,\"val-d-aosta.it\":1,\"val-daosta.it\":1,\"vald-aosta.it\":1,\"valdaosta.it\":1,\"valer.hedmark.no\":1,\"valer.ostfold.no\":1,\"valle-aosta.it\":1,\"valle-d-aosta.it\":1,\"valle-daosta.it\":1,\"valle.no\":1,\"valleaosta.it\":1,\"valled-aosta.it\":1,\"valledaosta.it\":1,\"vallee-aoste.it\":1,\"vallee-d-aoste.it\":1,\"valleeaoste.it\":1,\"valleedaoste.it\":1,\"valley.museum\":1,\"vang.no\":1,\"vantaa.museum\":1,\"vanylven.no\":1,\"vao.it\":1,\"vapor.cloud\":1,\"vaporcloud.io\":1,\"vardo.no\":1,\"varese.it\":1,\"varggat.no\":1,\"varoy.no\":1,\"vb.it\":1,\"vc.it\":1,\"vda.it\":1,\"ve.it\":1,\"vefsn.no\":1,\"vega.no\":1,\"vegarshei.no\":1,\"ven.it\":1,\"veneto.it\":1,\"venezia.it\":1,\"venice.it\":1,\"vennesla.no\":1,\"verbania.it\":1,\"vercel.app\":1,\"vercel.dev\":1,\"vercelli.it\":1,\"verdal.no\":1,\"verona.it\":1,\"verran.no\":1,\"versailles.museum\":1,\"vestby.no\":1,\"vestnes.no\":1,\"vestre-slidre.no\":1,\"vestre-toten.no\":1,\"vestvagoy.no\":1,\"vet.br\":1,\"veterinaire.fr\":1,\"veterinaire.km\":1,\"vevelstad.no\":1,\"vf.no\":1,\"vgs.no\":1,\"vi.it\":1,\"vi.us\":1,\"vibo-valentia.it\":1,\"vibovalentia.it\":1,\"vic.au\":1,\"vic.edu.au\":1,\"vic.gov.au\":1,\"vicenza.it\":1,\"video.hu\":1,\"vik.no\":1,\"viking.museum\":1,\"vikna.no\":1,\"village.museum\":1,\"vindafjord.no\":1,\"vinnica.ua\":1,\"vinnytsia.ua\":1,\"vip.jelastic.cloud\":1,\"vipsinaapp.com\":1,\"virginia.museum\":1,\"virtual-user.de\":1,\"virtual.museum\":1,\"virtualserver.io\":1,\"virtualuser.de\":1,\"virtueeldomein.nl\":1,\"virtuel.museum\":1,\"viterbo.it\":1,\"vix.br\":1,\"vlaanderen.museum\":1,\"vladikavkaz.ru\":1,\"vladikavkaz.su\":1,\"vladimir.ru\":1,\"vladimir.su\":1,\"vlog.br\":1,\"vm.bytemark.co.uk\":1,\"vn.ua\":1,\"voagat.no\":1,\"volda.no\":1,\"volkenkunde.museum\":1,\"vologda.su\":1,\"volyn.ua\":1,\"voorloper.cloud\":1,\"voss.no\":1,\"vossevangen.no\":1,\"vpndns.net\":1,\"vpnplus.to\":1,\"vps.mcdir.ru\":1,\"vps.myjino.ru\":2,\"vr.it\":1,\"vs.it\":1,\"vs.mythic-beasts.com\":1,\"vt.it\":1,\"vt.us\":1,\"vv.it\":1,\"vxl.sh\":1,\"w.bg\":1,\"w.se\":1,\"wa.au\":1,\"wa.edu.au\":1,\"wa.gov.au\":1,\"wa.us\":1,\"wada.nagano.jp\":1,\"wafflecell.com\":1,\"wajiki.tokushima.jp\":1,\"wajima.ishikawa.jp\":1,\"wakasa.fukui.jp\":1,\"wakasa.tottori.jp\":1,\"wakayama.jp\":1,\"wakayama.wakayama.jp\":1,\"wake.okayama.jp\":1,\"wakkanai.hokkaido.jp\":1,\"wakuya.miyagi.jp\":1,\"walbrzych.pl\":1,\"wales.museum\":1,\"wallonie.museum\":1,\"wanouchi.gifu.jp\":1,\"war.museum\":1,\"warabi.saitama.jp\":1,\"warmia.pl\":1,\"warszawa.pl\":1,\"washingtondc.museum\":1,\"washtenaw.mi.us\":1,\"wassamu.hokkaido.jp\":1,\"watarai.mie.jp\":1,\"watari.miyagi.jp\":1,\"watch-and-clock.museum\":1,\"watchandclock.museum\":1,\"waw.pl\":1,\"wazuka.kyoto.jp\":1,\"we.bs\":1,\"we.tc\":1,\"web.app\":1,\"web.bo\":1,\"web.co\":1,\"web.do\":1,\"web.gu\":1,\"web.id\":1,\"web.in\":1,\"web.lk\":1,\"web.nf\":1,\"web.ni\":1,\"web.pk\":1,\"web.tj\":1,\"web.tr\":1,\"web.ve\":1,\"web.za\":1,\"webhare.dev\":2,\"webhop.biz\":1,\"webhop.info\":1,\"webhop.me\":1,\"webhop.net\":1,\"webhop.org\":1,\"webhosting.be\":1,\"webredirect.org\":1,\"website.yandexcloud.net\":1,\"webspace.rocks\":1,\"wedeploy.io\":1,\"wedeploy.me\":1,\"wedeploy.sh\":1,\"wegrow.pl\":1,\"wellbeingzone.co.uk\":1,\"wellbeingzone.eu\":1,\"western.museum\":1,\"westfalen.museum\":1,\"whaling.museum\":1,\"wi.us\":1,\"wielun.pl\":1,\"wien.funkfeuer.at\":1,\"wif.gov.pl\":1,\"wiih.gov.pl\":1,\"wiki.bo\":1,\"wiki.br\":1,\"wildlife.museum\":1,\"williamsburg.museum\":1,\"winb.gov.pl\":1,\"windmill.museum\":1,\"wios.gov.pl\":1,\"witd.gov.pl\":1,\"withgoogle.com\":1,\"withyoutube.com\":1,\"wiw.gov.pl\":1,\"wlocl.pl\":1,\"wloclawek.pl\":1,\"wmcloud.org\":1,\"wmflabs.org\":1,\"wnext.app\":1,\"wodzislaw.pl\":1,\"wolomin.pl\":1,\"workers.dev\":1,\"workinggroup.aero\":1,\"workisboring.com\":1,\"works.aero\":1,\"workshop.museum\":1,\"worse-than.tv\":1,\"wpdevcloud.com\":1,\"wpenginepowered.com\":1,\"writesthisblog.com\":1,\"wroc.pl\":1,\"wroclaw.pl\":1,\"ws.na\":1,\"wsa.gov.pl\":1,\"wskr.gov.pl\":1,\"wuoz.gov.pl\":1,\"wv.us\":1,\"www.ck\":0,\"www.ro\":1,\"wy.us\":1,\"wzmiuw.gov.pl\":1,\"x.bg\":1,\"x.mythic-beasts.com\":1,\"x.se\":1,\"x443.pw\":1,\"xen.prgmr.com\":1,\"xenapponazure.com\":1,\"xj.cn\":1,\"xn--0trq7p7nn.jp\":1,\"xn--12c1fe0br.xn--o3cw4h\":1,\"xn--12cfi8ixb8l.xn--o3cw4h\":1,\"xn--12co0c3b4eva.xn--o3cw4h\":1,\"xn--1ctwo.jp\":1,\"xn--1lqs03n.jp\":1,\"xn--1lqs71d.jp\":1,\"xn--2m4a15e.jp\":1,\"xn--32vp30h.jp\":1,\"xn--4it168d.jp\":1,\"xn--4it797k.jp\":1,\"xn--4pvxs.jp\":1,\"xn--55qx5d.cn\":1,\"xn--55qx5d.hk\":1,\"xn--55qx5d.xn--j6w193g\":1,\"xn--5js045d.jp\":1,\"xn--5rtp49c.jp\":1,\"xn--5rtq34k.jp\":1,\"xn--6btw5a.jp\":1,\"xn--6orx2r.jp\":1,\"xn--7t0a264c.jp\":1,\"xn--80au.xn--90a3ac\":1,\"xn--8ltr62k.jp\":1,\"xn--8pvr4u.jp\":1,\"xn--90azh.xn--90a3ac\":1,\"xn--9dbhblg6di.museum\":1,\"xn--andy-ira.no\":1,\"xn--aroport-bya.ci\":1,\"xn--asky-ira.no\":1,\"xn--aurskog-hland-jnb.no\":1,\"xn--avery-yua.no\":1,\"xn--b-5ga.nordland.no\":1,\"xn--b-5ga.telemark.no\":1,\"xn--balsan-sdtirol-nsb.it\":1,\"xn--bdddj-mrabd.no\":1,\"xn--bearalvhki-y4a.no\":1,\"xn--berlevg-jxa.no\":1,\"xn--bhcavuotna-s4a.no\":1,\"xn--bhccavuotna-k7a.no\":1,\"xn--bidr-5nac.no\":1,\"xn--bievt-0qa.no\":1,\"xn--bjarky-fya.no\":1,\"xn--bjddar-pta.no\":1,\"xn--blt-elab.no\":1,\"xn--bmlo-gra.no\":1,\"xn--bod-2na.no\":1,\"xn--bozen-sdtirol-2ob.it\":1,\"xn--brnny-wuac.no\":1,\"xn--brnnysund-m8ac.no\":1,\"xn--brum-voa.no\":1,\"xn--btsfjord-9za.no\":1,\"xn--bulsan-sdtirol-nsb.it\":1,\"xn--c1avg.xn--90a3ac\":1,\"xn--c3s14m.jp\":1,\"xn--cesena-forl-mcb.it\":1,\"xn--cesenaforl-i8a.it\":1,\"xn--ciqpn.hk\":1,\"xn--comunicaes-v6a2o.museum\":1,\"xn--correios-e-telecomunicaes-ghc29a.museum\":1,\"xn--czrw28b.tw\":1,\"xn--d1at.xn--90a3ac\":1,\"xn--d5qv7z876c.jp\":1,\"xn--davvenjrga-y4a.no\":1,\"xn--djrs72d6uy.jp\":1,\"xn--djty4k.jp\":1,\"xn--dnna-gra.no\":1,\"xn--drbak-wua.no\":1,\"xn--dyry-ira.no\":1,\"xn--efvn9s.jp\":1,\"xn--ehqz56n.jp\":1,\"xn--elqq16h.jp\":1,\"xn--eveni-0qa01ga.no\":1,\"xn--f6qx53a.jp\":1,\"xn--finny-yua.no\":1,\"xn--fjord-lra.no\":1,\"xn--fl-zia.no\":1,\"xn--flor-jra.no\":1,\"xn--forl-cesena-fcb.it\":1,\"xn--forlcesena-c8a.it\":1,\"xn--frde-gra.no\":1,\"xn--frna-woa.no\":1,\"xn--frya-hra.no\":1,\"xn--ggaviika-8ya47h.no\":1,\"xn--gildeskl-g0a.no\":1,\"xn--givuotna-8ya.no\":1,\"xn--gjvik-wua.no\":1,\"xn--gls-elac.no\":1,\"xn--gmq050i.hk\":1,\"xn--gmqw5a.hk\":1,\"xn--gmqw5a.xn--j6w193g\":1,\"xn--h-2fa.no\":1,\"xn--h1aegh.museum\":1,\"xn--h3cuzk1di.xn--o3cw4h\":1,\"xn--hbmer-xqa.no\":1,\"xn--hcesuolo-7ya35b.no\":1,\"xn--hery-ira.nordland.no\":1,\"xn--hery-ira.xn--mre-og-romsdal-qqb.no\":1,\"xn--hgebostad-g3a.no\":1,\"xn--hkkinen-5wa.fi\":1,\"xn--hmmrfeasta-s4ac.no\":1,\"xn--hnefoss-q1a.no\":1,\"xn--hobl-ira.no\":1,\"xn--holtlen-hxa.no\":1,\"xn--hpmir-xqa.no\":1,\"xn--hyanger-q1a.no\":1,\"xn--hylandet-54a.no\":1,\"xn--indery-fya.no\":1,\"xn--io0a7i.cn\":1,\"xn--io0a7i.hk\":1,\"xn--jlster-bya.no\":1,\"xn--jrpeland-54a.no\":1,\"xn--k7yn95e.jp\":1,\"xn--karmy-yua.no\":1,\"xn--kbrq7o.jp\":1,\"xn--kfjord-iua.no\":1,\"xn--klbu-woa.no\":1,\"xn--klt787d.jp\":1,\"xn--kltp7d.jp\":1,\"xn--kltx9a.jp\":1,\"xn--klty5x.jp\":1,\"xn--koluokta-7ya57h.no\":1,\"xn--krager-gya.no\":1,\"xn--kranghke-b0a.no\":1,\"xn--krdsherad-m8a.no\":1,\"xn--krehamn-dxa.no\":1,\"xn--krjohka-hwab49j.no\":1,\"xn--ksnes-uua.no\":1,\"xn--kvfjord-nxa.no\":1,\"xn--kvitsy-fya.no\":1,\"xn--kvnangen-k0a.no\":1,\"xn--l-1fa.no\":1,\"xn--laheadju-7ya.no\":1,\"xn--langevg-jxa.no\":1,\"xn--lcvr32d.hk\":1,\"xn--ldingen-q1a.no\":1,\"xn--leagaviika-52b.no\":1,\"xn--lesund-hua.no\":1,\"xn--lgrd-poac.no\":1,\"xn--lhppi-xqa.no\":1,\"xn--linds-pra.no\":1,\"xn--lns-qla.museum\":1,\"xn--loabt-0qa.no\":1,\"xn--lrdal-sra.no\":1,\"xn--lrenskog-54a.no\":1,\"xn--lt-liac.no\":1,\"xn--lten-gra.no\":1,\"xn--lury-ira.no\":1,\"xn--m3ch0j3a.xn--o3cw4h\":1,\"xn--mely-ira.no\":1,\"xn--merker-kua.no\":1,\"xn--mgba3a4f16a.ir\":1,\"xn--mgba3a4fra.ir\":1,\"xn--mjndalen-64a.no\":1,\"xn--mk0axi.hk\":1,\"xn--mkru45i.jp\":1,\"xn--mlatvuopmi-s4a.no\":1,\"xn--mli-tla.no\":1,\"xn--mlselv-iua.no\":1,\"xn--moreke-jua.no\":1,\"xn--mori-qsa.nz\":1,\"xn--mosjen-eya.no\":1,\"xn--mot-tla.no\":1,\"xn--msy-ula0h.no\":1,\"xn--mtta-vrjjat-k7af.no\":1,\"xn--muost-0qa.no\":1,\"xn--mxtq1m.hk\":1,\"xn--mxtq1m.xn--j6w193g\":1,\"xn--nit225k.jp\":1,\"xn--nmesjevuemie-tcba.no\":1,\"xn--nry-yla5g.no\":1,\"xn--ntso0iqx3a.jp\":1,\"xn--ntsq17g.jp\":1,\"xn--nttery-byae.no\":1,\"xn--nvuotna-hwa.no\":1,\"xn--o1ac.xn--90a3ac\":1,\"xn--o1ach.xn--90a3ac\":1,\"xn--o3cyx2a.xn--o3cw4h\":1,\"xn--od0alg.cn\":1,\"xn--od0alg.hk\":1,\"xn--od0alg.xn--j6w193g\":1,\"xn--od0aq3b.hk\":1,\"xn--oppegrd-ixa.no\":1,\"xn--ostery-fya.no\":1,\"xn--osyro-wua.no\":1,\"xn--porsgu-sta26f.no\":1,\"xn--pssu33l.jp\":1,\"xn--qqqt11m.jp\":1,\"xn--rady-ira.no\":1,\"xn--rdal-poa.no\":1,\"xn--rde-ula.no\":1,\"xn--rdy-0nab.no\":1,\"xn--rennesy-v1a.no\":1,\"xn--rhkkervju-01af.no\":1,\"xn--rholt-mra.no\":1,\"xn--rht27z.jp\":1,\"xn--rht3d.jp\":1,\"xn--rht61e.jp\":1,\"xn--risa-5na.no\":1,\"xn--risr-ira.no\":1,\"xn--rland-uua.no\":1,\"xn--rlingen-mxa.no\":1,\"xn--rmskog-bya.no\":1,\"xn--rny31h.jp\":1,\"xn--rros-gra.no\":1,\"xn--rskog-uua.no\":1,\"xn--rst-0na.no\":1,\"xn--rsta-fra.no\":1,\"xn--ryken-vua.no\":1,\"xn--ryrvik-bya.no\":1,\"xn--s-1fa.no\":1,\"xn--sandnessjen-ogb.no\":1,\"xn--sandy-yua.no\":1,\"xn--sdtirol-n2a.it\":1,\"xn--seral-lra.no\":1,\"xn--sgne-gra.no\":1,\"xn--skierv-uta.no\":1,\"xn--skjervy-v1a.no\":1,\"xn--skjk-soa.no\":1,\"xn--sknit-yqa.no\":1,\"xn--sknland-fxa.no\":1,\"xn--slat-5na.no\":1,\"xn--slt-elab.no\":1,\"xn--smla-hra.no\":1,\"xn--smna-gra.no\":1,\"xn--snase-nra.no\":1,\"xn--sndre-land-0cb.no\":1,\"xn--snes-poa.no\":1,\"xn--snsa-roa.no\":1,\"xn--sr-aurdal-l8a.no\":1,\"xn--sr-fron-q1a.no\":1,\"xn--sr-odal-q1a.no\":1,\"xn--sr-varanger-ggb.no\":1,\"xn--srfold-bya.no\":1,\"xn--srreisa-q1a.no\":1,\"xn--srum-gra.no\":1,\"xn--stjrdal-s1a.no\":1,\"xn--stjrdalshalsen-sqb.no\":1,\"xn--stre-toten-zcb.no\":1,\"xn--tjme-hra.no\":1,\"xn--tn0ag.hk\":1,\"xn--tnsberg-q1a.no\":1,\"xn--tor131o.jp\":1,\"xn--trany-yua.no\":1,\"xn--trentin-sd-tirol-rzb.it\":1,\"xn--trentin-sdtirol-7vb.it\":1,\"xn--trentino-sd-tirol-c3b.it\":1,\"xn--trentino-sdtirol-szb.it\":1,\"xn--trentinosd-tirol-rzb.it\":1,\"xn--trentinosdtirol-7vb.it\":1,\"xn--trentinsd-tirol-6vb.it\":1,\"xn--trentinsdtirol-nsb.it\":1,\"xn--trgstad-r1a.no\":1,\"xn--trna-woa.no\":1,\"xn--troms-zua.no\":1,\"xn--tysvr-vra.no\":1,\"xn--uc0atv.hk\":1,\"xn--uc0atv.tw\":1,\"xn--uc0atv.xn--j6w193g\":1,\"xn--uc0ay4a.hk\":1,\"xn--uist22h.jp\":1,\"xn--uisz3g.jp\":1,\"xn--unjrga-rta.no\":1,\"xn--uuwu58a.jp\":1,\"xn--vads-jra.no\":1,\"xn--valle-aoste-ebb.it\":1,\"xn--valle-d-aoste-ehb.it\":1,\"xn--valleaoste-e7a.it\":1,\"xn--valledaoste-ebb.it\":1,\"xn--vard-jra.no\":1,\"xn--vegrshei-c0a.no\":1,\"xn--vestvgy-ixa6o.no\":1,\"xn--vg-yiab.no\":1,\"xn--vgan-qoa.no\":1,\"xn--vgsy-qoa0j.no\":1,\"xn--vgu402c.jp\":1,\"xn--vler-qoa.hedmark.no\":1,\"xn--vler-qoa.xn--stfold-9xa.no\":1,\"xn--vre-eiker-k8a.no\":1,\"xn--vrggt-xqad.no\":1,\"xn--vry-yla5g.no\":1,\"xn--wcvs22d.hk\":1,\"xn--wcvs22d.xn--j6w193g\":1,\"xn--yer-zna.no\":1,\"xn--ygarden-p1a.no\":1,\"xn--ystre-slidre-ujb.no\":1,\"xn--zbx025d.jp\":1,\"xn--zf0ao64a.tw\":1,\"xn--zf0avx.hk\":1,\"xnbay.com\":1,\"xs4all.space\":1,\"xx.gl\":1,\"xy.ax\":1,\"xz.cn\":1,\"y.bg\":1,\"y.se\":1,\"yabu.hyogo.jp\":1,\"yabuki.fukushima.jp\":1,\"yachimata.chiba.jp\":1,\"yachiyo.chiba.jp\":1,\"yachiyo.ibaraki.jp\":1,\"yaese.okinawa.jp\":1,\"yahaba.iwate.jp\":1,\"yahiko.niigata.jp\":1,\"yaita.tochigi.jp\":1,\"yaizu.shizuoka.jp\":1,\"yakage.okayama.jp\":1,\"yakumo.hokkaido.jp\":1,\"yakumo.shimane.jp\":1,\"yali.mythic-beasts.com\":1,\"yalta.ua\":1,\"yamada.fukuoka.jp\":1,\"yamada.iwate.jp\":1,\"yamada.toyama.jp\":1,\"yamaga.kumamoto.jp\":1,\"yamagata.gifu.jp\":1,\"yamagata.ibaraki.jp\":1,\"yamagata.jp\":1,\"yamagata.nagano.jp\":1,\"yamagata.yamagata.jp\":1,\"yamaguchi.jp\":1,\"yamakita.kanagawa.jp\":1,\"yamamoto.miyagi.jp\":1,\"yamanakako.yamanashi.jp\":1,\"yamanashi.jp\":1,\"yamanashi.yamanashi.jp\":1,\"yamanobe.yamagata.jp\":1,\"yamanouchi.nagano.jp\":1,\"yamashina.kyoto.jp\":1,\"yamato.fukushima.jp\":1,\"yamato.kanagawa.jp\":1,\"yamato.kumamoto.jp\":1,\"yamatokoriyama.nara.jp\":1,\"yamatotakada.nara.jp\":1,\"yamatsuri.fukushima.jp\":1,\"yamazoe.nara.jp\":1,\"yame.fukuoka.jp\":1,\"yanagawa.fukuoka.jp\":1,\"yanaizu.fukushima.jp\":1,\"yandexcloud.net\":1,\"yao.osaka.jp\":1,\"yaotsu.gifu.jp\":1,\"yasaka.nagano.jp\":1,\"yashio.saitama.jp\":1,\"yashiro.hyogo.jp\":1,\"yasu.shiga.jp\":1,\"yasuda.kochi.jp\":1,\"yasugi.shimane.jp\":1,\"yasuoka.nagano.jp\":1,\"yatomi.aichi.jp\":1,\"yatsuka.shimane.jp\":1,\"yatsushiro.kumamoto.jp\":1,\"yawara.ibaraki.jp\":1,\"yawata.kyoto.jp\":1,\"yawatahama.ehime.jp\":1,\"yazu.tottori.jp\":1,\"ybo.faith\":1,\"ybo.party\":1,\"ybo.review\":1,\"ybo.science\":1,\"ybo.trade\":1,\"ye\":2,\"yk.ca\":1,\"yn.cn\":1,\"yoichi.hokkaido.jp\":1,\"yoita.niigata.jp\":1,\"yoka.hyogo.jp\":1,\"yokaichiba.chiba.jp\":1,\"yokawa.hyogo.jp\":1,\"yokkaichi.mie.jp\":1,\"yokohama.jp\":2,\"yokoshibahikari.chiba.jp\":1,\"yokosuka.kanagawa.jp\":1,\"yokote.akita.jp\":1,\"yokoze.saitama.jp\":1,\"yolasite.com\":1,\"yombo.me\":1,\"yomitan.okinawa.jp\":1,\"yonabaru.okinawa.jp\":1,\"yonago.tottori.jp\":1,\"yonaguni.okinawa.jp\":1,\"yonezawa.yamagata.jp\":1,\"yono.saitama.jp\":1,\"yorii.saitama.jp\":1,\"york.museum\":1,\"yorkshire.museum\":1,\"yoro.gifu.jp\":1,\"yosemite.museum\":1,\"yoshida.saitama.jp\":1,\"yoshida.shizuoka.jp\":1,\"yoshikawa.saitama.jp\":1,\"yoshimi.saitama.jp\":1,\"yoshino.nara.jp\":1,\"yoshinogari.saga.jp\":1,\"yoshioka.gunma.jp\":1,\"yotsukaido.chiba.jp\":1,\"youth.museum\":1,\"yuasa.wakayama.jp\":1,\"yufu.oita.jp\":1,\"yugawa.fukushima.jp\":1,\"yugawara.kanagawa.jp\":1,\"yuki.ibaraki.jp\":1,\"yukuhashi.fukuoka.jp\":1,\"yura.wakayama.jp\":1,\"yurihonjo.akita.jp\":1,\"yusuhara.kochi.jp\":1,\"yusui.kagoshima.jp\":1,\"yuu.yamaguchi.jp\":1,\"yuza.yamagata.jp\":1,\"yuzawa.niigata.jp\":1,\"z.bg\":1,\"z.se\":1,\"za.bz\":1,\"za.com\":1,\"za.net\":1,\"za.org\":1,\"zachpomor.pl\":1,\"zagan.pl\":1,\"zakopane.pl\":1,\"zama.kanagawa.jp\":1,\"zamami.okinawa.jp\":1,\"zao.miyagi.jp\":1,\"zaporizhzhe.ua\":1,\"zaporizhzhia.ua\":1,\"zapto.org\":1,\"zapto.xyz\":1,\"zarow.pl\":1,\"zentsuji.kagawa.jp\":1,\"zgora.pl\":1,\"zgorzelec.pl\":1,\"zhitomir.ua\":1,\"zhytomyr.ua\":1,\"zj.cn\":1,\"zlg.br\":1,\"zoological.museum\":1,\"zoology.museum\":1,\"zp.gov.pl\":1,\"zp.ua\":1,\"zt.ua\":1,\"zushi.kanagawa.jp\":1}");

/***/ }),
/* 53 */
/***/ (function(module) {

module.exports = JSON.parse("{\"blank-text\":\"data:text/plain,\",\"blank-css\":\"data:text/css,\",\"blank-js\":\"data:application/javascript,\",\"blank-html\":\"data:text/html,<!DOCTYPE html><html><head></head><body></body></html>\",\"blank-mp3\":\"data:audio/mpeg;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU4LjIwLjEwMAAAAAAAAAAAAAAA//tUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASW5mbwAAAA8AAAAGAAADAABgYGBgYGBgYGBgYGBgYGBggICAgICAgICAgICAgICAgICgoKCgoKCgoKCgoKCgoKCgwMDAwMDAwMDAwMDAwMDAwMDg4ODg4ODg4ODg4ODg4ODg4P////////////////////8AAAAATGF2YzU4LjM1AAAAAAAAAAAAAAAAJAYAAAAAAAAAAwDVxttG//sUZAAP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAETEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sUZB4P8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sUZDwP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sUZFoP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sUZHgP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV//sUZJYP8AAAaQAAAAgAAA0gAAABAAABpAAAACAAADSAAAAEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\",\"blank-mp4\":\"data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAuJtZGF0AAACrwYF//+r3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE2MCByMzAxMU0gY2RlOWE5MyAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMjAgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0xIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDM6MHgxMTMgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MCB0cmVsbGlzPTEgOHg4ZGN0PTEgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz0yIGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MyBiX3B5cmFtaWQ9MiBiX2FkYXB0PTEgYl9iaWFzPTAgZGlyZWN0PTEgd2VpZ2h0Yj0xIG9wZW5fZ29wPTAgd2VpZ2h0cD0yIGtleWludD0yNTAga2V5aW50X21pbj0yNSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmNfbG9va2FoZWFkPTQwIHJjPWNyZiBtYnRyZWU9MSBjcmY9MjMuMCBxY29tcD0wLjYwIHFwbWluPTAgcXBtYXg9NjkgcXBzdGVwPTQgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAACNliIQAK//+9dvzLK5umjbe9jc2CT9EPcfnoOYC2tjtP+go4QAAAwRtb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAKAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACLnRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAZAAAADgAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAACgAAAAAAAEAAAAAAaZtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAADIAAAACAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAFRbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABEXN0YmwAAACtc3RzZAAAAAAAAAABAAAAnWF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAZAA4AEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAA3YXZjQwFkAAr/4QAaZ2QACvNlHJ42JwEQAAADABAAAAMDIPEiWWABAAZo6+PLIsD8+PgAAAAAEHBhc3AAAAABAAAAAQAAABhzdHRzAAAAAAAAAAEAAAABAAACAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAALaAAAAAQAAABRzdGNvAAAAAAAAAAEAAAAwAAAAYnVkdGEAAABabWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAtaWxzdAAAACWpdG9vAAAAHWRhdGEAAAABAAAAAExhdmY1OC40NS4xMDA=\",\"1x1-transparent-gif\":\"data:image/gif;base64,R0lGODlhAQABAIABAAAAAP///yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\",\"2x2-transparent-png\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAC0lEQVQI12NgQAcAABIAAe+JVKQAAAAASUVORK5CYII=\",\"3x2-transparent-png\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAC0lEQVQI12NgwAUAABoAASRETuUAAAAASUVORK5CYII=\",\"32x32-transparent-png\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGklEQVRYw+3BAQEAAACCIP+vbkhAAQAAAO8GECAAAZf3V9cAAAAASUVORK5CYII=\"}");

/***/ }),
/* 54 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"url\":\"https://easylist-downloads.adblockplus.org/exceptionrules.txt\",\"id\":\"acceptable_ads\",\"homepage\":\"\",\"languages\":[],\"type\":\"\",\"index\":1,\"title\":\"Acceptable Ads\"},{\"url\":\"https://easylist-downloads.adblockplus.org/exceptionrules-privacy-friendly.txt\",\"id\":\"acceptable_ads_privacy\",\"homepage\":\"\",\"languages\":[],\"type\":\"\",\"index\":2,\"title\":\"Acceptable Ads Privacy\"},{\"url\":\"https://cdn.adblockcdn.com/filters/adblock_custom.txt\",\"id\":\"adblock_custom\",\"homepage\":\"https://getadblock.com/help\",\"languages\":[],\"type\":\"ads\",\"index\":3,\"title\":\"AdBlock Custom\"},{\"url\":\"https://cdn.adblockcdn.com/filters/distraction-control-video.txt\",\"id\":\"distraction-control-video\",\"homepage\":\"https://getadblock.com/help\",\"languages\":[],\"type\":\"distraction-control\",\"index\":4,\"title\":\"Distraction Control - Video\"},{\"url\":\"https://cdn.adblockcdn.com/filters/distraction-control-survey.txt\",\"id\":\"distraction-control-survey\",\"homepage\":\"https://getadblock.com/help\",\"languages\":[],\"type\":\"distraction-control\",\"index\":5,\"title\":\"Distraction Control - Survey\"},{\"url\":\"https://cdn.adblockcdn.com/filters/distraction-control-newsletter.txt\",\"id\":\"distraction-control-newsletter\",\"homepage\":\"https://getadblock.com/help\",\"languages\":[],\"type\":\"distraction-control\",\"index\":6,\"title\":\"Distraction Control - Newsletter\"},{\"url\":\"https://cdn.adblockcdn.com/filters/distraction-control-push.txt\",\"id\":\"distraction-control-push\",\"homepage\":\"https://getadblock.com/help\",\"languages\":[],\"type\":\"distraction-control\",\"index\":7,\"title\":\"Distraction Control - Notifications\"},{\"url\":\"https://raw.githubusercontent.com/hoshsadiq/adblock-nocoin-list/master/nocoin.txt\",\"id\":\"bitcoin_mining_protection\",\"homepage\":\"\",\"languages\":[],\"type\":\"\",\"index\":8,\"title\":\"Acceptable Ads\"},{\"url\":\"https://easylist-downloads.adblockplus.org/antiadblockfilters.txt\",\"id\":\"warning_removal\",\"homepage\":\"\",\"languages\":[],\"type\":\"\",\"index\":9,\"title\":\"Warning Removal\"},{\"url\":\"https://www.void.gr/kargig/void-gr-filters.txt\",\"id\":\"easylist_plus_greek\",\"homepage\":\"mailto:kargig at void.gr\",\"languages\":[\"el\"],\"type\":\"ads\",\"index\":10,\"title\":\"EasyList Greek+EasyList\"},{\"url\":\"https://raw.githubusercontent.com/hufilter/hufilter/master/hufilter-abp.txt\",\"id\":\"hungarian\",\"homepage\":\"mailto:pete at teamlupus.hu\",\"languages\":[\"hu\"],\"type\":\"ads\",\"index\":11,\"title\":\"EasyList Hungarian+EasyList\"},{\"url\":\"https://raw.githubusercontent.com/k2jp/abp-japanese-filters/master/abpjf.txt\",\"id\":\"japanese\",\"homepage\":\"https://github.com/k2jp/abp-japanese-filters/\",\"languages\":[\"ja\"],\"type\":\"ads\",\"index\":12,\"title\":\"Japanese\"},{\"url\":\"https://easylist-downloads.adblockplus.org/abpindo+easylist.txt\",\"id\":\"easylist_plus_indonesian\",\"homepage\":\"http://abpindo.blogspot.com/\",\"languages\":[\"id\",\"ms\"],\"type\":\"ads\",\"index\":13,\"title\":\"ABPindo+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/abpvn+easylist.txt\",\"id\":\"easylist_plus_vietnamese\",\"homepage\":\"http://abpvn.com/\",\"languages\":[\"vi\"],\"type\":\"ads\",\"index\":14,\"title\":\"ABPVN List+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/bulgarian_list+easylist.txt\",\"id\":\"easylist_plus_bulgarian\",\"homepage\":\"http://stanev.org/abp/\",\"languages\":[\"bg\"],\"type\":\"ads\",\"index\":15,\"title\":\"Bulgarian list+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylist.txt\",\"id\":\"easylist\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"en\"],\"type\":\"ads\",\"index\":16,\"title\":\"EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt\",\"id\":\"chinese\",\"homepage\":\"http://abpchina.org/forum/\",\"languages\":[\"zh\"],\"type\":\"ads\",\"index\":17,\"title\":\"EasyList China+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistczechslovak+easylist.txt\",\"id\":\"czech\",\"homepage\":\"https://adblock.sk/\",\"languages\":[\"cs\",\"sk\"],\"type\":\"ads\",\"index\":18,\"title\":\"EasyList Czech and Slovak+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistdutch+easylist.txt\",\"id\":\"dutch\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"nl\"],\"type\":\"ads\",\"index\":19,\"title\":\"EasyList Dutch+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistgermany+easylist.txt\",\"id\":\"easylist_plus_german\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"de\"],\"type\":\"ads\",\"index\":20,\"title\":\"EasyList Germany+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/israellist+easylist.txt\",\"id\":\"israeli\",\"homepage\":\"https://github.com/easylist/EasyListHebrew\",\"languages\":[\"he\"],\"type\":\"ads\",\"index\":21,\"title\":\"EasyList Hebrew+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistitaly+easylist.txt\",\"id\":\"italian\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"it\"],\"type\":\"ads\",\"index\":22,\"title\":\"EasyList Italy+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistlithuania+easylist.txt\",\"id\":\"easylist_plus_lithuania\",\"homepage\":\"http://margevicius.lt/\",\"languages\":[\"lt\"],\"type\":\"ads\",\"index\":23,\"title\":\"EasyList Lithuania+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistpolish+easylist.txt\",\"id\":\"easylist_plus_polish\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"pl\"],\"type\":\"ads\",\"index\":24,\"title\":\"EasyList Polish+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistportuguese+easylist.txt\",\"id\":\"easylist_plus_portuguese\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"pt\"],\"type\":\"ads\",\"index\":25,\"title\":\"EasyList Portuguese+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistspanish+easylist.txt\",\"id\":\"easylist_plus_spanish\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"es\"],\"type\":\"ads\",\"index\":26,\"title\":\"EasyList Spanish+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/indianlist+easylist.txt\",\"id\":\"easylist_plus_indian\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"bn\",\"gu\",\"hi\",\"pa\",\"as\",\"mr\",\"ml\",\"te\",\"kn\",\"or\",\"ne\",\"si\"],\"type\":\"ads\",\"index\":27,\"title\":\"IndianList+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/koreanlist+easylist.txt\",\"id\":\"easylist_plun_korean\",\"homepage\":\"https://easylist.to/\",\"languages\":[\"ko\"],\"type\":\"ads\",\"index\":28,\"title\":\"KoreanList+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/latvianlist+easylist.txt\",\"id\":\"latvian\",\"homepage\":\"https://notabug.org/latvian-list/adblock-latvian\",\"languages\":[\"lv\"],\"type\":\"ads\",\"index\":29,\"title\":\"Latvian List+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/liste_ar+liste_fr+easylist.txt\",\"id\":\"easylist_plus_arabic_plus_french\",\"homepage\":\"https://code.google.com/p/liste-ar-adblock/\",\"languages\":[\"ar\"],\"type\":\"ads\",\"index\":30,\"title\":\"Liste AR+Liste FR+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/liste_fr+easylist.txt\",\"id\":\"easylist_plus_french\",\"homepage\":\"https://forums.lanik.us/viewforum.php?f\",\"languages\":[\"fr\"],\"type\":\"ads\",\"index\":31,\"title\":\"Liste FR+EasyList\"},{\"url\":\"https://easylist-downloads.adblockplus.org/ruadlist+easylist.txt\",\"id\":\"russian\",\"homepage\":\"https://forums.lanik.us/viewforum.php?f\",\"languages\":[\"ru\",\"uk\"],\"type\":\"ads\",\"index\":32,\"title\":\"RuAdList+EasyList\"},{\"type\":\"ads\",\"index\":33,\"languages\":[\"ro\"],\"id\":\"easylist_plus_romanian\",\"title\":\"ROList+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/rolist+easylist.txt\",\"homepage\":\"https://zoso.ro/rolist/\",\"language\":true,\"hidden\":false},{\"url\":\"https://easylist-downloads.adblockplus.org/abp-filters-anti-cv.txt\",\"id\":\"anticircumvent\",\"homepage\":\"https://github.com/abp-filters/abp-filters-anti-cv\",\"languages\":[],\"type\":\"circumvention\",\"index\":34,\"title\":\"ABP filters\"},{\"url\":\"https://easylist-downloads.adblockplus.org/easyprivacy.txt\",\"id\":\"easyprivacy\",\"homepage\":\"https://easylist.to/\",\"languages\":[],\"type\":\"privacy\",\"index\":35,\"title\":\"EasyPrivacy\"},{\"url\":\"https://easylist-downloads.adblockplus.org/i_dont_care_about_cookies.txt\",\"id\":\"idcac\",\"homepage\":\"https://www.i-dont-care-about-cookies.eu/\",\"languages\":[],\"type\":\"cookies\",\"index\":36,\"title\":\"I Don't Care About Cookies\"},{\"url\":\"https://easylist-downloads.adblockplus.org/fanboy-social.txt\",\"id\":\"antisocial\",\"homepage\":\"https://easylist.to/\",\"languages\":[],\"type\":\"social\",\"index\":37,\"title\":\"Fanboy's Social Blocking List\"},{\"url\":\"https://fanboy.co.nz/fanboy-annoyance.txt\",\"id\":\"annoyances\",\"homepage\":\"https://easylist.to/\",\"languages\":[],\"type\":\"social\",\"index\":38,\"title\":\"Fanboy's Annoyances\"},{\"type\":\"notifications\",\"index\":39,\"id\":\"fb_notifications\",\"title\":\"Fanboy's Notifications Blocking List\",\"url\":\"https://easylist-downloads.adblockplus.org/fanboy-notifications.txt\",\"homepage\":\"https://easylist.to/\",\"languages\":[]},{\"url\":\"https://fanboy.co.nz/fanboy-turkish.txt\",\"id\":\"turkish\",\"language\":true,\"index\":40,\"hidden\":false},{\"url\":\"https://easylist-downloads.adblockplus.org/Liste_AR.txt\",\"id\":\"easylist_plus_arabic\",\"language\":true,\"index\":41,\"hidden\":true},{\"url\":\"https://margevicius.lt/easylistlithuania.txt\",\"id\":\"easylist_plus_lithuania_old\",\"language\":true,\"index\":42,\"hidden\":true},{\"url\":\"https://notabug.org/latvian-list/adblock-latvian/raw/master/lists/latvian-list.txt\",\"id\":\"latvian_old\",\"index\":43,\"language\":true,\"hidden\":true},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistitaly.txt\",\"id\":\"italian_old\",\"index\":44,\"language\":true,\"hidden\":true},{\"url\":\"https://stanev.org/abp/adblock_bg.txt\",\"id\":\"easylist_plus_bulgarian_old\",\"index\":45,\"language\":true,\"hidden\":true},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistdutch.txt\",\"id\":\"dutch_old\",\"index\":46,\"language\":true,\"hidden\":true},{\"url\":\"https://easylist-downloads.adblockplus.org/liste_fr.txt\",\"id\":\"easylist_plus_french_old\",\"index\":47,\"language\":true,\"hidden\":true},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistgermany.txt\",\"id\":\"easylist_plus_german_old\",\"index\":48,\"language\":true,\"hidden\":true},{\"url\":\"https://raw.githubusercontent.com/heradhis/indonesianadblockrules/master/subscriptions/abpindo.txt\",\"id\":\"easylist_plus_indonesian_old\",\"index\":49,\"language\":true,\"hidden\":true},{\"url\":\"https://www.certyficate.it/adblock/adblock.txt\",\"id\":\"easylist_plus_polish_old\",\"index\":50,\"language\":true,\"hidden\":true},{\"url\":\"https://www.zoso.ro/pages/rolist.txt\",\"id\":\"easylist_plus_romanian_old\",\"index\":51,\"language\":true,\"hidden\":true},{\"url\":\"https://easylist-downloads.adblockplus.org/advblock.txt\",\"id\":\"russian_old\",\"index\":52,\"language\":true,\"hidden\":true},{\"url\":\"https://easylist-downloads.adblockplus.org/easylistchina.txt\",\"id\":\"chinese_old\",\"index\":53,\"language\":true,\"hidden\":true},{\"url\":\"https://raw.github.com/tomasko126/easylistczechandslovak/master/filters.txt\",\"id\":\"czech_old\",\"index\":54,\"language\":true,\"hidden\":true},{\"type\":\"ads\",\"index\":55,\"languages\":[\"no\",\"nb\",\"nn\",\"da\",\"is\",\"fo\",\"kl\",\"sv\",\"fi\"],\"title\":\"Nordic Filters+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/dandelion_sprouts_nordic_filters+easylist.txt\",\"homepage\":\"https://github.com/DandelionSprout/adfilt\",\"language\":true,\"hidden\":false,\"id\":\"nordic\"}]");

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

module.exports = self;

/***/ }),
/* 56 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IO", function() { return IO; });
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

const keyPrefix = "file:";

function fileToKey(fileName)
{
  return keyPrefix + fileName;
}

async function loadFile(fileName)
{
  let key = fileToKey(fileName);
  let items = await browser.storage.local.get(key);
  let entry = items[key];
  if (entry)
    return entry;
  throw {type: "NoSuchFile"};
}

function saveFile(fileName, data)
{
  return browser.storage.local.set({
    [fileToKey(fileName)]: {
      content: Array.from(data),
      lastModified: Date.now()
    }
  });
}

let IO =
{
  /**
   * Reads text lines from a file.
   * @param {string} fileName
   *    Name of the file to be read
   * @param {TextSink} listener
   *    Function that will be called for each line in the file
   * @return {Promise}
   *    Promise to be resolved or rejected once the operation is completed
   */
  async readFromFile(fileName, listener)
  {
    let entry = await loadFile(fileName);
    for (let line of entry.content)
      listener(line);
  },

  /**
   * Writes text lines to a file.
   * @param {string} fileName
   *    Name of the file to be written
   * @param {Iterable.<string>} data
   *    An array-like or iterable object containing the lines (without line
   *    endings)
   * @return {Promise}
   *    Promise to be resolved or rejected once the operation is completed
   */
  writeToFile(fileName, data)
  {
    return saveFile(fileName, data);
  },

  /**
   * Renames a file.
   * @param {string} fromFile
   *    Name of the file to be renamed
   * @param {string} newName
   *    New file name, will be overwritten if exists
   * @return {Promise}
   *    Promise to be resolved or rejected once the operation is completed
   */
  async renameFile(fromFile, newName)
  {
    let entry = await loadFile(fromFile);
    await browser.storage.local.set({[fileToKey(newName)]: entry});
    await browser.storage.local.remove(fileToKey(fromFile));
  },

  /**
   * Retrieves file metadata.
   * @param {string} fileName
   *    Name of the file to be looked up
   * @return {Promise.<StatData>}
   *    Promise to be resolved with file metadata once the operation is
   *    completed
   */
  async statFile(fileName)
  {
    try
    {
      let entry = await loadFile(fileName);
      return {
        exists: true,
        lastModified: entry.lastModified
      };
    }
    catch (error)
    {
      if (error.type == "NoSuchFile")
        return {exists: false};
      throw error;
    }
  }
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview INI parsing.
 */

const {isActiveFilter, Filter} = __webpack_require__(0);
const {Subscription} = __webpack_require__(2);
const {filterState} = __webpack_require__(14);

/**
 * Parses filter data.
 * @package
 */
exports.INIParser = class INIParser
{
  constructor()
  {
    /**
     * Properties of the filter data.
     * @type {object}
     */
    this.fileProperties = {};

    /**
     * The list of subscriptions in the filter data.
     * @type {Array.<module:subscriptionClasses.Subscription>}
     */
    this.subscriptions = [];

    this._wantObj = true;
    this._curObj = this.fileProperties;
    this._curSection = null;
  }

  /**
   * Processes a line of filter data.
   *
   * @param {string?} line The line of filter data to process. This may be
   *   `null`, which indicates the end of the filter data.
   */
  process(line)
  {
    let match = null;
    if (this._wantObj === true && (match = /^(\w+)=(.*)$/.exec(line)))
    {
      this._curObj[match[1]] = match[2];
    }
    else if (line === null || (match = /^\s*\[(.+)\]\s*$/.exec(line)))
    {
      if (this._curObj)
      {
        // Process current object before going to next section
        switch (this._curSection)
        {
          case "filter":
            if ("text" in this._curObj)
            {
              let {text} = this._curObj;
              if (isActiveFilter(Filter.fromText(text)))
                filterState.fromObject(text, this._curObj);
            }
            break;

          case "subscription":
            let subscription = Subscription.fromObject(this._curObj);
            if (subscription)
              this.subscriptions.push(subscription);
            break;

          case "subscription filters":
            if (this.subscriptions.length)
            {
              let currentSubscription = this.subscriptions[
                this.subscriptions.length - 1
              ];
              currentSubscription.updateFilterText(this._curObj);
            }
            break;
        }
      }

      if (line === null)
        return;

      this._curSection = match[1].toLowerCase();
      switch (this._curSection)
      {
        case "filter":
        case "subscription":
          this._wantObj = true;
          this._curObj = {};
          break;
        case "subscription filters":
          this._wantObj = false;
          this._curObj = [];
          break;
        default:
          this._wantObj = null;
          this._curObj = null;
      }
    }
    else if (this._wantObj === false && line)
    {
      this._curObj.push(line.replace(/\\\[/g, "["));
    }
  }
};


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



const {filterToRegExp} = __webpack_require__(34);

/**
 * The maximum number of patterns that
 * `{@link module:patterns.compilePatterns compilePatterns()}` will compile
 * into regular expressions.
 * @type {number}
 */
const COMPILE_PATTERNS_MAX = 100;

/**
 * A `CompiledPatterns` object represents the compiled version of multiple URL
 * request patterns. It is returned by
 * `{@link module:patterns.compilePatterns compilePatterns()}`.
 */
class CompiledPatterns
{
  /**
   * Creates an object with the given regular expressions for case-sensitive
   * and case-insensitive matching respectively.
   * @param {?RegExp} [caseSensitive]
   * @param {?RegExp} [caseInsensitive]
   * @private
   */
  constructor(caseSensitive, caseInsensitive)
  {
    this._caseSensitive = caseSensitive;
    this._caseInsensitive = caseInsensitive;
  }

  /**
   * Tests whether the given URL request matches the patterns used to create
   * this object.
   * @param {module:url.URLRequest} request
   * @returns {boolean}
   */
  test(request)
  {
    return ((this._caseSensitive &&
             this._caseSensitive.test(request.href)) ||
            (this._caseInsensitive &&
             this._caseInsensitive.test(request.lowerCaseHref)));
  }
}

/**
 * Compiles patterns from the given filters into a single
 * `{@link module:patterns~CompiledPatterns CompiledPatterns}` object.
 *
 * @param {module:filterClasses.URLFilter|
 *         Set.<module:filterClasses.URLFilter>} filters
 *   The filters. If the number of filters exceeds
 *   `{@link module:patterns~COMPILE_PATTERNS_MAX COMPILE_PATTERNS_MAX}`, the
 *   function returns `null`.
 *
 * @returns {?module:patterns~CompiledPatterns}
 *
 * @package
 */
exports.compilePatterns = function compilePatterns(filters)
{
  // If the number of filters is too large, it may choke especially on low-end
  // platforms. As a precaution, we refuse to compile. Ideally we would check
  // the length of the regular expression source rather than the number of
  // filters, but this is far more straightforward and practical.
  if (filters.size > COMPILE_PATTERNS_MAX)
    return null;

  let caseSensitive = "";
  let caseInsensitive = "";

  for (let filter of filters)
  {
    let source = filter.pattern != null ? filterToRegExp(filter.pattern) :
                   filter.regexp.source;

    if (filter.matchCase)
      caseSensitive += source + "|";
    else
      caseInsensitive += source + "|";
  }

  let caseSensitiveRegExp = null;
  let caseInsensitiveRegExp = null;

  try
  {
    if (caseSensitive)
      caseSensitiveRegExp = new RegExp(caseSensitive.slice(0, -1));

    if (caseInsensitive)
      caseInsensitiveRegExp = new RegExp(caseInsensitive.slice(0, -1));
  }
  catch (error)
  {
    // It is possible in theory for the regular expression to be too large
    // despite COMPILE_PATTERNS_MAX
    return null;
  }

  return new CompiledPatterns(caseSensitiveRegExp, caseInsensitiveRegExp);
};


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

/*
 * Copyright (c) 2003-2005  Tom Wu
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
 * THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * In addition, the following condition applies:
 *
 * All redistributions must retain an intact copy of this copyright notice
 * and disclaimer.
 */

// Basic JavaScript BN library - subset useful for RSA encryption.

// Bits per digit
var dbits;

// JavaScript engine analysis
var canary = 0xdeadbeefcafe;
var j_lm = ((canary&0xffffff)==0xefcafe);

// (public) Constructor
let BigInteger = exports.BigInteger = function BigInteger(a,b,c) {
  if(a != null)
    if("number" == typeof a) this.fromNumber(a,b,c);
    else if(b == null && "string" != typeof a) this.fromString(a,256);
    else this.fromString(a,b);
};

// return new, unset BigInteger
function nbi() { return new BigInteger(null); }

// am: Compute w_j += (x*this_i), propagate carries,
// c is initial carry, returns final carry.
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
// We need to select the fastest one that works in this environment.

// am1: use a single mult and divide to get the high bits,
// max digit bits should be 26 because
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
function am1(i,x,w,j,c,n) {
  while(--n >= 0) {
    var v = x*this[i++]+w[j]+c;
    c = Math.floor(v/0x4000000);
    w[j++] = v&0x3ffffff;
  }
  return c;
}
// am2 avoids a big mult-and-extract completely.
// Max digit bits should be <= 30 because we do bitwise ops
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
function am2(i,x,w,j,c,n) {
  var xl = x&0x7fff, xh = x>>15;
  while(--n >= 0) {
    var l = this[i]&0x7fff;
    var h = this[i++]>>15;
    var m = xh*l+h*xl;
    l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);
    c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);
    w[j++] = l&0x3fffffff;
  }
  return c;
}
// Alternately, set max digit bits to 28 since some
// browsers slow down when dealing with 32-bit numbers.
function am3(i,x,w,j,c,n) {
  var xl = x&0x3fff, xh = x>>14;
  while(--n >= 0) {
    var l = this[i]&0x3fff;
    var h = this[i++]>>14;
    var m = xh*l+h*xl;
    l = xl*l+((m&0x3fff)<<14)+w[j]+c;
    c = (l>>28)+(m>>14)+xh*h;
    w[j++] = l&0xfffffff;
  }
  return c;
}
if(j_lm && (navigator.appName == "Microsoft Internet Explorer")) {
  BigInteger.prototype.am = am2;
  dbits = 30;
}
else if(j_lm && (navigator.appName != "Netscape")) {
  BigInteger.prototype.am = am1;
  dbits = 26;
}
else { // Mozilla/Netscape seems to prefer am3
  BigInteger.prototype.am = am3;
  dbits = 28;
}

BigInteger.prototype.DB = dbits;
BigInteger.prototype.DM = ((1<<dbits)-1);
BigInteger.prototype.DV = (1<<dbits);

var BI_FP = 52;
BigInteger.prototype.FV = Math.pow(2,BI_FP);
BigInteger.prototype.F1 = BI_FP-dbits;
BigInteger.prototype.F2 = 2*dbits-BI_FP;

// Digit conversions
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
var BI_RC = new Array();
var rr,vv;
rr = "0".charCodeAt(0);
for(vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
rr = "a".charCodeAt(0);
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
rr = "A".charCodeAt(0);
for(vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;

function int2char(n) { return BI_RM.charAt(n); }
function intAt(s,i) {
  var c = BI_RC[s.charCodeAt(i)];
  return (c==null)?-1:c;
}

// (protected) copy this to r
function bnpCopyTo(r) {
  for(var i = this.t-1; i >= 0; --i) r[i] = this[i];
  r.t = this.t;
  r.s = this.s;
}

// (protected) set from integer value x, -DV <= x < DV
function bnpFromInt(x) {
  this.t = 1;
  this.s = (x<0)?-1:0;
  if(x > 0) this[0] = x;
  else if(x < -1) this[0] = x+DV;
  else this.t = 0;
}

// return bigint initialized to value
function nbv(i) { var r = nbi(); r.fromInt(i); return r; }

// (protected) set from string and radix
function bnpFromString(s,b) {
  var k;
  if(b == 16) k = 4;
  else if(b == 8) k = 3;
  else if(b == 256) k = 8; // byte array
  else if(b == 2) k = 1;
  else if(b == 32) k = 5;
  else if(b == 4) k = 2;
  else { this.fromRadix(s,b); return; }
  this.t = 0;
  this.s = 0;
  var i = s.length, mi = false, sh = 0;
  while(--i >= 0) {
    var x = (k==8)?s.charCodeAt(i)&0xff:intAt(s,i);   /** MODIFIED **/
    if(x < 0) {
      if(s.charAt(i) == "-") mi = true;
      continue;
    }
    mi = false;
    if(sh == 0)
      this[this.t++] = x;
    else if(sh+k > this.DB) {
      this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<<sh;
      this[this.t++] = (x>>(this.DB-sh));
    }
    else
      this[this.t-1] |= x<<sh;
    sh += k;
    if(sh >= this.DB) sh -= this.DB;
  }
  if(k == 8 && (s[0]&0x80) != 0) {
    this.s = -1;
    if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)<<sh;
  }
  this.clamp();
  if(mi) BigInteger.ZERO.subTo(this,this);
}

// (protected) clamp off excess high words
function bnpClamp() {
  var c = this.s&this.DM;
  while(this.t > 0 && this[this.t-1] == c) --this.t;
}

// (public) return string representation in given radix
function bnToString(b) {
  if(this.s < 0) return "-"+this.negate().toString(b);
  var k;
  if(b == 16) k = 4;
  else if(b == 8) k = 3;
  else if(b == 256) k = 8; // byte array      /** MODIFIED **/
  else if(b == 2) k = 1;
  else if(b == 32) k = 5;
  else if(b == 4) k = 2;
  else return this.toRadix(b);
  var km = (1<<k)-1, d, m = false, r = "", i = this.t;
  var p = this.DB-(i*this.DB)%k;
  if(i-- > 0) {
    if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = (k==8)?String.fromCharCode(d):int2char(d); }   /** MODIFIED **/
    while(i >= 0) {
      if(p < k) {
        d = (this[i]&((1<<p)-1))<<(k-p);
        d |= this[--i]>>(p+=this.DB-k);
      }
      else {
        d = (this[i]>>(p-=k))&km;
        if(p <= 0) { p += this.DB; --i; }
      }
      if(d > 0) m = true;
      if(m) r += (k==8)?String.fromCharCode(d):int2char(d);    /** MODIFIED **/
    }
  }
  return m?r:"0";
}

// (public) -this
function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }

// (public) |this|
function bnAbs() { return (this.s<0)?this.negate():this; }

// (public) return + if this > a, - if this < a, 0 if equal
function bnCompareTo(a) {
  var r = this.s-a.s;
  if(r != 0) return r;
  var i = this.t;
  r = i-a.t;
  if(r != 0) return r;
  while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;
  return 0;
}

// returns bit length of the integer x
function nbits(x) {
  var r = 1, t;
  if((t=x>>>16) != 0) { x = t; r += 16; }
  if((t=x>>8) != 0) { x = t; r += 8; }
  if((t=x>>4) != 0) { x = t; r += 4; }
  if((t=x>>2) != 0) { x = t; r += 2; }
  if((t=x>>1) != 0) { x = t; r += 1; }
  return r;
}

// (public) return the number of bits in "this"
function bnBitLength() {
  if(this.t <= 0) return 0;
  return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));
}

// (protected) r = this << n*DB
function bnpDLShiftTo(n,r) {
  var i;
  for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];
  for(i = n-1; i >= 0; --i) r[i] = 0;
  r.t = this.t+n;
  r.s = this.s;
}

// (protected) r = this >> n*DB
function bnpDRShiftTo(n,r) {
  for(var i = n; i < this.t; ++i) r[i-n] = this[i];
  r.t = Math.max(this.t-n,0);
  r.s = this.s;
}

// (protected) r = this << n
function bnpLShiftTo(n,r) {
  var bs = n%this.DB;
  var cbs = this.DB-bs;
  var bm = (1<<cbs)-1;
  var ds = Math.floor(n/this.DB), c = (this.s<<bs)&this.DM, i;
  for(i = this.t-1; i >= 0; --i) {
    r[i+ds+1] = (this[i]>>cbs)|c;
    c = (this[i]&bm)<<bs;
  }
  for(i = ds-1; i >= 0; --i) r[i] = 0;
  r[ds] = c;
  r.t = this.t+ds+1;
  r.s = this.s;
  r.clamp();
}

// (protected) r = this >> n
function bnpRShiftTo(n,r) {
  r.s = this.s;
  var ds = Math.floor(n/this.DB);
  if(ds >= this.t) { r.t = 0; return; }
  var bs = n%this.DB;
  var cbs = this.DB-bs;
  var bm = (1<<bs)-1;
  r[0] = this[ds]>>bs;
  for(var i = ds+1; i < this.t; ++i) {
    r[i-ds-1] |= (this[i]&bm)<<cbs;
    r[i-ds] = this[i]>>bs;
  }
  if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<<cbs;
  r.t = this.t-ds;
  r.clamp();
}

// (protected) r = this - a
function bnpSubTo(a,r) {
  var i = 0, c = 0, m = Math.min(a.t,this.t);
  while(i < m) {
    c += this[i]-a[i];
    r[i++] = c&this.DM;
    c >>= this.DB;
  }
  if(a.t < this.t) {
    c -= a.s;
    while(i < this.t) {
      c += this[i];
      r[i++] = c&this.DM;
      c >>= this.DB;
    }
    c += this.s;
  }
  else {
    c += this.s;
    while(i < a.t) {
      c -= a[i];
      r[i++] = c&this.DM;
      c >>= this.DB;
    }
    c -= a.s;
  }
  r.s = (c<0)?-1:0;
  if(c < -1) r[i++] = this.DV+c;
  else if(c > 0) r[i++] = c;
  r.t = i;
  r.clamp();
}

// (protected) r = this * a, r != this,a (HAC 14.12)
// "this" should be the larger one if appropriate.
function bnpMultiplyTo(a,r) {
  var x = this.abs(), y = a.abs();
  var i = x.t;
  r.t = i+y.t;
  while(--i >= 0) r[i] = 0;
  for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);
  r.s = 0;
  r.clamp();
  if(this.s != a.s) BigInteger.ZERO.subTo(r,r);
}

// (protected) r = this^2, r != this (HAC 14.16)
function bnpSquareTo(r) {
  var x = this.abs();
  var i = r.t = 2*x.t;
  while(--i >= 0) r[i] = 0;
  for(i = 0; i < x.t-1; ++i) {
    var c = x.am(i,x[i],r,2*i,0,1);
    if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {
      r[i+x.t] -= x.DV;
      r[i+x.t+1] = 1;
    }
  }
  if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);
  r.s = 0;
  r.clamp();
}

// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
// r != q, this != m.  q or r may be null.
function bnpDivRemTo(m,q,r) {
  var pm = m.abs();
  if(pm.t <= 0) return;
  var pt = this.abs();
  if(pt.t < pm.t) {
    if(q != null) q.fromInt(0);
    if(r != null) this.copyTo(r);
    return;
  }
  if(r == null) r = nbi();
  var y = nbi(), ts = this.s, ms = m.s;
  var nsh = this.DB-nbits(pm[pm.t-1]);	// normalize modulus
  if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }
  else { pm.copyTo(y); pt.copyTo(r); }
  var ys = y.t;
  var y0 = y[ys-1];
  if(y0 == 0) return;
  var yt = y0*(1<<this.F1)+((ys>1)?y[ys-2]>>this.F2:0);
  var d1 = this.FV/yt, d2 = (1<<this.F1)/yt, e = 1<<this.F2;
  var i = r.t, j = i-ys, t = (q==null)?nbi():q;
  y.dlShiftTo(j,t);
  if(r.compareTo(t) >= 0) {
    r[r.t++] = 1;
    r.subTo(t,r);
  }
  BigInteger.ONE.dlShiftTo(ys,t);
  t.subTo(y,y);	// "negative" y so we can replace sub with am later
  while(y.t < ys) y[y.t++] = 0;
  while(--j >= 0) {
    // Estimate quotient digit
    var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);
    if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) {	// Try it out
      y.dlShiftTo(j,t);
      r.subTo(t,r);
      while(r[i] < --qd) r.subTo(t,r);
    }
  }
  if(q != null) {
    r.drShiftTo(ys,q);
    if(ts != ms) BigInteger.ZERO.subTo(q,q);
  }
  r.t = ys;
  r.clamp();
  if(nsh > 0) r.rShiftTo(nsh,r);	// Denormalize remainder
  if(ts < 0) BigInteger.ZERO.subTo(r,r);
}

// (public) this mod a
function bnMod(a) {
  var r = nbi();
  this.abs().divRemTo(a,null,r);
  if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);
  return r;
}

// Modular reduction using "classic" algorithm
function Classic(m) { this.m = m; }
function cConvert(x) {
  if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
  else return x;
}
function cRevert(x) { return x; }
function cReduce(x) { x.divRemTo(this.m,null,x); }
function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }
function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }

Classic.prototype.convert = cConvert;
Classic.prototype.revert = cRevert;
Classic.prototype.reduce = cReduce;
Classic.prototype.mulTo = cMulTo;
Classic.prototype.sqrTo = cSqrTo;

// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
// justification:
//         xy == 1 (mod m)
//         xy =  1+km
//   xy(2-xy) = (1+km)(1-km)
// x[y(2-xy)] = 1-k^2m^2
// x[y(2-xy)] == 1 (mod m^2)
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
// JS multiply "overflows" differently from C/C++, so care is needed here.
function bnpInvDigit() {
  if(this.t < 1) return 0;
  var x = this[0];
  if((x&1) == 0) return 0;
  var y = x&3;		// y == 1/x mod 2^2
  y = (y*(2-(x&0xf)*y))&0xf;	// y == 1/x mod 2^4
  y = (y*(2-(x&0xff)*y))&0xff;	// y == 1/x mod 2^8
  y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff;	// y == 1/x mod 2^16
  // last step - calculate inverse mod DV directly;
  // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
  y = (y*(2-x*y%this.DV))%this.DV;		// y == 1/x mod 2^dbits
  // we really want the negative inverse, and -DV < y < DV
  return (y>0)?this.DV-y:-y;
}

// Montgomery reduction
function Montgomery(m) {
  this.m = m;
  this.mp = m.invDigit();
  this.mpl = this.mp&0x7fff;
  this.mph = this.mp>>15;
  this.um = (1<<(m.DB-15))-1;
  this.mt2 = 2*m.t;
}

// xR mod m
function montConvert(x) {
  var r = nbi();
  x.abs().dlShiftTo(this.m.t,r);
  r.divRemTo(this.m,null,r);
  if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);
  return r;
}

// x/R mod m
function montRevert(x) {
  var r = nbi();
  x.copyTo(r);
  this.reduce(r);
  return r;
}

// x = x/R mod m (HAC 14.32)
function montReduce(x) {
  while(x.t <= this.mt2)	// pad x so am has enough room later
    x[x.t++] = 0;
  for(var i = 0; i < this.m.t; ++i) {
    // faster way of calculating u0 = x[i]*mp mod DV
    var j = x[i]&0x7fff;
    var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;
    // use am to combine the multiply-shift-add into one call
    j = i+this.m.t;
    x[j] += this.m.am(0,u0,x,i,0,this.m.t);
    // propagate carry
    while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }
  }
  x.clamp();
  x.drShiftTo(this.m.t,x);
  if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);
}

// r = "x^2/R mod m"; x != r
function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }

// r = "xy/R mod m"; x,y != r
function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }

Montgomery.prototype.convert = montConvert;
Montgomery.prototype.revert = montRevert;
Montgomery.prototype.reduce = montReduce;
Montgomery.prototype.mulTo = montMulTo;
Montgomery.prototype.sqrTo = montSqrTo;

// (protected) true iff this is even
function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }

// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
function bnpExp(e,z) {
  if(e > 0xffffffff || e < 1) return BigInteger.ONE;
  var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;
  g.copyTo(r);
  while(--i >= 0) {
    z.sqrTo(r,r2);
    if((e&(1<<i)) > 0) z.mulTo(r2,g,r);
    else { var t = r; r = r2; r2 = t; }
  }
  return z.revert(r);
}

// (public) this^e % m, 0 <= e < 2^32
function bnModPowInt(e,m) {
  var z;
  if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);
  return this.exp(e,z);
}

// protected
BigInteger.prototype.copyTo = bnpCopyTo;
BigInteger.prototype.fromInt = bnpFromInt;
BigInteger.prototype.fromString = bnpFromString;
BigInteger.prototype.clamp = bnpClamp;
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
BigInteger.prototype.lShiftTo = bnpLShiftTo;
BigInteger.prototype.rShiftTo = bnpRShiftTo;
BigInteger.prototype.subTo = bnpSubTo;
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
BigInteger.prototype.squareTo = bnpSquareTo;
BigInteger.prototype.divRemTo = bnpDivRemTo;
BigInteger.prototype.invDigit = bnpInvDigit;
BigInteger.prototype.isEven = bnpIsEven;
BigInteger.prototype.exp = bnpExp;

// public
BigInteger.prototype.toString = bnToString;
BigInteger.prototype.negate = bnNegate;
BigInteger.prototype.abs = bnAbs;
BigInteger.prototype.compareTo = bnCompareTo;
BigInteger.prototype.bitLength = bnBitLength;
BigInteger.prototype.mod = bnMod;
BigInteger.prototype.modPowInt = bnModPowInt;

// "constants"
BigInteger.ZERO = nbv(0);
BigInteger.ONE = nbv(1);


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

(function () {
    var /*
 * Rusha, a JavaScript implementation of the Secure Hash Algorithm, SHA-1,
 * as defined in FIPS PUB 180-1, tuned for high performance with large inputs.
 * (http://github.com/srijs/rusha)
 *
 * Inspired by Paul Johnstons implementation (http://pajhome.org.uk/crypt/md5).
 *
 * Copyright (c) 2013 Sam Rijs (http://awesam.de).
 * Released under the terms of the MIT license as follows:
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */
    util = {
        getDataType: function (data) {
            if (typeof data === 'string') {
                return 'string';
            }
            if (data instanceof Array) {
                return 'array';
            }
            if (typeof global !== 'undefined' && global.Buffer && global.Buffer.isBuffer(data)) {
                return 'buffer';
            }
            if (data instanceof ArrayBuffer) {
                return 'arraybuffer';
            }
            if (data.buffer instanceof ArrayBuffer) {
                return 'view';
            }
            if (data instanceof Blob) {
                return 'blob';
            }
            throw new Error('Unsupported data type.');
        }
    };
    function Rusha(chunkSize) {
        'use strict';
        var // Private object structure.
        self$2 = { fill: 0 };
        var // Calculate the length of buffer that the sha1 routine uses
        // including the padding.
        padlen = function (len) {
            for (len += 9; len % 64 > 0; len += 1);
            return len;
        };
        var padZeroes = function (bin, len) {
            for (var i$2 = len >> 2; i$2 < bin.length; i$2++)
                bin[i$2] = 0;
        };
        var padData = function (bin, chunkLen, msgLen) {
            bin[chunkLen >> 2] |= 128 << 24 - (chunkLen % 4 << 3);
            // To support msgLen >= 2 GiB, use a float division when computing the
            // high 32-bits of the big-endian message length in bits.
            bin[((chunkLen >> 2) + 2 & ~15) + 14] = msgLen / (1 << 29) | 0;
            bin[((chunkLen >> 2) + 2 & ~15) + 15] = msgLen << 3;
        };
        var // Convert a binary string and write it to the heap.
        // A binary string is expected to only contain char codes < 256.
        convStr = function (H8, H32, start, len, off) {
            var str = this, i$2, om = off % 4, lm = len % 4, j = len - lm;
            if (j > 0) {
                switch (om) {
                case 0:
                    H8[off + 3 | 0] = str.charCodeAt(start);
                case 1:
                    H8[off + 2 | 0] = str.charCodeAt(start + 1);
                case 2:
                    H8[off + 1 | 0] = str.charCodeAt(start + 2);
                case 3:
                    H8[off | 0] = str.charCodeAt(start + 3);
                }
            }
            for (i$2 = om; i$2 < j; i$2 = i$2 + 4 | 0) {
                H32[off + i$2 >> 2] = str.charCodeAt(start + i$2) << 24 | str.charCodeAt(start + i$2 + 1) << 16 | str.charCodeAt(start + i$2 + 2) << 8 | str.charCodeAt(start + i$2 + 3);
            }
            switch (lm) {
            case 3:
                H8[off + j + 1 | 0] = str.charCodeAt(start + j + 2);
            case 2:
                H8[off + j + 2 | 0] = str.charCodeAt(start + j + 1);
            case 1:
                H8[off + j + 3 | 0] = str.charCodeAt(start + j);
            }
        };
        var // Convert a buffer or array and write it to the heap.
        // The buffer or array is expected to only contain elements < 256.
        convBuf = function (H8, H32, start, len, off) {
            var buf = this, i$2, om = off % 4, lm = len % 4, j = len - lm;
            if (j > 0) {
                switch (om) {
                case 0:
                    H8[off + 3 | 0] = buf[start];
                case 1:
                    H8[off + 2 | 0] = buf[start + 1];
                case 2:
                    H8[off + 1 | 0] = buf[start + 2];
                case 3:
                    H8[off | 0] = buf[start + 3];
                }
            }
            for (i$2 = 4 - om; i$2 < j; i$2 = i$2 += 4 | 0) {
                H32[off + i$2 >> 2] = buf[start + i$2] << 24 | buf[start + i$2 + 1] << 16 | buf[start + i$2 + 2] << 8 | buf[start + i$2 + 3];
            }
            switch (lm) {
            case 3:
                H8[off + j + 1 | 0] = buf[start + j + 2];
            case 2:
                H8[off + j + 2 | 0] = buf[start + j + 1];
            case 1:
                H8[off + j + 3 | 0] = buf[start + j];
            }
        };
        var convBlob = function (H8, H32, start, len, off) {
            var blob = this, i$2, om = off % 4, lm = len % 4, j = len - lm;
            var buf = new Uint8Array(reader.readAsArrayBuffer(blob.slice(start, start + len)));
            if (j > 0) {
                switch (om) {
                case 0:
                    H8[off + 3 | 0] = buf[0];
                case 1:
                    H8[off + 2 | 0] = buf[1];
                case 2:
                    H8[off + 1 | 0] = buf[2];
                case 3:
                    H8[off | 0] = buf[3];
                }
            }
            for (i$2 = 4 - om; i$2 < j; i$2 = i$2 += 4 | 0) {
                H32[off + i$2 >> 2] = buf[i$2] << 24 | buf[i$2 + 1] << 16 | buf[i$2 + 2] << 8 | buf[i$2 + 3];
            }
            switch (lm) {
            case 3:
                H8[off + j + 1 | 0] = buf[j + 2];
            case 2:
                H8[off + j + 2 | 0] = buf[j + 1];
            case 1:
                H8[off + j + 3 | 0] = buf[j];
            }
        };
        var convFn = function (data) {
            switch (util.getDataType(data)) {
            case 'string':
                return convStr.bind(data);
            case 'array':
                return convBuf.bind(data);
            case 'buffer':
                return convBuf.bind(data);
            case 'arraybuffer':
                return convBuf.bind(new Uint8Array(data));
            case 'view':
                return convBuf.bind(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
            case 'blob':
                return convBlob.bind(data);
            }
        };
        var slice = function (data, offset) {
            switch (util.getDataType(data)) {
            case 'string':
                return data.slice(offset);
            case 'array':
                return data.slice(offset);
            case 'buffer':
                return data.slice(offset);
            case 'arraybuffer':
                return data.slice(offset);
            case 'view':
                return data.buffer.slice(offset);
            }
        };
        var // Precompute 00 - ff strings
        precomputedHex = new Array(256);
        for (var i = 0; i < 256; i++) {
            precomputedHex[i] = (i < 16 ? '0' : '') + i.toString(16);
        }
        var // Convert an ArrayBuffer into its hexadecimal string representation.
        hex = function (arrayBuffer) {
            var binarray = new Uint8Array(arrayBuffer);
            var res = new Array(arrayBuffer.byteLength);
            for (var i$2 = 0; i$2 < res.length; i$2++) {
                res[i$2] = precomputedHex[binarray[i$2]];
            }
            return res.join('');
        };
        var ceilHeapSize = function (v) {
            // The asm.js spec says:
            // The heap object's byteLength must be either
            // 2^n for n in [12, 24) or 2^24 * n for n ≥ 1.
            // Also, byteLengths smaller than 2^16 are deprecated.
            var p;
            if (// If v is smaller than 2^16, the smallest possible solution
                // is 2^16.
                v <= 65536)
                return 65536;
            if (// If v < 2^24, we round up to 2^n,
                // otherwise we round up to 2^24 * n.
                v < 16777216) {
                for (p = 1; p < v; p = p << 1);
            } else {
                for (p = 16777216; p < v; p += 16777216);
            }
            return p;
        };
        var // Initialize the internal data structures to a new capacity.
        init = function (size) {
            if (size % 64 > 0) {
                throw new Error('Chunk size must be a multiple of 128 bit');
            }
            self$2.maxChunkLen = size;
            self$2.padMaxChunkLen = padlen(size);
            // The size of the heap is the sum of:
            // 1. The padded input message size
            // 2. The extended space the algorithm needs (320 byte)
            // 3. The 160 bit state the algoritm uses
            self$2.heap = new ArrayBuffer(ceilHeapSize(self$2.padMaxChunkLen + 320 + 20));
            self$2.h32 = new Int32Array(self$2.heap);
            self$2.h8 = new Int8Array(self$2.heap);
            self$2.core = new Rusha._core({
                Int32Array: Int32Array,
                DataView: DataView
            }, {}, self$2.heap);
            self$2.buffer = null;
        };
        // Initialize the data structures according
        // to a chunk size.
        init(chunkSize || 64 * 1024);
        var initState = function (heap, padMsgLen) {
            var io = new Int32Array(heap, padMsgLen + 320, 5);
            io[0] = 1732584193;
            io[1] = -271733879;
            io[2] = -1732584194;
            io[3] = 271733878;
            io[4] = -1009589776;
        };
        var padChunk = function (chunkLen, msgLen) {
            var padChunkLen = padlen(chunkLen);
            var view = new Int32Array(self$2.heap, 0, padChunkLen >> 2);
            padZeroes(view, chunkLen);
            padData(view, chunkLen, msgLen);
            return padChunkLen;
        };
        var // Write data to the heap.
        write = function (data, chunkOffset, chunkLen) {
            convFn(data)(self$2.h8, self$2.h32, chunkOffset, chunkLen, 0);
        };
        var // Initialize and call the RushaCore,
        // assuming an input buffer of length len * 4.
        coreCall = function (data, chunkOffset, chunkLen, msgLen, finalize) {
            var padChunkLen = chunkLen;
            if (finalize) {
                padChunkLen = padChunk(chunkLen, msgLen);
            }
            write(data, chunkOffset, chunkLen);
            self$2.core.hash(padChunkLen, self$2.padMaxChunkLen);
        };
        var getRawDigest = function (heap, padMaxChunkLen) {
            var io = new Int32Array(heap, padMaxChunkLen + 320, 5);
            var out = new Int32Array(5);
            var arr = new DataView(out.buffer);
            arr.setInt32(0, io[0], false);
            arr.setInt32(4, io[1], false);
            arr.setInt32(8, io[2], false);
            arr.setInt32(12, io[3], false);
            arr.setInt32(16, io[4], false);
            return out;
        };
        var // Calculate the hash digest as an array of 5 32bit integers.
        rawDigest = this.rawDigest = function (str) {
            var msgLen = str.byteLength || str.length || str.size || 0;
            initState(self$2.heap, self$2.padMaxChunkLen);
            var chunkOffset = 0, chunkLen = self$2.maxChunkLen, last;
            for (chunkOffset = 0; msgLen > chunkOffset + chunkLen; chunkOffset += chunkLen) {
                coreCall(str, chunkOffset, chunkLen, msgLen, false);
            }
            coreCall(str, chunkOffset, msgLen - chunkOffset, msgLen, true);
            return getRawDigest(self$2.heap, self$2.padMaxChunkLen);
        };
        // The digest and digestFrom* interface returns the hash digest
        // as a hex string.
        this.digest = this.digestFromString = this.digestFromBuffer = this.digestFromArrayBuffer = function (str) {
            return hex(rawDigest(str).buffer);
        };
    }
    ;
    // The low-level RushCore module provides the heart of Rusha,
    // a high-speed sha1 implementation working on an Int32Array heap.
    // At first glance, the implementation seems complicated, however
    // with the SHA1 spec at hand, it is obvious this almost a textbook
    // implementation that has a few functions hand-inlined and a few loops
    // hand-unrolled.
    Rusha._core = function RushaCore(stdlib, foreign, heap) {
        'use asm';
        var H = new stdlib.Int32Array(heap);
        function hash(k, x) {
            // k in bytes
            k = k | 0;
            x = x | 0;
            var i = 0, j = 0, y0 = 0, z0 = 0, y1 = 0, z1 = 0, y2 = 0, z2 = 0, y3 = 0, z3 = 0, y4 = 0, z4 = 0, t0 = 0, t1 = 0;
            y0 = H[x + 320 >> 2] | 0;
            y1 = H[x + 324 >> 2] | 0;
            y2 = H[x + 328 >> 2] | 0;
            y3 = H[x + 332 >> 2] | 0;
            y4 = H[x + 336 >> 2] | 0;
            for (i = 0; (i | 0) < (k | 0); i = i + 64 | 0) {
                z0 = y0;
                z1 = y1;
                z2 = y2;
                z3 = y3;
                z4 = y4;
                for (j = 0; (j | 0) < 64; j = j + 4 | 0) {
                    t1 = H[i + j >> 2] | 0;
                    t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | ~y1 & y3) | 0) + ((t1 + y4 | 0) + 1518500249 | 0) | 0;
                    y4 = y3;
                    y3 = y2;
                    y2 = y1 << 30 | y1 >>> 2;
                    y1 = y0;
                    y0 = t0;
                    H[k + j >> 2] = t1;
                }
                for (j = k + 64 | 0; (j | 0) < (k + 80 | 0); j = j + 4 | 0) {
                    t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) >>> 31;
                    t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | ~y1 & y3) | 0) + ((t1 + y4 | 0) + 1518500249 | 0) | 0;
                    y4 = y3;
                    y3 = y2;
                    y2 = y1 << 30 | y1 >>> 2;
                    y1 = y0;
                    y0 = t0;
                    H[j >> 2] = t1;
                }
                for (j = k + 80 | 0; (j | 0) < (k + 160 | 0); j = j + 4 | 0) {
                    t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) >>> 31;
                    t0 = ((y0 << 5 | y0 >>> 27) + (y1 ^ y2 ^ y3) | 0) + ((t1 + y4 | 0) + 1859775393 | 0) | 0;
                    y4 = y3;
                    y3 = y2;
                    y2 = y1 << 30 | y1 >>> 2;
                    y1 = y0;
                    y0 = t0;
                    H[j >> 2] = t1;
                }
                for (j = k + 160 | 0; (j | 0) < (k + 240 | 0); j = j + 4 | 0) {
                    t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) >>> 31;
                    t0 = ((y0 << 5 | y0 >>> 27) + (y1 & y2 | y1 & y3 | y2 & y3) | 0) + ((t1 + y4 | 0) - 1894007588 | 0) | 0;
                    y4 = y3;
                    y3 = y2;
                    y2 = y1 << 30 | y1 >>> 2;
                    y1 = y0;
                    y0 = t0;
                    H[j >> 2] = t1;
                }
                for (j = k + 240 | 0; (j | 0) < (k + 320 | 0); j = j + 4 | 0) {
                    t1 = (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) << 1 | (H[j - 12 >> 2] ^ H[j - 32 >> 2] ^ H[j - 56 >> 2] ^ H[j - 64 >> 2]) >>> 31;
                    t0 = ((y0 << 5 | y0 >>> 27) + (y1 ^ y2 ^ y3) | 0) + ((t1 + y4 | 0) - 899497514 | 0) | 0;
                    y4 = y3;
                    y3 = y2;
                    y2 = y1 << 30 | y1 >>> 2;
                    y1 = y0;
                    y0 = t0;
                    H[j >> 2] = t1;
                }
                y0 = y0 + z0 | 0;
                y1 = y1 + z1 | 0;
                y2 = y2 + z2 | 0;
                y3 = y3 + z3 | 0;
                y4 = y4 + z4 | 0;
            }
            H[x + 320 >> 2] = y0;
            H[x + 324 >> 2] = y1;
            H[x + 328 >> 2] = y2;
            H[x + 332 >> 2] = y3;
            H[x + 336 >> 2] = y4;
        }
        return { hash: hash };
    };
    exports = Rusha;
    if (// If we'e running in Node.JS, export a module.
        true) {
        module.exports = Rusha;
    } else {}
    if (// If we're running in a webworker, accept
        // messages containing a jobid and a buffer
        // or blob object, and return the hash result.
        typeof FileReaderSync !== 'undefined') {
        var reader = new FileReaderSync(), hasher = new Rusha(4 * 1024 * 1024);
        self.onmessage = function onMessage(event) {
            var hash, data = event.data.data;
            try {
                hash = hasher.digest(data);
                self.postMessage({
                    id: event.data.id,
                    hash: hash
                });
            } catch (e) {
                self.postMessage({
                    id: event.data.id,
                    error: e.name
                });
            }
        };
    }
}());


/***/ }),
/* 61 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _messaging_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */



let lastError = null;

function safeToString(value)
{
  try
  {
    return String(value);
  }
  catch (e)
  {
    return "<string conversion error>";
  }
}

self.addEventListener("error", event =>
{
  lastError = safeToString(event.error);
});

self.addEventListener("unhandledrejection", event =>
{
  lastError = safeToString(event.reason);
});

let consoleError = console.error;
console.error = function error(...args)
{
  lastError = args.map(safeToString).join(" ");
  consoleError.apply(this, args);
};

_messaging_js__WEBPACK_IMPORTED_MODULE_0__["port"].on("debug.getLastError", () =>
{
  let error = lastError;
  lastError = null;
  return error;
});


/***/ }),
/* 62 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
/* harmony import */ var _adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _url_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13);
/* harmony import */ var _allowlisting_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8);
/* harmony import */ var _hitLogger_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(11);
/* harmony import */ var info__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(7);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module popupBlocker */










let loadingPopups = new Map();

function forgetPopup(tabId)
{
  loadingPopups.delete(tabId);

  if (loadingPopups.size == 0)
  {
    browser.webRequest.onBeforeRequest.removeListener(onPopupURLChanged);
    browser.webNavigation.onCommitted.removeListener(onPopupURLChanged);
    browser.webNavigation.onCompleted.removeListener(onCompleted);
    browser.tabs.onRemoved.removeListener(forgetPopup);
  }
}

function checkPotentialPopup(tabId, popup)
{
  let url = popup.url || "about:blank";
  let documentHost = Object(_url_js__WEBPACK_IMPORTED_MODULE_4__["extractHostFromFrame"])(popup.sourceFrame);

  let specificOnly = !!Object(_allowlisting_js__WEBPACK_IMPORTED_MODULE_5__["checkAllowlisted"])(
    popup.sourcePage, popup.sourceFrame, null,
    _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].GENERICBLOCK
  );

  let filter = _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__["defaultMatcher"].match(
    Object(_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__["parseURL"])(url), _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].POPUP,
    documentHost, null, specificOnly
  );

  if (filter instanceof _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__["BlockingFilter"])
    browser.tabs.remove(tabId).catch(() => {});

  Object(_hitLogger_js__WEBPACK_IMPORTED_MODULE_6__["logRequest"])(
    [popup.sourcePage.id],
    {url, type: "POPUP", docDomain: documentHost, specificOnly},
    filter
  );
}

function onPopupURLChanged(details)
{
  // Ignore frames inside the popup window.
  if (details.frameId != 0)
    return;

  let popup = loadingPopups.get(details.tabId);
  if (popup)
  {
    popup.url = details.url;
    if (popup.sourceFrame)
      checkPotentialPopup(details.tabId, popup);
  }
}

function onCompleted(details)
{
  if (details.frameId == 0 && details.url != "about:blank")
    forgetPopup(details.tabId);
}

function onPopupCreated(tabId, url, sourceTabId, sourceFrameId)
{
  if (loadingPopups.size == 0)
  {
    browser.webRequest.onBeforeRequest.addListener(
      onPopupURLChanged,
      {
        urls: ["http://*/*", "https://*/*"],
        types: ["main_frame"]
      }
    );
    browser.webNavigation.onCommitted.addListener(onPopupURLChanged);
    browser.webNavigation.onCompleted.addListener(onCompleted);
    browser.tabs.onRemoved.addListener(forgetPopup);
  }

  let popup = {
    url,
    sourcePage: new ext.Page({id: sourceTabId}),
    sourceFrame: null
  };

  loadingPopups.set(tabId, popup);

  let frame = ext.getFrame(sourceTabId, sourceFrameId);

  if (Object(_allowlisting_js__WEBPACK_IMPORTED_MODULE_5__["checkAllowlisted"])(popup.sourcePage, frame))
  {
    forgetPopup(tabId);
  }
  else
  {
    popup.sourceFrame = frame;
    checkPotentialPopup(tabId, popup);
  }
}

// Versions of Firefox before 54 do not support
// webNavigation.onCreatedNavigationTarget
// https://bugzilla.mozilla.org/show_bug.cgi?id=1190687
if ("onCreatedNavigationTarget" in browser.webNavigation)
{
  browser.webNavigation.onCreatedNavigationTarget.addListener(details =>
  {
    onPopupCreated(details.tabId, details.url, details.sourceTabId,
                   details.sourceFrameId);
  });
}

// On Firefox, clicking on a <a target="_blank" rel="noopener"> link doesn't
// emit the webNavigation.onCreatedNavigationTarget event (and since Firefox 79,
// "noopener" is implied by default). But on Chrome, opening a new empty tab
// emits the tabs.onCreated event with openerTabId set. So the code below would
// cause new tabs created by the user to be considered popups too, on Chrome.
if (info__WEBPACK_IMPORTED_MODULE_7__["platform"] == "gecko")
{
  browser.tabs.onCreated.addListener(details =>
  {
    // We only care about tabs created by another tab.
    // e.g. clicking on a link with target=_blank.
    if (typeof details.openerTabId == "undefined")
      return;

    // onCreated doesn't provide the frameId of the opener.
    onPopupCreated(details.id, details.url, details.openerTabId, 0);
  });
}


/***/ }),
/* 63 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(10);
/* harmony import */ var _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
/* harmony import */ var _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
/* harmony import */ var _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9);
/* harmony import */ var _adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _url_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(13);
/* harmony import */ var _allowlisting_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(8);
/* harmony import */ var _hitLogger_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(11);
/* harmony import */ var _stats_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(16);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */










browser.webRequest.onHeadersReceived.addListener(details =>
{
  let url = Object(_adblockpluscore_lib_url_js__WEBPACK_IMPORTED_MODULE_3__["parseURL"])(details.url);
  let parentFrame = ext.getFrame(details.tabId, details.parentFrameId);
  let hostname = Object(_url_js__WEBPACK_IMPORTED_MODULE_4__["extractHostFromFrame"])(parentFrame) || url.hostname;

  let cspMatch = _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__["defaultMatcher"].match(url, _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].CSP,
                                      hostname, null, false);
  if (cspMatch)
  {
    let page = new ext.Page({id: details.tabId, url: details.url});
    let frame = ext.getFrame(details.tabId, details.frameId);

    if (Object(_allowlisting_js__WEBPACK_IMPORTED_MODULE_5__["checkAllowlisted"])(page, frame))
      return;

    // To avoid an extra match for the common case we assumed no
    // $genericblock filters applied when searching for a matching $csp filter.
    // We must now pay the price by first checking for a $genericblock filter
    // and if necessary that our $csp filter is specific.
    let specificOnly = !!Object(_allowlisting_js__WEBPACK_IMPORTED_MODULE_5__["checkAllowlisted"])(page, frame, null,
                                          _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].GENERICBLOCK);
    if (specificOnly && !(cspMatch instanceof _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__["AllowingFilter"]))
    {
      cspMatch = _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__["defaultMatcher"].match(url, _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].CSP,
                                      hostname, null, specificOnly);
      if (!cspMatch)
        return;
    }

    if (cspMatch instanceof _adblockpluscore_lib_filterClasses_js__WEBPACK_IMPORTED_MODULE_1__["AllowingFilter"])
    {
      Object(_hitLogger_js__WEBPACK_IMPORTED_MODULE_6__["logRequest"])([details.tabId], {
        url: details.url, type: "CSP", docDomain: hostname,
        specificOnly
      }, cspMatch);
      Object(_stats_js__WEBPACK_IMPORTED_MODULE_7__["recordBlockedRequest"])(cspMatch, [details.tabId]);
      return;
    }

    let {blocking} = _adblockpluscore_lib_matcher_js__WEBPACK_IMPORTED_MODULE_0__["defaultMatcher"].search(url, _adblockpluscore_lib_contentTypes_js__WEBPACK_IMPORTED_MODULE_2__["contentTypes"].CSP, hostname,
                                           null, specificOnly, "blocking");
    for (cspMatch of blocking)
    {
      Object(_hitLogger_js__WEBPACK_IMPORTED_MODULE_6__["logRequest"])([details.tabId], {
        url: details.url, type: "CSP", docDomain: hostname,
        specificOnly
      }, cspMatch);
      Object(_stats_js__WEBPACK_IMPORTED_MODULE_7__["recordBlockedRequest"])(cspMatch, [details.tabId]);

      details.responseHeaders.push({
        name: "Content-Security-Policy",
        value: cspMatch.csp
      });
    }

    return {responseHeaders: details.responseHeaders};
  }
}, {
  urls: ["http://*/*", "https://*/*"],
  types: ["main_frame", "sub_frame"]
}, ["blocking", "responseHeaders"]);


/***/ }),
/* 64 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _messaging_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
/* harmony import */ var info__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module messageResponder */




function forward(type, message, sender)
{
  return new Promise(resolve =>
  {
    _messaging_js__WEBPACK_IMPORTED_MODULE_0__["port"]._onMessage(Object.assign({}, message, {type}), sender, resolve);
  });
}

/**
 * @deprecated Please send the "filters.getTypes" message instead.
 *
 * @event "types.get"
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_0__["port"].on("types.get",
        (message, sender) => forward("filters.getTypes", message, sender));

/**
 * @deprecated Please send the "options.open" message instead.
 *
 * @event "app.open"
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_0__["port"].on("app.open", (message, sender) =>
{
  if (message.what == "options")
    return forward("options.open", message, sender);
});

/**
 * @deprecated Please send the "subscriptions.getInitIssues",
 *             "prefs.getDocLink", "subscriptions.getRecommendations",
 *             "devtools.supported" or "info.get" messages, or call the
 *             browser.tabs.getCurrent(), browser.i18n.getUILanguage(),
 *             browser.i18n.getMessage("@@bidi_dir") APIs instead.
 *
 * @event "app.get"
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_0__["port"].on("app.get", async(message, sender) =>
{
  if (message.what == "localeInfo")
  {
    return {
      locale: browser.i18n.getUILanguage(),
      bidiDir: browser.i18n.getMessage("@@bidi_dir")
    };
  }

  if (message.what == "senderId")
    return sender.page.id;

  if (message.what == "doclink")
    return forward("prefs.getDocLink", message, sender);

  if (message.what == "recommendations")
    return forward("subscriptions.getRecommendations", message, sender);

  if (message.what == "features")
  {
    let devToolsPanel = await forward("devtools.supported", message, sender);
    return {devToolsPanel};
  }

  if (message.what == "os")
  {
    let platformInfo = await browser.runtime.getPlatformInfo();
    return platformInfo.os;
  }

  return info__WEBPACK_IMPORTED_MODULE_1__[message.what];
});

/**
 * @typedef {object} infoGetResult
 * @property {string} addonName
 *   The extension's name, e.g. "adblockpluschrome".
 * @property {string} addonVersion
 *   The extension's version, e.g. "3.6.3".
 * @property {string} application
 *   The browser's name, e.g. "chrome".
 * @property {string} applicationVersion
 *   The browser's version, e.g. "77.0.3865.90".
 * @property {string} platform
 *   The browser platform, e.g. "chromium".
 * @property {string} platformVersion
 *   The browser platform's version, e.g. "77.0.3865.90".
 */

/**
 * Returns the browser platform information.
 *
 * @event "info.get"
 * @returns {infoGetResult}
 */
_messaging_js__WEBPACK_IMPORTED_MODULE_0__["port"].on("info.get", (message, sender) => info__WEBPACK_IMPORTED_MODULE_1__);


/***/ }),
/* 65 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"type\":\"ads\",\"languages\":[\"id\",\"ms\"],\"title\":\"ABPindo+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/abpindo+easylist.txt\",\"homepage\":\"http://abpindo.blogspot.com/\"},{\"type\":\"ads\",\"languages\":[\"vi\"],\"title\":\"ABPVN List+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/abpvn+easylist.txt\",\"homepage\":\"http://abpvn.com/\"},{\"type\":\"ads\",\"languages\":[\"bg\"],\"title\":\"Bulgarian list+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/bulgarian_list+easylist.txt\",\"homepage\":\"https://stanev.org/abp/\"},{\"type\":\"ads\",\"languages\":[\"no\",\"nb\",\"nn\",\"da\",\"is\",\"fo\",\"kl\",\"sv\",\"fi\"],\"title\":\"Dandelion Sprout's Nordic Filters+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/dandelion_sprouts_nordic_filters+easylist.txt\",\"homepage\":\"https://github.com/DandelionSprout/adfilt\"},{\"type\":\"ads\",\"languages\":[\"en\"],\"title\":\"EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"zh\"],\"title\":\"EasyList China+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistchina+easylist.txt\",\"homepage\":\"https://github.com/easylist/easylistchina\"},{\"type\":\"ads\",\"languages\":[\"cs\",\"sk\"],\"title\":\"EasyList Czech and Slovak+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistczechslovak+easylist.txt\",\"homepage\":\"https://adblock.sk/\"},{\"type\":\"ads\",\"languages\":[\"nl\"],\"title\":\"EasyList Dutch+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistdutch+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"de\"],\"title\":\"EasyList Germany+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistgermany+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"he\"],\"title\":\"EasyList Hebrew+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/israellist+easylist.txt\",\"homepage\":\"https://github.com/easylist/EasyListHebrew\"},{\"type\":\"ads\",\"languages\":[\"it\"],\"title\":\"EasyList Italy+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistitaly+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"lt\"],\"title\":\"EasyList Lithuania+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistlithuania+easylist.txt\",\"homepage\":\"https://github.com/EasyList-Lithuania/easylist_lithuania\"},{\"type\":\"ads\",\"languages\":[\"pl\"],\"title\":\"EasyList Polish+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistpolish+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"pt\"],\"title\":\"EasyList Portuguese+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistportuguese+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"es\"],\"title\":\"EasyList Spanish+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/easylistspanish+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"bn\",\"gu\",\"hi\",\"pa\",\"as\",\"mr\",\"ml\",\"te\",\"kn\",\"or\",\"ne\",\"si\"],\"title\":\"IndianList+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/indianlist+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"ko\"],\"title\":\"KoreanList+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/koreanlist+easylist.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"ads\",\"languages\":[\"lv\"],\"title\":\"Latvian List+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/latvianlist+easylist.txt\",\"homepage\":\"https://notabug.org/latvian-list/adblock-latvian\"},{\"type\":\"ads\",\"languages\":[\"ar\"],\"title\":\"Liste AR+Liste FR+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/liste_ar+liste_fr+easylist.txt\",\"homepage\":\"https://forums.lanik.us/viewforum.php?f=98\"},{\"type\":\"ads\",\"languages\":[\"fr\"],\"title\":\"Liste FR+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/liste_fr+easylist.txt\",\"homepage\":\"https://forums.lanik.us/viewforum.php?f=91\"},{\"type\":\"ads\",\"languages\":[\"ro\"],\"title\":\"ROList+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/rolist+easylist.txt\",\"homepage\":\"https://zoso.ro/rolist/\"},{\"type\":\"ads\",\"languages\":[\"ru\",\"uk\"],\"title\":\"RuAdList+EasyList\",\"url\":\"https://easylist-downloads.adblockplus.org/ruadlist+easylist.txt\",\"homepage\":\"https://forums.lanik.us/viewforum.php?f=102\"},{\"type\":\"circumvention\",\"title\":\"ABP filters\",\"url\":\"https://easylist-downloads.adblockplus.org/abp-filters-anti-cv.txt\",\"homepage\":\"https://github.com/abp-filters/abp-filters-anti-cv\"},{\"type\":\"cookies\",\"title\":\"I don't care about cookies\",\"url\":\"https://easylist-downloads.adblockplus.org/i_dont_care_about_cookies.txt\",\"homepage\":\"https://www.i-dont-care-about-cookies.eu/\"},{\"type\":\"notifications\",\"title\":\"Fanboy's Notifications Blocking List\",\"url\":\"https://easylist-downloads.adblockplus.org/fanboy-notifications.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"privacy\",\"title\":\"EasyPrivacy\",\"url\":\"https://easylist-downloads.adblockplus.org/easyprivacy.txt\",\"homepage\":\"https://easylist.to/\"},{\"type\":\"social\",\"title\":\"Fanboy's Social Blocking List\",\"url\":\"https://easylist-downloads.adblockplus.org/fanboy-social.txt\",\"homepage\":\"https://easylist.to/\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, chromeStorageSetHelper */

// Send the file name and line number of any error message. This will help us
// to trace down any frequent errors we can't confirm ourselves.
window.addEventListener('error', (e) => {
  if (!e.filename && !e.lineno && !e.colno && !e.error && !e.message) {
    return;
  }
  let str = `Error: ${
    (e.filename || 'anywhere').replace(browser.runtime.getURL(''), '')
  }:${e.lineno || 'anywhere'
  }:${e.colno || 'anycol'}`;
  if (e.message) {
    str += `: ${e.message}`;
  }
  const src = e.target.src || e.target.href;
  if (src) {
    str += `src: ${src}`;
  }
  if (e.error) {
    let stack = `-${e.error.message || ''
    }-${e.error.stack || ''}`;
    stack = stack.replace(/:/gi, ';').replace(/\n/gi, '');
    // only append the stack info if there isn't any URL info in the stack trace
    if (stack.indexOf('http') === -1) {
      str += stack;
    }
    // don't send large stack traces
    if (str.length > 1024) {
      str = str.substr(0, 1023);
    }
  }
  chromeStorageSetHelper('errorkey', `Date added:${new Date()} ${str}`);
  // eslint-disable-next-line no-console
  console.log(str);
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, log, License, runBandaids, openTab */

// Set to true to get noisier console.log statements
const VERBOSE_DEBUG = false;
let loggingEnable = false;
const THIRTY_MINUTES_IN_MILLISECONDS = 1800000;

// Enabled in adblock_start_common.js and background.js if the user wants
const logging = function (enabled) {
  if (enabled) {
    loggingEnable = true;
    window.log = function log(...args) {
      if (VERBOSE_DEBUG || args[0] !== '[DEBUG]') { // comment out for verbosity
        // eslint-disable-next-line no-console
        console.log(...args);
      }
    };
  } else {
    window.log = function log() {
    };

    loggingEnable = false;
  }
};

logging(false); // disabled by default

// Behaves very similarly to $.ready() but does not require jQuery.
const onReady = function (callback) {
  if (document.readyState === 'complete') {
    window.setTimeout(callback, 0);
  } else {
    window.addEventListener('load', callback, false);
  }
};

// Excecute any bandaid for the specific site, if the bandaids.js was loaded.
onReady(() => {
  if (typeof runBandaids === 'function') {
    runBandaids();
  }
});

// Inputs:
//   - messageName : Str
//   - substitutions : Array of Str or a String
const translate = function (messageName, substitutions) {
  if (!messageName || typeof messageName !== 'string') {
    // eslint-disable-next-line no-console
    console.trace('missing messageName');
    return '';
  }

  let parts = substitutions;
  if (Array.isArray(parts)) {
    for (let i = 0; i < parts.length; i++) {
      if (typeof parts[i] !== 'string') {
        parts[i] = parts[i].toString();
      }
    }
  } else if (parts && typeof parts !== 'string') {
    parts = parts.toString();
  }

  // if VERBOSE_DEBUG is set to true, duplicate (double the length) of the translated strings
  // used for testing purposes only
  if (VERBOSE_DEBUG) {
    return `${browser.i18n.getMessage(messageName, parts)}
            ${browser.i18n.getMessage(messageName, parts)}`;
  }
  return browser.i18n.getMessage(messageName, parts);
};

const splitMessageWithReplacementText = function (rawMessageText, messageID) {
  const anchorStartPos = rawMessageText.indexOf('[[');
  const anchorEndPos = rawMessageText.indexOf(']]');

  if (anchorStartPos === -1 || anchorEndPos === -1) {
    log('replacement tag not found', messageID, rawMessageText, anchorStartPos, anchorEndPos);
    return { error: 'no brackets found' };
  }
  const returnObj = {};
  returnObj.anchorPrefixText = rawMessageText.substring(0, anchorStartPos);
  returnObj.anchorText = rawMessageText.substring(anchorStartPos + 2, anchorEndPos);
  returnObj.anchorPostfixText = rawMessageText.substring(anchorEndPos + 2);
  return returnObj;
};

const processReplacementChildren = function ($el, replacementText, messageId) {
  // Replace a dummy <a/> inside of localized text with a real element.
  // Give the real element the same text as the dummy link.
  const $element = $el;
  const messageID = $element.attr('i18n') || messageId;
  if (!messageID || typeof messageID !== 'string') {
    $(this).addClass('i18n-replaced');
    return;
  }
  if (!$element.get(0).firstChild) {
    log('returning, no first child found', $element.attr('i18n'));
    return;
  }
  if (!$element.get(0).lastChild) {
    log('returning, no last child found', $element.attr('i18n'));
    return;
  }
  const replaceElId = `#${$element.attr('i18n_replacement_el')}`;
  if ($(replaceElId).length === 0) {
    log('returning, no child element found', $element.attr('i18n'), replaceElId);
    return;
  }
  const rawMessageText = browser.i18n.getMessage(messageID) || '';
  const messageSplit = splitMessageWithReplacementText(rawMessageText, messageID);
  $element.get(0).firstChild.nodeValue = messageSplit.anchorPrefixText;
  $element.get(0).lastChild.nodeValue = messageSplit.anchorPostfixText;
  if ($(replaceElId).get(0).tagName === 'INPUT') {
    $(`#${$element.attr('i18n_replacement_el')}`).prop('value', replacementText || messageSplit.anchorText);
  } else {
    $(`#${$element.attr('i18n_replacement_el')}`).text(replacementText || messageSplit.anchorText);
  }

  // If localizePage is run again, don't let the [i18n] code above
  // clobber our work
  $element.addClass('i18n-replaced');
};

// Processes any replacement children in the passed-in element. Unlike the
// above processReplacementChildren, this function expects the text to already
// be inside the element (as textContent).
const processReplacementChildrenInContent = function ($el) {
  // Replace a dummy <a/> inside of localized text with a real element.
  // Give the real element the same text as the dummy link.
  const $element = $el;
  const message = $element.get(0).textContent;
  if (!message || typeof message !== 'string' || !$element.get(0).firstChild || !$element.get(0).lastChild) {
    return;
  }
  const replaceElId = `#${$element.attr('i18n_replacement_el')}`;
  const replaceEl = $element.find(replaceElId);
  if (replaceEl.length === 0) {
    log('returning, no child element found', replaceElId);
    return;
  }
  const messageSplit = splitMessageWithReplacementText(message);
  $element.get(0).firstChild.nodeValue = messageSplit.anchorPrefixText;
  $element.get(0).lastChild.nodeValue = messageSplit.anchorPostfixText;
  if (replaceEl.get(0).tagName === 'INPUT') {
    replaceEl.prop('value', messageSplit.anchorText);
  } else {
    replaceEl.text(messageSplit.anchorText);
  }
};

// Determine what language the user's browser is set to use
const determineUserLanguage = function () {
  return browser.i18n.getUILanguage();
};

// Set dir and lang attributes to the given el or to document.documentElement by default
const setLangAndDirAttributes = function (el) {
  const element = el instanceof HTMLElement ? el : document.documentElement;
  browser.runtime.sendMessage({
    type: 'app.get',
    what: 'localeInfo',
  }).then((localeInfo) => {
    element.lang = localeInfo.locale;
    // Note: the 'dir' attribute is only set to RTL on 'our' pages with the
    // (AdBlock Menu, Options) to prevent AdBlock for incorrectly setting it on webpages where
    // this file is injected.
    if (
      localeInfo
      && localeInfo.bidiDir === 'rtl'
      && (window.location.protocol.startsWith('moz-extension:')
        || window.location.protocol.startsWith('chrome-extension:'))) {
      let lang = determineUserLanguage();
      // For RTL languages, only update the directionality of the page if
      // an appropriate locale message file is bundled with the extension
      // Note: this code is assuming that we would only have generic message files
      // for any RTL languages (just 'ar'), and not any country
      // specific RTL locale files like 'en-US'
      lang = lang.substring(0, 2);
      fetch(`_locales/${lang}/messages.json`).then(() => {
        element.dir = localeInfo.bidiDir;
      }).catch(() => {
        element.dir = 'ltr';
      });
    } else {
      element.dir = localeInfo.bidiDir;
    }
  });
};

const isLangRTL = function (language) {
  const lang = language || determineUserLanguage();
  return (lang.startsWith('ar') || lang.startsWith('he') || lang.startsWith('fa'));
};

const localizePage = function () {
  // translate a page into the users language
  $('[i18n]:not(.i18n-replaced, [i18n_replacement_el])').each(function i18n() {
    $(this).text(translate($(this).attr('i18n')));
  });

  $('[i18n_value]:not(.i18n-replaced)').each(function i18nValue() {
    $(this).val(translate($(this).attr('i18n_value')));
  });

  $('[i18n_title]:not(.i18n-replaced)').each(function i18nTitle() {
    $(this).attr('title', translate($(this).attr('i18n_title')));
  });

  $('[i18n_placeholder]:not(.i18n-replaced)').each(function i18nPlaceholder() {
    $(this).attr('placeholder', translate($(this).attr('i18n_placeholder')));
  });

  $('[i18n_replacement_el]:not(.i18n-replaced)').each(function i18nReplacementEl() {
    processReplacementChildren($(this));
  });

  $('[i18n-alt]').each(function i18nImgAlt() {
    $(this).attr('alt', translate($(this).attr('i18n-alt')));
  });

  $('[i18n-aria-label]').each(function i18nAriaLabel() {
    $(this).attr('aria-label', translate($(this).attr('i18n-aria-label')));
  });
}; // end of localizePage

// Parse a URL. Based upon http://blog.stevenlevithan.com/archives/parseuri
// parseUri 1.2.2, (c) Steven Levithan <stevenlevithan.com>, MIT License
// Inputs: url: the URL you want to parse
// Outputs: object containing all parts of |url| as attributes
const parseUriRegEx = /^(([^:]+(?::|$))(?:(?:\w+:)?\/\/)?(?:[^:@/]*(?::[^:@/]*)?@)?(([^:/?#]*)(?::(\d*))?))((?:[^?#/]*\/)*[^?#]*)(\?[^#]*)?(#.*)?/;
const parseUri = function (url) {
  const matches = parseUriRegEx.exec(url);

  // The key values are identical to the JS location object values for that key
  const keys = ['href', 'origin', 'protocol', 'host', 'hostname', 'port',
    'pathname', 'search', 'hash'];
  const uri = {};
  for (let i = 0; (matches && i < keys.length); i++) {
    uri[keys[i]] = matches[i] || '';
  }
  return uri;
};

// Parses the search part of a URL into a key: value object.
// e.g., ?hello=world&ext=adblock would become {hello:"world", ext:"adblock"}
// Inputs: search: the search query of a URL. Must have &-separated values.
parseUri.parseSearch = function parseSearch(searchQuery) {
  const params = {};
  let search = searchQuery;
  let pair;

  // Fails if a key exists twice (e.g., ?a=foo&a=bar would return {a:"bar"}
  search = search.substring(search.indexOf('?') + 1).split('&');

  for (let i = 0; i < search.length; i++) {
    pair = search[i].split('=');
    if (pair[0] && !pair[1]) {
      pair[1] = '';
    }
    const pairKey = decodeURIComponent(pair[0]);
    const pairValue = decodeURIComponent(pair[1]);
    if (pairKey && pairValue !== 'undefined') {
      params[pairKey] = pairValue;
    }
  }
  return params;
};

// Strip third+ level domain names from the domain and return the result.
// Inputs: domain: the domain that should be parsed
// keepDot: true if trailing dots should be preserved in the domain
// Returns: the parsed domain
parseUri.secondLevelDomainOnly = function stripThirdPlusLevelDomain(domain, keepDot) {
  if (domain) {
    const match = domain.match(/([^.]+\.(?:co\.)?[^.]+)\.?$/) || [domain, domain];
    return match[keepDot ? 0 : 1].toLowerCase();
  }

  return domain;
};

// Inputs: key:string.
// Returns value if key exists, else undefined.
const sessionStorageGet = function (key) {
  const json = sessionStorage.getItem(key);
  if (json == null) {
    return undefined;
  }
  try {
    return JSON.parse(json);
  } catch (e) {
    log(`Couldn't parse json for ${key}`);
    return undefined;
  }
};

// Inputs: key:string.
// Returns value if key exists, else undefined.
const sessionStorageSet = function (key, value) {
  if (value === undefined) {
    sessionStorage.removeItem(key);
    return;
  }
  try {
    sessionStorage.setItem(key, JSON.stringify(value));
  } catch (ex) {
    if (ex.name === 'QUOTA_EXCEEDED_ERR') {
      // eslint-disable-next-line no-alert
      alert(translate('storage_quota_exceeded'));
      openTab('options/index.html#ui-tabs-2');
    }
  }
};

// Inputs: key:string.
// Returns object from localStorage.
// The following two functions should only be used when
// multiple 'sets' & 'gets' may occur in immediately preceding each other
// browser.storage.local.get & set instead
const storageGet = function (key) {
  const store = localStorage;
  const json = store.getItem(key);
  if (json == null) {
    return undefined;
  }
  try {
    return JSON.parse(json);
  } catch (e) {
    log(`Couldn't parse json for ${key}`, e);
    return undefined;
  }
};

// Inputs: key:string, value:object.
// If value === undefined, removes key from storage.
// Returns undefined.
const storageSet = function (key, value) {
  const store = localStorage;
  if (value === undefined) {
    store.removeItem(key);
    return;
  }
  try {
    store.setItem(key, JSON.stringify(value));
  } catch (ex) {
    // eslint-disable-next-line no-console
    console.log(ex);
  }
};

const chromeStorageSetHelper = function (key, value, callback) {
  const items = {};
  items[key] = value;
  browser.storage.local.set(items).then(() => {
    if (typeof callback === 'function') {
      callback();
    }
  }).catch((error) => {
    if (typeof callback === 'function') {
      callback(error);
    }
  });
};

const chromeStorageGetHelper = function (storageKey) {
  return new Promise(((resolve, reject) => {
    browser.storage.local.get(storageKey).then((items) => {
      resolve(items[storageKey]);
    }).catch((error) => {
      // eslint-disable-next-line no-console
      console.error(error);
      reject(error);
    });
  }));
};

const chromeLocalStorageOnChangedHelper = function (storageKey, callback) {
  browser.storage.onChanged.addListener((changes, namespace) => {
    if (namespace !== 'local') {
      return;
    }
    for (const key in changes) {
      if (key !== storageKey) {
        return;
      }
      callback();
    }
  });
};

const reloadOptionsPageTabs = function () {
  const optionTabQuery = {
    url: `chrome-extension://${browser.runtime.id}/options.html*`,
  };
  browser.tabs.query(optionTabQuery).then((tabs) => {
    for (const i in tabs) {
      browser.tabs.reload(tabs[i].id);
    }
  });
};

const reloadAllOpenedTabs = function () {
  const optionTabQuery = {
    url: `chrome-extension://${browser.runtime.id}/*`,
  };
  browser.tabs.query(optionTabQuery).then((tabs) => {
    for (const i in tabs) {
      browser.tabs.reload(tabs[i].id);
    }
  });
};

// selected attaches a click and keydown event handler to the matching selector and calls
// the handler if a click or keydown event occurs (with a CR or space is pressed). We support
// both mouse and keyboard events to increase accessibility of the popup menu.
// Returns a reference to the keydown handler for future removal.
const selected = function (selector, handler) {
  const $matched = $(selector);
  $matched.on('click', handler);
  function keydownHandler(event) {
    if (event.which === 13 || event.which === 32) {
      handler(event);
    }
  }
  $matched.on('keydown', keydownHandler);
  return keydownHandler;
};

// selectedOff removes a click and keydown event handler from the matching selector.
const selectedOff = function (selector, clickHandler, keydownHandler) {
  const $matched = $(selector);
  $matched.off('click', clickHandler);
  $matched.off('keydown', keydownHandler);
};

// selectedOnce adds event listeners to the given element for mouse click or keydown CR or space
// events which runs the handler and immediately removes the event handlers so it cannot fire again.
const selectedOnce = function (element, handler) {
  if (!element) {
    return;
  }
  const clickHandler = function () {
    element.removeEventListener('click', clickHandler);
    handler();
  };
  element.addEventListener('click', clickHandler);

  const keydownHandler = function (event) {
    if (event.keyCode === 13 || event.keyCode === 32) {
      element.removeEventListener('keydown', keydownHandler);
      handler();
    }
  };
  element.addEventListener('keydown', keydownHandler);
};

// Join 2 or more sentences once translated.
// Inputs: arg:str -- Each arg is the string of a full sentence in message.json
const i18nJoin = function (...args) {
  let joined = '';
  for (let i = 0; i < args.length; i++) {
    const isLastSentence = i + 1 === args.length;
    if (!isLastSentence) {
      joined += `${translate(args[i])} `;
    } else {
      joined += `${translate(args[i])}`;
    }
  }
  return joined;
};

const isEmptyObject = obj => !!(Object.keys(obj).length === 0 && obj.constructor === Object);

// Sets expirable object in storage to be used in place of a cookie
// Inputs:
//   name: string,
//   value: object,
//   millisecondsUntilExpire: number of milliseconds until the "cookie" expires
const setStorageCookie = function (name, value, millisecondsUntilExpire) {
  const expirationTime = Date.now() + (millisecondsUntilExpire || 0);
  storageSet(name, { value, expires: expirationTime });
};

// Returns value of storage "cookie" or undefined if the it doesn't exist or
// has expired
// Inputs:
//  name: string
const getStorageCookie = function (name) {
  const storedCookie = storageGet(name);
  if (storedCookie && (storedCookie.expires > Date.now())) {
    return storedCookie.value;
  }

  return undefined;
};

// the Navigator object is used here because this code is
// executed in functions.js, which is loaded prior to any other
// background page JS modules (like 'info').
// Althought 'webp' is a preferred for Custom Image Swap
// because it is generally a smaller, more efficient image format,
// Firefox doesn't like working with 'webp' as much as 'png' in Blobs and Data URLs.
let customImageSwapMimeType = 'image/webp';
const firefoxMatch = navigator.userAgent.match(/(?:Firefox)\/([\d.]+)/);
if (firefoxMatch) {
  customImageSwapMimeType = 'image/png';
}

// converts a Base64 encoded string to
// a Blob.
// Used in the custom image swap processing
// Input:
//   base64Data: a string, base64 string encoded representing an image
// Returns:
//   a Blob
const base64toBlob = function (base64Data) {
  let updatedBase64Data = base64Data;
  if (updatedBase64Data.startsWith('data:image/')) {
    [, updatedBase64Data] = updatedBase64Data.split(',');
  }
  const sliceSize = 512;
  const byteChars = atob(updatedBase64Data);
  const byteArrays = [];
  const len = byteChars.length;
  for (let offset = 0; offset < len; offset += sliceSize) {
    const chunk = byteChars.slice(offset, offset + sliceSize);
    const chunkLength = chunk.length;
    const byteNumbers = new Array(chunkLength);
    for (let i = 0; i < chunkLength; i++) {
      byteNumbers[i] = chunk.charCodeAt(i);
    }
    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }
  return new Blob(byteArrays, { type: customImageSwapMimeType });
};

function debounced(delay, fn) {
  let timerId;
  return function debouncedAgain(...args) {
    if (timerId) {
      clearTimeout(timerId);
    }
    timerId = setTimeout(() => {
      fn(...args);
      timerId = null;
    }, delay);
  };
}

// Return a copy of value that has been truncated with an ellipsis in
// the middle if it is too long.
// Inputs: valueToTruncate:string - value to truncate
//         maxSize?:int - max size above which to truncate, defaults to 50
const ellipsis = function ellipsis(valueToTruncate, maxSize) {
  let value = valueToTruncate;
  let size = maxSize;

  if (!value) {
    return value;
  }

  if (!size) {
    size = 50;
  }

  const half = size / 2 - 2; // With ellipsis, the total length will be ~= size
  if (value.length > size) {
    value = (`${value.substring(0, half)}...${value.substring(value.length - half)}`);
  }

  return value;
};

Object.assign(window, {
  sessionStorageSet,
  sessionStorageGet,
  storageGet,
  storageSet,
  parseUri,
  determineUserLanguage,
  chromeStorageSetHelper,
  logging,
  translate,
  chromeStorageGetHelper,
  reloadOptionsPageTabs,
  reloadAllOpenedTabs,
  chromeLocalStorageOnChangedHelper,
  selected,
  selectedOnce,
  i18nJoin,
  isEmptyObject,
  setStorageCookie,
  getStorageCookie,
  THIRTY_MINUTES_IN_MILLISECONDS,
  debounced,
  ellipsis,
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, exports, require, log, getSettings
 */
const OnPageIconManager = (function initialize() {
  const MAX_MSG_TEXT_LENGTH = 280;

  const isIconDataValid = function (iconData) {
    if (!iconData) {
      return false;
    }
    if (!iconData.msgText || !iconData.titleText) {
      return false;
    }
    if (!iconData.buttonText && iconData.buttonURL) {
      return false;
    }
    if (iconData.buttonText && !iconData.buttonURL) {
      return false;
    }
    if (iconData.buttonText && typeof iconData.buttonText !== 'string') {
      return false;
    }
    if (iconData.msgText && typeof iconData.msgText !== 'string') {
      return false;
    }
    if (iconData.titleText && typeof iconData.titleText !== 'string') {
      return false;
    }
    if (iconData.buttonURL && typeof iconData.buttonURL !== 'string') {
      return false;
    }
    if (iconData.buttonURL && !iconData.buttonURL.startsWith('/')) {
      return false;
    }
    return true;
  };


  return {
    // shows / display the AdBlock annimated icon on the specified tab
    // Inputs: tabId : integer - the id of the tab
    //         tabUrl : string - the top level URL of the tab, used for confirmation purposes
    //         iconData : object - with the following:
    //             msgText : string - The text of the message (will truncate after 280 characters)
    //             titleText : string - The title text in the speech bubble
    //             buttonText : string (optional) - The text in the button
    //             buttonURL : string (optional) - only the path part of the URL,
    //                         required to start with a '/' character
    //                         the '/' indicates that a new tab should be opened on gab.com
    //                         (the extension will add the 'gab.com' prefix for security reasons)
    showOnPageIcon(tabId, tabUrl, iconData) {
      if (!getSettings().onpageMessages) {
        return;
      }
      if (!isIconDataValid(iconData)) {
        log('OnPageIconManager:showOnPageIcon::isIconDataValid: false');
        return;
      }
      let { msgText } = iconData;
      if (msgText && msgText.length > MAX_MSG_TEXT_LENGTH) {
        msgText = msgText.slice(0, MAX_MSG_TEXT_LENGTH);
      }
      browser.tabs.insertCSS(tabId, {
        file: 'adblock-onpage-icon-user.css',
        allFrames: false,
        runAt: 'document_start',
      }).then(() => {
        browser.tabs.executeScript(tabId, {
          file: 'purify.min.js',
          allFrames: false,
        }).then(() => {
          const data = {
            command: 'showonpageicon',
            tabURL: tabUrl,
            titleText: iconData.titleText,
            msgText,
            surveyId: iconData.surveyId,
            buttonText: iconData.buttonText,
            buttonURL: iconData.buttonURL,
          };
          browser.tabs.sendMessage(tabId, data).catch((error) => {
            log('error', error);
          });
        }).catch((error) => {
          log('Injection of DOM Purify failed');
          log(error);
        });
      }).catch((error) => {
        log('Injection of adblock-onpage-icon-user.css failed');
        log(error);
      });
    }, // end of showOnPageIcon
  };
}());

exports.OnPageIconManager = OnPageIconManager;


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, log, chromeStorageSetHelper, logging */

const { EventEmitter } = __webpack_require__(12);
const minjQuery = __webpack_require__(29);

const settingsNotifier = new EventEmitter();
const abpPrefPropertyNames = ['show_statsinicon', 'shouldShowBlockElementMenu', 'show_statsinpopup', 'show_devtools_panel'];
const validThemes = ['default_theme', 'dark_theme', 'watermelon_theme', 'solarized_theme', 'solarized_light_theme', 'rebecca_purple_theme', 'ocean_theme', 'sunshine_theme'];

window.jQuery = minjQuery;
window.$ = minjQuery;

// OPTIONAL SETTINGS
function Settings() {
  this.settingsKey = 'settings';
  this.defaults = {
    debug_logging: false,
    youtube_channel_whitelist: true,
    youtube_manage_subscribed: true,
    show_advanced_options: false,
    show_block_counts_help_link: true,
    show_survey: true,
    local_cdn: false,
    picreplacement: false,
    twitch_hiding: false,
    onpageMessages: true,
    color_themes: {
      popup_menu: 'default_theme',
      options_page: 'default_theme',
    },
  };
  const that = this;
  this.init = new Promise(((resolve) => {
    browser.storage.local.get(that.settingsKey).then((response) => {
      const settings = response.settings || {};
      that.data = $.extend(that.defaults, settings);
      if (settings.debug_logging) {
        logging(true);
      }
      if ('managed' in browser.storage) {
        browser.storage.managed.get(null).then((items) => {
          for (const key in items) {
            if (key === 'suppress_update_page' || key === 'suppress_surveys' || key === 'suppress_first_run_page') {
              that.data[key] = items[key];
            }
          }
          resolve();
        },
        // Opera and FF doesn't support browser.storage.managed, but instead of simply
        // removing the API, it gives an asynchronous error which we ignore here.
        () => {
          resolve();
        });
      } else {
        resolve();
      }
    });
  })).then(() => {
    log('\n===SETTINGS FINISHED LOADING===\n\n');
  });
}

Settings.prototype = {
  set(name, isEnabled, callback) {
    const originalValue = this.data[name];
    // Firefox passes weak references to objects, so in case isEnabled is an object,
    // we need to store a local copy of the object
    const localIsEnabled = JSON.parse(JSON.stringify(isEnabled));
    this.data[name] = localIsEnabled;
    const that = this;

    // Don't store defaults that the user hasn't modified
    browser.storage.local.get(this.settingsKey).then((response) => {
      const storedData = response.settings || {};

      storedData[name] = localIsEnabled;
      chromeStorageSetHelper(that.settingsKey, storedData);
      if (originalValue !== localIsEnabled) {
        settingsNotifier.emit('settings.changed', name, localIsEnabled, originalValue);
      }
      if (callback !== undefined && typeof callback === 'function') {
        callback();
      }
    });
  },

  getAll() {
    return this.data;
  },

  onload() {
    return this.init;
  },

};

const settings = new Settings();
settings.onload();

const getSettings = function () {
  return settings.getAll();
};

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'getSettings') {
    return;
  } // not for us
  sendResponse(getSettings());
});

const setSetting = function (name, isEnabled, callback) {
  settings.set(name, isEnabled, callback);

  if (name === 'debug_logging') {
    logging(isEnabled);
  }
};

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'setSetting' || !message.name || (typeof message.isEnabled === 'undefined')) {
    return;
  }
  setSetting(message.name, message.isEnabled);
  sendResponse({});
});

const disableSetting = function (name) {
  settings.set(name, false);
};

const isValidTheme = themeName => validThemes.includes(themeName);

// Attach methods to window
Object.assign(window, {
  disableSetting,
  getSettings,
  setSetting,
  settings,
  settingsNotifier,
  isValidTheme,
  abpPrefPropertyNames,
});


/***/ }),
/* 70 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var filterClasses__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
/* harmony import */ var filterClasses__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(filterClasses__WEBPACK_IMPORTED_MODULE_0__);
/*
 * Similar to some previous functionality in ABP - adblockpluschrome/adblockpluscore/lib/messageResponder.js
 * except:
 * - only included the FilterError class and the parseFilter function
 * - added 'parseFilter' message listener
 * - 'parseFilter' returns an object instead of an array
 * - 'parseFilter' sets filter to the text in the case of an invalid header
 * - linted according to our style rules

/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */





class FilterError {
  constructor(type, reason = null) {
    this.lineno = null;
    this.reason = reason;
    this.selector = null;
    this.type = type;
  }

  toJSON() {
    return {
      lineno: this.lineno,
      reason: this.reason,
      selector: this.selector,
      type: this.type
    };
  }
}

function parseFilter(text) {
  let filter = null;
  let error = null;

  text = Filter.normalize(text);
  if (text) {
    if (text[0] == "[") {
      filter = text;
      error = new FilterError("unexpected_filter_list_header");
    } else {
      filter = Filter.fromText(text);
      if (filter instanceof filterClasses__WEBPACK_IMPORTED_MODULE_0__["InvalidFilter"]) error = new FilterError("invalid_filter", filter.reason);
    }
  }

  return { filter, error };
}

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== "parseFilter" || !message.filterTextToParse) {
    return;
  }
  sendResponse(parseFilter(message.filterTextToParse));
});

Object.assign(window, {
  parseFilter
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, chromeStorageSetHelper, log, License, translate,
   gabQuestion, ext, getSettings, parseUri, sessionStorageGet, setSetting,
  blockCounts, sessionStorageSet, updateButtonUIAndContextMenus, settings,
  storageGet, parseFilter, channels, twitchChannelNamePages, ytChannelNamePages */

const { Filter } = __webpack_require__(0);
const { WhitelistFilter } = __webpack_require__(0);
const { Subscription } = __webpack_require__(2);
const { DownloadableSubscription } = __webpack_require__(2);
const { SpecialSubscription } = __webpack_require__(2);
const { filterStorage } = __webpack_require__(3);
const { filterNotifier } = __webpack_require__(4);
const { Prefs } = __webpack_require__(5);
const { synchronizer } = __webpack_require__(18);
const { getBlockedPerPage } = __webpack_require__(16);
const { RegExpFilter, InvalidFilter, URLFilter } = __webpack_require__(0);
const info = __webpack_require__(17);
const { checkAllowlisted } = __webpack_require__(8);
const { URLRequest } = __webpack_require__(9);
const { getNewBadgeTextReason } = __webpack_require__(21);

// Object's used on the option, pop up, etc. pages...
const { STATS } = __webpack_require__(33);

const { CtaABManager } = __webpack_require__(41);

const { SURVEY } = __webpack_require__(30);
const { SyncService } = __webpack_require__(42);
const { DataCollectionV2 } = __webpack_require__(72);
const { LocalDataCollection } = __webpack_require__(74);
const { ServerMessages } = __webpack_require__(19);
const { recommendations } = __webpack_require__(35);
const { setUninstallURL } = __webpack_require__(43);
const { ExcludeFilter } = __webpack_require__(44);
const {
  recordGeneralMessage,
  recordErrorMessage,
  recordAdreportMessage,
  recordAnonymousErrorMessage,
  recordAnonymousMessage,
} = __webpack_require__(19).ServerMessages;
const {
  getUrlFromId,
  unsubscribe,
  getSubscriptionsMinusText,
  getAllSubscriptionsMinusText,
  getSubscriptionsChecksum,
  getDCSubscriptionsMinusText,
  getIdFromURL,
  getSubscriptionInfoFromURL,
  isLanguageSpecific,
} = __webpack_require__(75).SubscriptionAdapter;

Object.assign(window, {
  filterStorage,
  filterNotifier,
  Prefs,
  synchronizer,
  Subscription,
  SpecialSubscription,
  DownloadableSubscription,
  Filter,
  WhitelistFilter,
  checkAllowlisted,
  info,
  getBlockedPerPage,
  STATS,
  SURVEY,
  SyncService,
  DataCollectionV2,
  LocalDataCollection,
  ServerMessages,
  recordGeneralMessage,
  recordErrorMessage,
  recordAdreportMessage,
  recordAnonymousMessage,
  recordAnonymousErrorMessage,
  getUrlFromId,
  unsubscribe,
  recommendations,
  getSubscriptionsMinusText,
  getAllSubscriptionsMinusText,
  getDCSubscriptionsMinusText,
  getIdFromURL,
  getSubscriptionInfoFromURL,
  getSubscriptionsChecksum,
  ExcludeFilter,
  URLFilter,
  CtaABManager,
  getNewBadgeTextReason,
});

// CUSTOM FILTERS

const isSelectorFilter = function (text) {
  // This returns true for both hiding rules as hiding whitelist rules
  // This means that you'll first have to check if something is an excluded rule
  // before checking this, if the difference matters.
  return /#@?#./.test(text);
};

// custom filter countCache singleton.
const countCache = (function countCache() {
  let cache;

  // Update custom filter count stored in localStorage
  const updateCustomFilterCount = function () {
    chromeStorageSetHelper('custom_filter_count', cache);
  };

  return {
    // Update custom filter count cache and value stored in localStorage.
    // Inputs: new_count_map:count map - count map to replace existing count
    // cache
    updateCustomFilterCountMap(newCountMap) {
      cache = newCountMap || cache;
      updateCustomFilterCount();
    },

    // Remove custom filter count for host
    // Inputs: host:string - url of the host
    removeCustomFilterCount(host) {
      if (host && cache[host]) {
        delete cache[host];
        updateCustomFilterCount();
      }
    },

    // Get current custom filter count for a particular domain
    // Inputs: host:string - url of the host
    getCustomFilterCount(host) {
      let customCount = 0;
      if (cache) {
        customCount = cache[host];
      }
      return customCount || 0;
    },

    // Add 1 to custom filter count for the filters domain.
    // Inputs: filter:string - line of text to be added to custom filters.
    addCustomFilterCount(filter) {
      const host = filter.split('##')[0];
      cache[host] = this.getCustomFilterCount(host) + 1;
      updateCustomFilterCount();
    },

    init() {
      browser.storage.local.get('custom_filter_count').then((response) => {
        cache = response.custom_filter_count || {};
      });
    },
  };
}());

countCache.init();

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'getCustomFilterCount' || !message.host) {
    return;
  }
  sendResponse({ response: countCache.getCustomFilterCount(message.host) });
});

// Add a new custom filter entry.
// Inputs: filter:string line of text to add to custom filters.
// Returns: null if succesfull, otherwise an exception
const addCustomFilter = function (filterText) {
  try {
    const filter = Filter.fromText(filterText);
    if (filter instanceof InvalidFilter) {
      return { error: filter.reason };
    }
    filterStorage.addFilter(filter);
    if (isSelectorFilter(filterText)) {
      countCache.addCustomFilterCount(filterText);
    }

    return null;
  } catch (ex) {
    // convert to a string so that Safari can pass
    // it back to content scripts
    return ex.toString();
  }
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'addCustomFilter' || !message.filterTextToAdd) {
    return;
  }
  sendResponse({ response: addCustomFilter(message.filterTextToAdd) });
});

// Creates a custom filter entry that whitelists a given page
// Inputs: pageUrl:string url of the page
// Returns: null if successful, otherwise an exception
const createPageWhitelistFilter = function (pageUrl) {
  const theURL = new URL(pageUrl);
  const host = theURL.hostname.replace(/^www\./, '');
  const filter = `@@||${host}${theURL.pathname}${theURL.search}^$document`;
  return addCustomFilter(filter);
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'createPageWhitelistFilter' || !message.url) {
    return;
  }
  sendResponse({ response: createPageWhitelistFilter(message.url) });
});

// Creates a custom filter entry that allowlists a given domain
// Inputs: pageUrl:string url of the page
// Returns: null if successful, otherwise an exception
const createDomainAllowlistFilter = function (pageUrl) {
  const theURL = new URL(pageUrl);
  const host = theURL.hostname.replace(/^www\./, '');
  const filter = `@@||${host}/*^$document`;
  return addCustomFilter(filter);
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'createDomainAllowlistFilter' || !message.url) {
    return;
  }
  sendResponse({ response: createDomainAllowlistFilter(message.url) });
});

// UNWHITELISTING

function getUserFilters() {
  const filters = [];

  for (const subscription of filterStorage.subscriptions()) {
    if ((subscription instanceof SpecialSubscription)) {
      for (let j = 0; j < subscription._filterText.length; j++) {
        const filter = subscription._filterText[j];
        filters.push(filter);
      }
    }
  }
  return filters;
}

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command === 'getUserFilters') {
    sendResponse({ response: getUserFilters() });
  }
});

const isWhitelistFilter = function (text) {
  return /^@@/.test(text);
};

// Look for a custom filter that would whitelist the 'url' parameter
// and if any exist, remove the first one.
// Inputs: url:string - a URL that may be whitelisted by a custom filter
// Returns: true if a filter was found and removed; false otherwise.
const tryToUnwhitelist = function (pageUrl) {
  const url = pageUrl.replace(/#.*$/, ''); // Whitelist ignores anchors
  const customFilters = getUserFilters();
  if (!customFilters || !customFilters.length === 0) {
    return false;
  }

  for (let i = 0; i < customFilters.length; i++) {
    const text = customFilters[i];
    const whitelist = text.search(/@@\*\$document,domain=~/);

    // Blacklist site, which is whitelisted by global @@*&document,domain=~
    // filter
    if (whitelist > -1) {
      // Remove protocols
      const [finalUrl] = url.replace(/((http|https):\/\/)?(www.)?/, '').split(/[/?#]/);
      const oldFilter = Filter.fromText(text);
      filterStorage.removeFilter(oldFilter);
      const newFilter = Filter.fromText(`${text}|~${finalUrl}`);
      filterStorage.addFilter(newFilter);
      return true;
    }

    if (isWhitelistFilter(text)) {
      try {
        const filter = Filter.fromText(text);
        if (filter.matches(URLRequest.from(url), URLFilter.typeMap.DOCUMENT, false)) {
          filterStorage.removeFilter(filter);
          return true;
        }
      } catch (ex) {
        // do nothing;
      }
    }
  }
  return false;
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'tryToUnwhitelist' || !message.url) {
    return;
  }
  sendResponse({ unwhitelisted: tryToUnwhitelist(message.url) });
});

// Removes a custom filter entry.
// Inputs: host:domain of the custom filters to be reset.
const removeCustomFilter = function (host) {
  const customFilters = getUserFilters();
  if (!customFilters || !customFilters.length === 0) {
    return;
  }

  const identifier = host;

  for (let i = 0; i < customFilters.length; i++) {
    const entry = customFilters[i];

    // If the identifier is at the start of the entry
    // then delete it.
    if (entry.indexOf(identifier) === 0) {
      const filter = Filter.fromText(entry);
      filterStorage.removeFilter(filter);
    }
  }
};

// Entry point for customize.js, used to update custom filter count cache.
const updateCustomFilterCountMap = function (newCountMap) {
  // Firefox passes weak references to objects, so we need a local copy
  const localCountMap = JSON.parse(JSON.stringify(newCountMap));
  countCache.updateCustomFilterCountMap(localCountMap);
};

const removeCustomFilterForHost = function (host) {
  if (countCache.getCustomFilterCount(host)) {
    removeCustomFilter(host);
    countCache.removeCustomFilterCount(host);
  }
};

// Currently, Firefox doesn't allow the background page to use alert() or confirm(),
// so some JavaScript is injected into the active tab, which does the confirmation for us.
// If the user confirms the removal of the entries, then they are removed, and the page reloaded.
const confirmRemovalOfCustomFiltersOnHost = function (host, activeTabId) {
  const customFilterCount = countCache.getCustomFilterCount(host);
  const confirmationText = translate('confirm_undo_custom_filters', [customFilterCount, host]);
  const messageListenerFN = function (request) {
    browser.runtime.onMessage.removeListener(messageListenerFN);
    if (request === `remove_custom_filters_on_host${host}:true`) {
      removeCustomFilterForHost(host);
      browser.tabs.reload(activeTabId);
    }
  };

  browser.runtime.onMessage.addListener(messageListenerFN);
  /* eslint-disable prefer-template */
  const codeToExecute = 'var host = "' + host + '"; var confirmResponse = confirm("' + confirmationText + '"); browser.runtime.sendMessage("remove_custom_filters_on_host" + host + ":" + confirmResponse); ';
  const details = { allFrames: false, code: codeToExecute };
  browser.tabs.executeScript(activeTabId, details);
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'confirmRemovalOfCustomFiltersOnHost' || !message.host || !message.activeTabId) {
    return;
  }
  confirmRemovalOfCustomFiltersOnHost(message.host, message.activeTabId);
  sendResponse({});
});

// Reload already opened tab
// Input:
// id: integer - id of the tab which should be reloaded
const reloadTab = function (id, callback) {
  let tabId = id;
  const localCallback = callback;
  const listener = function (updatedTabId, changeInfo, tab) {
    if (changeInfo.status === 'complete' && tab.status === 'complete') {
      setTimeout(() => {
        browser.tabs.sendMessage(updatedTabId, { command: 'reloadcomplete' });
        if (typeof localCallback === 'function') {
          localCallback(tab);
        }
        browser.tabs.onUpdated.removeListener(listener);
      }, 2000);
    }
  };

  if (typeof tabId === 'string') {
    tabId = parseInt(tabId, 10);
  }
  browser.tabs.onUpdated.addListener(listener);
  browser.tabs.reload(tabId, { bypassCache: true });
};

const isSelectorExcludeFilter = function (text) {
  return /#@#./.test(text);
};

const getAdblockUserId = function () {
  return STATS.userId();
};

// INFO ABOUT CURRENT PAGE

// Returns true if the url cannot be blocked
const pageIsUnblockable = function (url) {
  if (!url) { // Protect against empty URLs - e.g. Safari empty/bookmarks/top sites page
    return true;
  }
  let scheme = '';
  if (!url.protocol) {
    scheme = parseUri(url).protocol;
  } else {
    scheme = url.protocol;
  }

  return (scheme !== 'http:' && scheme !== 'https:' && scheme !== 'feed:');
};

// Returns true if the page is whitelisted.
// Called from a content script
const pageIsWhitelisted = function (page) {
  const whitelisted = checkAllowlisted(page);
  return (whitelisted !== undefined && whitelisted !== null);
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'pageIsWhitelisted' || !message.page) {
    return;
  }
  sendResponse(pageIsWhitelisted(JSON.parse(message.page)));
});

const pausedKey = 'paused';
// white-list all blocking requests regardless of frame / document, but still allows element hiding
const pausedFilterText1 = '@@';
// white-list all documents, which prevents element hiding
const pausedFilterText2 = '@@*$document';

// Get or set if AdBlock is paused
// Inputs: newValue (optional boolean): if true, AdBlock will be paused, if
// false, AdBlock will not be paused.
// Returns: undefined if newValue was specified, otherwise it returns true
// if paused, false otherwise.
const adblockIsPaused = function (newValue) {
  if (newValue === undefined) {
    return (sessionStorageGet(pausedKey) === true);
  }

  // Add a filter to white list every page.
  const result1 = parseFilter(pausedFilterText1);
  const result2 = parseFilter(pausedFilterText2);
  if (newValue === true) {
    filterStorage.addFilter(result1.filter);
    filterStorage.addFilter(result2.filter);
    chromeStorageSetHelper(pausedKey, true);
  } else {
    filterStorage.removeFilter(result1.filter);
    filterStorage.removeFilter(result2.filter);
    browser.storage.local.remove(pausedKey);
  }
  sessionStorageSet(pausedKey, newValue);
  return undefined;
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'adblockIsPaused') {
    return;
  }
  sendResponse(adblockIsPaused(message.newValue));
});

const domainPausedKey = 'domainPaused';

// Helper that saves the domain pauses
// Inputs:  domainPauses (required object): domain pauses to save
// Returns: undefined
const saveDomainPauses = function (domainPauses) {
  chromeStorageSetHelper(domainPausedKey, domainPauses);
  sessionStorageSet(domainPausedKey, domainPauses);
};

// Helper that removes any domain pause filter rules based on tab events
// Inputs:  tabId (required integer): identifier for the affected tab
//          newDomain (optional string): the current domain of the tab
// Returns: undefined
const domainPauseChangeHelper = function (tabId, newDomain) {
  // get stored domain pauses
  const storedDomainPauses = sessionStorageGet(domainPausedKey);

  // check if any of the stored domain pauses match the affected tab
  for (const aDomain in storedDomainPauses) {
    if (storedDomainPauses[aDomain] === tabId && aDomain !== newDomain) {
      // Remove the filter that white-listed the domain
      const result = parseFilter(`@@${aDomain}$document`);
      filterStorage.removeFilter(result.filter);
      delete storedDomainPauses[aDomain];

      // save updated domain pauses
      saveDomainPauses(storedDomainPauses);
    }
  }
  updateButtonUIAndContextMenus();
};

// Handle the effects of a tab update event on any existing domain pauses
// Inputs:  tabId (required integer): identifier for the affected tab
//          changeInfo (required object with a url property): contains the
// new url for the tab
//          tab (optional Tab object): the affected tab
// Returns: undefined
const domainPauseNavigationHandler = function (tabId, changeInfo) {
  if (changeInfo === undefined || changeInfo.url === undefined || tabId === undefined) {
    return;
  }

  const newDomain = parseUri(changeInfo.url).host;

  domainPauseChangeHelper(tabId, newDomain);
};

// Handle the effects of a tab remove event on any existing domain pauses
// Inputs:  tabId (required integer): identifier for the affected tab
//          changeInfo (optional object): info about the remove event
// Returns: undefined
const domainPauseClosedTabHandler = function (tabId) {
  if (tabId === undefined) {
    return;
  }

  domainPauseChangeHelper(tabId);
};

// Get or set if AdBlock is domain paused for the domain of the specified tab
// Inputs:  activeTab (optional object with url and id properties): the paused tab
//          newValue (optional boolean): if true, AdBlock will be domain paused
// on the tab's domain, if false, AdBlock will not be domain paused on that domain.
// Returns: undefined if activeTab and newValue were specified; otherwise if activeTab
// is specified it returns true if domain paused, false otherwise; finally it returns
// the complete storedDomainPauses if activeTab is not specified

const adblockIsDomainPaused = function (activeTab, newValue) {
  // get stored domain pauses
  let storedDomainPauses = sessionStorageGet(domainPausedKey);

  // return the complete list of stored domain pauses if activeTab is undefined
  if (activeTab === undefined) {
    return storedDomainPauses;
  }

  // return a boolean indicating whether the domain is paused if newValue is undefined
  const activeDomain = parseUri(activeTab.url).host;
  if (newValue === undefined) {
    if (storedDomainPauses) {
      return Object.prototype.hasOwnProperty.call(storedDomainPauses, activeDomain);
    }
    return false;
  }

  // create storedDomainPauses object if needed
  if (!storedDomainPauses) {
    storedDomainPauses = {};
  }

  // set or delete a domain pause
  const result = parseFilter(`@@${activeDomain}$document`);
  if (newValue === true) {
    // add a domain pause
    filterStorage.addFilter(result.filter);
    storedDomainPauses[activeDomain] = activeTab.id;
    browser.tabs.onUpdated.removeListener(domainPauseNavigationHandler);
    browser.tabs.onRemoved.removeListener(domainPauseClosedTabHandler);
    browser.tabs.onUpdated.addListener(domainPauseNavigationHandler);
    browser.tabs.onRemoved.addListener(domainPauseClosedTabHandler);
  } else {
    // remove the domain pause
    filterStorage.removeFilter(result.filter);
    delete storedDomainPauses[activeDomain];
  }

  // save the updated list of domain pauses
  saveDomainPauses(storedDomainPauses);
  return undefined;
};
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'adblockIsDomainPaused') {
    return;
  }
  sendResponse(adblockIsDomainPaused(message.activeTab, message.newValue));
});

// If AdBlock was paused on shutdown (adblock_is_paused is true), then
// unpause / remove the white-list all entry at startup.
browser.storage.local.get(pausedKey).then((response) => {
  if (response[pausedKey]) {
    const pauseHandler = function () {
      filterNotifier.off('load', pauseHandler);
      const result1 = parseFilter(pausedFilterText1);
      const result2 = parseFilter(pausedFilterText2);
      filterStorage.removeFilter(result1.filter);
      filterStorage.removeFilter(result2.filter);
      browser.storage.local.remove(pausedKey);
    };

    filterNotifier.on('load', pauseHandler);
  }
});

// If AdBlock was domain paused on shutdown, then unpause / remove
// all domain pause white-list entries at startup.
browser.storage.local.get(domainPausedKey).then((response) => {
  try {
    const storedDomainPauses = response[domainPausedKey];
    if (!jQuery.isEmptyObject(storedDomainPauses)) {
      const domainPauseHandler = function () {
        filterNotifier.off('load', domainPauseHandler);
        for (const aDomain in storedDomainPauses) {
          const result = parseFilter(`@@${aDomain}$document`);
          filterStorage.removeFilter(result.filter);
        }
        browser.storage.local.remove(domainPausedKey);
      };
      filterNotifier.on('load', domainPauseHandler);
    }
  } catch (err) {
    // do nothing
  }
});

browser.commands.onCommand.addListener((command) => {
  if (command === 'toggle_pause') {
    adblockIsPaused(!adblockIsPaused());
    recordGeneralMessage('pause_shortcut_used');
  }
});

const getTab = function (tabId) {
  return new Promise((resolve) => {
    if (tabId) {
      let id = tabId;
      if (typeof id === 'string') {
        id = parseInt(id, 10);
      }
      browser.tabs.get(id).then((tab) => {
        resolve(tab);
      });
    } else {
      browser.tabs.query({
        active: true,
        lastFocusedWindow: true,
      }).then((tabs) => {
        if (tabs.length === 0) {
          resolve(); // For example: only the background devtools or a popup are opened
        }
        resolve(tabs[0]);
      });
    }
  });
};


// Get interesting information about the current tab.
// Inputs:
// secondTime: bool - whether this is a recursive call
// info object passed to resolve: {
// page: Page object
// tab: Tab object
// whitelisted: bool - whether the current tab's URL is whitelisted.
// disabled_site: bool - true if the url is e.g. about:blank or the
// Extension Gallery, where extensions don't run.
// settings: Settings object
// paused: bool - whether AdBlock is paused
// domainPaused: bool - whether the current tab's URL is paused
// blockCountPage: int - number of ads blocked on the current page
// blockCountTotal: int - total number of ads blocked since install
// showStatsInPopup: bool - whether to show stats in popup menu
// customFilterCount: int - number of custom rules for the current tab's URL
// showMABEnrollment: bool - whether to show MAB enrollment
// popupMenuThemeCTA: string - name of current popup menu CTA theme
// lastGetStatusCode: int - status code for last GET request
// lastGetErrorResponse: error object - error response for last GET request
// lastPostStatusCode: int - status code for last POST request
// allowlistRuleText: string - allowlist rule text for use on YouTube and Twitch
// }
// Returns: Promise
const getCurrentTabInfo = function (secondTime, tabId) {
  return new Promise((resolve) => {
    getTab(tabId).then((tab) => {
      if (tab && !tab.url) {
        // Issue 6877: tab URL is not set directly after you opened a window
        // using window.open()
        if (!secondTime) {
          window.setTimeout(() => {
            getCurrentTabInfo(true);
          }, 250);
        }
        return resolve();
      }
      try {
        const page = new ext.Page(tab);
        const disabledSite = pageIsUnblockable(page.url.href);
        const customFilterCheckUrl = info.disabledSite ? undefined : page.url.hostname;

        const result = {
          disabledSite,
          url: String(page.url || tab.url),
          id: page.id,
          settings: getSettings(),
          paused: adblockIsPaused(),
          domainPaused: adblockIsDomainPaused({ url: page.url.href, id: page.id }),
          blockCountPage: getBlockedPerPage(tab),
          blockCountTotal: Prefs.blocked_total,
          showStatsInPopup: Prefs.show_statsinpopup,
          customFilterCount: countCache.getCustomFilterCount(customFilterCheckUrl),
          showMABEnrollment: License.shouldShowMyAdBlockEnrollment(),
          popupMenuThemeCTA: License.getCurrentPopupMenuThemeCTA(),
          showVPNCTA: CtaABManager.isEnrolled(),
          showVPNCTAVar: CtaABManager.getVar(),
          showVPNCTAExp: CtaABManager.getExp(),
          showDcCTA: License.shouldShowPremiumDcCTA(),
          lastGetStatusCode: SyncService.getLastGetStatusCode(),
          lastGetErrorResponse: SyncService.getLastGetErrorResponse(),
          lastPostStatusCode: SyncService.getLastPostStatusCode(),
          newBadgeTextReason: getNewBadgeTextReason(),
        };

        if (!disabledSite) {
          result.whitelisted = checkAllowlisted(page);
        }
        if (License && License.isActiveLicense()) {
          result.activeLicense = true;
          result.subscriptions = getSubscriptionsMinusText();
        }
        if (
          getSettings()
          && getSettings().youtube_channel_whitelist
          && parseUri(tab.url).hostname === 'www.youtube.com'
        ) {
          result.youTubeChannelName = ytChannelNamePages.get(page.id);
          // handle the odd occurence of when the  YT Channel Name
          // isn't available in the ytChannelNamePages map
          // obtain the channel name from the URL
          // for instance, when the forward / back button is clicked
          if (!result.youTubeChannelName && /ab_channel/.test(tab.url)) {
            result.youTubeChannelName = parseUri.parseSearch(tab.url).ab_channel;
          }
          if (result.youTubeChannelName) {
            result.allowlistRuleText = `@@||www.youtube.com/*${result.youTubeChannelName}|$document`;
          }
        }
        if (
          twitchChannelNamePages
          && getSettings()
          && getSettings().twitch_channel_allowlist
          && parseUri(tab.url).hostname === 'www.twitch.tv'
        ) {
          result.twitchChannelName = twitchChannelNamePages.get(page.id);
          if (result.twitchChannelName) {
            result.allowlistRuleText = `@@||twitch.tv/*${result.twitchChannelName}^$document`;
          }
        }
        return resolve(result);
      } catch (err) {
        return resolve({ errorStr: err.toString(), stack: err.stack, message: err.message });
      }
    });
  });
};
browser.runtime.onMessage.addListener((message) => {
  if (message.command !== 'getCurrentTabInfo') {
    return undefined;
  }
  return getCurrentTabInfo(false, message.tabId).then(results => results);
});

// BETA CODE
if (browser.runtime.id === 'pljaalgmajnlogcgiohkhdmgpomjcihk') {
  // Display beta page after each update for beta-users only
  browser.runtime.onInstalled.addListener((details) => {
    if (details.reason === 'update' || details.reason === 'install') {
      browser.tabs.create({ url: 'https://getadblock.com/beta' });
    }
  });
}

const updateStorageKey = 'last_known_version';
browser.runtime.onInstalled.addListener((details) => {
  if (details.reason === 'update' || details.reason === 'install') {
    localStorage.setItem(updateStorageKey, browser.runtime.getManifest().version);
  }
});

const openTab = function (url) {
  browser.tabs.create({ url });
};

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'openTab' || !message.urlToOpen) {
    return;
  }
  openTab(message.urlToOpen);
  sendResponse({});
});

// These functions are usually only called by content scripts.

// DEBUG INFO

// Get debug info as a JSON object for bug reporting and ad reporting
const getDebugInfo = function (callback) {
  const response = {};
  response.otherInfo = {};

  // Is this installed build of AdBlock the official one?
  if (browser.runtime.id === 'pljaalgmajnlogcgiohkhdmgpomjcihk') {
    response.otherInfo.buildtype = ' Beta';
  } else if (browser.runtime.id === 'gighmmpiobklfepjocnamgkkbiglidom'
    || browser.runtime.id === 'aobdicepooefnbaeokijohmhjlleamfj'
    || browser.runtime.id === 'ndcileolkflehcjpmjnfbnaibdcgglog'
    || browser.runtime.id === 'jid1-NIfFY2CA8fy1tg@jetpack') {
    response.otherInfo.buildtype = ' Stable';
  } else {
    response.otherInfo.buildtype = ' Unofficial';
  }

  // Get AdBlock version
  response.otherInfo.version = browser.runtime.getManifest().version;

  // Get subscribed filter lists
  const subscriptionInfo = {};
  const subscriptions = getSubscriptionsMinusText();
  for (const id in subscriptions) {
    if (subscriptions[id].subscribed) {
      subscriptionInfo[id] = {};
      subscriptionInfo[id].lastSuccess = new Date(subscriptions[id].lastSuccess * 1000);
      subscriptionInfo[id].lastDownload = new Date(subscriptions[id]._lastDownload * 1000);
      subscriptionInfo[id].downloadCount = subscriptions[id].downloadCount;
      subscriptionInfo[id].downloadStatus = subscriptions[id].downloadStatus;
    }
  }

  response.subscriptions = subscriptionInfo;

  const userFilters = getUserFilters();
  if (userFilters && userFilters.length) {
    response.customFilters = userFilters.join('\n');
  }

  // Get settings
  const adblockSettings = {};
  const settings = getSettings();
  for (const setting in settings) {
    adblockSettings[setting] = JSON.stringify(settings[setting]);
  }

  response.settings = adblockSettings;
  response.prefs = JSON.stringify(Prefs);
  response.otherInfo.browser = STATS.browser;
  response.otherInfo.browserVersion = STATS.browserVersion;
  response.otherInfo.osVersion = STATS.osVersion;
  response.otherInfo.os = STATS.os;
  if (window.blockCounts) {
    response.otherInfo.blockCounts = blockCounts.get();
  }
  if (localStorage && localStorage.length) {
    response.otherInfo.localStorageInfo = {};
    response.otherInfo.localStorageInfo.length = localStorage.length;
    let inx = 1;
    for (const key in localStorage) {
      response.otherInfo.localStorageInfo[`key${inx}`] = key;
      inx += 1;
    }
    // Temporarly add Edge migration logs to debug data
    const edgeMigrationLogs = storageGet('migrateLogMessageKey') || [];
    if (edgeMigrationLogs || edgeMigrationLogs.length) {
      response.otherInfo.edgeMigrationLogs = Object.assign({}, edgeMigrationLogs);
    }
  } else {
    response.otherInfo.localStorageInfo = 'no data';
  }
  response.otherInfo.isAdblockPaused = adblockIsPaused();
  response.otherInfo.licenseState = License.get().status;
  response.otherInfo.licenseVersion = License.get().lv;
  LocalDataCollection.getRawStatsSize((rawStatsSize) => {
    response.otherInfo.rawStatsSize = rawStatsSize;
    // Get total pings
    browser.storage.local.get('total_pings').then((storageResponse) => {
      response.otherInfo.totalPings = storageResponse.totalPings || 0;

      // Now, add exclude filters (if there are any)
      const excludeFiltersKey = 'exclude_filters';
      browser.storage.local.get(excludeFiltersKey).then((secondResponse) => {
        if (secondResponse && secondResponse[excludeFiltersKey]) {
          response.excludedFilters = secondResponse[excludeFiltersKey];
        }
        // Now, add JavaScript exception error (if there is one)
        const errorKey = 'errorkey';
        browser.storage.local.get(errorKey).then((errorResponse) => {
          if (errorResponse && errorResponse[errorKey]) {
            response.otherInfo[errorKey] = errorResponse[errorKey];
          }
          // Now, add the migration messages (if there are any)
          const migrateLogMessageKey = 'migrateLogMessageKey';
          browser.storage.local.get(migrateLogMessageKey).then((migrateLogMessageResponse) => {
            if (migrateLogMessageResponse && migrateLogMessageResponse[migrateLogMessageKey]) {
              const messages = migrateLogMessageResponse[migrateLogMessageKey].split('\n');
              for (let i = 0; i < messages.length; i++) {
                const key = `migration_message_${i}`;
                response.otherInfo[key] = messages[i];
              }
            }
            const getDebugLicenseInfo = function () {
              if (License.isActiveLicense()) {
                response.otherInfo.licenseInfo = {};
                response.otherInfo.licenseInfo.extensionGUID = STATS.userId();
                response.otherInfo.licenseInfo.licenseId = License.get().licenseId;
                if (getSettings().sync_settings) {
                  const syncInfo = {};
                  syncInfo.SyncCommitVersion = SyncService.getCommitVersion();
                  syncInfo.SyncCommitName = SyncService.getCurrentExtensionName();
                  syncInfo.SyncCommitLog = SyncService.getSyncLog();
                  response.otherInfo.syncInfo = syncInfo;
                }
                browser.alarms.getAll((alarms) => {
                  if (alarms && alarms.length > 0) {
                    response.otherInfo['Alarm info'] = `length: ${alarms.length}`;
                    for (let i = 0; i < alarms.length; i++) {
                      const alarm = alarms[i];
                      response.otherInfo[`${i} Alarm Name`] = alarm.name;
                      response.otherInfo[`${i} Alarm Scheduled Time`] = new Date(alarm.scheduledTime);
                    }
                  } else {
                    response.otherInfo['No alarm info'] = 'No alarm info';
                  }
                  License.getLicenseInstallationDate((installdate) => {
                    response.otherInfo['License Installation Date'] = installdate;
                    const customChannelId = channels.getIdByName('CustomChannel');
                    if (channels.getGuide()[customChannelId].enabled) {
                      const customChannel = channels.channelGuide[customChannelId].channel;
                      customChannel.getTotalBytesInUse().then((result) => {
                        response.otherInfo['Custom Channel total bytes in use'] = result;
                        if (typeof callback === 'function') {
                          callback(response);
                        }
                      });
                    } else if (typeof callback === 'function') {
                      callback(response);
                    }
                  });
                });
              } else if (typeof callback === 'function') { // License is not active
                callback(response);
              }
            };
            if (browser.permissions && browser.permissions.getAll) {
              browser.permissions.getAll((allPermissions) => {
                response.otherInfo.hostPermissions = allPermissions;
                getDebugLicenseInfo();
              });
            } else {
              response.otherInfo.hostPermissions = 'no data';
              getDebugLicenseInfo();
            }
          });
        });
      });
    });
  });
};

// Called when user explicitly requests filter list updates
function updateFilterLists() {
  for (const subscription of filterStorage.subscriptions()) {
    if (subscription instanceof DownloadableSubscription) {
      synchronizer.execute(subscription, true, true);
    }
  }
}
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'updateFilterLists') {
    return;
  }
  updateFilterLists();
  sendResponse({});
});

// Checks if the filter lists are currently in the process of
// updating and if there were errors the last time they were
// updated
function checkUpdateProgress() {
  let inProgress = false;
  let filterError = false;
  for (const subscription of filterStorage.subscriptions()) {
    if (synchronizer.isExecuting(subscription.url)) {
      inProgress = true;
    } else if (subscription.downloadStatus && subscription.downloadStatus !== 'synchronize_ok') {
      filterError = true;
    }
  }
  return { inProgress, filterError };
}
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'checkUpdateProgress') {
    return;
  }
  sendResponse(checkUpdateProgress());
});

STATS.untilLoaded(() => {
  STATS.startPinging();
  setUninstallURL();
});

// Create the "blockage stats" for the uninstall logic ...
browser.runtime.onInstalled.addListener((details) => {
  if (details.reason === 'install') {
    browser.storage.local.get('blockage_stats').then((response) => {
      const { blockage_stats } = response;
      if (!blockage_stats) {
        const data = {};
        data.start = Date.now();
        data.version = 1;
        chromeStorageSetHelper('blockage_stats', data);
      }
    });
  }
});

function isAcceptableAds(filterList) {
  if (!filterList) {
    return undefined;
  }
  return filterList.id === 'acceptable_ads';
}

function isAcceptableAdsPrivacy(filterList) {
  if (!filterList) {
    return undefined;
  }
  return filterList.id === 'acceptable_ads_privacy';
}

const rateUsCtaKey = 'rate-us-cta-clicked';
const vpnWaitlistCtaKey = 'vpn-waitlist-cta-clicked';
const mailCtaKey = 'mail-cta-clicked';

// Attach methods to window
Object.assign(window, {
  adblockIsPaused,
  createPageWhitelistFilter,
  getUserFilters,
  updateFilterLists,
  checkUpdateProgress,
  getDebugInfo,
  openTab,
  saveDomainPauses,
  adblockIsDomainPaused,
  pageIsWhitelisted,
  pageIsUnblockable,
  getCurrentTabInfo,
  getAdblockUserId,
  tryToUnwhitelist,
  addCustomFilter,
  removeCustomFilter,
  countCache,
  updateCustomFilterCountMap,
  removeCustomFilterForHost,
  confirmRemovalOfCustomFiltersOnHost,
  reloadTab,
  isSelectorFilter,
  isWhitelistFilter,
  isSelectorExcludeFilter,
  pausedFilterText1,
  pausedFilterText2,
  isLanguageSpecific,
  isAcceptableAds,
  isAcceptableAdsPrivacy,
  rateUsCtaKey,
  mailCtaKey,
  vpnWaitlistCtaKey,
  updateStorageKey,
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, ext, exports, require, chromeStorageSetHelper, getSettings, adblockIsPaused,
   adblockIsDomainPaused, filterStorage, Filter, parseUri, settings, getAllSubscriptionsMinusText,
   getUserFilters, setSetting */

const { extractHostFromFrame } = __webpack_require__(13);
const { ElemHideFilter } = __webpack_require__(0);
const { filterNotifier } = __webpack_require__(4);
const { port } = __webpack_require__(1);
const info = __webpack_require__(17);
const { postFilterStatsToLogServer } = __webpack_require__(19).ServerMessages;
const { idleHandler } = __webpack_require__(73);

const DataCollectionV2 = (function getDataCollectionV2() {
  const HOUR_IN_MS = 1000 * 60 * 60;
  const TIME_LAST_PUSH_KEY = 'timeLastPush';

  // Setup memory cache
  let dataCollectionCache = {};
  dataCollectionCache.filters = {};
  dataCollectionCache.domains = {};

  const handleTabUpdated = function (tabId, changeInfo, tabInfo) {
    if (browser.runtime.lastError) {
      return;
    }
    if (!tabInfo || !tabInfo.url || !tabInfo.url.startsWith('http')) {
      return;
    }
    if (
      getSettings().data_collection_v2
      && !adblockIsPaused()
      && !adblockIsDomainPaused({ url: tabInfo.url, id: tabId })
      && changeInfo.status === 'complete'
    ) {
      browser.tabs.sendMessage(tabId, { command: 'ping_dc_content_script' }).then((pingResponse) => {
        if (pingResponse && pingResponse.status === 'yes') {
          return;
        }
        browser.tabs.executeScript(tabId, {
          file: 'adblock-datacollection-contentscript.js',
          allFrames: true,
        });
      });
    }
  };

  const addFilterToCache = function (filter, page) {
    const validFilterText = filter && filter.text && (typeof filter.text === 'string');
    if (validFilterText && page && page.url) {
      let domain = page.url.hostname;
      if (!domain) {
        domain = new URL(page.url).hostname;
        if (!domain) {
          return;
        }
      }
      const { text } = filter;

      if (!(text in dataCollectionCache.filters)) {
        dataCollectionCache.filters[text] = {};
        dataCollectionCache.filters[text].firstParty = {};
        dataCollectionCache.filters[text].thirdParty = {};
        dataCollectionCache.filters[text].subscriptions = [];
      }
      if (filter.thirdParty) {
        if (!dataCollectionCache.filters[text].thirdParty[domain]) {
          dataCollectionCache.filters[text].thirdParty[domain] = {};
          dataCollectionCache.filters[text].thirdParty[domain].hits = 0;
        }
        dataCollectionCache.filters[text].thirdParty[domain].hits += 1;
      } else {
        if (!dataCollectionCache.filters[text].firstParty[domain]) {
          dataCollectionCache.filters[text].firstParty[domain] = {};
          dataCollectionCache.filters[text].firstParty[domain].hits = 0;
        }
        dataCollectionCache.filters[text].firstParty[domain].hits += 1;
      }
      for (const sub of filterStorage.subscriptions(text)) {
        const dataCollectionSubscriptions = dataCollectionCache.filters[text].subscriptions;
        if (!sub.disabled && sub.url && dataCollectionSubscriptions.indexOf(sub.url) === -1) {
          if (sub.url.length > 256) {
            dataCollectionCache.filters[text].subscriptions.push(sub.substring(0, 256));
          } else {
            dataCollectionCache.filters[text].subscriptions.push(sub.url);
          }
        }
      }
    }
  };

  const addMessageListener = function () {
    port.on('datacollection.elementHide', (message, sender) => {
      const dataCollectionEnabled = getSettings().data_collection_v2;
      const domainInfo = { url: sender.page.url, id: sender.page.id };
      if (dataCollectionEnabled && !adblockIsPaused() && !adblockIsDomainPaused(domainInfo)) {
        const { selectors } = message;
        const docDomain = extractHostFromFrame(sender.frame);
        for (const subscription of filterStorage.subscriptions()) {
          if (!subscription.disabled) {
            for (const text of subscription.filterText()) {
              const filter = Filter.fromText(text);
              // We only know the exact filter in case of element hiding emulation.
              // For regular element hiding filters, the content script only knows
              // the selector, so we have to find a filter that has an identical
              // selector and is active on the domain the match was reported from.
              const isActiveElemHideFilter = filter instanceof ElemHideFilter
                                           && selectors.includes(filter.selector)
                                           && filter.isActiveOnDomain(docDomain);
              if (isActiveElemHideFilter) {
                addFilterToCache(filter, sender.page);
              }
            }
          }
        }
      }
    });
    port.on('datacollection.exceptionElementHide', (message, sender) => {
      const domainInfo = { url: sender.page.url, id: sender.page.id };
      if (
        getSettings().data_collection_v2
          && !adblockIsPaused()
          && !adblockIsDomainPaused(domainInfo)) {
        const selectors = message.exceptions;
        for (const text of selectors) {
          const filter = Filter.fromText(text);
          addFilterToCache(filter, sender.page);
        }
      }
    });
  };

  const webRequestListener = function (details) {
    if (details.url && details.type === 'main_frame' && !adblockIsPaused() && !adblockIsDomainPaused({ url: details.url, id: details.id })) {
      const domain = parseUri(details.url).host;
      if (!dataCollectionCache.domains[domain]) {
        dataCollectionCache.domains[domain] = {};
        dataCollectionCache.domains[domain].pages = 0;
      }
      dataCollectionCache.domains[domain].pages += 1;
    }
  };

  const filterListener = function (item, newValue, oldValue, tabIds) {
    if (getSettings().data_collection_v2 && !adblockIsPaused()) {
      for (const tabId of tabIds) {
        browser.tabs.get(tabId).then((tab) => {
          if (tab && !adblockIsDomainPaused({ url: tab.url.href, id: tab.id })) {
            addFilterToCache(item, tab);
          }
        });
      }
    } else if (!getSettings().data_collection_v2) {
      filterNotifier.off('filter.hitCount', filterListener);
    }
  };

  // If enabled at startup periodic saving of memory cache &
  // sending of data to the log server
  settings.onload().then(() => {
    const dataCollectionEnabled = getSettings().data_collection_v2;
    if (dataCollectionEnabled) {
      window.setInterval(() => {
        idleHandler.scheduleItemOnce(() => {
          if (dataCollectionEnabled && Object.keys(dataCollectionCache.filters).length > 0) {
            const subscribedSubs = [];
            const subs = getAllSubscriptionsMinusText();
            for (const id in subs) {
              if (subs[id].subscribed) {
                if (subs[id].url && subs[id].url.length > 256) {
                  subscribedSubs.push(subs[id].url.substring(0, 256));
                } else {
                  subscribedSubs.push(subs[id].url);
                }
              }
            }
            if (getUserFilters().length) {
              subscribedSubs.push('customlist');
            }
            const data = {
              version: '5',
              addonName: info.addonName,
              addonVersion: info.addonVersion,
              application: info.application,
              applicationVersion: info.applicationVersion,
              platform: info.platform,
              platformVersion: info.platformVersion,
              appLocale: browser.i18n.getUILanguage(),
              filterListSubscriptions: subscribedSubs,
              domains: dataCollectionCache.domains,
              filters: dataCollectionCache.filters,
            };
            browser.storage.local.get(TIME_LAST_PUSH_KEY).then((response) => {
              let timeLastPush = 'n/a';
              if (response[TIME_LAST_PUSH_KEY]) {
                const serverTimestamp = new Date(response[TIME_LAST_PUSH_KEY]);
                // Format the timeLastPush
                const yearStr = `${serverTimestamp.getUTCFullYear()}`;
                let monthStr = `${serverTimestamp.getUTCMonth() + 1}`;
                let dateStr = `${serverTimestamp.getUTCDate()}`;
                let hourStr = `${serverTimestamp.getUTCHours()}`;
                // round the minutes up to the nearest 10
                let minStr = `${Math.floor(serverTimestamp.getUTCMinutes() / 10) * 10}`;

                if (monthStr.length === 1) {
                  monthStr = `0${monthStr}`;
                }
                if (dateStr.length === 1) {
                  dateStr = `0${dateStr}`;
                }
                if (hourStr.length === 1) {
                  hourStr = `0${hourStr}`;
                }
                if (minStr.length === 1) {
                  minStr = `0${minStr}`;
                }
                if (minStr === '60') {
                  minStr = '00';
                }
                timeLastPush = `${yearStr}-${monthStr}-${dateStr} ${hourStr}:${minStr}:00`;
              }
              data.timeOfLastPush = timeLastPush;
              postFilterStatsToLogServer(data, (text, status, xhr) => {
                let nowTimestamp = (new Date()).toGMTString();
                if (xhr && typeof xhr.getResponseHeader === 'function') {
                  try {
                    if (xhr.getResponseHeader('Date')) {
                      nowTimestamp = xhr.getResponseHeader('Date');
                    }
                  } catch (e) {
                    nowTimestamp = (new Date()).toGMTString();
                  }
                }
                chromeStorageSetHelper(TIME_LAST_PUSH_KEY, nowTimestamp);
                // Reset memory cache
                dataCollectionCache = {};
                dataCollectionCache.filters = {};
                dataCollectionCache.domains = {};
              });
            }); // end of TIME_LAST_PUSH_KEY
          }
        });
      }, HOUR_IN_MS);
      filterNotifier.on('filter.hitCount', filterListener);
      browser.webRequest.onBeforeRequest.addListener(webRequestListener, {
        urls: ['http://*/*', 'https://*/*'],
        types: ['main_frame'],
      });
      browser.tabs.onUpdated.addListener(handleTabUpdated);
      addMessageListener();
    }
  });// End of then

  const returnObj = {};
  returnObj.start = function returnObjStart(callback) {
    dataCollectionCache.filters = {};
    dataCollectionCache.domains = {};
    filterNotifier.on('filter.hitCount', filterListener);
    browser.webRequest.onBeforeRequest.addListener(webRequestListener, {
      urls: ['http://*/*', 'https://*/*'],
      types: ['main_frame'],
    });
    browser.tabs.onUpdated.addListener(handleTabUpdated);
    addMessageListener();
    setSetting('data_collection_v2', true, callback);
  };
  returnObj.end = function returnObjEnd(callback) {
    dataCollectionCache = {};
    filterNotifier.off('filter.hitCount', filterListener);
    browser.webRequest.onBeforeRequest.removeListener(webRequestListener);
    browser.storage.local.remove(TIME_LAST_PUSH_KEY);
    browser.tabs.onUpdated.removeListener(handleTabUpdated);
    setSetting('data_collection_v2', false, callback);
  };
  returnObj.getCache = function returnObjGetCache() {
    return dataCollectionCache;
  };

  return returnObj;
}());

exports.DataCollectionV2 = DataCollectionV2;


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, log, exports */

// Schedules a function to be executed once when the computer is idle.
// Call idleHandler.scheduleItem to schedule a function for exection upon idle
// inputs: theFunction: function to be executed
//         seconds: maximum time to wait upon idle, in seconds. 600 if omitted.
const idleHandler = {
  scheduleItemOnce(callback, seconds) {
    // Schedule the item to be executed
    idleHandler.scheduledItems.push({
      callback,
      runAt: new Date(Date.now() + 1000 * (seconds || 600)),
    });
    if (!idleHandler.timer) {
      idleHandler.timer = window.setInterval(idleHandler.runIfIdle, 5000);
    }
  },
  timer: null,
  scheduledItems: [],
  runIfIdle() {
    // Checks if the browser is idle. If so, it executes all waiting functions
    // Otherwise, it checks if an item has waited longer than allowed, and
    // executes the ones who should be executed
    browser.idle.queryState(15, (state) => {
      if (state === 'idle') {
        while (idleHandler.scheduledItems.length) {
          idleHandler.scheduledItems.shift().callback();
        }
      } else {
        const now = Date.now();
        // Inversed loop, to prevent splice() making it skip the item after an
        // executed item.
        for (let i = idleHandler.scheduledItems.length - 1; i >= 0; i--) {
          if (idleHandler.scheduledItems[i].runAt <= now) {
            idleHandler.scheduledItems.splice(i, 1)[0].callback();
          }
        }
      }
      if (!idleHandler.scheduledItems.length) {
        idleHandler.timer = window.clearInterval(idleHandler.timer);
      }
    });
  },
};

exports.idleHandler = idleHandler;


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, ext, exports, chromeStorageSetHelper, getSettings, adblockIsPaused,
   adblockIsDomainPaused, filterStorage, Filter, parseUri, settings, getAllSubscriptionsMinusText,
   getUserFilters, Utils, replacedCounts, setSetting, storageGet, storageSet */

const { extractHostFromFrame } = __webpack_require__(13);
const { ElemHideFilter } = __webpack_require__(0);
const { filterNotifier } = __webpack_require__(4);
const { port } = __webpack_require__(1);
const info = __webpack_require__(17);

const LocalDataCollection = (function getLocalDataCollection() {
  const easyPrivacyURL = 'https://easylist-downloads.adblockplus.org/easyprivacy.txt';
  const FIFTEEN_MINS = 1000 * 60 * 15;
  let intervalFN;
  const EXT_STATS_KEY = 'ext_stats_key';
  const STORED_DATA_CLEAN = 'STORED_DATA_CLEAN';

  // Setup memory cache
  let dataCollectionCache = {};
  dataCollectionCache.domains = {};

  const initializeDomainIfNeeded = function (domain) {
    if (!(domain in dataCollectionCache.domains)) {
      dataCollectionCache.domains[domain] = {};
      dataCollectionCache.domains[domain].ads = 0;
      dataCollectionCache.domains[domain].trackers = 0;
      dataCollectionCache.domains[domain].adsReplaced = 0;
    }
  };

  const handleTabUpdated = function (tabId, changeInfo, tabInfo) {
    if (browser.runtime.lastError) {
      return;
    }
    if (!tabInfo || !tabInfo.url || !tabInfo.url.startsWith('http') || tabInfo.incognito) {
      return;
    }
    if (
      getSettings().local_data_collection
      && !getSettings().data_collection_v2 // the content script will be injected from that module
      && !adblockIsPaused()
      && !adblockIsDomainPaused({ url: tabInfo.url, id: tabId })
      && changeInfo.status === 'complete'
    ) {
      browser.tabs.executeScript(tabId, {
        file: 'adblock-datacollection-contentscript.js',
        allFrames: true,
      });
    }
  };

  const addFilterToCache = function (filter, page) {
    const validFilterText = filter && filter.text && (typeof filter.text === 'string');
    const validFilterType = (filter.type === 'blocking'
                             || filter.type === 'elemhide'
                             || filter.type === 'elemhideemulation'
                             || filter.type === 'snippet');
    if (validFilterType && validFilterText && page && page.url) {
      browser.tabs.get(page.id).then((tab) => {
        if (tab.incognito) {
          return;
        }
        const theURL = new URL(page.url);
        const domain = theURL.hostname;
        initializeDomainIfNeeded(domain);
        const { text } = filter;
        let isAd = true;
        for (const sub of filterStorage.subscriptions(text)) {
          if (!sub.disabled && sub.url && sub.url === easyPrivacyURL) {
            isAd = false;
          }
        }
        if (isAd) {
          dataCollectionCache.domains[domain].ads += 1;
        } else {
          dataCollectionCache.domains[domain].trackers += 1;
        }
      });
    }
  };

  const addMessageListener = function () {
    port.on('datacollection.elementHide', (message, sender) => {
      const dataCollectionEnabled = getSettings().local_data_collection;
      const domainInfo = { url: sender.page.url, id: sender.page.id };
      if (dataCollectionEnabled && !adblockIsPaused() && !adblockIsDomainPaused(domainInfo)) {
        const { selectors } = message;
        const docDomain = extractHostFromFrame(sender.frame);
        for (const subscription of filterStorage.subscriptions()) { // test if we double count hits
          if (!subscription.disabled) {
            for (const text of subscription.filterText()) {
              const filter = Filter.fromText(text);
              // We only know the exact filter in case of element hiding emulation.
              // For regular element hiding filters, the content script only knows
              // the selector, so we have to find a filter that has an identical
              // selector and is active on the domain the match was reported from.
              const isActiveElemHideFilter = filter instanceof ElemHideFilter
                                           && selectors.includes(filter.selector)
                                           && filter.isActiveOnDomain(docDomain);
              if (isActiveElemHideFilter) {
                addFilterToCache(filter, sender.page);
              }
            }
          }
        }
      }
    });
    port.on('datacollection.exceptionElementHide', (message, sender) => {
      const domainInfo = { url: sender.page.url, id: sender.page.id };
      if (
        getSettings().local_data_collection
          && !adblockIsPaused()
          && !adblockIsDomainPaused(domainInfo)) {
        const selectors = message.exceptions;
        for (const text of selectors) {
          const filter = Filter.fromText(text);
          addFilterToCache(filter, sender.page);
        }
      }
    });
  };

  const filterListener = function (item, newValue, oldValue, tabIds) {
    if (getSettings().local_data_collection && !adblockIsPaused()) {
      for (const tabId of tabIds) {
        browser.tabs.get(tabId).then((tab) => {
          if (tab && tab.url && !adblockIsDomainPaused({ url: tab.url.href, id: tab.id })) {
            addFilterToCache(item, tab);
          }
        });
      }
    } else if (!getSettings().local_data_collection) {
      LocalDataCollection.end();
    }
  };

  const adReplacedListener = function (tabId, url) {
    if (getSettings().local_data_collection && !adblockIsPaused()) {
      const domain = new URL(url).hostname;
      initializeDomainIfNeeded(domain);
      dataCollectionCache.domains[domain].adsReplaced += 1;
    } else if (!getSettings().local_data_collection) {
      LocalDataCollection.end();
    }
  };

  // 'clean' the stored data
  // there was a bug that allowed blank domains ("") to be saved in the data
  // the following code removes the blank domain
  // this function only needs to run once
  const cleanStoredData = function () {
    if (storageGet(STORED_DATA_CLEAN)) {
      return;
    }
    browser.storage.local.get(LocalDataCollection.EXT_STATS_KEY).then((hourlyResponse) => {
      const savedData = hourlyResponse[LocalDataCollection.EXT_STATS_KEY] || {};
      const parsedData = {};
      for (const timestamp in savedData) {
        if (!Number.isNaN(timestamp)) {
          for (const domain in savedData[timestamp].doms) {
            if (domain && domain.length > 1) { // check if domain is not blank
              const domData = savedData[timestamp].doms[domain];
              if (!parsedData[timestamp]) {
                parsedData[timestamp] = {};
                parsedData[timestamp].v = '1';
                parsedData[timestamp].doms = {};
              }
              parsedData[timestamp].doms[domain] = {};
              parsedData[timestamp].doms[domain].ads = domData.ads;
              parsedData[timestamp].doms[domain].trackers = domData.trackers;
              parsedData[timestamp].doms[domain].adsReplaced = domData.adsReplaced;
            }
          }
        }
      }
      chromeStorageSetHelper(LocalDataCollection.EXT_STATS_KEY, parsedData);
      storageSet(STORED_DATA_CLEAN, true);
    });
  };

  const clearCache = function () {
    dataCollectionCache = {};
    dataCollectionCache.domains = {};
  };

  const saveCacheData = function (callback) {
    if (getSettings().local_data_collection && !$.isEmptyObject(dataCollectionCache.domains)) {
      const hourSnapShot = JSON.parse(JSON.stringify({
        v: '1',
        doms: dataCollectionCache.domains,
      }));
      browser.storage.local.get(EXT_STATS_KEY).then((hourlyResponse) => {
        const savedData = hourlyResponse[EXT_STATS_KEY] || { };
        savedData[Date.now().toString()] = hourSnapShot;
        chromeStorageSetHelper(EXT_STATS_KEY, savedData, callback);
        clearCache();
      });
    } else {
      if (!getSettings().local_data_collection) {
        clearInterval(intervalFN);
      }
      if (typeof callback === 'function') {
        callback();
      }
    }
  };

  const startProcessInterval = function () {
    intervalFN = window.setInterval(() => {
      saveCacheData();
    }, FIFTEEN_MINS);
  };

  // If enabled at startup periodic saving of memory cache &
  // sending of data to the log server
  settings.onload().then(() => {
    if (getSettings().local_data_collection) {
      startProcessInterval();
      filterNotifier.on('filter.hitCount', filterListener);
      replacedCounts.adReplacedNotifier.on('adReplaced', adReplacedListener);
      browser.tabs.onUpdated.addListener(handleTabUpdated);
      addMessageListener();
      cleanStoredData();
    }
  });// End of then

  const returnObj = {};
  returnObj.EXT_STATS_KEY = EXT_STATS_KEY;
  returnObj.start = function returnObjStart(callback) {
    dataCollectionCache.domains = {};
    filterNotifier.on('filter.hitCount', filterListener);
    replacedCounts.adReplacedNotifier.on('adReplaced', adReplacedListener);
    browser.tabs.onUpdated.addListener(handleTabUpdated);
    addMessageListener();
    startProcessInterval();
    setSetting('local_data_collection', true, callback);
  };
  returnObj.end = function returnObjEnd(callback) {
    clearInterval(intervalFN);
    clearCache();
    storageSet(STORED_DATA_CLEAN);
    filterNotifier.off('filter.hitCount', filterListener);
    replacedCounts.adReplacedNotifier.off('adReplaced', adReplacedListener);
    browser.tabs.onUpdated.removeListener(handleTabUpdated);
    setSetting('local_data_collection', false, callback);
  };
  returnObj.clearCache = clearCache;
  returnObj.getCache = function returnObjGetCache() {
    return dataCollectionCache;
  };
  returnObj.saveCacheData = saveCacheData;
  returnObj.easyPrivacyURL = easyPrivacyURL;
  returnObj.exportRawStats = function returnObjFilterStats(callback) {
    browser.storage.local.get(EXT_STATS_KEY).then((hourlyResponse) => {
      const savedData = hourlyResponse[EXT_STATS_KEY] || { };
      if (typeof callback === 'function') {
        callback(savedData);
      }
    });
  };
  returnObj.getRawStatsSize = function returnObjFilterStatsSize(callback) {
    LocalDataCollection.exportRawStats((rawStats) => {
      callback(JSON.stringify(rawStats).length);
    });
  };
  // Note: the following function is used for testing purposes
  // Import filter list statistics which will be converted to the format needed / used
  // by the 'stats' tab.
  // Inputs: filterStatsArray: array of stringified JSON filter list statistics data
  //         from the DataCollection V2 messages.
  // Returns: a Promise, resolved when complete
  returnObj.importFilterStats = function returnObjFilterStats(filterStatsArray) {
    return new Promise((resolve) => {
      let parsedfilterStats = {};
      try {
        parsedfilterStats = JSON.parse(filterStatsArray);
      } catch (e) {
        // eslint-disable-next-line no-console
        console.log(e);
        resolve(`error : ${e.toString()}`);
        return;
      }
      browser.storage.local.get(EXT_STATS_KEY).then((hourlyResponse) => {
        const savedData = hourlyResponse[EXT_STATS_KEY] || { };
        for (let inx = 0; inx < parsedfilterStats.length; inx++) {
          const dupDataCache = parsedfilterStats[inx];
          // only process new data
          // don't overwrite existing data
          if (!savedData[Date.parse(dupDataCache.timeOfLastPush)]) {
            const hourSnapShot = {};
            const initializeDomainDataObject = function (domain) {
              hourSnapShot[domain] = {};
              hourSnapShot[domain].ads = 0;
              hourSnapShot[domain].trackers = 0;
              hourSnapShot[domain].adsReplaced = 0;
              if (dupDataCache.domains[domain] && typeof dupDataCache.domains[domain].adsReplaced === 'number') {
                hourSnapShot[domain].adsReplaced = dupDataCache.domains[domain].adsReplaced;
              }
            };
            for (const domain in dupDataCache.domains) {
              initializeDomainDataObject(domain);
            }
            const processDomainByFilterType = function (filter, domains, filterRequestType) {
              for (const domain in domains) {
                if (!hourSnapShot[domain]) {
                  initializeDomainDataObject(domain);
                }
                if (dupDataCache.filters[filter].subscriptions
                    && dupDataCache.filters[filter].subscriptions.length
                    && dupDataCache.filters[filter].subscriptions.includes(easyPrivacyURL)) {
                  hourSnapShot[domain].trackers
                    += dupDataCache.filters[filter][filterRequestType][domain].hits;
                } else {
                  hourSnapShot[domain].ads
                    += dupDataCache.filters[filter][filterRequestType][domain].hits;
                }
              }
            };
            for (const filter in dupDataCache.filters) {
              processDomainByFilterType(filter, dupDataCache.filters[filter].firstParty, 'firstParty');
              processDomainByFilterType(filter, dupDataCache.filters[filter].thirdParty, 'thirdParty');
            }
            savedData[Date.parse(dupDataCache.timeOfLastPush)] = JSON.parse(JSON.stringify({
              v: '1',
              doms: hourSnapShot,
            }));
          }
        }// end for loop
        chromeStorageSetHelper(EXT_STATS_KEY, savedData);
        resolve(' success! ');
      });
    });
  };
  return returnObj;
}());

exports.LocalDataCollection = LocalDataCollection;


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global require, exports, recommendations, Subscription
   DownloadableSubscription, browser, synchronizer */

const { filterStorage } = __webpack_require__(3);
const subClasses = __webpack_require__(2);

if (subClasses) {
  this.Subscription = subClasses.Subscription;
  this.SpecialSubscription = subClasses.SpecialSubscription;
  this.DownloadableSubscription = subClasses.DownloadableSubscription;
}

// Adapters & helpers to add the legacy AB 'id' to the ABP subscriptions
// Also adds the 'language' and 'hidden' properties
const SubscriptionAdapter = (function getSubscriptionAdapter() {
  // Get the URL for the corresponding ID
  const getUrlFromId = function (searchID) {
    for (const subscription of recommendations()) {
      const { url, id } = subscription;
      if (searchID === id) {
        return url;
      }
    }
    return '';
  };

  // Get the ID for the corresponding URL
  const getIdFromURL = function (searchURL) {
    for (const subscription of recommendations()) {
      const { url, id } = subscription;
      if (searchURL === url) {
        return id;
      }
    }
    return null;
  };

  // determine if the specified filter list is language specific
  // returns the boolean language attribue (if found)
  //         false otherwise
  const isLanguageSpecific = function (searchID) {
    // check for EasyList, as it is a language-specific list (en), but
    // shouldn't be treated as such by the AdBlock code
    if (searchID === 'easylist') {
      return false;
    }

    for (const subscription of recommendations()) {
      const { id } = subscription;
      if (id === searchID) {
        return subscription.language;
      }
    }
    return false;
  };

  // Get the ID for the corresponding URL
  const getSubscriptionInfoFromURL = function (searchURL) {
    for (const subscription of recommendations()) {
      const { url } = subscription;
      if (searchURL === url) {
        return subscription;
      }
    }
    return null;
  };

  // Unsubcribe the user from the subscription specified in the argument
  const unsubscribe = function (options) {
    const subscriptionUrl = getUrlFromId(options.id);
    if (subscriptionUrl !== '') {
      const subscription = Subscription.fromURL(subscriptionUrl);
      if (subscription) {
        filterStorage.removeSubscription(subscription);
      }
    }
  };

  // Get only the user's subscriptions with in the AB format
  // without the filter contents (text)
  const getSubscriptionsMinusText = function () {
    const result = {};
    for (const subscription of filterStorage.subscriptions()) {
      if (subscription instanceof DownloadableSubscription) {
        const tempSub = {};
        for (const attr in subscription) {
          // if the subscription has a 'URL' property use it to
          // add the other attributes (id, language, hidden)
          if ((attr === 'url' || attr === '_url') && !tempSub.id) {
            const subscriptionInfo = getSubscriptionInfoFromURL(subscription[attr]);
            if (subscriptionInfo && subscriptionInfo.url) {
              tempSub.id = subscriptionInfo.id;
              tempSub.languages = subscriptionInfo.languages;
              tempSub.language = subscriptionInfo.language;
              tempSub.type = subscriptionInfo.type;
              tempSub.homepage = subscriptionInfo.homepage;
              tempSub.title = subscriptionInfo.title;
              tempSub.hidden = subscriptionInfo.hidden;
              tempSub.index = subscriptionInfo.index;
            }
          }
          if (attr !== '_filterText' && attr !== '_filterTextIndex') {
            tempSub[attr] = subscription[attr];
          }
        }
        // if the subscription doesn't have a 'id' property, use the 'URL' as an
        // 'id' property
        if (!tempSub.id || tempSub.id === undefined) {
          tempSub.id = `url:${subscription.url}`;
        }
        // if the subscription doesn't have a 'url' property, copy the '_url' property
        if (!tempSub.url && tempSub._url) {
          tempSub.url = tempSub._url;
        }
        if (!tempSub.downloadStatus && subscription._downloadStatus) {
          tempSub.downloadStatus = subscription._downloadStatus;
        }
        // Since FilterStorage.subscriptions only contains subscribed FilterLists,
        // add the 'subscribed' property
        tempSub.subscribed = true;
        result[tempSub.id] = tempSub;
      }
    }
    return result;
  };

  const rareFilterLists = {
    'http://fanboy.co.nz/fanboy-turkish.txt': 56,
    'https://pgl.yoyo.org/adservers/serverlist.php?hostformat=adblockplus&mimetype=plaintext': 57,
    'https://adblock.gardar.net/is.abp.txt': 58,
    'https://github.com/SlashArash/adblockfa': 59,
    'https://adblock.ee/list.php': 60,
  };

  // Get a binary string representation of the users subscriptions
  const getSubscriptionsChecksum = function () {
    let resultA = 0;
    let resultB = 0;
    for (const subscription of filterStorage.subscriptions()) {
      if (subscription instanceof DownloadableSubscription) {
        const subscriptionInfo = getSubscriptionInfoFromURL(subscription.url);
        let index = (subscriptionInfo && subscriptionInfo.index) || 0; // 0 is the 'unkown' index
        // if URL wasn't found in our subscription file, check the rareFilterLists to get the index
        if (index === 0 && rareFilterLists[subscription.url]) {
          index = rareFilterLists[subscription.url];
        }
        index = parseInt(index, 10);
        if (index < 32) {
          resultA |= (2 ** index); // eslint-disable-line no-bitwise
        } else {
          resultB |= (2 ** (index - 32)); // eslint-disable-line no-bitwise
        }
      }
    }
    return resultB.toString(2).padStart(32, '0') + resultA.toString(2).padStart(32, '0');
  };

  // Get all subscriptions in the AB format
  // without the filter contents (text)
  const getAllSubscriptionsMinusText = function () {
    const userSubs = getSubscriptionsMinusText();
    for (const subscription of recommendations()) {
      const {
        url, id, languages, language, type, title, homepage, hidden, index,
      } = subscription;
      if (!(id in userSubs)) {
        userSubs[id] = {};
        userSubs[id].subscribed = false;
        userSubs[id].id = id;
        userSubs[id].url = url;
        userSubs[id].userSubmitted = false;
        userSubs[id].language = language;
        userSubs[id].languages = languages;
        userSubs[id].hidden = hidden;
        userSubs[id].type = type;
        userSubs[id].title = title;
        userSubs[id].homepage = homepage;
        userSubs[id].index = index;
      }
    }
    return userSubs;
  };
  // Get all distraction control subscriptions
  // without the filter contents (text)
  const getDCSubscriptionsMinusText = function () {
    const userSubs = getAllSubscriptionsMinusText();
    const result = {};
    for (const id in userSubs) {
      const {
        url, type, title, homepage, hidden, subscribed, index,
      } = userSubs[id];
      if (type === 'distraction-control') {
        result[id] = {};
        result[id].subscribed = subscribed;
        result[id].id = id;
        result[id].url = url;
        result[id].userSubmitted = false;
        result[id].hidden = hidden;
        result[id].type = type;
        result[id].title = title;
        result[id].homepage = homepage;
        result[id].index = index;
      }
    }
    return result;
  };


  browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.command !== 'unsubscribe' || !message.id) {
      return;
    }
    unsubscribe({ id: message.id });
    sendResponse({});
  });

  // Subcribe the user to the subscription specified in the argument
  const subscribe = function (options) {
    if (options && options.id) {
      const subscriptionUrl = getUrlFromId(options.id);
      if (subscriptionUrl !== '') {
        const subscription = Subscription.fromURL(subscriptionUrl);
        if (subscription) {
          filterStorage.addSubscription(subscription);
          synchronizer.execute(subscription);
        }
      }
    }
  };

  browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message.command !== 'subscribe' || !message.id) {
      return;
    }
    subscribe({ id: message.id });
    sendResponse({});
  });


  return {
    getSubscriptionInfoFromURL,
    getUrlFromId,
    unsubscribe,
    getSubscriptionsMinusText,
    getSubscriptionsChecksum,
    getAllSubscriptionsMinusText,
    getDCSubscriptionsMinusText,
    getIdFromURL,
    isLanguageSpecific,
  };
}());

exports.SubscriptionAdapter = SubscriptionAdapter;


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, ext, adblockIsPaused, adblockIsDomainPaused
   recordGeneralMessage, log, License, reloadTab, getSettings */

const { filterNotifier } = __webpack_require__(4);
const { Prefs } = __webpack_require__(5);
const { checkAllowlisted } = __webpack_require__(8);
const browserAction = __webpack_require__(15);

const updateButtonUIAndContextMenus = function () {
  browser.tabs.query({}).then((tabs) => {
    for (const tab of tabs) {
      tab.url = tab.url ? tab.url : tab.pendingUrl;
      if (adblockIsPaused() || adblockIsDomainPaused({ url: tab.url.href, id: tab.id })) {
        browserAction.setBadge(tab.id, { number: '' });
      }
      const page = new ext.Page(tab);
      // eslint-disable-next-line no-use-before-define
      updateContextMenuItems(page);
    }
  });
};
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'updateButtonUIAndContextMenus') {
    updateButtonUIAndContextMenus();
    sendResponse({});
  }
});

// Bounce messages back to content scripts.
const emitPageBroadcast = (function emitBroadcast() {
  const injectMap = {
    topOpenWhitelistUI:
      {
        allFrames: false,
        include: [
          'jquery-3.5.1.min.js',
          'adblock-uiscripts-load_wizard_resources.js',
          'adblock-uiscripts-top_open_whitelist_ui.js',
        ],
      },
    topOpenWhitelistCompletionUI:
      {
        allFrames: false,
        include: [
          'jquery-3.5.1.min.js',
          'adblock-uiscripts-load_wizard_resources.js',
          'adblock-uiscripts-top_open_whitelist_completion_ui.js',
        ],
      },
    topOpenBlacklistUI:
      {
        allFrames: false,
        include: [
          'jquery-3.5.1.min.js',
          'purify.min.js',
          'adblock-uiscripts-load_wizard_resources.js',
          'adblock-uiscripts-blacklisting-overlay.js',
          'adblock-uiscripts-blacklisting-clickwatcher.js',
          'adblock-uiscripts-blacklisting-elementchain.js',
          'adblock-uiscripts-blacklisting-blacklistui.js',
          'adblock-uiscripts-top_open_blacklist_ui.js',
        ],
      },
    sendContentToBack:
      {
        allFrames: true,
        include: ['adblock-uiscripts-send_content_to_back.js'],
      },
  };

  // Inject the required scripts to execute fnName(parameter) in
  // the given tab.
  // Inputs: fnName:string name of function to execute on tab.
  //         fnName must exist in injectMap above.
  //         parameter:object to pass to fnName.  Must be JSON.stringify()able.
  //         alreadyInjected?:int used to recursively inject required scripts.
  //         tabID:int representing the ID of the tab to execute in.
  //         tabID defaults to the active tab
  const executeOnTab = function (fnName, parameter, alreadyInjected, tabID) {
    const injectedSoFar = alreadyInjected || 0;
    const data = injectMap[fnName];
    const details = { allFrames: data.allFrames };

    // If there's anything to inject, inject the next item and recurse.
    if (data.include.length > injectedSoFar) {
      details.file = data.include[injectedSoFar];
      browser.tabs.executeScript(tabID, details).then(() => {
        executeOnTab(fnName, parameter, injectedSoFar + 1, tabID);
      }).catch((error) => {
        log(error);
      });
    } else {
      // Nothing left to inject, so execute the function.
      const param = JSON.stringify(parameter);
      details.code = `${fnName}(${param});`;
      browser.tabs.executeScript(tabID, details);
    }
  };

  // The emitPageBroadcast() function
  const theFunction = function (request) {
    executeOnTab(request.fn, request.options, 0, request.tabID);
  };

  return theFunction;
}());

const contextMenuItem = (() => ({
  pauseAll:
    {
      title: browser.i18n.getMessage('pause_adblock_everywhere'),
      contexts: ['all'],
      onclick: () => {
        recordGeneralMessage('cm_pause_clicked');
        adblockIsPaused(true);
        updateButtonUIAndContextMenus();
      },
    },
  unpauseAll:
    {
      title: browser.i18n.getMessage('resume_blocking_ads'),
      contexts: ['all'],
      onclick: () => {
        recordGeneralMessage('cm_unpause_clicked');
        adblockIsPaused(false);
        updateButtonUIAndContextMenus();
      },
    },
  pauseDomain:
    {
      title: browser.i18n.getMessage('domain_pause_adblock'),
      contexts: ['all'],
      onclick: (info, tab) => {
        recordGeneralMessage('cm_domain_pause_clicked');
        adblockIsDomainPaused({ url: tab.url, id: tab.id }, true);
        updateButtonUIAndContextMenus();
      },
    },
  unpauseDomain:
    {
      title: browser.i18n.getMessage('resume_blocking_ads'),
      contexts: ['all'],
      onclick: (info, tab) => {
        recordGeneralMessage('cm_domain_unpause_clicked');
        adblockIsDomainPaused({ url: tab.url, id: tab.id }, false);
        updateButtonUIAndContextMenus();
      },
    },
  blockThisAd:
    {
      title: browser.i18n.getMessage('block_this_ad'),
      contexts: ['all'],
      onclick(info, tab) {
        emitPageBroadcast({
          fn: 'topOpenBlacklistUI',
          options: {
            info,
            showBlacklistCTA: License.shouldShowBlacklistCTA(),
            isActiveLicense: License.isActiveLicense(),
            settings: getSettings(),
          },
        }, {
          tab,
        });
      },
    },
  blockAnAd:
    {
      title: browser.i18n.getMessage('block_an_ad_on_this_page'),
      contexts: ['all'],
      onclick(info, tab) {
        emitPageBroadcast({
          fn: 'topOpenBlacklistUI',
          options: {
            nothingClicked: true,
            showBlacklistCTA: License.shouldShowBlacklistCTA(),
            isActiveLicense: License.isActiveLicense(),
            settings: getSettings(),
          },
        }, {
          tab,
        });
      },
    },
}))();

let updateContextMenuItems = function (page) {
  // Remove the AdBlock context menu items
  browser.contextMenus.removeAll();

  // Check if the context menu items should be added
  if (!Prefs.shouldShowBlockElementMenu) {
    return;
  }

  const adblockIsPaused = window.adblockIsPaused();
  const domainIsPaused = window.adblockIsDomainPaused({ url: page.url.href, id: page.id });
  if (adblockIsPaused) {
    browser.contextMenus.create(contextMenuItem.unpauseAll);
  } else if (domainIsPaused) {
    browser.contextMenus.create(contextMenuItem.unpauseDomain);
  } else if (checkAllowlisted(page)) {
    browser.contextMenus.create(contextMenuItem.pauseAll);
  } else {
    browser.contextMenus.create(contextMenuItem.blockThisAd);
    browser.contextMenus.create(contextMenuItem.blockAnAd);
    browser.contextMenus.create(contextMenuItem.pauseDomain);
    browser.contextMenus.create(contextMenuItem.pauseAll);
  }
};

const updateContextMenuItemsNoOp = function () {
  // Remove the AdBlock context menu items
  browser.contextMenus.removeAll();
};
// startup test to check if the context menu API functions correctly
// the `create` function is invoked twice, because it's the second
// and all subsequent calls that fail.
try {
  browser.contextMenus.create(contextMenuItem.blockThisAd);
  browser.contextMenus.create(contextMenuItem.blockThisAd);
} catch (e) {
  updateContextMenuItems = updateContextMenuItemsNoOp;
}
browser.contextMenus.removeAll();

browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
  if (changeInfo.status) {
    updateContextMenuItems(new ext.Page(tab));
  }
});

browser.runtime.onMessage.addListener((msg, sender) => {
  if (msg.type === 'report-html-page') {
    updateContextMenuItems(sender.page);
  }
});

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'sendContentToBack') {
    return;
  } // not for us
  emitPageBroadcast({ fn: 'sendContentToBack', options: {} });
  sendResponse({});
});

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'reloadTabForWhitelist') {
    reloadTab(sender.tab.id, () => {
      emitPageBroadcast({
        fn: 'topOpenWhitelistCompletionUI',
        options: {
          rule: request.rule,
          isActiveLicense: License.isActiveLicense(),
          showWhitelistCTA: License.shouldShowWhitelistCTA(),
        },
        tabID: sender.tab.id,
      });
    });
    sendResponse({});
  }
});

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'showWhitelistCompletion') {
    emitPageBroadcast({
      fn: 'topOpenWhitelistCompletionUI',
      options: {
        rule: request.rule,
        isActiveLicense: License.isActiveLicense(),
        showWhitelistCTA: License.shouldShowWhitelistCTA(),
      },
      tabID: sender.tab.id,
    });
    sendResponse({});
  }
});

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'showBlacklist' && typeof request.nothingClicked === 'boolean') {
    emitPageBroadcast({
      fn: 'topOpenBlacklistUI',
      options: {
        nothingClicked: request.nothingClicked,
        isActiveLicense: License.isActiveLicense(),
        showBlacklistCTA: License.shouldShowBlacklistCTA(),
        settings: getSettings(),
      },
      tabID: request.tabId,
    });
    sendResponse({});
  }
});

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'showWhitelist') {
    emitPageBroadcast({
      fn: 'topOpenWhitelistUI',
      options: {},
      tabID: request.tabId,
    });
    sendResponse({});
  }
});

// Update browser actions and context menus when whitelisting might have
// changed. That is now when initally loading the filters and later when
// importing backups or saving filter changes.
filterNotifier.on('load', updateButtonUIAndContextMenus);
filterNotifier.on('save', updateButtonUIAndContextMenus);

Prefs.on(Prefs.shouldShowBlockElementMenu, () => {
  updateButtonUIAndContextMenus();
});

updateButtonUIAndContextMenus();

Object.assign(window, {
  emitPageBroadcast,
  updateButtonUIAndContextMenus,
});


/***/ }),
/* 77 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "chooseFilterSubscriptions", function() { return chooseFilterSubscriptions; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isDataCorrupted", function() { return isDataCorrupted; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setSubscriptionsCallback", function() { return setSubscriptionsCallback; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setNotifyUserCallback", function() { return setNotifyUserCallback; });
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterEngine_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(47);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterEngine_js__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterEngine_js__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_recommendations_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(23);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_recommendations_js__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_recommendations_js__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_notifications_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(22);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_notifications_js__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_notifications_js__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_synchronizer_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(18);
/* harmony import */ var _adblockplusui_adblockpluschrome_adblockpluscore_lib_synchronizer_js__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_adblockplusui_adblockpluschrome_adblockpluscore_lib_synchronizer_js__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var info__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(17);
/* harmony import */ var messaging_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(1);
/* harmony import */ var prefs_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(5);
/* harmony import */ var _notificationHelper_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(48);
/* harmony import */ var _notificationHelper_js__WEBPACK_IMPORTED_MODULE_9___default = /*#__PURE__*/__webpack_require__.n(_notificationHelper_js__WEBPACK_IMPORTED_MODULE_9__);
/** @module adblock-betafish/alias/subscriptionInit */

/** similar to adblockpluschrome\lib\subscriptionInit.js */



/** @module subscriptionInit */












let firstRun;
let subscriptionsCallback = null;
let userNotificationCallback = null;
let reinitialized = false;
let dataCorrupted = false;

/**
 * If there aren't any filters, the default subscriptions are added.
 * However, if patterns.ini already did exist and/or any preference
 * is set to a non-default value, this indicates that this isn't the
 * first run, but something went wrong.
 *
 * This function detects the first run, and makes sure that the user
 * gets notified (on the first run page) if the data appears incomplete
 * and therefore will be reinitialized.
 */
function detectFirstRun() {
  return new Promise(resolve => {
    firstRun = _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1__["filterStorage"].getSubscriptionCount() == 0;

    if (firstRun && (!_adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1__["filterStorage"].firstRun || prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].currentVersion)) {
      reinitialized = true;
    }
    prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].currentVersion = info__WEBPACK_IMPORTED_MODULE_6__["addonVersion"];

    browser.storage.local.get(null).then(currentData => {
      const edgeMigrationNeeded = currentData.filter_lists;
      if (edgeMigrationNeeded && firstRun) {
        firstRun = false;
      }
      resolve();
    });
  });
}

/**
 * In case of data corruption, we don't want to show users
 * any non-essential notifications so we need to instruct
 * the notification manager to ignore them.
 *
 * @param {boolean} value
 */
function setDataCorrupted(value) {
  dataCorrupted = value;
  _adblockplusui_adblockpluschrome_adblockpluscore_lib_notifications_js__WEBPACK_IMPORTED_MODULE_4__["notifications"].ignored = value;
}

/**
 * Determines whether to add the default ad blocking subscriptions.
 * Returns true, if there are no filter subscriptions besides those
 * other subscriptions added automatically, and no custom filters.
 *
 * On first run, this logic should always result in true since there
 * is no data and therefore no subscriptions. But it also causes the
 * default ad blocking subscriptions to be added again after some
 * data corruption or misconfiguration.
 *
 * @return {boolean}
 */
function shouldAddDefaultSubscriptions() {
  for (let subscription of _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1__["filterStorage"].subscriptions()) {
    if (
      subscription instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["DownloadableSubscription"] &&
      subscription.url != prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].subscriptions_exceptionsurl &&
      subscription.type != "circumvention"
    )
      return false;

    if (subscription instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["SpecialSubscription"] && subscription.filterCount > 0) return false;
  }

  return true;
}

/**
 * Finds the default filter subscriptions.
 *
 * Returns an array that includes one subscription of the type "ads" for the
 * current UI language, and any subscriptions of the type "circumvention".
 *
 * @param {Array.<object>} subscriptions
 * @return {Array.<object>}
 */
function chooseFilterSubscriptions(subscriptions) {
  let currentLang = browser.i18n.getUILanguage().split("-")[0];
  let defaultLang = browser.runtime.getManifest().default_locale.split("_")[0];

  let adSubscriptions = [];
  let adSubscriptionsDefaultLang = [];
  let chosenSubscriptions = [];

  for (let subscription of subscriptions) {
    switch (subscription.type) {
      case "ads":
        if (subscription.languages.includes(currentLang)) adSubscriptions.push(subscription);
        if (subscription.languages.includes(defaultLang))
          adSubscriptionsDefaultLang.push(subscription);
        break;

      case "circumvention":
        chosenSubscriptions.push(subscription);
        break;
    }
  }

  if (adSubscriptions.length > 0 || (adSubscriptions = adSubscriptionsDefaultLang).length > 0) {
    let randomIndex = Math.floor(Math.random() * adSubscriptions.length);
    chosenSubscriptions.unshift(adSubscriptions[randomIndex]);
  }

  return chosenSubscriptions;
}

/**
 * Gets the filter subscriptions to be added when the extnesion is loaded.
 *
 * @return {Promise|Subscription[]}
 */
function getSubscriptions() {
  let subscriptions = [];

  // Add pre-configured subscriptions
  for (let url of prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].additional_subscriptions) subscriptions.push(_adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["Subscription"].fromURL(url));

  // Add "acceptable ads", and "AdBlock Custom" subscriptions
  if (firstRun) {
    if (info__WEBPACK_IMPORTED_MODULE_6__["platform"] !== "gecko") {
      let acceptableAdsSubscription = _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["Subscription"].fromURL(prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].subscriptions_exceptionsurl);
      acceptableAdsSubscription.title = "Allow non-intrusive advertising";
      subscriptions.push(acceptableAdsSubscription);
    }

    let abcSubscription = _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["Subscription"].fromURL(
      "https://cdn.adblockcdn.com/filters/adblock_custom.txt"
    );
    abcSubscription.title = "AdBlock custom filters";
    subscriptions.push(abcSubscription);

  }

  // Add default ad blocking subscriptions (e.g. EasyList, Anti-Circumvention)
  let addDefaultSubscription = shouldAddDefaultSubscriptions();
  if (addDefaultSubscription || !prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].subscriptions_addedanticv) {
    for (let { url, type, title, homepage } of chooseFilterSubscriptions(Object(_adblockplusui_adblockpluschrome_adblockpluscore_lib_recommendations_js__WEBPACK_IMPORTED_MODULE_3__["recommendations"])())) {
      // Make sure that we don't add Easylist again if we want
      // to just add the Anti-Circumvention subscription.
      if (!addDefaultSubscription && type != "circumvention") continue;

      let subscription = _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["Subscription"].fromURL(url);
      subscription.disabled = false;
      subscription.title = title;
      subscription.homepage = homepage;
      subscriptions.push(subscription);

      if (subscription.type == "circumvention") prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].subscriptions_addedanticv = true;
    }

    return subscriptions;
  }

  return subscriptions;
}

function removeSubscriptions() {
  return new Promise(function(resolve, reject) {
    if ("managed" in browser.storage) {
      browser.storage.managed.get(null).then(
        items => {
          for (let key in items) {
            if (key === "remove_subscriptions" && Array.isArray(items[key]) && items[key].length) {
              for (let inx = 0; inx < items[key].length; inx++) {
                let subscription = _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["Subscription"].fromURL(items[key][inx]);
                _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1__["filterStorage"].removeSubscription(subscription);
              }
            }
          }
          resolve();
        },

        // Opera doesn't support browser.storage.managed, but instead of simply
        // removing the API, it gives an asynchronous error which we ignore here.
        () => {
          resolve();
        }
      );
    } else {
      resolve();
    }
  });
}

function openInstalled() {
  STATS.untilLoaded(function(userID) {
    browser.tabs.create({
      url:
        "https://getadblock.com/installed/?u=" +
        userID +
        "&lg=" +
        browser.i18n.getUILanguage() +
        "&dc=" +
        dataCorrupted
    });
  });
}

function addSubscriptionsAndNotifyUser(subscriptions) {
  if (subscriptionsCallback) subscriptions = subscriptionsCallback(subscriptions);

  for (let subscription of subscriptions) {
    _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterStorage_js__WEBPACK_IMPORTED_MODULE_1__["filterStorage"].addSubscription(subscription);
    if (subscription instanceof _adblockplusui_adblockpluschrome_adblockpluscore_lib_subscriptionClasses_js__WEBPACK_IMPORTED_MODULE_0__["DownloadableSubscription"] && !subscription.lastDownload)
      _adblockplusui_adblockpluschrome_adblockpluscore_lib_synchronizer_js__WEBPACK_IMPORTED_MODULE_5__["synchronizer"].execute(subscription);
  }

  // Show first run page or the updates page. The latter is only shown
  // on Chromium (since the current updates page announces features that
  // aren't new to Firefox users), and only if this version of the
  // updates page hasn't been shown yet.
  if (firstRun && !prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].suppress_first_run_page) {
    // Always show the first run page if a data corruption was detected
    // (either through failure of reading from or writing to storage.local).
    // The first run page notifies the user about the data corruption.
    let url;
    if (firstRun || dataCorrupted) {
      // see if the there's a tab to the Premium Sunset page, if so, don't open /installed
      browser.tabs.query({ currentWindow: true }).then(tabs => {
        if (!tabs || tabs.length === 0) {
          openInstalled();
          return;
        }
        const updateFreeURL = "https://getadblockpremium.com/sunset/free/?";
        const updatePaidURL = "https://getadblockpremium.com/sunset/paid/?";
        const sunsetFreePageFound = tabs.some(tab => {
          return tab && tab.url && tab.url.startsWith(updateFreeURL);
        });
        const sunsetPaidPageFound = tabs.some(tab => {
          return tab && tab.url && tab.url.startsWith(updatePaidURL);
        });
        if (!sunsetFreePageFound && !sunsetPaidPageFound) {
          openInstalled();
        }
      });
    }
  }

  if (userNotificationCallback)
    userNotificationCallback({ dataCorrupted, firstRun, reinitialized });
}

/**
 * We need to check whether we can safely write to/read from storage
 * before we start relying on it for storing preferences.
 */
async function testStorage() {
  let testKey = "readwrite_test";
  let testValue = Math.random();

  try {
    await browser.storage.local.set({ [testKey]: testValue });
    let result = await browser.storage.local.get(testKey);
    if (result[testKey] != testValue)
      throw new Error("Storage test: Failed to read and write value");
  } finally {
    await browser.storage.local.remove(testKey);
  }
}

(async () => {
  await Promise.all([
    _adblockplusui_adblockpluschrome_adblockpluscore_lib_filterEngine_js__WEBPACK_IMPORTED_MODULE_2__["filterEngine"].initialize().then(() => _adblockplusui_adblockpluschrome_adblockpluscore_lib_synchronizer_js__WEBPACK_IMPORTED_MODULE_5__["synchronizer"].start()),
    prefs_js__WEBPACK_IMPORTED_MODULE_8__["Prefs"].untilLoaded.catch(() => {
      setDataCorrupted(true);
    }),
    testStorage().catch(() => {
      setDataCorrupted(true);
    })
  ]);
  await detectFirstRun();
  let subscriptions = await getSubscriptions();
  addSubscriptionsAndNotifyUser(subscriptions);
  await removeSubscriptions();
  // We have to require the "uninstall" module on demand,
  // as the "uninstall" module in turn requires this module.
  (await Promise.resolve(/* import() */).then(__webpack_require__.bind(null, 43))).setUninstallURL();
  Object(_notificationHelper_js__WEBPACK_IMPORTED_MODULE_9__["initNotifications"])(firstRun);
})();

/**
 * Gets a value indicating whether a data corruption was detected.
 *
 * @return {boolean}
 */
function isDataCorrupted() {
  return dataCorrupted;
}

/**
 * Sets a callback that is called with an array of subscriptions to be added
 * during initialization. The callback must return an array of subscriptions
 * that will effectively be added.
 *
 * @param {function} callback
 */
function setSubscriptionsCallback(callback) {
  subscriptionsCallback = callback;
}

/**
 * Sets a callback that is called with environment information after
 * initialization to notify users.
 *
 * @param {function} callback
 */
function setNotifyUserCallback(callback) {
  userNotificationCallback = callback;
}

/**
 * @typedef {object} subscriptionsGetInitIssuesResult
 * @property {boolean} dataCorrupted
 *   true if it appears that the user's extension data was corrupted.
 * @property {boolean} reinitialized
 *   true if we have reset the user's settings due to data corruption.
 */

/**
 * Returns an Object with boolean flags for any subscription initialization
 * issues.
 *
 * @event "subscriptions.getInitIssues"
 * @returns {subscriptionsGetInitIssuesResult}
 */
messaging_js__WEBPACK_IMPORTED_MODULE_7__["port"].on("subscriptions.getInitIssues", (message, sender) => ({ dataCorrupted, reinitialized }));


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

"use strict";
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */



// Promise.prototype.finally is not supported in Firefox < 58
if (!Promise.prototype.finally)
{
  Promise.prototype.finally = function(fn)
  {
    return this.then(fn, fn);
  };
}


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

"use strict";
/*
  Same as the original source adblockpluschrome\adblockpluscore\lib\filterListener.js
 * except:
 * - updated require paths
 * - added "distraction-control" as type of filter list that allow snippets
 */

/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module */



/**
 * @fileOverview Synchronization between filter storage and the filter engine.
 */

const { filterStorage } = __webpack_require__(3);
const { filterNotifier } = __webpack_require__(4);
const { isActiveFilter, Filter } = __webpack_require__(0);
const { SpecialSubscription } = __webpack_require__(2);
const { filterState } = __webpack_require__(14);

/**
 * Checks whether filters from a given subscription should be deployed to the
 * filter engine.
 *
 * If the subscription is both valid and enabled, the function returns `true`;
 * otherwise, it returns `false`.
 *
 * @param {module:subscriptionClasses.Subscription} subscription
 *   The subscription.
 *
 * @returns {boolean} Whether filters from the subscription should be deployed
 *   to the filter engine.
 */
function shouldDeployFilters(subscription) {
  return subscription.valid && !subscription.disabled;
}

/**
 * Deploys a filter to the filter engine.
 *
 * The filter is deployed only if it belongs to at least one subscription that
 * is both valid and enabled.
 *
 * If the filter is a snippet filter, it is deployed only if it belongs to at
 * least one subscription that is valid, enabled, and of
 * {@link module:subscriptionClasses.Subscription#type type}
 * `circumvention` or a
 * {@link module:subscriptionClasses.SpecialSubscription special subscription}
 * that keeps user-defined filters.
 *
 * @param {module:filterEngine~FilterEngine} engine A reference to the
 *   filter engine.
 * @param {Filter} filter The filter.
 * @param {?Array.<module:subscriptionClasses.Subscription>} [subscriptions]
 *   A list of subscriptions to which the filter belongs. If omitted or `null`,
 *   the information is looked up from
 *   {@link module:filterStorage.filterStorage filter storage}.
 */
function deployFilter(engine, filter, subscriptions = null) {
  if (!isActiveFilter(filter) || !filterState.isEnabled(filter.text)) return;

  let deploy = false;
  let allowSnippets = false;

  for (let subscription of subscriptions || filterStorage.subscriptions(filter.text)) {
    if (shouldDeployFilters(subscription)) {
      deploy = true;

      // Allow snippets to be executed only by the circumvention lists or the
      // user's own filters.
      if (
        subscription.type == "circumvention" ||
        subscription.type == "distraction-control" ||
        subscription instanceof SpecialSubscription
      ) {
        allowSnippets = true;
        break;
      }
    }
  }

  if (!deploy) return;

  if (!allowSnippets && filter.type == "snippet") return;

  engine.add(filter);
}

/**
 * Undeploys a filter from the filter engine.
 *
 * The filter is undeployed only if it does not belong to at least one
 * subscription that is both valid and enabled.
 *
 * @param {module:filterEngine~FilterEngine} engine A reference to the
 *   filter engine.
 * @param {module:filterClasses.Filter} filter The filter.
 */
function undeployFilter(engine, filter) {
  if (!isActiveFilter(filter)) return;

  if (filterState.isEnabled(filter.text)) {
    let keep = false;
    for (let subscription of filterStorage.subscriptions(filter.text)) {
      if (shouldDeployFilters(subscription)) {
        keep = true;
        break;
      }
    }

    if (keep) return;
  }

  engine.remove(filter);
}

/**
 * `{@link module:filterListener.filterListener filterListener}`
 * implementation.
 */
class FilterListener {
  /**
   * Initializes filter listener on startup, registers the necessary hooks.
   *
   * Initialization is asynchronous; once complete,
   * `{@link module:filterNotifier.filterNotifier filterNotifier}` emits the
   * `ready` event.
   *
   * @hideconstructor
   */
  constructor() {
    /**
     * A reference to the filter engine.
     * @type {?module:filterEngine~FilterEngine}
     * @private
     */
    this._engine = null;

    /**
     * Increases on filter changes, filters will be saved if it exceeds 1.
     * @type {number}
     * @private
     */
    this._isDirty = 0;
  }

  /**
   * Initializes filter listener.
   * @param {module:filterEngine~FilterEngine} engine A reference to the
   *   filter engine.
   * @returns {Promise} A promise that is fulfilled when the initialization is
   *   complete.
   * @package
   */
  async initialize(engine) {
    if (engine == null || typeof engine != "object")
      throw new Error("engine must be a non-null object.");

    if (this._engine != null) throw new Error("Filter listener already initialized.");

    this._engine = engine;

    await filterStorage.loadFromDisk();

    let promise = Promise.resolve();

    // Initialize filters from each subscription asynchronously on startup by
    // setting up a chain of promises.
    for (let subscription of filterStorage.subscriptions()) {
      if (shouldDeployFilters(subscription)) {
        promise = promise.then(() => {
          for (let text of subscription.filterText())
            deployFilter(this._engine, Filter.fromText(text), [subscription]);
        });
      }
    }

    await promise;

    filterNotifier.on("filter.added", this._onFilterAdded.bind(this));
    filterNotifier.on("filter.removed", this._onFilterRemoved.bind(this));
    filterNotifier.on("filter.moved", this._onGenericChange.bind(this));

    filterNotifier.on("filterState.enabled", this._onFilterStateEnabled.bind(this));
    filterNotifier.on("filterState.hitCount", this._onFilterStateHitCount.bind(this));
    filterNotifier.on("filterState.lastHit", this._onFilterStateLastHit.bind(this));

    filterNotifier.on("subscription.added", this._onSubscriptionAdded.bind(this));
    filterNotifier.on("subscription.removed", this._onSubscriptionRemoved.bind(this));
    filterNotifier.on("subscription.disabled", this._onSubscriptionDisabled.bind(this));
    filterNotifier.on("subscription.updated", this._onSubscriptionUpdated.bind(this));
    filterNotifier.on("subscription.title", this._onGenericChange.bind(this));
    filterNotifier.on("subscription.fixedTitle", this._onGenericChange.bind(this));
    filterNotifier.on("subscription.homepage", this._onGenericChange.bind(this));
    filterNotifier.on("subscription.downloadStatus", this._onGenericChange.bind(this));
    filterNotifier.on("subscription.lastCheck", this._onGenericChange.bind(this));
    filterNotifier.on("subscription.errors", this._onGenericChange.bind(this));

    filterNotifier.on("load", this._onLoad.bind(this));
    filterNotifier.on("save", this._onSave.bind(this));

    // Indicate that all filters are ready for use.
    filterNotifier.emit("ready");
  }

  /**
   * Increases "dirty factor" of the filters and calls
   * filterStorage.saveToDisk() if it becomes 1 or more.
   *
   * Save is executed delayed to prevent multiple subsequent calls. If the
   * parameter is 0 it forces saving filters if any changes were recorded after
   * the previous save.
   *
   * @param {number} factor
   *
   * @private
   */
  _setDirty(factor) {
    if (factor == 0 && this._isDirty > 0) this._isDirty = 1;
    else this._isDirty += factor;
    if (this._isDirty >= 1) {
      this._isDirty = 0;
      filterStorage.saveToDisk();
    }
  }

  _onSubscriptionAdded(subscription) {
    this._setDirty(1);

    if (shouldDeployFilters(subscription)) {
      for (let text of subscription.filterText())
        deployFilter(this._engine, Filter.fromText(text), [subscription]);
    }
  }

  _onSubscriptionRemoved(subscription) {
    this._setDirty(1);

    if (shouldDeployFilters(subscription)) {
      for (let text of subscription.filterText())
        undeployFilter(this._engine, Filter.fromText(text));
    }
  }

  _onSubscriptionDisabled(subscription, newValue) {
    this._setDirty(1);

    if (filterStorage.hasSubscription(subscription)) {
      if (newValue == false) {
        for (let text of subscription.filterText())
          deployFilter(this._engine, Filter.fromText(text), [subscription]);
      } else {
        for (let text of subscription.filterText())
          undeployFilter(this._engine, Filter.fromText(text));
      }
    }
  }

  _onSubscriptionUpdated(subscription, textDelta) {
    this._setDirty(1);

    if (shouldDeployFilters(subscription) && filterStorage.hasSubscription(subscription)) {
      for (let text of textDelta.removed) undeployFilter(this._engine, Filter.fromText(text));

      for (let text of textDelta.added)
        deployFilter(this._engine, Filter.fromText(text), [subscription]);
    }
  }

  _onFilterAdded(filter) {
    this._setDirty(1);

    if (filterState.isEnabled(filter.text)) deployFilter(this._engine, filter);
  }

  _onFilterRemoved(filter) {
    this._setDirty(1);

    if (filterState.isEnabled(filter.text)) undeployFilter(this._engine, filter);
  }

  _onFilterStateEnabled(text, newValue) {
    this._setDirty(1);

    if (newValue == false) undeployFilter(this._engine, Filter.fromText(text));
    else deployFilter(this._engine, Filter.fromText(text));
  }

  _onFilterStateHitCount(text, newValue) {
    if (newValue == 0) this._setDirty(0);
    else this._setDirty(0.002);
  }

  _onFilterStateLastHit() {
    this._setDirty(0.002);
  }

  _onGenericChange() {
    this._setDirty(1);
  }

  _onLoad() {
    this._isDirty = 0;

    this._engine.clear();

    for (let subscription of filterStorage.subscriptions()) {
      if (shouldDeployFilters(subscription)) {
        for (let text of subscription.filterText())
          deployFilter(this._engine, Filter.fromText(text), [subscription]);
      }
    }
  }

  _onSave() {
    this._isDirty = 0;
  }
}

/**
 * Component synchronizing filter storage with the filter engine.
 * @type {module:filterListener~FilterListener}
 * @package
 */
exports.filterListener = new FilterListener();


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global require, getUrlFromId, getSettings, storageGet, storageSet */

const { Subscription } = __webpack_require__(2);
const { filterStorage } = __webpack_require__(3);
const { EventEmitter } = __webpack_require__(12);
const {
  imageSizesMap, WIDE, TALL, SKINNYWIDE, SKINNYTALL,
} = __webpack_require__(45);

const minjQuery = __webpack_require__(29);

const channelsNotifier = new EventEmitter();

const subscription1 = Subscription.fromURL(getUrlFromId('antisocial'));
const subscription2 = Subscription.fromURL(getUrlFromId('annoyances'));

// Inputs: width:int, height:int, url:url, title:string, attributionUrl:url
function Listing(data) {
  this.width = data.width;
  this.height = data.height;
  this.url = data.url;
  this.title = data.title;
  this.attributionUrl = data.attributionUrl;
  this.channelName = data.channelName;
  if (data.name) {
    this.name = data.name;
  }
  if (data.thumbURL) {
    this.thumbURL = data.thumbURL;
  }
  if (data.userLink) {
    this.userLink = data.userLink;
  }
  if (data.anySize) {
    this.anySize = data.anySize;
  }
  if (data.type) {
    this.type = data.type;
  }
  if (data.ratio) {
    this.ratio = data.ratio;
  }
  if (data.customImage) {
    this.customImage = data.customImage;
  }
}

// Contains and provides access to all the photo channels.
function Channels() {
  this.channelGuide = undefined; // maps channel ids to channels and metadata
  this.loadFromStorage();
}
Channels.prototype = {
  // Inputs:
  //   name:string - a Channel class name.
  //   param:object - the single ctor parameter to the Channel class.
  //   enabled:bool - true if this channel is to be used for pictures.
  // Returns:
  //   id of newly created channel, or undefined if the channel already existed.
  add(data) {
    let Klass = window[data.name];
    if (!Klass) {
      Klass = window.UnknownChannel;
    }
    const dataParam = JSON.stringify(data.param);
    for (const id in this.channelGuide) {
      const c = this.channelGuide[id];
      if (c.name === data.name && JSON.stringify(c.param) === dataParam) {
        return undefined;
      }
    }
    const id = Math.floor(Math.random() * Date.now());
    const channel = new Klass(data.param);
    this.channelGuide[id] = {
      name: data.name,
      param: data.param,
      enabled: data.enabled,
      channel,
    };
    this.saveToStorage();
    const that = this;
    minjQuery(channel).on('updated', () => {
      if (that.channelGuide[id].enabled) {
        that.channelGuide[id].channel.prefetch();
      }
    });
    channel.refresh();
    return id;
  },

  remove(channelId) {
    delete this.channelGuide[channelId];
    this.saveToStorage();
  },

  // Return read-only map from each channel ID to
  // { name, param, enabled }.
  getGuide() {
    const results = {};
    for (const id in this.channelGuide) {
      const c = this.channelGuide[id];
      results[id] = {
        name: c.name,
        param: c.param,
        enabled: c.enabled,
      };
    }

    return results;
  },

  // Return id for channel name
  getIdByName(name) {
    for (const id in this.channelGuide) {
      if (this.channelGuide[id].name === name) {
        return id;
      }
    }
    return undefined;
  },

  isCustomChannel(id) {
    return (this.getIdByName('CustomChannel') === id);
  },

  isCustomChannelEnabled() {
    return (this.channelGuide[this.getIdByName('CustomChannel')].enabled);
  },

  getListings(id) {
    return this.channelGuide[id].channel.getListings();
  },

  setEnabled(id, enabled) {
    const originalValue = this.channelGuide[id].enabled;
    this.channelGuide[id].enabled = enabled;
    this.saveToStorage();
    if (originalValue !== enabled) {
      channelsNotifier.emit('channels.changed', id, enabled, originalValue);
    }
  },

  refreshAllEnabled() {
    for (const id in this.channelGuide) {
      const data = this.channelGuide[id];
      if (data.enabled) {
        data.channel.refresh();
      }
    }
  },

  isAnyEnabled() {
    for (const id in this.channelGuide) {
      const channel = this.channelGuide[id];
      if (channel.enabled) {
        return true;
      }
    }
    return false;
  },

  disableAllChannels() {
    for (const id in this.channelGuide) {
      if (this.channelGuide[id].enabled) {
        this.channelGuide[id].enabled = false;
        channelsNotifier.emit('channels.changed', id, false, true);
      }
    }
  },

  // Returns a random Listing from all enabled channels or from channel
  // |channelId| if specified, trying to match the ratio of |width| and
  // |height| decently.  Returns undefined if there are no enabled channels.
  randomListing(opts) {
    if (!getSettings().picreplacement) {
      return undefined;
    }
    // if the element to be replace is 'fixed' in position, it may make for bad pic
    // replacement element.
    if (opts.position === 'fixed') {
      for (const sub of filterStorage.subscriptions()) {
        if (sub.url === subscription1.url || sub.url === subscription2.url) {
          return undefined;
        }
      }
    }

    const heightLowRange = opts.height;
    const widthLowRange = opts.width;
    const heightHighRange = (opts.height * 1.25);
    const widthHighRange = (opts.width * 1.25);
    const typeMatchListings = [];
    const rangeLimitedListings = [];
    let targetRatio = Math.max(opts.width, opts.height) / Math.min(opts.width, opts.height);

    for (const id in this.channelGuide) {
      const data = this.channelGuide[id];
      if (opts.channelId === id || (data.enabled && !opts.channelId)) {
        data.channel.getListings().forEach((element) => {
          if (
            (opts.type === WIDE || opts.type === SKINNYWIDE)
            && (element.type !== SKINNYTALL)
            && (element.width <= widthHighRange)
            && (element.height >= heightLowRange)
            && (element.height <= heightHighRange)
          ) {
            rangeLimitedListings.push(element);
          } else if (
            (opts.type === TALL || opts.type === SKINNYTALL)
            && (element.type !== SKINNYWIDE)
            && (element.width >= widthLowRange)
            && (element.width <= widthHighRange)
            && (element.height <= heightHighRange)
          ) {
            rangeLimitedListings.push(element);
          } else if (
            (opts.type !== WIDE)
            && (opts.type !== TALL)
            && (opts.type !== SKINNYTALL)
            && (opts.type !== SKINNYWIDE)
            && (element.width >= widthLowRange)
            && (element.width <= widthHighRange)
            && (element.height >= heightLowRange)
            && (element.height <= heightHighRange)
          ) {
            rangeLimitedListings.push(element);
          }
          if (
            opts.type === element.type
            && element.width >= widthLowRange
            && element.height >= heightLowRange
          ) {
            typeMatchListings.push(element);
          }
        });
      }
    }
    let exactTypeMatchListings = [];
    if (rangeLimitedListings.length > 0) {
      const randomIndex = Math.floor(Math.random() * rangeLimitedListings.length);
      const theListing = Object.assign({}, rangeLimitedListings[randomIndex]);
      theListing.listingHeight = theListing.height;
      theListing.listingWidth = theListing.width;
      if (opts.height !== theListing.height && opts.width !== theListing.width) {
        theListing.height = (theListing.height * opts.width) / theListing.width;
        theListing.width = opts.width;
      }
      return theListing;
    }
    let bestMatchRatio = 0;
    targetRatio = Math.max(opts.width, opts.height) / Math.min(opts.width, opts.height);
    typeMatchListings.forEach((listing) => {
      if (Math.abs(listing.ratio - targetRatio) < Math.abs(bestMatchRatio - targetRatio)) {
        exactTypeMatchListings = []; // remove previous matches
        exactTypeMatchListings.push(listing);
        bestMatchRatio = listing.ratio;
      } else if (listing.ratio === bestMatchRatio) {
        exactTypeMatchListings.push(listing);
      }
    });
    if (exactTypeMatchListings.length > 0) {
      const randomIndex = Math.floor(Math.random() * exactTypeMatchListings.length);
      const theListing = Object.assign({}, exactTypeMatchListings[randomIndex]);
      theListing.listingHeight = theListing.height;
      theListing.listingWidth = theListing.width;
      return theListing;
    }

    return undefined;
  },

  // adds any new or missing channels (in a disabled state) to the users channel guide
  addNewChannels() {
    const channelNames = ['DogsChannel', 'CatsChannel', 'LandscapesChannel', 'OceanChannel', 'GoatsChannel', 'BirdChannel', 'FoodChannel', 'CustomChannel'];
    for (const name of channelNames) {
      if (!this.getIdByName(name)) {
        this.add({
          name,
          param: undefined,
          enabled: false,
        });
      }
    }
  },

  loadFromStorage() {
    this.channelGuide = {};
    const entries = storageGet('channels');
    if (entries) {
      for (let i = 0; i < entries.length; i++) {
        this.add(entries[i]);
      }
    }
    this.addNewChannels();
  },

  saveToStorage() {
    const toStore = [];
    const guide = this.getGuide();
    for (const id in guide) {
      toStore.push(guide[id]);
    }
    storageSet('channels', toStore);
  },
};


// Base class representing a channel of photos.
// Concrete constructors must accept a single argument, because Channels.add()
// relies on that.
function Channel() {
  this.listings = [];
}
Channel.prototype = {
  getListings() {
    return this.listings.slice(0); // shallow copy
  },

  listingFactory(widthParam, heightParam, url, title, channelName) {
    let width = widthParam;
    let height = heightParam;
    const type = this.calculateType(width, height);

    if (typeof width === 'number') {
      width = `${width}`;
    }
    if (typeof height === 'number') {
      height = `${height}`;
    }
    return new Listing({
      width,
      height,
      url,
      attributionUrl: url,
      type,
      ratio: Math.max(width, height) / Math.min(width, height),
      title,
      channelName, // message.json key for channel name
    });
  },

  // Update the channel's listings and trigger an 'updated' event.
  refresh() {
    const that = this;
    this.getLatestListings((listings) => {
      that.listings = listings;
      minjQuery(that).trigger('updated');
    });
  },

  // Load all photos so that they're in the cache.
  prefetch() {
    // current - noop, since all of the URLs are hard coded.
  },

  getLatestListings() {
    throw new Error('Implemented by subclass. Call callback with up-to-date listings.');
  },

  calculateType(w, h) {
    let width = w;
    let height = h;

    if (typeof width === 'string') {
      width = parseInt(width, 10);
    }
    if (typeof height === 'string') {
      height = parseInt(height, 10);
    }
    let type = '';
    const ratio = Math.max(width, height) / Math.min(width, height);
    if (ratio >= 1.5 && ratio < 7) {
      type = (width > height ? imageSizesMap.get('wide') : imageSizesMap.get('tall'));
    } else if (ratio > 7) {
      type = (width > height ? imageSizesMap.get('skinnywide') : imageSizesMap.get('skinnytall'));
    } else {
      type = ((width > 125 || height > 125) ? imageSizesMap.get('big') : imageSizesMap.get('small'));
    }
    return type;
  },
};

Object.assign(window, {
  Channel,
  Channels,
  Listing,
  channelsNotifier,
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, require */

const catData = __webpack_require__(82);

// Channel containing hard coded cats loaded from disk.
// Subclass of Channel.
function CatsChannel() {
  Channel.call(this);
}

CatsChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    const listingArray = [];
    for (const cat of catData) {
      listingArray.push(this.listingFactory(cat.width, cat.height, cat.url, 'This is a cat!', 'catchannelswitchlabel'));
    }
    callback(listingArray);
  },
};

Object.assign(window, {
  CatsChannel,
});


/***/ }),
/* 82 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/12--x628/cat-7784.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/12--x628/cat-animal-animal-portrait-pet.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/12--x628/cat-feline-cute-domestic.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/12--x628/cat-kitten-rozkosne-little.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/12--x628/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/12--x628/eyes-cats-cat-couch.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/24--x1256/cat-7784.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/24--x1256/cat-animal-animal-portrait-pet.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/24--x1256/cat-feline-cute-domestic.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/24--x1256/cat-kitten-rozkosne-little.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/24--x1256/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x628/24--x1256/eyes-cats-cat-couch.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-7784.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-82072.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-animal-animal-portrait-pet.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-animal-cute-pet-39500.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-balcony-surprised-look-80363.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-british-shorthair-mieze-blue-eye-162174.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-british-shorthair-thoroughbred-adidas-162064.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-close-animal-cat-face-162309.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-eyes-view-face-66292.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-feline-cute-domestic.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-feline-furry-pet-53446.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-feline-kitty-kitten-39380.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-home-animal-cat-s-eyes-46208.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-kitten-rozkosne-little.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-pet-eyes-animal-50566.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-pet-furry-face-162319.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-portrait-eyes-animal-162216.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-portrait-kitten-cute-128884.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-relax-chill-out-camacho-70844.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-tiger-getiegert-feel-at-home-160722.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/eyes-cats-cat-couch.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-105587.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-106131.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-116835.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-135859.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-142615.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-171216.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-172420.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-173909.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-192384.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-207166.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208845.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208860.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208878.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208880.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208906.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208907.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208954.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208971.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-208998.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-209117.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-209800.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-210081.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-214657.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-220826.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-220876.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-220951.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-220970.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-220983.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-236630.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-236633.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-244848.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-247007.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-248254.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-248289.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-248304.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-257423.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-271889.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-272124.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-289345.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-289381.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-290263.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-327014.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-349388.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-372651.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-372657.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-416088.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-416138.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-416208.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-437886.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-461872.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-549237.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-576802.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-583250.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-596590.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-599492.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-605048.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-622549.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-65536.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-674568.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-674577 (1).jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-674577.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-679855.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-680437.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-683205.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-689042.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-709482.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-720684.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-731553.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-731637.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-733105.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-736528.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-745241.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-749212.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-751050.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-89951.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-92174.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-94434.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-95328.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-close-animal-cat-face-1623-9.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/cat-feline-kitty-kitten-3938-.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-1-5587.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-17242-.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-1739-9.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-2-886-.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-2-8878.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-58325-.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-6832-5.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-7-9482.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/3--x25-/pexels-photo-751-5-.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-7784.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-82072.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-animal-animal-portrait-pet.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-animal-cute-pet-39500.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-balcony-surprised-look-80363.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-british-shorthair-mieze-blue-eye-162174.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-british-shorthair-thoroughbred-adidas-162064.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-close-animal-cat-face-162309.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-eyes-view-face-66292.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-feline-cute-domestic.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-feline-furry-pet-53446.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-feline-kitty-kitten-39380.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-home-animal-cat-s-eyes-46208.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-kitten-rozkosne-little.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-pet-eyes-animal-50566.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-pet-furry-face-162319.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-portrait-eyes-animal-162216.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-portrait-kitten-cute-128884.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-relax-chill-out-camacho-70844.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/cat-tiger-getiegert-feel-at-home-160722.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/eyes-cats-cat-couch.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-105587.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-106131.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-116835.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-135859.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-142615.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-171216.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-172420.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-173909.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-192384.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-207166.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208845.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208860.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208878.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208880.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208906.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208907.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208954.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208971.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-208998.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-209117.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-209800.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-210081.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-214657.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-220826.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-220876.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-220951.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-220970.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-220983.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-236630.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-236633.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-244848.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-247007.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-248254.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-248289.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-248304.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-257423.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-271889.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-272124.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-289345.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-289381.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-290263.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-327014.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-349388.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-372651.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-372657.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-416088.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-416138.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-416208.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-437886.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-461872.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-549237.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-576802.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-583250.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-596590.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-599492.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-605048.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-622549.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-65536.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-674568.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-674577 (1).jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-674577.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-679855.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-680437.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-683205.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-689042.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-709482.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-720684.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-731553.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-731637.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-733105.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-736528.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-745241.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-749212.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-751050.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-89951.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-92174.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-94434.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-95328.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-1-6131.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-2-89-6.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-2-9117.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-22-983.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-23663-.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-4162-8.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-5768-2.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-68-437.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/6--x5--/pexels-photo-7331-5.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/_6--x5--/pexels-photo-116835.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/_6--x5--/pexels-photo-59659-.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/_6--x5--/pexels-photo-7331-5.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x25-/_6--x5--/pexels-photo-94434.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/3--x6--/cat-7784.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/3--x6--/cat-animal-animal-portrait-pet.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/3--x6--/cat-feline-cute-domestic.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/3--x6--/cat-kitten-rozkosne-little.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/3--x6--/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/3--x6--/eyes-cats-cat-couch.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/6--x12--/cat-7784.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/6--x12--/cat-animal-animal-portrait-pet.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/6--x12--/cat-feline-cute-domestic.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/6--x12--/cat-kitten-rozkosne-little.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/6--x12--/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/3--x6--/6--x12--/eyes-cats-cat-couch.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/336x28-/cat-7784.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/336x28-/cat-animal-animal-portrait-pet.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/336x28-/cat-feline-cute-domestic.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/336x28-/cat-kitten-rozkosne-little.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/336x28-/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/336x28-/eyes-cats-cat-couch.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/672x56-/cat-7784.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/672x56-/cat-animal-animal-portrait-pet.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/672x56-/cat-feline-cute-domestic.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/672x56-/cat-kitten-rozkosne-little.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/672x56-/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/336x28-/672x56-/eyes-cats-cat-couch.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/cat_468x6-_01.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/cat_468x6-_02.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/cat_468x6-_03.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/cat_468x6-_04.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/cat_468x6-_05.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/-2.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/-3.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/-4.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/-5.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/468x6-/cat_468x6-_-3.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/936x12-/cat_936x120_01.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/936x12-/cat_936x120_02.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/936x12-/cat_936x120_03.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/936x12-/cat_936x120_04.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/936x12-/cat_936x120_05.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/936x12-/cat_936x12-_-1.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/468x6-/936x12-/-4.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/cat_1200x50_01.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/cat_1200x50_02.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/cat_1200x50_03.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/cat_1200x50_04.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/cat_1200x50_05.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/-1.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/-2.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/-3.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/cat_12--x5-_-3.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/12--x5-/cat_12--x5-_-5.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/cat_2400x100_01.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/cat_2400x100_02.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/cat_2400x100_03.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/cat_2400x100_04.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/cat_2400x100_05.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/-1.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/-2.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/cat_24--x1--_-2.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/12--x5-/24--x1--/cat_24--x1--_-4.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/ad_1090x43_01.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/ad_1090x43_02.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/ad_1090x43_03.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/ad_1090x43_04.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/ad_1090x43_05.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/-3.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/-4.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/1-9-x43/ad_1-9-x43_-5.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/cat_2180x86_01.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/cat_2180x86_02.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/cat_2180x86_03.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/cat_2180x86_04.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/cat_2180x86_05.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/-2.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/-3.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/-4.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/-5.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/cat_218-x86_-1.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/1-9-x43/218-x86/cat_218-x86_-3.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/45-x62/cat_450x62_01.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/45-x62/cat_450x62_02.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/45-x62/cat_450x62_03.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/45-x62/cat_450x62_04.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/45-x62/cat_450x62_05.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/45-x62/-1.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/45-x62/-2.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_900x124_01.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_900x124_02.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_900x124_03.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_900x124_04.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_900x124_05.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/-1.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/-2.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/-3.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/-4.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/-5.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_9--x124_-1.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_9--x124_-2.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_9--x124_-3.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_9--x124_-4.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/45-x62/9--x124/cat_9--x124_-5.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/1440x90/cat_1440x90_01.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/1440x90/cat_1440x90_02.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/1440x90/cat_1440x90_03.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/1440x90/cat_1440x90_04.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/1440x90/cat_1440x90_05.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/2880x180/cat_2880x180_01.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/2880x180/cat_2880x180_02.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/2880x180/cat_2880x180_03.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/2880x180/cat_2880x180_04.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/2880x180/cat_2880x180_05.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/-1.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/-4.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/-5.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/cat_144-x9-_-1.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/cat_144-x9-_-2.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/cat_144-x9-_-3.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/cat_144-x9-_-4.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/144-x9-/cat_144-x9-_-5.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/-1.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/-2.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/-3.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/-4.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/-5.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/cat_288-x18-_-1.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/cat_288-x18-_-2.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/cat_288-x18-_-3.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/cat_288-x18-_-4.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/144-x9-/288-x18-/cat_288-x18-_-5.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x180_01.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x180_02.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x180_03.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x180_04.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x180_05.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_01.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_02.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_03.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_04.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_05.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_-3.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_-4.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_-6.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_-7.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_-8.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/1456x18-/cat_1456x18-_1-.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x90_01.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x90_02.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x90_03.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x90_04.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x90_05.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x9-_01.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x9-_02.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x9-_03.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x9-_04.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x9-_05.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x9-_-4.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/728x9-/728x9-/cat_728x9-_-1.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/34-x9-/Cats_34-x9-_01.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/34-x9-/Cats_34-x9-_02.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/34-x9-/Cats_34-x9-_03.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/34-x9-/Cats_34-x9-_04.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/34-x9-/Cats_34-x9-_05.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_01.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_02.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_03.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_04.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_05.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_-1.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_-2.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_-4.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_-5.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_-9.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_1-.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/34-x9-/68-x18-/Cats_68-x18-_11.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/16-x6--/32-x12--/cat-kitten-rozkosne-little.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/16-x6--/32-x12--/cat-7784.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/112-x1344/pexels-photo-437886.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/112-x1344/pexels-photo-2-8845.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/112-x1344/pexels-photo-21--81.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/112-x1344/pexels-photo-22-983.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/56-x672/pexels-photo-22-97-.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/56-x672/pexels-photo-416138.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/56-x672/pexels-photo-59659-.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/56-x672/pexels-photo-731553.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/56-x672/56-x672/pexels-photo-89951.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/cat-7784.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/cat-82-72.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/cat-feline-cute-domestic.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-1-5587.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-1-6131.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-142615.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-17242-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-1739-9.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2-8845.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2-886-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2-888-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2-89-6.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2-89-7.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2-9117.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2-98--.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-22-826.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-22-876.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-22-951.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-22-983.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-244848.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-2483-4.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-416138.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-549237.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-59659-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-599492.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-6-5-48.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-622549.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-674568.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-674577.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-679855.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-689-42.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-7-9482.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-7331-5.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-736528.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-745241.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/18-x68-/pexels-photo-749212.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/cat-7784.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/cat-82-72.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/cat-feline-cute-domestic.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/domestic-cat-cat-adidas-relaxed.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-1-5587.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-1-6131.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-142615.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-17242-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-1739-9.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2-8845.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2-886-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2-888-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2-89-6.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2-89-7.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2-9117.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2-98--.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-22-826.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-22-876.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-22-951.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-22-983.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-244848.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-2483-4.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-416138.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-549237.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-59659-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-599492.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-6-5-48.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-622549.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-674568.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-674577.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-679855.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-689-42.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-7-9482.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-7331-5.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-736528.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-745241.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Cats/18-x68-/36-x136-/pexels-photo-749212.jpg\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, require */

const dogData = __webpack_require__(84);

// Channel containing hard coded dogs loaded from CDN
// Subclass of Channel.
function DogsChannel() {
  Channel.call(this);
}
DogsChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    const listingArray = [];
    for (const dog of dogData) {
      listingArray.push(this.listingFactory(dog.width, dog.height, dog.url, 'This is a dog!', 'dogchannelswitchlabel'));
    }
    callback(listingArray);
  },
};

Object.assign(window, {
  DogsChannel,
});


/***/ }),
/* 84 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/animal-dog-golden-retriever-9716.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/animal-dog-pet-brown.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/dalmatians-dog-animal-head.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/dog-brown-snout-fur.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/dog-cute-pet.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/nature-animal-dog-pet.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/night-animal-dog-pet.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/night-garden-yellow-animal.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/wall-animal-dog-pet.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/animal-dog-golden-retriever-9716.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/animal-dog-pet-brown.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/dalmatians-dog-animal-head.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/dog-brown-snout-fur.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/dog-cute-pet.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/nature-animal-dog-pet.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/night-animal-dog-pet.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/night-garden-yellow-animal.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/wall-animal-dog-pet.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/animal-dog-golden-retriever-9716.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/animal-dog-pet-brown.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/dalmatians-dog-animal-head.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/dog-brown-snout-fur.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/dog-cute-pet.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/nature-animal-dog-pet.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/night-animal-dog-pet.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/night-garden-yellow-animal.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/wall-animal-dog-pet.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/animal-dog-golden-retriever-9716.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/animal-dog-pet-brown.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/dalmatians-dog-animal-head.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/dog-brown-snout-fur.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/dog-cute-pet.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/nature-animal-dog-pet.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/night-animal-dog-pet.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/night-garden-yellow-animal.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/wall-animal-dog-pet.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/animal-dog-golden-retriever-9716.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/animal-dog-pet-brown.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/dalmatians-dog-animal-head.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/dog-brown-snout-fur.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/dog-cute-pet.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/nature-animal-dog-pet.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/night-animal-dog-pet.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/night-garden-yellow-animal.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/wall-animal-dog-pet.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/animal-dog-golden-retriever-9716.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/animal-dog-pet-brown.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/dalmatians-dog-animal-head.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/dog-brown-snout-fur.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/dog-cute-pet.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/nature-animal-dog-pet.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/night-animal-dog-pet.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/night-garden-yellow-animal.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/wall-animal-dog-pet.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/animal-dog-golden-retriever-9716.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/animal-dog-pet-brown.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/dalmatians-dog-animal-head.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/dog-brown-snout-fur.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/dog-cute-pet.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/nature-animal-dog-pet.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/night-animal-dog-pet.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/night-garden-yellow-animal.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/wall-animal-dog-pet.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/animal-dog-golden-retriever-9716.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/animal-dog-pet-brown.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/dalmatians-dog-animal-head.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/dog-brown-snout-fur.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/dog-cute-pet.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/nature-animal-dog-pet.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/night-animal-dog-pet.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/night-garden-yellow-animal.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/wall-animal-dog-pet.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/dog_468x6-_01.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/dog_468x6-_02.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/dog_468x6-_03.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/dog_468x6-_04.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/dog_468x6-_05.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/-3.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/-4.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/dog_468x6-_-2.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/468x6-/dog_468x6-_-4.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x120_01.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x120_02.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x120_03.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x120_04.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x120_05.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/-1.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/-2.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/-3.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/-4.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/-5.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x12-_-1.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x12-_-2.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x12-_-4.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/468x6-/936x12-/dog_936x12-_-5.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/dog_450x62_01.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/dog_450x62_02.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/dog_450x62_03.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/dog_450x62_04.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/dog_450x62_05.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/-4.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/-5.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/45-x62/dog_45-x62_-1.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_900x124_01.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_900x124_02.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_900x124_03.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_900x124_04.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_900x124_05.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/-1.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/-3.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/-4.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/-5.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_9--x124_-1.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_9--x124_-2.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_9--x124_-3.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_9--x124_-4.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/45-x62/9--x124/dog_9--x124_-5.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1090x43_01.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1090x43_02.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1090x43_03.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1090x43_04.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1090x43_05.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/-2.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/-3.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1-9-x43_-1.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1-9-x43_-2.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/1-9-x43/dog_1-9-x43_-3.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_2180x86_01.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_2180x86_02.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_2180x86_03.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_2180x86_04.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_2180x86_05.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/-1.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/-2.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/-3.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/-5.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_218-x86_-2.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_218-x86_-3.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/1-9-x43/218-x86/dog_218-x86_-4.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/dog_1200x50_01.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/dog_1200x50_02.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/dog_1200x50_03.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/dog_1200x50_04.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/dog_1200x50_05.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/-2.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/dog_12--x5-_-2.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/12--x5-/dog_12--x5-_-3.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/dog_2400x100_01.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/dog_2400x100_02.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/dog_2400x100_03.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/dog_2400x100_04.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/dog_2400x100_05.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/-3.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/-4.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/dog_24--x1--_-1.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x5-/24--x1--/dog_24--x1--_-4.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/144-x9-/dog_1440x90_01.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/144-x9-/dog_1440x90_02.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/144-x9-/dog_1440x90_03.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/144-x9-/dog_1440x90_04.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/144-x9-/dog_1440x90_05.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/144-x9-/-5.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/144-x9-/dog_144-x9-_-2.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/dog_2880x180_01.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/dog_2880x180_02.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/dog_2880x180_03.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/dog_2880x180_04.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/dog_2880x180_05.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/-2.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/dog_288-x18-_-5.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/144-x9-/288-x18-/-5.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x180_01.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x180_02.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x180_03.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x180_04.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x180_05.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_01.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_02.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_03.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_04.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_05.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-1.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-2.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-3.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-4.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-5.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-6.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-7.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-8.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_-9.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_1-.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/1456x18-/Dog_1456x18-_11.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x90_01.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x90_02.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x90_03.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x90_04.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x90_05.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x9-_01.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x9-_02.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x9-_03.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x9-_04.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x9-_05.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x9-_-2.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/728x9-/728x9-/Dog_728x9-_-4.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_01.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_02.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_03.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_04.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_05.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_-1.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_-3.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_-4.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_-8.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_-9.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/34-x9-/Dogs_34-x9-_1-.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_01.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_02.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_03.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_04.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_05.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_-1.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_-2.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_-4.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_-5.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_-6.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_-7.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_-9.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_1-.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/34-x9-/68-x18-/Dogs_68-x18-_11.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/16-x6--/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/16-x6--/dog-cute-pet.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/16-x6--/wall-animal-dog-pet.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/32-x12--/animal-dog-pet-brown.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/32-x12--/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/32-x12--/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/32-x12--/night-garden-yellow-animal.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/56-x672/56-x672/pexels-photo-97863.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/56-x672/56-x672/dog-animal-friend-pointer-16226-.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/56-x672/56-x672/pexels-photo-594687.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/56-x672/112-x1344/pexels-photo-113883.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/56-x672/112-x1344/pexels-photo-434-9-.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/56-x672/112-x1344/pexels-photo-46-186.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/56-x672/112-x1344/pexels-photo-58997.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/12--x628/pexels-photo-89249.png\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/12--x628/24--x1256/pexels-photo-89249.png\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/3--x25-/pexels-photo-89249.png\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x25-/6--x5--/pexels-photo-89249.png\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/3--x6--/pexels-photo-89249.png\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/3--x6--/6--x12--/pexels-photo-89249.png\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/336x28-/pexels-photo-89249.png\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/336x28-/672x56-/pexels-photo-89249.png\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/16-x6--/16-x6--/pexels-photo-89249.png\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/dalmatians-dog-animal-head.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/dog-bernese-mountain-dog-berner-senner-dog-577-8.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/dog-bulldog-white-tongue-4-986.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/dog-cavalier-king-charles-spaniel-funny-pet-162193.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/dog-hybrid-animal-lying-162349.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/dog-young-dog-puppy-59965.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/english-bulldog-bulldog-canine-dog-4-544.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/french-bulldog-summer-smile-joy-16-846.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/nature-animal-dog-pet.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/papillon-dog-animal-59969.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-13-763.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-134392.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-164446.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-169524.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-2358-5.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-247997.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-25757-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-257577.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-271824.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-356378.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-3749-8.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-412465.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-4162-4.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-452772.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-46-132.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-46-823.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-485294.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-532423.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-58997.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-594687.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-612813.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-61372.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-66687-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-688694.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-71-927.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-72-678.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-752383.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-8--33-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/pexels-photo-9238-.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/tibet-terrier-cute-pet-dog-162276.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/wall-animal-dog-pet.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/weimaraner-puppy-dog-snout-97-82.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/wildlife-photography-pet-photography-dog-animal-159541.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/18-x68-/wildlife-photography-pet-photography-dog-dog-runs-159492.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/bordeaux-mastiff-dog-animal.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/dalmatians-dog-animal-head.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/dog-bernese-mountain-dog-berner-senner-dog-577-8.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/dog-bulldog-white-tongue-4-986.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/dog-cavalier-king-charles-spaniel-funny-pet-162193.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/dog-hybrid-animal-lying-162349.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/dog-young-dog-puppy-59965.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/dog-young-dog-small-dog-maltese.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/english-bulldog-bulldog-canine-dog-4-544.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/french-bulldog-summer-smile-joy-16-846.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/nature-animal-dog-pet.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/papillon-dog-animal-59969.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-13-763.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-134392.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-164446.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-169524.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-2358-5.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-247997.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-25757-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-257577.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-271824.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-356378.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-3749-8.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-412465.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-4162-4.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-452772.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-46-132.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-46-823.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-485294.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-532423.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-58997.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-594687.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-612813.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-61372.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-66687-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-688694.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-71-927.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-72-678.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-752383.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-8--33-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/pexels-photo-9238-.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/tibet-terrier-cute-pet-dog-162276.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/wall-animal-dog-pet.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/weimaraner-puppy-dog-snout-97-82.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/wildlife-photography-pet-photography-dog-animal-159541.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Dogs/18-x68-/36-x136-/wildlife-photography-pet-photography-dog-dog-runs-159492.jpg\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, require */

const landscapeData = __webpack_require__(86);

// Channel containing hard coded Landscapes loaded from CDN.
// Subclass of Channel.
function LandscapesChannel() {
  Channel.call(this);
}
LandscapesChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    const listingArray = [];
    for (const landscape of landscapeData) {
      listingArray.push(this.listingFactory(landscape.width, landscape.height, landscape.url, 'This is a landscape!', 'landscapechannelswitchlabel'));
    }
    callback(listingArray);
  },
};

Object.assign(window, {
  LandscapesChannel,
});


/***/ }),
/* 86 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/amazing-beautiful-beauty-blue.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/delicate-arch-night-stars-landscape.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/italian-landscape-mountains-nature.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/pexels-photo (1).jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/pexels-photo (2).jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/pexels-photo.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/road-sun-rays-path.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/12--x628/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/amazing-beautiful-beauty-blue.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/delicate-arch-night-stars-landscape.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/italian-landscape-mountains-nature.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/pexels-photo (1).jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/pexels-photo (2).jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/pexels-photo.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/road-sun-rays-path.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x628/24--x1256/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/amazing-beautiful-beauty-blue.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/delicate-arch-night-stars-landscape.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/italian-landscape-mountains-nature.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/pexels-photo (1).jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/pexels-photo (2).jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/pexels-photo.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/road-sun-rays-path.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/3--x25-/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/amazing-beautiful-beauty-blue.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/delicate-arch-night-stars-landscape.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/italian-landscape-mountains-nature.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/pexels-photo (1).jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/pexels-photo (2).jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/pexels-photo.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/road-sun-rays-path.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x25-/6--x5--/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/amazing-beautiful-beauty-blue.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/delicate-arch-night-stars-landscape.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/italian-landscape-mountains-nature.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/pexels-photo (1).jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/pexels-photo (2).jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/pexels-photo.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/road-sun-rays-path.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":300,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/3--x6--/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/amazing-beautiful-beauty-blue.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/delicate-arch-night-stars-landscape.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/italian-landscape-mountains-nature.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/pexels-photo (1).jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/pexels-photo (2).jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/pexels-photo.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/road-sun-rays-path.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/3--x6--/6--x12--/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/amazing-beautiful-beauty-blue.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/delicate-arch-night-stars-landscape.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/italian-landscape-mountains-nature.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/pexels-photo (1).jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/pexels-photo (2).jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/pexels-photo.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/road-sun-rays-path.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/336x28-/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/amazing-beautiful-beauty-blue.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/delicate-arch-night-stars-landscape.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/italian-landscape-mountains-nature.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/pexels-photo (1).jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/pexels-photo (2).jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/pexels-photo.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/road-sun-rays-path.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/336x28-/672x56-/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/1-9-x43/landscape_1090x43_01.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/1-9-x43/landscape_1090x43_02.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/1-9-x43/landscape_1090x43_03.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/1-9-x43/landscape_1090x43_04.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/1-9-x43/landscape_1090x43_05.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/1-9-x43/-2.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/1-9-x43/landscape_1-9-x43_-2.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/218-x86/landscape_2180x86_01.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/218-x86/landscape_2180x86_02.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/218-x86/landscape_2180x86_03.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/218-x86/landscape_2180x86_04.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/218-x86/landscape_2180x86_05.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/218-x86/landscape_218-x86_-1.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/1-9-x43/218-x86/landscape_218-x86_-4.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/landscape_450x62_01.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/landscape_450x62_02.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/landscape_450x62_03.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/landscape_450x62_04.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/landscape_450x62_05.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/-3.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/-4.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/-5.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/45-x62/landscape_45-x62_-5.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_900x124_01.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_900x124_02.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_900x124_03.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_900x124_04.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_900x124_05.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/-1.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/-2.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/-3.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/-4.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/-5.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_9--x124_-2.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_9--x124_-3.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/45-x62/9--x124/landscape_9--x124_-4.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/landscape_1440x90_01.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/landscape_1440x90_02.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/landscape_1440x90_03.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/landscape_1440x90_04.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/landscape_1440x90_05.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/-1.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/-2.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/-3.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/-5.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/landscape_144-x9-_-1.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/144-x9-/landscape_144-x9-_-3.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/landscape_2880x180_01.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/landscape_2880x180_02.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/landscape_2880x180_03.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/landscape_2880x180_04.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/landscape_2880x180_05.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/-3.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/landscape_288-x18-_-2.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/144-x9-/288-x18-/landscape_288-x18-_-5.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_1200x50_01.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_1200x50_02.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_1200x50_03.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_1200x50_04.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_1200x50_05.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/-1.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/-2.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/-3.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/-4.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/-5.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_12--x5-_-2.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_12--x5-_-3.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_12--x5-_-4.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_12--x5-_-5.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/12--x5-/landscape_12--x5-_-1.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_2400x100_01.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_2400x100_02.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_2400x100_03.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_2400x100_04.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_2400x100_05.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/-1.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/-2.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/-3.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/-4.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/-5.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_24--x1--_-1.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_24--x1--_-2.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_24--x1--_-3.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_24--x1--_-4.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/12--x5-/24--x1--/landscape_24--x1--_-5.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/468x6-/landscape_468x6-_01.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/468x6-/landscape_468x6-_02.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/468x6-/landscape_468x6-_03.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/468x6-/landscape_468x6-_04.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/468x6-/landscape_468x6-_05.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/468x6-/-4.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/468x6-/landscape_468x6-_-4.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/936x12-/landscape_936x120_01.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/936x12-/landscape_936x120_02.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/936x12-/landscape_936x120_03.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/936x12-/landscape_936x120_04.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/936x12-/landscape_936x120_05.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/936x12-/-1.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/468x6-/936x12-/landscape_936x12-_-3.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x180_01.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x180_02.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x180_03.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x180_04.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x180_05.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_01.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_02.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_03.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_04.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_05.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_-3.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_-4.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_-7.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_1-.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_11.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_12.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_15.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_17.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/1456x18-/Landscape_1456x18-_-2.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x90_01.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x90_02.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x90_03.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x90_04.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x90_05.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_01.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_02.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_03.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_04.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_05.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_-1.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_-4.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/728x9-/728x9-/Landscape_728x9-_-5.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_01.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_02.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_03.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_04.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_05.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_-2.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_-3.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_-4.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_1-.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/34-x9-/Landscape_34-x9-_11.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_01.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_02.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_03.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_04.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_05.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_-2.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_-3.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_-5.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_-6.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_-8.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_1-.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_11.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_12.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_14.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_15.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_16.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/34-x9-/68-x18-/Landscape_68-x18-_17.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/amazing-beautiful-beauty-blue.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/delicate-arch-night-stars-landscape.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/italian-landscape-mountains-nature.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/pexels-photo (1).jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/pexels-photo (2).jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/road-sun-rays-path.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/sunset-field-poppy-sun-priroda.jpg\"},{\"width\":160,\"height\":600,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/16-x6--/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/amazing-beautiful-beauty-blue.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/antelope-canyon-lower-canyon-arizona.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/italian-landscape-mountains-nature.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/pexels-photo (1).jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/pexels-photo (2).jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/road-sun-rays-path.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/sunrise-phu-quoc-island-ocean.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/16-x6--/32-x12--/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/18-x68-/pexels-photo-414-83.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/18-x68-/pexels-photo-351448.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/36-x136-/amazing-animal-beautiful-beautifull.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/36-x136-/pexels-photo-164196.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/36-x136-/pexels-photo-189848.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/36-x136-/pexels-photo-21-186.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/36-x136-/pexels-photo-221148.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/36-x136-/pexels-photo-388-65.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/18-x68-/36-x136-/pexels-photo-443446.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/112-x1344/pexels-photo-355241.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/112-x1344/pexels-photo-552791.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/112-x1344/switzerland-zermatt-mountains-snow.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/56-x672/boat-house-cottage-waters-lake-65225.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/56-x672/pexels-photo (1).jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/56-x672/pexels-photo-117843.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/56-x672/pexels-photo-221148.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Landscapes/56-x672/56-x672/yellowstone-national-park-sunset-twilight-dusk-158489.jpg\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, browser */

// Channel containing user imported images
// Subclass of Channel.

function CustomChannel() {
  Channel.call(this); // check if licensed in an init() function
  const that = this;

  // load the meta data Array from storage
  browser.storage.local.get(this.CUSTOM_META_KEY).then((customImageMetaData) => {
    const savedCustomImageMetaData = customImageMetaData;
    if (!savedCustomImageMetaData[this.CUSTOM_META_KEY]) {
      savedCustomImageMetaData[this.CUSTOM_META_KEY] = [];
    }
    const customMetaData = savedCustomImageMetaData[this.CUSTOM_META_KEY];
    for (let inx = 0; inx < customMetaData.length; inx++) {
      const listingData = customMetaData[inx];
      if (
        listingData
          && listingData.url
          && listingData.width
          && listingData.height
          && listingData.title
      ) {
        const theNewListing = that.createListing(listingData.width,
          listingData.height, listingData.url, listingData.title);
        that.listings.push(theNewListing);
      }
    }
  });
}
CustomChannel.prototype = {
  __proto__: Channel.prototype,
  createListing: function L(theWidth, theHeight, theURL, theName) {
    let width = theWidth;
    let height = theHeight;
    const url = theURL;
    const type = this.calculateType(width, height);

    if (typeof width === 'number') {
      width = `${width}`;
    }
    if (typeof height === 'number') {
      height = `${height}`;
    }
    return new Listing({
      width,
      height,
      url,
      attributionUrl: url,
      type,
      ratio: Math.max(width, height) / Math.min(width, height),
      title: `This is an image from your PC! : ${theName}`,
      channelName: 'custom_channel_name', // message.json key for channel name
      customImage: true,
    });
  },
  listings: [],
  CUSTOM_META_KEY: 'customMetaData',
  // to run - channels.channelGuide[channels.getIdByName("CustomChannel")].channel.deleteAll()
  deleteAll() {
    const customImagesArray = this.listings;
    for (let inx = 0; inx < customImagesArray.length; inx++) {
      if (customImagesArray[inx] && customImagesArray[inx].url) {
        browser.storage.local.remove(customImagesArray[inx].url);
      }
    }
    browser.storage.local.remove(this.CUSTOM_META_KEY).then(() => {
      this.listings = [];
    });
  },
  getLatestListings(callback) {
    callback(this.listings);
  },
  isMaximumAllowedImages() {
    return (this.listings.length >= 9);
  },
  saveListings() {
    const that = this;
    return new Promise((resolve, reject) => {
      const persistedMetaImageObj = {};
      persistedMetaImageObj[that.CUSTOM_META_KEY] = that.listings;
      browser.storage.local.set(persistedMetaImageObj).then(() => {
        if (browser.runtime.lastError) {
          reject(browser.runtime.lastError);
        }
        resolve(true);
      });
    });
  },
  removeListingByURL(theURLToRemove) {
    for (let inx = 0; inx < this.listings.length; inx++) {
      const theListing = this.listings[inx];
      if (theListing && theListing.url === theURLToRemove) {
        this.listings.splice(inx, 1);
      }
    }
    const that = this;
    return new Promise((resolve, reject) => {
      that.saveListings().then((response) => {
        if (response) {
          browser.storage.local.remove(theURLToRemove).then(() => {
            if (browser.runtime.lastError) {
              reject(browser.runtime.lastError);
            }
            resolve(true);
          });
        } else {
          resolve(response);
        }
      });
    });
  },
  addCustomImage(imageInfo) {
    const that = this;
    return new Promise((resolve, reject) => {
      const randomKey = `file:///${new Date().getTime()}`;
      const persistedImageObj = {};
      persistedImageObj[randomKey] = {
        name: imageInfo.name,
        width: imageInfo.width,
        height: imageInfo.height,
        src: imageInfo.imageAsBase64,
      };
      browser.storage.local.set(persistedImageObj).then(() => {
        if (browser.runtime.lastError) {
          reject(browser.runtime.lastError);
        }
        const theNewListing = this.createListing(imageInfo.width,
          imageInfo.height, randomKey, imageInfo.name);
        that.listings.push(theNewListing);
        that.saveListings()
          .then((response) => {
            if (response) {
              resolve(randomKey);
            } else {
              reject(response);
            }
          })
          .catch((response) => {
            reject(response);
          });
      });
    });
  },
  getBytesInUseForEachImage() {
    if (typeof browser.storage.local.getBytesInUse !== 'function') {
      return new Promise((resolve) => {
        resolve([0]);
      });
    }
    const customImagesArray = this.getListings();
    const promises = [];
    for (let inx = 0; inx < customImagesArray.length; inx++) {
      const thePromise = new Promise((resolve) => {
        if (customImagesArray[inx] && customImagesArray[inx].url) {
          browser.storage.local.getBytesInUse(customImagesArray[inx].url, (biu) => {
            resolve(biu);
          });
        }
      });
      promises.push(thePromise);
    }
    return Promise.all(promises);
  },
  getTotalBytesInUse() {
    if (typeof browser.storage.local.getBytesInUse !== 'function') {
      return new Promise((resolve) => {
        resolve(0);
      });
    }
    return new Promise((resolve) => {
      this.getBytesInUseForEachImage().then((results) => {
        let sum = 0;
        let numResults = results.length;
        while (numResults > 0) {
          numResults -= 1;
          sum += results[numResults];
        }
        resolve(sum);
      });
    });
  },
};

Object.assign(window, {
  CustomChannel,
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, require */

const birdData = __webpack_require__(89);

// Channel containing hard coded birds loaded from disk.
// Subclass of Channel.
function BirdChannel() {
  Channel.call(this);
}

BirdChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    const listingArray = [];
    for (const bird of birdData) {
      listingArray.push(this.listingFactory(bird.width, bird.height, bird.url, 'This is a bird!', 'birdchannelswitchlabel'));
    }
    callback(listingArray);
  },
};

Object.assign(window, {
  BirdChannel,
});


/***/ }),
/* 89 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_000.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_001.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_002.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_003.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_004.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_005.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_006.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_007.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_008.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_009.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_010.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_011.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_012.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_013.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_014.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_015.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_016.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_017.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/18-x68-/file_018.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_000.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_001.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_002.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_003.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_004.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_005.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_006.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_007.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_008.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_009.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_010.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_011.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_012.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_013.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_014.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_015.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_016.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_017.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_018.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_019.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_020.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_021.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_022.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_023.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_024.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_025.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_026.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_027.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_028.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_029.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_030.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_031.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_032.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_033.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_034.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_035.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_036.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_037.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_038.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_039.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_040.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_041.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_042.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_043.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_044.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_045.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_046.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_047.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_048.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_049.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_050.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_051.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_052.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_053.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_054.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_055.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_056.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_057.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_058.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_059.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_060.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_061.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_062.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_063.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_064.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_065.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_066.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_067.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_068.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_069.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_070.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_071.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_072.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_073.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_074.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_075.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_076.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_077.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_078.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_079.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_080.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_081.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_082.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_083.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_084.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_085.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_086.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_087.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_088.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_089.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_090.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_091.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_092.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_093.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_094.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_095.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_096.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_097.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/24--x1256/file_098.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_000.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_001.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_002.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_003.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_004.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_005.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_006.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_007.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_008.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_009.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_010.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_011.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_012.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_013.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_014.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_015.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_016.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_017.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_018.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_019.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_020.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_021.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_022.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_023.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_024.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_025.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_026.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_027.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_028.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_029.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_030.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_031.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_032.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_033.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_034.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_035.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_036.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_037.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_038.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_039.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_040.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_041.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_042.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_043.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_044.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_045.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_046.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_047.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_048.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_049.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_050.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_051.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_052.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_053.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_054.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_055.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_056.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_057.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_058.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_059.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_060.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_061.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_062.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_063.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_064.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_065.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_066.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_067.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_068.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_069.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_070.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_071.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_072.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_073.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_074.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_075.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_076.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_077.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_078.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_079.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_080.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_081.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_082.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_083.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_084.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_085.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_086.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_087.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_088.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_089.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_090.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_091.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_092.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_093.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_094.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_095.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_096.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_097.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/3--x25-/file_098.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_000.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_001.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_002.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_003.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_004.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_005.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_006.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_007.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_008.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_009.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_010.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_011.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_012.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_013.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_014.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_015.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_016.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_017.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_018.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_019.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_020.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_021.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_022.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_023.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_024.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_025.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_026.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_027.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_028.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_029.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_030.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_031.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_032.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_033.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_034.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_035.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_036.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_037.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_038.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_039.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_040.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_041.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_042.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_043.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_044.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_045.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_046.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_047.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_048.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_049.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_050.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_051.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_052.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_053.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_054.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_055.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_056.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_057.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_058.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_059.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_060.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_061.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_062.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_063.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_064.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_065.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_066.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_067.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_068.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_069.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_070.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_071.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_072.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_073.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_074.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_075.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_076.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_077.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_078.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_079.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_080.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_081.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_082.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_083.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_084.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_085.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_086.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_087.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_088.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_089.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_090.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_091.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_092.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_093.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_094.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_095.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_096.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_097.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/336x28-/file_098.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_000.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_001.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_002.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_003.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_004.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_005.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_006.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_007.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_008.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_009.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_010.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_011.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_012.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_013.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_014.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_015.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_016.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_017.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_018.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_019.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_020.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_021.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_022.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_023.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/36-x136-/file_024.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_000.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_001.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_002.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_003.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_004.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_005.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_006.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_007.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_008.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_009.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_010.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_011.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_012.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_013.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_014.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_015.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_016.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_017.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_018.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_019.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_020.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_021.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_022.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_023.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_024.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_025.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_026.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_027.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_028.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_029.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_030.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_031.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_032.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_033.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_034.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_035.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_036.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_037.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_038.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_039.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_040.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_041.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_042.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_043.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_044.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_045.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_046.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_047.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_048.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_049.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_050.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_051.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_052.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_053.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_054.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_055.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_056.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_057.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_058.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_059.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_060.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_061.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_062.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_063.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_064.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_065.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_066.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_067.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_068.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_069.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/6--x5--/file_070.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/random/file_000.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/random/file_001.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/random/file_002.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/random/file_003.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/random/file_004.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Birds/random/file_005.jpg\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, require */

const foodData = __webpack_require__(91);

// Channel containing hard coded cats loaded from disk.
// Subclass of Channel.
function FoodChannel() {
  Channel.call(this);
}

FoodChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    const listingArray = [];
    for (const food of foodData) {
      listingArray.push(this.listingFactory(food.width, food.height, food.url, 'This is food!', 'foodchannelswitchlabel'));
    }
    callback(listingArray);
  },
};

Object.assign(window, {
  FoodChannel,
});


/***/ }),
/* 91 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_000.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_001.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_002.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_003.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_004.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_005.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_006.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_007.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_008.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_009.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_010.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_011.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_012.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_013.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_014.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_015.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_016.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_017.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_018.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_019.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_020.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_021.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_022.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_023.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_024.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_025.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_026.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_027.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_028.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_029.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_030.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_031.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_032.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_033.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_034.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_035.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_036.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_037.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_038.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_039.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_040.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_041.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_042.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_043.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_044.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_045.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_046.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_047.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_048.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_049.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_050.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_051.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_052.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_053.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_054.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_055.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_056.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_057.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_058.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_059.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_060.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_061.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_062.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_063.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_064.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_065.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_066.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_067.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_068.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_069.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_070.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_071.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_072.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_073.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_074.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_075.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_076.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_077.jpg\"},{\"width\":\"180\",\"height\":\" 680\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/18-x68-/file_078.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_000.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_001.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_002.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_003.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_004.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_005.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_006.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_007.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_008.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_009.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_010.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_011.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_012.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_013.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_014.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_015.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_016.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_017.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_018.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_019.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_020.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_021.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_022.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_023.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_024.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_025.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_026.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_027.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_028.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_029.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_030.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_031.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_032.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_033.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_034.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_035.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_036.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_037.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_038.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_039.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_040.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_041.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_042.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_043.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_044.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_045.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_046.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_047.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_048.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_049.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_050.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_051.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_052.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_053.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_054.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_055.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_056.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_057.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_058.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_059.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_060.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_061.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_062.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_063.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_064.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_065.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_066.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_067.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_068.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_069.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_070.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_071.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_072.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_073.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_074.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_075.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_076.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_077.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_078.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_079.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_080.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_081.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_082.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_083.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_084.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_085.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_086.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_087.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_088.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_089.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_090.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_091.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_092.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_093.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_094.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_095.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_096.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_097.jpg\"},{\"width\":\"2400\",\"height\":\" 1256\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/24--x1256/file_098.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_000.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_001.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_002.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_003.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_004.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_005.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_006.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_007.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_008.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_009.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_010.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_011.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_012.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_013.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_014.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_015.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_016.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_017.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_018.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_019.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_020.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_021.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_022.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_023.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_024.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_025.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_026.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_027.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_028.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_029.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_030.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_031.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_032.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_033.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_034.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_035.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_036.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_037.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_038.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_039.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_040.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_041.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_042.jpg\"},{\"width\":\"300\",\"height\":\" 250\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/3--x25-/file_043.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_000.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_001.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_002.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_003.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_004.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_005.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_006.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_007.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_008.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_009.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_010.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_011.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_012.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_013.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_014.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_015.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_016.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_017.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_018.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_019.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_020.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_021.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_022.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_023.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_024.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_025.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_026.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_027.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_028.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_029.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_030.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_031.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_032.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_033.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_034.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_035.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_036.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_037.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_038.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_039.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_040.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_041.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_042.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_043.jpg\"},{\"width\":\"336\",\"height\":\" 280\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/336x28-/file_044.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_000.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_001.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_002.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_003.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_004.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_005.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_006.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_007.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_008.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_009.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_010.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_011.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_012.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_013.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_014.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_015.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_016.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_017.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_018.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_019.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_020.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_021.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_022.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_023.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_024.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_025.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_026.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_027.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_028.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_029.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_030.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_031.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_032.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_033.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_034.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_035.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_036.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_037.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_038.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_039.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_040.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_041.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_042.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_043.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_044.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_045.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_046.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_047.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_048.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_049.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_050.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_051.jpg\"},{\"width\":\"360\",\"height\":\" 1360\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/36-x136-/file_052.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_000.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_001.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_002.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_003.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_004.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_005.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_006.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_007.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_008.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_009.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_010.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_011.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_012.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_013.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_014.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_015.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_016.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_017.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_018.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_019.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_020.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_021.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_022.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_023.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_024.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_025.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_026.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_027.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_028.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_029.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_030.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_031.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_032.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_033.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_034.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_035.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_036.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_037.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_038.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_039.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_040.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_041.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_042.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_043.jpg\"},{\"width\":\"600\",\"height\":\" 500\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/6--x5--/file_044.jpg\"},{\"width\":\"1120\",\"height\":\" 1344\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/random/112-x1344.jpg\"},{\"width\":\"1200\",\"height\":\" 678\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/random/12--x678.jpg\"},{\"width\":\"320\",\"height\":\" 1200\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/random/32-x12--.jpg\"},{\"width\":\"570\",\"height\":\" 672\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/random/57-x672.jpg\"},{\"width\":\"600\",\"height\":\" 1200\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/random/6--x12--.jpg\"},{\"width\":\"672 560\",\"height\":\"https://cdn.adblockcdn.com/pix/Food/random/672x56-.jpg\",\"url\":\"\"},{\"width\":\"680\",\"height\":\" 180\",\"url\":\"https://cdn.adblockcdn.com/pix/Food/random/68-x18-.jpg\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, require */

const goatData = __webpack_require__(93);

// Channel containing hard coded cats loaded from disk.
// Subclass of Channel.
function GoatsChannel() {
  Channel.call(this);
}

GoatsChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    const listingArray = [];
    for (const goat of goatData) {
      listingArray.push(this.listingFactory(goat.width, goat.height, goat.url, 'This is a goat!', 'goatchannelswitchlabel'));
    }
    callback(listingArray);
  },
};

Object.assign(window, {
  GoatsChannel,
});


/***/ }),
/* 93 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_000.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_001.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_002.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_003.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_004.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_005.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_006.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_007.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_008.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/18-x68-/file_009.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_000.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_001.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_002.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_003.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_004.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_005.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_006.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_007.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_008.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_009.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_010.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_011.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_012.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_013.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_014.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_015.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_016.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_017.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_018.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_019.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_020.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_021.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_022.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_023.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/24--x1256/file_024.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_000.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_001.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_002.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_003.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_004.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_005.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_006.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_007.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_008.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_009.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_010.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_011.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_012.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_013.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_014.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_015.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_016.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_017.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_018.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_019.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_020.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_021.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_022.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_023.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/3--x25-/file_024.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_000.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_001.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_002.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_003.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_004.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_005.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_006.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_007.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_008.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_009.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_010.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_011.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_012.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_013.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_014.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_015.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_016.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_017.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_018.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_019.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_020.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_021.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_022.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_023.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/336x28-/file_024.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_000.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_001.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_002.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_003.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_004.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_005.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_006.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_007.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_008.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/36-x136-/file_009.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_000.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_001.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_002.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_003.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_004.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_005.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_006.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_007.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_008.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_009.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_010.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_011.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_012.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_013.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_014.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_015.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_016.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_017.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_018.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_019.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_020.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_021.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/6--x5--/file_022.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_000.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_001.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_002.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_003.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_004.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_005.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_006.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_007.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_008.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Goats/file_009.jpg\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel, Listing, require */

const oceanData = __webpack_require__(95);

// Channel containing hard coded cats loaded from disk.
// Subclass of Channel.
function OceanChannel() {
  Channel.call(this);
}

OceanChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    const listingArray = [];
    for (const ocean of oceanData) {
      listingArray.push(this.listingFactory(ocean.width, ocean.height, ocean.url, 'This is a ocean!', 'oceanchannelswitchlabel'));
    }
    callback(listingArray);
  },
};

Object.assign(window, {
  OceanChannel,
});


/***/ }),
/* 95 */
/***/ (function(module) {

module.exports = JSON.parse("[{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_000.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_001.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_002.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_003.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_004.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_005.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_006.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_007.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_008.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_009.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_010.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_011.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_012.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_013.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_014.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_015.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_016.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_017.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_018.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_019.jpg\"},{\"width\":180,\"height\":680,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/18-x68-/file_020.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_000.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_001.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_002.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_003.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_004.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_005.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_006.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_007.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_008.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_009.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_010.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_011.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_012.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_013.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_014.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_015.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_016.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_017.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_018.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_019.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_020.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_021.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_022.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_023.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_024.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_025.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_026.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_027.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_028.jpg\"},{\"width\":2400,\"height\":1256,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/24--x1256/file_029.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_000.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_001.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_002.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_003.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_004.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_005.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_006.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_007.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_008.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_009.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_010.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_011.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_012.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_013.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_014.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_015.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_016.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_017.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_018.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_019.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_020.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_021.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_022.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_023.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_024.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_025.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_026.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_027.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_028.jpg\"},{\"width\":300,\"height\":250,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/3--x25-/file_029.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_000.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_001.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_002.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_003.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_004.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_005.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_006.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_007.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_008.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_009.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_010.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_011.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_012.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_013.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_014.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_015.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_016.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_017.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_018.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_019.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_020.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_021.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_022.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_023.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_024.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_025.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_026.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_027.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_028.jpg\"},{\"width\":336,\"height\":280,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/336x28-/file_029.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_000.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_001.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_002.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_003.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_004.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_005.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_006.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_007.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_008.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_009.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_010.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_011.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_012.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_013.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_014.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_015.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_016.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_017.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_018.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_019.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_020.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_021.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_022.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_023.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_024.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_025.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_026.jpg\"},{\"width\":360,\"height\":1360,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/36-x136-/file_027.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_000.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_001.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_002.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_003.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_004.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_005.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_006.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_007.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_008.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_009.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_010.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_011.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_012.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_013.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_014.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_015.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_016.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_017.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_018.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_019.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_020.jpg\"},{\"width\":600,\"height\":500,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/6--x5--/file_021.jpg\"},{\"width\":1200,\"height\":628,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_000.jpg\"},{\"width\":600,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_001.jpg\"},{\"width\":672,\"height\":560,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_002.jpg\"},{\"width\":468,\"height\":60,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_003.jpg\"},{\"width\":936,\"height\":120,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_004.jpg\"},{\"width\":1200,\"height\":50,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_005.jpg\"},{\"width\":2400,\"height\":100,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_006.jpg\"},{\"width\":1090,\"height\":43,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_007.jpg\"},{\"width\":2180,\"height\":86,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_008.jpg\"},{\"width\":450,\"height\":62,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_009.jpg\"},{\"width\":900,\"height\":124,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_010.jpg\"},{\"width\":1440,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_011.jpg\"},{\"width\":2880,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_012.jpg\"},{\"width\":1456,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_013.jpg\"},{\"width\":728,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_014.jpg\"},{\"width\":340,\"height\":90,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_015.jpg\"},{\"width\":680,\"height\":180,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_016.jpg\"},{\"width\":320,\"height\":1200,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_017.jpg\"},{\"width\":1120,\"height\":1344,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_018.jpg\"},{\"width\":560,\"height\":672,\"url\":\"https://cdn.adblockcdn.com/pix/Oceans/random/file_019.jpg\"}]");

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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global Channel */

// Empty Channel
// Subclass of Channel.
//
// Allows the Sync process to create an new named Channel
// when the sync process recieves a request with a unknown channel name
function UnknownChannel() {
  Channel.call(this);
}

UnknownChannel.prototype = {
  __proto__: Channel.prototype,

  getLatestListings(callback) {
    callback([]);
  },
};

Object.assign(window, {
  UnknownChannel,
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global ext, browser, require, storageGet, storageSet, log, STATS, Channels, Prefs,
   getSettings, setSetting, translate, reloadOptionsPageTabs, filterNotifier, openTab,
   emitPageBroadcast, SyncService, Subscription, filterStorage, unsubscribe */

// Yes, you could hack my code to not check the license.  But please don't.
// Paying for this extension supports the work on AdBlock.  Thanks very much.
const { EventEmitter } = __webpack_require__(12);
const { checkAllowlisted } = __webpack_require__(8);
const { recordGeneralMessage } = __webpack_require__(19).ServerMessages;
const { loadAdBlockSnippets } = __webpack_require__(38);
const { showIconBadgeCTA, NEW_BADGE_REASONS } = __webpack_require__(21);

const licenseNotifier = new EventEmitter();
const newBadgeShownForDCKey = 'new_badge_shown_dc';

const License = (function getLicense() {
  const isProd = true;
  const licenseStorageKey = 'license';
  const installTimestampStorageKey = 'install_timestamp';
  const userClosedSyncCTAKey = 'user_closed_sync_cta';
  const userSawSyncCTAKey = 'user_saw_sync_cta';
  const pageReloadedOnSettingChangeKey = 'page_reloaded_on_user_settings_change';
  const licenseAlarmName = 'licenseAlarm';
  const sevenDayAlarmName = 'sevenDayLicenseAlarm';

  let theLicense;
  const fiveMinutes = 300000;
  const initialized = false;
  let ajaxRetryCount = 0;
  let readyComplete;
  const licensePromise = new Promise(((resolve) => {
    readyComplete = resolve;
  }));
  const themesForCTA = [
    'solarized_theme', 'solarized_light_theme', 'watermelon_theme', 'sunshine_theme', 'ocean_theme',
  ];
  let currentThemeIndex = 0;
  const mabConfig = {
    prod: {
      licenseURL: 'https://myadblock-licensing.firebaseapp.com/license/',
      syncURL: 'https://myadblock.sync.getadblock.com/v1/sync',
      subscribeKey: 'sub-c-9eccffb2-8c6a-11e9-97ab-aa54ad4b08ec',
      payURL: 'https://getadblock.com/premium/enrollment/',
      subscriptionURL: 'https://getadblock.com/premium/manage-subscription/',
    },
    dev: {
      licenseURL: 'https://dev.myadblock.licensing.getadblock.com/license/',
      syncURL: 'https://dev.myadblock.sync.getadblock.com/v1/sync',
      subscribeKey: 'sub-c-9e0a7270-83e7-11e9-99de-d6d3b84c4a25',
      payURL: 'https://getadblock.com/premium/enrollment/?testmode=true',
      subscriptionURL: 'https://dev.getadblock.com/premium/manage-subscription/',
    },
  };
  STATS.untilLoaded((userID) => {
    mabConfig.prod.payURL = `${mabConfig.prod.payURL}?u=${userID}`;
    mabConfig.dev.payURL = `${mabConfig.dev.payURL}&u=${userID}`;
  });
  const MAB_CONFIG = isProd ? mabConfig.prod : mabConfig.dev;

  const sevenDayAlarmIdleListener = function (newState) {
    if (newState === 'active') {
      License.checkSevenDayAlarm();
    }
  };

  const removeSevenDayAlarmStateListener = function () {
    browser.idle.onStateChanged.removeListener(sevenDayAlarmIdleListener);
  };

  const addSevenDayAlarmStateListener = function () {
    removeSevenDayAlarmStateListener();
    browser.idle.onStateChanged.addListener(sevenDayAlarmIdleListener);
  };

  const cleanUpSevenDayAlarm = function () {
    removeSevenDayAlarmStateListener();
    browser.storage.local.remove(License.sevenDayAlarmName);
    browser.alarms.clear(License.sevenDayAlarmName);
  };

  const processSevenDayAlarm = function () {
    cleanUpSevenDayAlarm();
    showIconBadgeCTA(true, NEW_BADGE_REASONS.SEVEN_DAY);
  };

  browser.alarms.onAlarm.addListener((alarm) => {
    if (alarm && alarm.name === licenseAlarmName) {
      // At this point, no alarms exists, so
      // create an temporary alarm to avoid race condition issues
      browser.alarms.create(licenseAlarmName, { delayInMinutes: (24 * 60) });
      License.ready().then(() => {
        License.updatePeriodically();
      });
    }
    if (alarm && alarm.name === sevenDayAlarmName) {
      processSevenDayAlarm();
    }
  });

  // Check if the computer was woken up, and if there was a pending alarm
  // that should fired during the sleep, then
  // remove it, and fire the update ourselves.
  // see - https://bugs.chromium.org/p/chromium/issues/detail?id=471524
  browser.idle.onStateChanged.addListener((newState) => {
    if (newState === 'active') {
      browser.alarms.get(licenseAlarmName, (alarm) => {
        if (alarm && Date.now() > alarm.scheduledTime) {
          browser.alarms.clear(licenseAlarmName, () => {
            License.updatePeriodically();
          });
        } else if (alarm) {
          // if the alarm should fire in the future,
          // re-add the license so it fires at the correct time
          const originalTime = alarm.scheduledTime;
          browser.alarms.clear(licenseAlarmName, (wasCleared) => {
            if (wasCleared) {
              browser.alarms.create(licenseAlarmName, { when: originalTime });
            }
          });
        } else {
          License.updatePeriodically();
        }
      });
    }
  });

  // check the 7 alarm when the browser starts
  // or is woken up
  const checkSevenDayAlarm = function () {
    browser.alarms.get(License.sevenDayAlarmName, (alarm) => {
      if (alarm && Date.now() > alarm.scheduledTime) {
        browser.alarms.clear(License.sevenDayAlarmName, () => {
          showIconBadgeCTA(true, NEW_BADGE_REASONS.SEVEN_DAY);
          removeSevenDayAlarmStateListener();
          browser.storage.local.remove(License.sevenDayAlarmName);
        });
      } else if (alarm) {
        // if the alarm should fire in the future,
        // re-add the license so it fires at the correct time
        const originalTime = alarm.scheduledTime;
        browser.alarms.clear(License.sevenDayAlarmName, (wasCleared) => {
          if (wasCleared) {
            browser.alarms.create(License.sevenDayAlarmName, { when: originalTime });
            browser.storage.local.set({ [License.sevenDayAlarmName]: true });
            License.addSevenDayAlarmStateListener();
          }
        });
      } else {
        // since there's no alarm, we may need to show the 'new' text,
        // check if the temporary seven day alarm indicator is set, and
        // if the install date is 7 days or more than now
        browser.storage.local.get(License.sevenDayAlarmName).then((data) => {
          if (data && data[License.sevenDayAlarmName]) {
            browser.storage.local.get('blockage_stats').then((response) => {
              const { blockage_stats } = response;
              if (blockage_stats && blockage_stats.start) {
                const installDate = new Date(blockage_stats.start);
                const now = new Date();
                const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
                const diffDays = Math.round((now - installDate) / oneDay);
                if (diffDays >= 7) {
                  showIconBadgeCTA(true, NEW_BADGE_REASONS.SEVEN_DAY);
                  removeSevenDayAlarmStateListener();
                  browser.storage.local.remove(License.sevenDayAlarmName);
                }
              }
            });
          }
        });
        removeSevenDayAlarmStateListener();
      }
    });
  };
  addSevenDayAlarmStateListener();

  // Load the license from persistent storage
  // Should only be called during startup / initialization
  const loadFromStorage = function (callback) {
    browser.storage.local.get(licenseStorageKey).then((response) => {
      const localLicense = storageGet(licenseStorageKey);
      theLicense = response[licenseStorageKey] || localLicense || {};
      if (typeof callback === 'function') {
        callback();
      }
    });
  };
  const checkForManagedSettings = function () {
    return new Promise(((resolve) => {
      if ('managed' in browser.storage) {
        browser.storage.managed.get(null).then((items) => {
          for (const key in items) {
            if (key === 'suppress_premium_cta') {
              theLicense = License.get();
              theLicense[key] = items[key];
              License.set(theLicense);
            }
          }
          resolve();
        },
        // Opera and FF doesn't support browser.storage.managed, but instead of simply
        // removing the API, it gives an asynchronous error which we ignore here.
        () => {
          resolve();
        });
      } else {
        resolve();
      }
    }));
  };

  return {
    licenseStorageKey,
    userClosedSyncCTAKey,
    userSawSyncCTAKey,
    themesForCTA,
    pageReloadedOnSettingChangeKey,
    initialized,
    licenseAlarmName,
    sevenDayAlarmName,
    checkSevenDayAlarm,
    addSevenDayAlarmStateListener,
    removeSevenDayAlarmStateListener,
    cleanUpSevenDayAlarm,
    licenseTimer: undefined, // the license update timer token
    licenseNotifier,
    MAB_CONFIG,
    isProd,
    enrollUser(enrollReason) {
      loadFromStorage(() => {
        // only enroll users if they were not previously enrolled
        if (typeof theLicense.myadblock_enrollment === 'undefined') {
          theLicense.myadblock_enrollment = true;
          License.set(theLicense);
          if (enrollReason === 'update') {
            showIconBadgeCTA(true, NEW_BADGE_REASONS.UPDATE);
          }
        }
      });
    },
    get() {
      return theLicense;
    },
    set(newLicense) {
      if (newLicense) {
        theLicense = newLicense;
        // store in redudant locations
        browser.storage.local.set({ license: theLicense });
        storageSet('license', theLicense);
      }
    },
    initialize(callback) {
      loadFromStorage(() => {
        checkForManagedSettings().then(() => {
          if (typeof callback === 'function') {
            callback();
          }
          readyComplete();
        });
      });
    },
    getCurrentPopupMenuThemeCTA() {
      const theme = License.themesForCTA[currentThemeIndex];
      const lastThemeIndex = License.themesForCTA.length - 1;
      currentThemeIndex = lastThemeIndex === currentThemeIndex ? 0 : currentThemeIndex += 1;
      return theme || '';
    },
    // Get the latest license data from the server, and talk to the user if needed.
    update() {
      STATS.untilLoaded((userID) => {
        licenseNotifier.emit('license.updating');
        const postData = {};
        postData.u = userID;
        postData.cmd = 'license_check';
        const licsenseStatusBefore = License.get().status;
        // license version
        postData.v = '1';
        $.ajax({
          jsonp: false,
          url: License.MAB_CONFIG.licenseURL,
          type: 'post',
          success(text) {
            ajaxRetryCount = 0;
            let updatedLicense = {};
            if (typeof text === 'object') {
              updatedLicense = text;
            } else if (typeof text === 'string') {
              try {
                updatedLicense = JSON.parse(text);
              } catch (e) {
                // eslint-disable-next-line no-console
                console.log('Something went wrong with parsing license data.');
                // eslint-disable-next-line no-console
                console.log('error', e);
                // eslint-disable-next-line no-console
                console.log(text);
                return;
              }
            }
            licenseNotifier.emit('license.updated', updatedLicense);
            if (!updatedLicense) {
              return;
            }
            // merge the updated license
            theLicense = $.extend(theLicense, updatedLicense);
            theLicense.licenseId = theLicense.code;
            License.set(theLicense);
            // now check to see if we need to do anything because of a status change
            if (
              licsenseStatusBefore === 'active'
              && updatedLicense.status
              && updatedLicense.status === 'expired'
            ) {
              License.processExpiredLicense();
              recordGeneralMessage('trial_license_expired');
            }
          },
          error(xhr, textStatus, errorThrown) {
            log('license server error response', xhr, textStatus, errorThrown, ajaxRetryCount);
            licenseNotifier.emit('license.updated.error', ajaxRetryCount);
            ajaxRetryCount += 1;
            if (ajaxRetryCount > 3) {
              log('Retry Count exceeded, giving up', ajaxRetryCount);
              return;
            }
            const oneMinute = 1 * 60 * 1000;
            setTimeout(() => {
              License.updatePeriodically(`error${ajaxRetryCount}`);
            }, oneMinute);
          },
          data: postData,
        });
      });
    },
    processExpiredLicense() {
      theLicense = License.get();
      theLicense.myadblock_enrollment = true;
      License.set(theLicense);
      setSetting('picreplacement', false);
      if (getSettings().sync_settings) {
        SyncService.disableSync();
      }
      setSetting('color_themes', { popup_menu: 'default_theme', options_page: 'default_theme' });
      unsubscribe({ id: 'distraction-control-push' });
      unsubscribe({ id: 'distraction-control-newsletter' });
      unsubscribe({ id: 'distraction-control-survey' });
      unsubscribe({ id: 'distraction-control-video' });
      browser.alarms.clear(licenseAlarmName);
    },
    ready() {
      return licensePromise;
    },
    updatePeriodically() {
      if (!License.isActiveLicense()) {
        return;
      }
      License.update();
      browser.storage.local.get(installTimestampStorageKey).then((response) => {
        let installTimestamp = response[installTimestampStorageKey];
        const localTimestamp = storageGet(installTimestampStorageKey);
        const originalInstallTimestamp = installTimestamp || localTimestamp || Date.now();
        // If the installation timestamp is missing from both storage locations,
        // save an updated version
        if (!(response[installTimestampStorageKey] || localTimestamp)) {
          installTimestamp = Date.now();
          storageSet(installTimestampStorageKey, installTimestamp);
          browser.storage.local.set({ install_timestamp: installTimestamp });
        }
        const originalInstallDate = new Date(originalInstallTimestamp);
        let nextLicenseCheck = new Date();
        if (originalInstallDate.getHours() <= nextLicenseCheck.getHours()) {
          nextLicenseCheck.setDate(nextLicenseCheck.getDate() + 1);
        }
        nextLicenseCheck.setHours(originalInstallDate.getHours());
        nextLicenseCheck.setMinutes(originalInstallDate.getMinutes());
        // Add 5 minutes to the 'minutes' to make sure we've allowed enought time for '1' day
        nextLicenseCheck = new Date(nextLicenseCheck.getTime() + fiveMinutes);
        browser.alarms.create(licenseAlarmName, { when: nextLicenseCheck.getTime() });
      });
    },
    getLicenseInstallationDate(callback) {
      if (typeof callback !== 'function') {
        return;
      }
      browser.storage.local.get(installTimestampStorageKey).then((response) => {
        const localTimestamp = storageGet(installTimestampStorageKey);
        const originalInstallTimestamp = response[installTimestampStorageKey] || localTimestamp;
        if (originalInstallTimestamp) {
          callback(new Date(originalInstallTimestamp));
        } else {
          callback(undefined);
        }
      });
    },
    // activate the current license and configure the extension in licensed mode.
    // Call with an optional delay parameter (in milliseconds) if the first license
    // update should be delayed by a custom delay (default is 0 minutes).
    activate(delayMs) {
      let delay = delayMs;
      const currentLicense = License.get() || {};
      currentLicense.status = 'active';
      License.set(currentLicense);
      reloadOptionsPageTabs();
      if (typeof delay !== 'number') {
        delay = 0; // 0 minutes
      }
      if (!this.licenseTimer) {
        this.licenseTimer = window.setTimeout(() => {
          License.updatePeriodically();
        }, delay);
      }
      setSetting('picreplacement', false);
      loadAdBlockSnippets();
    },
    getFormattedActiveSinceDate() {
      if (
        !License
        || !License.isActiveLicense()
        || !License.get()
        || !License.get().createdAtUTC
        || !Number.isInteger(License.get().createdAtUTC)
      ) {
        return null;
      }
      const dateFormat = { year: 'numeric', month: 'long' };
      let formattedDate = null;
      try {
        const createdAtUTC = parseInt(License.get().createdAtUTC, 10);
        formattedDate = new Date(createdAtUTC).toLocaleDateString(undefined, dateFormat);
      } catch (e) {
        return null;
      }
      return formattedDate;
    },
    isActiveLicense() {
      return License && License.get() && License.get().status === 'active';
    },
    isLicenseCodeValid() {
      return License && License.get().code && typeof License.get().code === 'string';
    },
    isMyAdBlockEnrolled() {
      return License && License.get() && License.get().myadblock_enrollment === true;
    },
    shouldShowMyAdBlockEnrollment() {
      return License.isMyAdBlockEnrolled()
        && !License.isActiveLicense()
        && License.shouldShowPremiumCTA();
    },
    shouldShowPremiumDcCTA() {
      return (License && License.isActiveLicense() && License.get().suppress_premium_cta !== true);
    },
    shouldShowPremiumCTA() {
      return !(License && License.get().suppress_premium_cta === true);
    },
    shouldShowBlacklistCTA(newValue) {
      if (!License.shouldShowPremiumCTA()) {
        return false;
      }
      const currentLicense = License.get() || {};
      if (typeof newValue === 'boolean') {
        currentLicense.showBlacklistCTA = newValue;
        License.set(currentLicense);
        return null;
      }

      if (typeof currentLicense.showBlacklistCTA === 'undefined') {
        currentLicense.showBlacklistCTA = true;
        License.set(currentLicense);
      }
      return License && License.get() && License.get().showBlacklistCTA === true;
    },
    shouldShowWhitelistCTA(newValue) {
      if (!License.shouldShowPremiumCTA()) {
        return false;
      }
      const currentLicense = License.get() || {};
      if (typeof newValue === 'boolean') {
        currentLicense.showWhitelistCTA = newValue;
        License.set(currentLicense);
        return null;
      }

      if (typeof currentLicense.showWhitelistCTA === 'undefined') {
        currentLicense.showWhitelistCTA = true;
        License.set(currentLicense);
      }
      return License && License.get() && License.get().showWhitelistCTA === true;
    },
    displayPopupMenuNewCTA() {
      const isNotActive = !License.isActiveLicense();
      const variant = License.get() ? License.get().var : undefined;
      return License && isNotActive && [3, 4].includes(variant) && License.shouldShowPremiumCTA();
    },
    // fetchLicenseAPI automates the common steps required to call the /license/api endpoint.
    // POST bodies will always automatically contain the command, license and userid so only
    // provide the missing fields in the body parameter. The ok callback handler receives the
    // data returned by the API and the fail handler receives any error information available.
    fetchLicenseAPI(command, requestBody, ok, requestFail) {
      const licenseCode = License.get().code;
      const userID = STATS.userId();
      const body = requestBody;
      let fail = requestFail;
      body.cmd = command;
      body.userid = userID;
      if (licenseCode) {
        body.license = licenseCode;
      }
      const request = new Request('https://myadblock.licensing.getadblock.com/license/api/', {
        method: 'POST',
        body: JSON.stringify(body),
      });
      fetch(request)
        .then((response) => {
          if (response.ok) {
            return response.json();
          }
          fail(response.status);
          fail = null;
          return Promise.resolve({});
        })
        .then((data) => {
          ok(data);
        })
        .catch((err) => {
          fail(err);
        });
    },
  };
}());

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.command === 'payment_success' && request.version === 1) {
    License.activate();
    sendResponse({ ack: true });
  }
});

const replacedPerPage = new ext.PageMap();

// Records how many ads have been replaced by AdBlock.  This is used
// by the AdBlock to display statistics to the user.
const replacedCounts = (function getReplacedCount() {
  const adReplacedNotifier = new EventEmitter();
  const key = 'replaced_stats';
  let data = storageGet(key);
  if (!data) {
    data = {};
  }
  if (data.start === undefined) {
    data.start = Date.now();
  }
  if (data.total === undefined) {
    data.total = 0;
  }
  data.version = 1;
  storageSet(key, data);

  return {
    recordOneAdReplaced(tabId) {
      data = storageGet(key);
      data.total += 1;
      storageSet(key, data);
      browser.tabs.get(tabId).then((tab) => {
        const myPage = new ext.Page(tab);
        let replaced = replacedPerPage.get(myPage) || 0;
        replacedPerPage.set(myPage, replaced += 1);
        adReplacedNotifier.emit('adReplaced', tabId, tab.url);
      });
    },
    get() {
      return storageGet(key);
    },
    getTotalAdsReplaced(tabId) {
      if (tabId) {
        return replacedPerPage.get(ext.getPage(tabId));
      }
      return this.get().total;
    },
    adReplacedNotifier,
  };
}());

// for use in the premium enrollment process
// de-coupled from the `License.ready().then` code below because the delay
// prevents the addListener from being fired in a timely fashion.
const onInstalledPromise = new Promise(((resolve) => {
  browser.runtime.onInstalled.addListener((details) => {
    resolve(details);
  });
}));
const onBehaviorPromise = new Promise(((resolve) => {
  filterNotifier.on('filter.behaviorChanged', () => {
    resolve();
  });
}));
// the order of Promises below dictacts the order of the data in the detailsArray
Promise.all([onInstalledPromise, License.ready(), onBehaviorPromise]).then((detailsArray) => {
  // Enroll existing users in Premium
  if (detailsArray.length > 0 && detailsArray[0].reason) {
    License.enrollUser(detailsArray[0].reason);
    if (detailsArray[0].reason === 'install') {
      // create an alarm that will fire in ~ 7 days to show the "New" badge text
      browser.alarms.create(License.sevenDayAlarmName, { delayInMinutes: (60 * 24 * 7) });
      License.addSevenDayAlarmStateListener();
      browser.storage.local.set({ [License.sevenDayAlarmName]: true });
    }
  }
});

let channels = {};
License.ready().then(() => {
  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (!(request.message === 'load_my_adblock')) {
      return;
    }
    if (
      License.isActiveLicense()
      && sender.url
      && sender.url.startsWith('http')
      && getSettings().picreplacement
    ) {
      const logError = function (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      };
      browser.tabs.executeScript(sender.tab.id, { file: 'adblock-picreplacement-image-sizes-map.js', frameId: sender.frameId, runAt: 'document_start' }).catch(logError);
      browser.tabs.executeScript(sender.tab.id, { file: 'adblock-picreplacement.js', frameId: sender.frameId, runAt: 'document_start' }).catch(logError);
    }
    const subscription = Subscription.fromURL('https://cdn.adblockcdn.com/filters/distraction-control-push.txt');
    if (
      License.isActiveLicense()
      && sender.url
      && sender.url.startsWith('http')
      && filterStorage.hasSubscription(subscription)
      && !checkAllowlisted(new ext.Page(sender.tab))
    ) {
      const logError = function (e) {
        // eslint-disable-next-line no-console
        console.error(e);
      };
      browser.tabs.executeScript(sender.tab.id, { file: 'adblock-picreplacement-push-notification-wrapper-cs.js', runAt: 'document_start' }).catch(logError);
    }
    sendResponse({});
  });

  channels = new Channels();
  Object.assign(window, {
    channels,
  });
  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.message !== 'get_random_listing') {
      return;
    }

    const myPage = ext.getPage(sender.tab.id);
    if (checkAllowlisted(myPage) || !License.isActiveLicense()) {
      sendResponse({ disabledOnPage: true });
      return;
    }
    const result = channels.randomListing(request.opts);
    if (result) {
      sendResponse(result);
    } else {
      // if not found, and data collection enabled, send message to log server with domain,
      // and request
      sendResponse({ disabledOnPage: true });
    }
  });

  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.message === 'recordOneAdReplaced') {
      sendResponse({});
      if (License.isActiveLicense()) {
        replacedCounts.recordOneAdReplaced(sender.tab.id);
      }
    }
  });

  License.checkSevenDayAlarm();

  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.command === 'setBlacklistCTAStatus') {
      if (typeof request.isEnabled === 'boolean') {
        License.shouldShowBlacklistCTA(request.isEnabled);
      }
      sendResponse({});
    }
  });

  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.command === 'setWhitelistCTAStatus') {
      if (typeof request.isEnabled === 'boolean') {
        License.shouldShowWhitelistCTA(request.isEnabled);
      }
      sendResponse({});
    }
  });

  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.command === 'openPremiumPayURL') {
      openTab(License.MAB_CONFIG.payURL);
      sendResponse({});
    }
  });

  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.command === 'cleanUpSevenDayAlarm') {
      License.cleanUpSevenDayAlarm();
      sendResponse({});
    }
  });

  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.command === 'License.MAB_CONFIG' && typeof request.url === 'string') {
      sendResponse({ url: License.MAB_CONFIG[request.url] });
    }
  });

  browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
    if (request.command === 'isActiveLicense') {
      sendResponse(License.isActiveLicense());
    }
  });

  if (License.isActiveLicense()) {
    loadAdBlockSnippets();
  }
});

License.initialize(() => {
  if (!License.initialized) {
    License.initialized = true;
  }
});

Object.assign(window, {
  License,
  replacedCounts,
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, STATS, getUILanguage, getSubscriptionsMinusText */

const sendDCReport = function (url, type, id) {
  if (!url || !type) {
    return;
  }
  const reportData = {
    url,
    type,
    platform: STATS && `browser:${STATS.browser}, browser version:${STATS.browserVersion}, OS:${STATS.os}, OS version:${STATS.osVersion}`,
    locale: getUILanguage(),
    version: browser.runtime.getManifest().version,
  };
  if (id) {
    const subs = getSubscriptionsMinusText();
    if (subs && subs[id]) {
      const lastUpdate = subs[id].lastDownload || subs[id]._lastDownload || 0;
      reportData.filterListLastUpdate = new Date(lastUpdate * 1000);
    }
  }
  $.ajax({
    url: 'https://getadblock.com/freshdesk/bugReportDistractionControl.php',
    data: {
      bug_report: JSON.stringify(reportData),
    },
    success() {
      // Do nothing
    },
    error(e) {
      // eslint-disable-next-line no-console
      console.log('error: ', e.status);
    },
    type: 'POST',
  });
};

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command !== 'sendDCReport' || !message.url || !message.type) {
    return;
  }
  sendDCReport(message.url, message.type, message.id);
  sendResponse({});
});


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

"use strict";
/** @module adblock-betafish/getselectors */

/** call by the data collection content script, and if the user has myadblock enabled */

/*
  inspired by the code in this module:
    https://github.com/adblockplus/adblockpluschrome/blob/master/lib/contentFiltering.js#L248
*/



/* For ESLint: List any global identifiers used in this file below */
/* global require, URLFilter */

const {
  elemHide,
  createStyleSheet,
  rulesFromStyleSheet,
} = __webpack_require__(26);
const { RegExpFilter } = __webpack_require__(0);
const { elemHideEmulation } = __webpack_require__(28);
const { extractHostFromFrame } = __webpack_require__(13);
const { port } = __webpack_require__(1);
const { checkAllowlisted } = __webpack_require__(8);

port.on('getSelectors', (_message, sender) => {
  let selectors = [];
  let exceptions = [];
  const emulatedPatterns = [];

  if (!checkAllowlisted(sender.page, sender.frame, null,
    URLFilter.typeMap.DOCUMENT || URLFilter.typeMap.ELEMHIDE)) {
    const hostname = extractHostFromFrame(sender.frame);
    const specificOnly = checkAllowlisted(sender.page, sender.frame, null,
      URLFilter.typeMap.GENERICHIDE);

    ({ selectors, exceptions } = elemHide.generateStyleSheetForDomain(
      hostname,
      specificOnly ? elemHide.SPECIFIC_ONLY : elemHide.ALL_MATCHING,
      true, true,
    ));

    for (const filter of elemHideEmulation.getRulesForDomain(hostname)) {
      emulatedPatterns.push({ selector: filter.selector, text: filter.text });
    }
  }

  const response = { emulatedPatterns, selectors, exceptions };

  return response;
});


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

"use strict";
/* eslint-disable no-console */
/* eslint-disable camelcase */



/* For ESLint: List any global identifiers used in this file below */
/* global browser, require, isEmptyObject, storageSet, getSubscriptionsMinusText, Subscription,
   filterStorage, getUrlFromId, synchronizer, DownloadableSubscription, Prefs, parseFilter,
   recordAnonymousMessage */

(() => {
  const migrateLogMessageKey = 'migrateLogMessageKey';
  const storeMigrationLogs = (...args) => {
    console.log(...args);
    const timedLogMessage = `${new Date().toUTCString()}, ${args.join(' ')}`;
    const storedLog = JSON.parse(localStorage.getItem(migrateLogMessageKey) || '[]');
    while (storedLog.length > 500) { // only keep the last 500 log entries
      storedLog.shift();
    }
    storedLog.push(timedLogMessage);
    storageSet(migrateLogMessageKey, storedLog);
  };
  const reloadExtension = () => {
    browser.runtime.reload();
  };

  // Works for all |input| that are not 'stringified' or stringified' once or twice
  const parse = (input) => {
    try {
      // |input| is double 'stringified'
      return JSON.parse(JSON.parse(input));
    } catch (e) {
      // |input| is not double 'stringified'
      try {
        // |input| is 'stringified' once
        return JSON.parse(input);
      } catch (err) {
        // |input| is not 'stringified' so return it unparsed
        return input;
      }
    }
  };

  const migrateLegacyFilterLists = (edgeFilterLists) => {
    const myEdgeSubsParsed = parse(edgeFilterLists);
    // If we got an Array of Edge filter lists IDs
    if (myEdgeSubsParsed && myEdgeSubsParsed.constructor === Array) {
      const currentSubs = getSubscriptionsMinusText();
      // Unsubscribe default subscriptions if not in the Edge filter lists Array
      for (const id in currentSubs) {
        if (!myEdgeSubsParsed.includes(id)) {
          const currentSub = Subscription.fromURL(currentSubs[id].url);
          filterStorage.removeSubscription(currentSub);
        }
      }
      // Subscribe each Edge filter lists in Chrome if not alreayd subscribed
      for (const id of myEdgeSubsParsed) {
        const changeEdgeIDs = {
          swedish: 'norwegian',
          easylist_lite: 'easylist',
          easylist_plus_estonian: 'url:https://gurud.ee/ab.txt',
        };
        if ((!currentSubs[id] || !currentSubs[id].subscribed)) {
          const filterListId = changeEdgeIDs[id] ? changeEdgeIDs[id] : id;
          let url = getUrlFromId(filterListId);
          let subscription = Subscription.fromURL(url);
          if (!url && filterListId.startsWith('url:')) {
            url = filterListId.slice(4);
            subscription = Subscription.fromURL(url);
          }
          filterStorage.addSubscription(subscription);
          if (subscription instanceof DownloadableSubscription && !subscription.lastDownload) {
            synchronizer.execute(subscription);
          }
        }
      }
    }
  };

  const migrateLegacyCustomFilters = (edgeCustomFilters) => {
    const customFiltersParsed = parse(edgeCustomFilters);
    if (customFiltersParsed && typeof customFiltersParsed === 'string') {
      const customFiltersArray = customFiltersParsed.trim().split('\n');
      for (const customFilter of customFiltersArray) {
        if (customFilter.length > 0) {
          const result = parseFilter(customFilter);
          if (result.filter) {
            filterStorage.addFilter(result.filter);
          }
        }
      }
    }
  };

  const migrateLegacyCustomFilterCount = (edgeCustomFilterCount) => {
    const customFilterCountParsed = parse(edgeCustomFilterCount);
    if (
      customFilterCountParsed
      && customFilterCountParsed.constructor === Object
      && customFilterCountParsed !== edgeCustomFilterCount
    ) {
      return customFilterCountParsed;
    }
    return {};
  };

  const migrateLegacyExcludeFilters = (edgeExcludeFilters) => {
    const parsedExcludeFitlers = parse(edgeExcludeFilters);
    if (parsedExcludeFitlers !== edgeExcludeFilters && typeof parsedExcludeFitlers === 'string') {
      return parsedExcludeFitlers;
    }
    return '';
  };

  const migrateLegacyBlockageStats = (edgeBlockageStats) => {
    let blockStats = parse(edgeBlockageStats);
    // Preventive approach in case at this point is not an object
    if (blockStats.constructor !== Object) {
      blockStats = {};
    }
    // If invalid start value set it to now
    if (typeof blockStats.start !== 'number') {
      blockStats.start = Date.now();
    }
    // If invalid version value set it to 1
    if (typeof blockStats.version !== 'number') {
      blockStats.version = 1;
    }
    // Copy Edge total blocked count before deleting only if valid type
    if (typeof blockStats.total === 'number') {
      Prefs.blocked_total = blockStats.total;
    }
    delete blockStats.total; // Moved and no longer needed
    delete blockStats.malware_total; // Obsolete
    return blockStats;
  };

  // settings are stored only in browser.storage.local in both Edge and Chrome
  // No localStorage logic necessary here
  const migrateLegacySettings = (edgeSettings) => {
    // Parse data to cover all basis from Chromium odd migration of data formatting
    const settings = parse(edgeSettings);

    if (settings && !isEmptyObject(settings)) {
      const keysToRemove = ['whitelist_hulu_ads', 'show_language_selector'];
      const keysToRename = { data_collection: 'data_collection_v2' };
      const keysToPrefs = {
        display_stats: 'show_statsinicon',
        display_menu_stats: 'show_statsinpopup',
        show_context_menu_items: 'shouldShowBlockElementMenu',
      };

      for (const key in settings) {
        if (typeof settings[key] !== 'boolean') {
          // If invalid value remove the entry to use Chrome default values
          delete settings[key];
        } else if (keysToRemove.includes(key)) {
          // Remove if value explicitly doesn't exist in Chrome
          delete settings[key];
        } else if (Object.keys(keysToRename).includes(key)) {
          // Rename if key changed in Chrome
          settings[keysToRename[key]] = settings[key];
          delete settings[key];
        } else if (Object.keys(keysToPrefs).includes(key)) {
          // Move value from settings to Prefs
          Prefs[keysToPrefs[key]] = settings[key];
          delete settings[key];
        }
      }
      return settings;
    }
    return {};
  };

  // userid, total_pings, next_ping_time
  const migrateLegacyStats = (key, value) => {
    const suffix = '_alt';
    if (key === 'userid') {
      const parsedUserId = parse(value);
      if (typeof parsedUserId === 'string') {
        storageSet(`${key}${suffix}`, parsedUserId);
        return parsedUserId;
      }
    } else {
      const parsedValue = parse(value);
      if (typeof parsedValue === 'number') {
        storageSet(`${key}${suffix}`, parsedValue);
        return parsedValue;
      }
    }
    return key === 'userid' ? '' : 0; // Default values if value type is invalid
  };

  const migrateLastKnownVersion = (key, originalLastKnownVersion) => {
    const versionParsed = parse(originalLastKnownVersion);
    if (versionParsed && typeof versionParsed === 'string') {
      storageSet(key, versionParsed);
    }
  };

  const initMigration = (currentData) => {
    const migratedData = {};

    // Modify or remove data for keys that are in Edge or in both Edge and Chrome
    for (const key in currentData) {
      switch (key) {
        case 'custom_filter_count':
          migratedData[key] = migrateLegacyCustomFilterCount(currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'exclude_filters':
          migratedData[key] = migrateLegacyExcludeFilters(currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'blockage_stats':
          migratedData[key] = migrateLegacyBlockageStats(currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'settings':
          migratedData[key] = migrateLegacySettings(currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'userid':
          migratedData[key] = migrateLegacyStats(key, currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'total_pings':
          migratedData[key] = migrateLegacyStats(key, currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'next_ping_time':
          migratedData[key] = migrateLegacyStats(key, currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'custom_filters':
          migrateLegacyCustomFilters(currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'subscribed_filter_lists':
          migrateLegacyFilterLists(currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        case 'last_known_version':
          migrateLastKnownVersion(key, currentData[key]);
          storeMigrationLogs(`Migration for '${key}' done.`);
          break;
        default:
          // Do nothing since all other keys don't need to be migrated because they
          // are either only in Chrome or they are useless and should be removed
      }
    }

    // Edge specific keys deemed useless at this point
    const removeAfterMigration = [
      'filter_lists',
      'custom_filters',
      'last_known_version',
      'subscribed_filter_lists',
      'last_subscriptions_check',
      'malware-notification',
    ];

    browser.storage.local.set(migratedData).then(() => {
      browser.storage.local.remove(removeAfterMigration).then(() => {
        storeMigrationLogs('migration finished.');
        recordAnonymousMessage('cm_migration_finished', 'general', reloadExtension);
      });
    });
  };

  browser.storage.local.get(null).then((currentData) => {
    const edgeMigrationNeeded = currentData.filter_lists || currentData.subscribed_filter_lists;
    if (edgeMigrationNeeded) {
      try {
        storeMigrationLogs('Migration started.');
        Prefs.untilLoaded.then(() => {
          Prefs.suppress_first_run_page = true;
          Prefs.subscriptions_addedanticv = true;
          initMigration(currentData);
        });
      } catch (error) {
        storeMigrationLogs(`Migration logic error: ${error}`);
      }
    }
  });
})();


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, getSettings, settings, require, ext, setSetting,
   addCustomFilter, filterNotifier, checkAllowlisted */

const browserAction = __webpack_require__(15);

const twitchChannelNamePages = new Map();

// On single page sites, such as Twitch, that update the URL using the History API pushState(),
// they don't actually load a new page, we need to get notified when this happens
// and update the URLs in the Page and Frame objects
const twitchHistoryStateUpdateHandler = function (details) {
  if (details
      && Object.prototype.hasOwnProperty.call(details, 'frameId')
      && Object.prototype.hasOwnProperty.call(details, 'tabId')
      && Object.prototype.hasOwnProperty.call(details, 'url')
      && details.transitionType === 'link') {
    const myURL = new URL(details.url);
    if (myURL.hostname === 'www.twitch.tv') {
      const myFrame = ext.getFrame(details.tabId, details.frameId);
      const myPage = ext.getPage(details.tabId);
      myPage._url = myURL;
      myFrame.url = myURL;
      myFrame._url = myURL;
      if (checkAllowlisted(myPage)) {
        browserAction.setBadge(details.tabId, { number: '' });
      }
    }
  }
};

// Creates a custom filter entry that whitelists a YouTube channel
// Inputs: url:string url of the page
// Returns: null if successful, otherwise an exception
const createWhitelistFilterForTwitchChannel = function (url) {
  let twitchChannel;
  if (/ab_channel=/.test(url)) {
    [, twitchChannel] = url.match(/ab_channel=([^]*)/);
  } else {
    twitchChannel = url.split('/').pop();
  }
  if (twitchChannel) {
    const filter = `@@||twitch.tv/*${twitchChannel}^$document`;
    return addCustomFilter(filter);
  }
  return undefined;
};

const twitchMessageHandler = function (message, sender, sendResponse) {
  if (message.command === 'createWhitelistFilterForTwitchChannel' && message.url) {
    sendResponse(createWhitelistFilterForTwitchChannel(message.url));
    return;
  }
  if (message.command === 'updateTwitchChannelName' && message.channelName) {
    twitchChannelNamePages.set(sender.tab.id, message.channelName);
    sendResponse({});
  }
  if (message.command === 'allowlistingStateRevalidate') {
    const page = new ext.Page(sender.tab);
    filterNotifier.emit('page.WhitelistingStateRevalidate', page, checkAllowlisted(page));
    sendResponse({});
  }
};

const addTwitchAllowlistListeners = function () {
  twitchChannelNamePages.clear();
  browser.runtime.onMessage.addListener(twitchMessageHandler);
  browser.webNavigation.onHistoryStateUpdated.addListener(twitchHistoryStateUpdateHandler);
};

const removeTwitchAllowlistListeners = function () {
  twitchChannelNamePages.clear();
  browser.runtime.onMessage.removeListener(twitchMessageHandler);
  browser.webNavigation.onHistoryStateUpdated.removeListener(twitchHistoryStateUpdateHandler);
};

settings.onload().then(() => {
  if (getSettings().twitch_channel_allowlist) {
    addTwitchAllowlistListeners();
  }
});

Object.assign(window, {
  addTwitchAllowlistListeners,
  removeTwitchAllowlistListeners,
  twitchChannelNamePages,
});


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, getSettings, settings, require, ext, setSetting,
   addCustomFilter, checkAllowlisted, getUserFilters,
   isWhitelistFilter */

const { Filter } = __webpack_require__(0);
const { filterStorage } = __webpack_require__(3);
const { filterNotifier } = __webpack_require__(4);

const ytChannelNamePages = new Map();

const webRequestFilter = {
  url:
  [
    { hostEquals: 'www.youtube.com' },
  ],
};

// Creates a custom filter entry that whitelists a YouTube channel
// Inputs: channelName:string parsed channel name
// Returns:  null if successful, otherwise an exception
const createAllowlistFilterForYoutubeChannelName = function (channelName) {
  if (channelName) {
    const filterText = `@@||www.youtube.com/*${channelName}|$document`;
    return addCustomFilter(filterText);
  }
  return undefined;
};

// Creates a custom filter entry that whitelists a YouTube channel
// Inputs: url:string url of the page
// Returns: null if successful, otherwise an exception
const createWhitelistFilterForYoutubeChannel = function (url) {
  let ytChannel;
  if (/ab_channel=/.test(url)) {
    [, ytChannel] = url.match(/ab_channel=([^]*)/);
  } else {
    ytChannel = url.split('/').pop();
  }
  if (ytChannel) {
    return createAllowlistFilterForYoutubeChannelName(ytChannel);
  }
  return undefined;
};

const removeAllowlistFilterForYoutubeChannel = function (text) {
  if (isWhitelistFilter(text)) {
    try {
      const filter = Filter.fromText(text);
      filterStorage.removeFilter(filter);
    } catch (ex) {
      // do nothing;
    }
  }
};

// inject the manage YT subscription
const injectManagedContentScript = function (details, historyUpdated) {
  const { tabId } = details;

  browser.tabs.sendMessage(tabId, { command: 'ping_yt_manage_cs' }).then((pingResponse) => {
    if (pingResponse && pingResponse.status === 'yes') {
      browser.tabs.sendMessage(tabId, { command: 'addYouTubeOnPageIcons', historyUpdated });
    } else {
      browser.tabs.executeScript(tabId, {
        file: 'purify.min.js',
        allFrames: false,
        runAt: 'document_end',
      }).then(() => {
        browser.tabs.executeScript(tabId, {
          file: 'adblock-yt-manage-cs.js',
          allFrames: false,
          runAt: 'document_end',
        }).then(() => {
          browser.tabs.sendMessage(tabId, { command: 'addYouTubeOnPageIcons', historyUpdated });
        });
      });
    }
  });
};


// On single page sites, such as YouTube, that update the URL using the History API pushState(),
// they don't actually load a new page, we need to get notified when this happens
// and update the URLs in the Page and Frame objects
const ytHistoryHandler = function (details) {
  if (details
      && Object.prototype.hasOwnProperty.call(details, 'frameId')
      && Object.prototype.hasOwnProperty.call(details, 'tabId')
      && Object.prototype.hasOwnProperty.call(details, 'url')
      && details.transitionType === 'link') {
    const myURL = new URL(details.url);
    if (myURL.hostname === 'www.youtube.com') {
      const myFrame = ext.getFrame(details.tabId, details.frameId);
      const myPage = ext.getPage(details.tabId);
      myPage._url = myURL;
      myFrame.url = myURL;
      myFrame._url = myURL;
      if (!/ab_channel/.test(details.url) && myURL.pathname === '/watch') {
        browser.tabs.sendMessage(details.tabId, { command: 'updateURLWithYouTubeChannelName' });
      } else if (/ab_channel/.test(details.url) && myURL.pathname !== '/watch') {
        browser.tabs.sendMessage(details.tabId, { command: 'removeYouTubeChannelName' });
      }
      if (getSettings().youtube_manage_subscribed && myURL.pathname === '/feed/channels') {
        // check if the user clicked the back / forward buttons, if so,
        // the data on the page is already loaded,
        // so the content script does not have to wait for it to load.
        injectManagedContentScript(details, !(details.transitionQualifiers && details.transitionQualifiers.includes('forward_back')));
      }
      filterNotifier.emit('page.WhitelistingStateRevalidate', myPage, checkAllowlisted(myPage));
    }
  }
};

const managedSubPageCompleted = function (details) {
  const theURL = new URL(details.url);
  if (theURL.pathname === '/feed/channels') {
    injectManagedContentScript(details);
  }
};

const addYTChannelListeners = function () {
  browser.webNavigation.onHistoryStateUpdated.addListener(ytHistoryHandler, webRequestFilter);
  if (getSettings().youtube_manage_subscribed) {
    browser.webNavigation.onCompleted.addListener(managedSubPageCompleted, webRequestFilter);
  }
};

const removeYTChannelListeners = function () {
  browser.webNavigation.onHistoryStateUpdated.removeListener(ytHistoryHandler, webRequestFilter);
  browser.webNavigation.onCompleted.removeListener(managedSubPageCompleted, webRequestFilter);
};

settings.onload().then(() => {
  if (getSettings().youtube_channel_whitelist) {
    addYTChannelListeners();
  }
});

const openYTManagedSubPage = function () {
  browser.tabs.create({ url: 'https://www.youtube.com/feed/channels' });
};

const getAllAdsAllowedUserFilters = function () {
  const userFilters = getUserFilters();
  const adsAllowedUserFilters = [];
  for (let inx = 0; inx < userFilters.length; inx++) {
    const filterText = userFilters[inx];
    if (isWhitelistFilter(filterText) && filterText.includes('youtube.com')) {
      adsAllowedUserFilters.push(filterText);
    }
  }
  return adsAllowedUserFilters;
};

let previousYTchannelId = '';
const previousYTvideoId = '';
let previousYTuserId = '';

// Listen for the message from the content scripts
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.command === 'updateYouTubeChannelName' && message.channelName) {
    ytChannelNamePages.set(sender.tab.id, message.channelName);
    sendResponse({});
    return;
  }
  if (message.command === 'get_channel_name_by_channel_id' && message.channelId) {
    if (previousYTchannelId !== message.channelId) {
      previousYTchannelId = message.channelId;
      const xhr = new XMLHttpRequest();
      const { channelId } = message;
      const key = atob('QUl6YVN5QzJKMG5lbkhJZ083amZaUUYwaVdaN3BKd3dsMFczdUlz');
      const url = 'https://www.googleapis.com/youtube/v3/channels';
      xhr.open('GET', `${url}?part=snippet&id=${channelId}&key=${key}`);
      xhr.onload = function xhrOnload() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          const json = JSON.parse(xhr.response);
          // Got name of the channel
          if (json && json.items && json.items[0]) {
            const channelName = json.items[0].snippet.title;
            ytChannelNamePages.set(sender.tab.id, channelName);
            browser.tabs.sendMessage(sender.tab.id, {
              command: 'updateURLWithYouTubeChannelName',
              channelName,
            });
          }
        }
      };
      xhr.send();
      sendResponse({});
      return;
    }
    browser.tabs.sendMessage(sender.tab.id, {
      command: 'updateURLWithYouTubeChannelName',
      channelName: ytChannelNamePages.get(sender.tab.id),
    });
    sendResponse({});
    return;
  }
  if (message.command === 'get_channel_name_by_user_id' && message.userId) {
    if (previousYTuserId !== message.userId) {
      previousYTuserId = message.userId;
      const xhr = new XMLHttpRequest();
      const { userId } = message;
      const key = atob('QUl6YVN5QzJKMG5lbkhJZ083amZaUUYwaVdaN3BKd3dsMFczdUlz');
      const url = 'https://www.googleapis.com/youtube/v3/channels';
      xhr.open('GET', `${url}?part=snippet&forUsername=${userId}&key=${key}`);
      xhr.onload = function xhrOnload() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          const json = JSON.parse(xhr.response);
          // Got name of the channel
          if (json && json.items && json.items[0]) {
            const channelName = json.items[0].snippet.title;
            ytChannelNamePages.set(sender.tab.id, channelName);
            browser.tabs.sendMessage(sender.tab.id, {
              command: 'updateURLWithYouTubeChannelName',
              channelName,
            });
          }
        }
      };
      xhr.send();
      sendResponse({});
    } else {
      browser.tabs.sendMessage(sender.tab.id, {
        command: 'updateURLWithYouTubeChannelName',
        channelName: ytChannelNamePages.get(sender.tab.id),
      });
      sendResponse({});
    }
  }
  if (message.command === 'openYTManagedSubPage' && getSettings().youtube_manage_subscribed) {
    openYTManagedSubPage();
    sendResponse({});
  }
  if (message.command === 'getAllAdsAllowedUserFilters') {
    sendResponse({ adsAllowedUserFilters: getAllAdsAllowedUserFilters() });
  }
  if (message.command === 'removeAllowlistFilterForYoutubeChannel' && message.text) {
    removeAllowlistFilterForYoutubeChannel(message.text);
    sendResponse({});
  }
  if (message.command === 'createWhitelistFilterForYoutubeChannel' && message.url) {
    sendResponse(createWhitelistFilterForYoutubeChannel(message.url));
  }
  if (message.command === 'createAllowlistFilterForYoutubeChannelName' && message.channelName) {
    sendResponse(createAllowlistFilterForYoutubeChannelName(message.channelName));
  }
  if (message.command === 'blockAllSubscribedChannel' && message.channelNames) {
    const { channelNames } = message;
    const parsedChannelNames = [];
    const userFilters = getAllAdsAllowedUserFilters();
    for (const [channelName] of Object.entries(channelNames)) {
      const name = channelNames[channelName].parsedChannelName;
      parsedChannelNames.push(name);
      for (let inx = 0; inx < userFilters.length; inx++) {
        const filterText = userFilters[inx];
        if (filterText.indexOf(name) > 1) {
          removeAllowlistFilterForYoutubeChannel(filterText);
        }
      }
    }
    sendResponse({});
  }
  if (message.command === 'allowAllSubscribedChannel' && message.channelNames) {
    const { channelNames } = message;
    for (const [channelName] of Object.entries(channelNames)) {
      const name = channelNames[channelName].parsedChannelName;
      createAllowlistFilterForYoutubeChannelName(name);
    }
    sendResponse({});
  }
});

Object.assign(window, {
  addYTChannelListeners,
  removeYTChannelListeners,
  ytChannelNamePages,
  openYTManagedSubPage,
});


/***/ }),
/* 103 */
/***/ (function(__webpack_module__, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var node_fetch__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(49);


var commonjsGlobal$1 = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

function getAugmentedNamespace(n) {
	if (n.__esModule) return n;
	var a = Object.defineProperty({}, '__esModule', {value: true});
	Object.keys(n).forEach(function (k) {
		var d = Object.getOwnPropertyDescriptor(n, k);
		Object.defineProperty(a, k, d.get ? d : {
			enumerable: true,
			get: function () {
				return n[k];
			}
		});
	});
	return a;
}

var partial_bundle_ml = {};

// shim for using process in browser
// based off https://github.com/defunctzombie/node-process/blob/master/browser.js

function defaultSetTimout() {
    throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
    throw new Error('clearTimeout has not been defined');
}
var cachedSetTimeout = defaultSetTimout;
var cachedClearTimeout = defaultClearTimeout;
if (typeof global.setTimeout === 'function') {
    cachedSetTimeout = setTimeout;
}
if (typeof global.clearTimeout === 'function') {
    cachedClearTimeout = clearTimeout;
}

function runTimeout(fun) {
    if (cachedSetTimeout === setTimeout) {
        //normal enviroments in sane situations
        return setTimeout(fun, 0);
    }
    // if setTimeout wasn't available but was latter defined
    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
        cachedSetTimeout = setTimeout;
        return setTimeout(fun, 0);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedSetTimeout(fun, 0);
    } catch(e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
            return cachedSetTimeout.call(null, fun, 0);
        } catch(e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
            return cachedSetTimeout.call(this, fun, 0);
        }
    }


}
function runClearTimeout(marker) {
    if (cachedClearTimeout === clearTimeout) {
        //normal enviroments in sane situations
        return clearTimeout(marker);
    }
    // if clearTimeout wasn't available but was latter defined
    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
        cachedClearTimeout = clearTimeout;
        return clearTimeout(marker);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedClearTimeout(marker);
    } catch (e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
            return cachedClearTimeout.call(null, marker);
        } catch (e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
            return cachedClearTimeout.call(this, marker);
        }
    }



}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;

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

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

    var len = queue.length;
    while(len) {
        currentQueue = queue;
        queue = [];
        while (++queueIndex < len) {
            if (currentQueue) {
                currentQueue[queueIndex].run();
            }
        }
        queueIndex = -1;
        len = queue.length;
    }
    currentQueue = null;
    draining = false;
    runClearTimeout(timeout);
}
function nextTick(fun) {
    var args = new Array(arguments.length - 1);
    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            args[i - 1] = arguments[i];
        }
    }
    queue.push(new Item(fun, args));
    if (queue.length === 1 && !draining) {
        runTimeout(drainQueue);
    }
}
// v8 likes predictible objects
function Item(fun, array) {
    this.fun = fun;
    this.array = array;
}
Item.prototype.run = function () {
    this.fun.apply(null, this.array);
};
var title = 'browser';
var platform = 'browser';
var browser$1 = true;
var env$1 = {};
var argv = [];
var version = ''; // empty string to avoid regexp issues
var versions = {};
var release = {};
var config = {};

function noop() {}

var on = noop;
var addListener = noop;
var once = noop;
var off = noop;
var removeListener = noop;
var removeAllListeners = noop;
var emit = noop;

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

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

// from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js
var performance$1 = global.performance || {};
var performanceNow =
  performance$1.now        ||
  performance$1.mozNow     ||
  performance$1.msNow      ||
  performance$1.oNow       ||
  performance$1.webkitNow  ||
  function(){ return (new Date()).getTime() };

// generate timestamp or delta
// see http://nodejs.org/api/process.html#process_process_hrtime
function hrtime(previousTimestamp){
  var clocktime = performanceNow.call(performance$1)*1e-3;
  var seconds = Math.floor(clocktime);
  var nanoseconds = Math.floor((clocktime%1)*1e9);
  if (previousTimestamp) {
    seconds = seconds - previousTimestamp[0];
    nanoseconds = nanoseconds - previousTimestamp[1];
    if (nanoseconds<0) {
      seconds--;
      nanoseconds += 1e9;
    }
  }
  return [seconds,nanoseconds]
}

var startTime = new Date();
function uptime() {
  var currentTime = new Date();
  var dif = currentTime - startTime;
  return dif / 1000;
}

var browser$1$1 = {
  nextTick: nextTick,
  title: title,
  browser: browser$1,
  env: env$1,
  argv: argv,
  version: version,
  versions: versions,
  on: on,
  addListener: addListener,
  once: once,
  off: off,
  removeListener: removeListener,
  removeAllListeners: removeAllListeners,
  emit: emit,
  binding: binding,
  cwd: cwd,
  chdir: chdir,
  umask: umask,
  hrtime: hrtime,
  platform: platform,
  release: release,
  config: config,
  uptime: uptime
};

var inherits;
if (typeof Object.create === 'function'){
  inherits = function inherits(ctor, superCtor) {
    // implementation from standard node.js 'util' module
    ctor.super_ = superCtor;
    ctor.prototype = Object.create(superCtor.prototype, {
      constructor: {
        value: ctor,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
  };
} else {
  inherits = function inherits(ctor, superCtor) {
    ctor.super_ = superCtor;
    var TempCtor = function () {};
    TempCtor.prototype = superCtor.prototype;
    ctor.prototype = new TempCtor();
    ctor.prototype.constructor = ctor;
  };
}
var inherits$1 = inherits;

// Copyright Joyent, Inc. and other Node contributors.
var formatRegExp = /%[sdj%]/g;
function format(f) {
  if (!isString$1(f)) {
    var objects = [];
    for (var i = 0; i < arguments.length; i++) {
      objects.push(inspect(arguments[i]));
    }
    return objects.join(' ');
  }

  var i = 1;
  var args = arguments;
  var len = args.length;
  var str = String(f).replace(formatRegExp, function(x) {
    if (x === '%%') return '%';
    if (i >= len) return x;
    switch (x) {
      case '%s': return String(args[i++]);
      case '%d': return Number(args[i++]);
      case '%j':
        try {
          return JSON.stringify(args[i++]);
        } catch (_) {
          return '[Circular]';
        }
      default:
        return x;
    }
  });
  for (var x = args[i]; i < len; x = args[++i]) {
    if (isNull(x) || !isObject(x)) {
      str += ' ' + x;
    } else {
      str += ' ' + inspect(x);
    }
  }
  return str;
}

// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
function deprecate(fn, msg) {
  // Allow for deprecating things in the process of starting up.
  if (isUndefined(global.process)) {
    return function() {
      return deprecate(fn, msg).apply(this, arguments);
    };
  }

  if (browser$1$1.noDeprecation === true) {
    return fn;
  }

  var warned = false;
  function deprecated() {
    if (!warned) {
      if (browser$1$1.throwDeprecation) {
        throw new Error(msg);
      } else if (browser$1$1.traceDeprecation) {
        console.trace(msg);
      } else {
        console.error(msg);
      }
      warned = true;
    }
    return fn.apply(this, arguments);
  }

  return deprecated;
}

var debugs = {};
var debugEnviron;
function debuglog(set) {
  if (isUndefined(debugEnviron))
    debugEnviron = browser$1$1.env.NODE_DEBUG || '';
  set = set.toUpperCase();
  if (!debugs[set]) {
    if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
      var pid = 0;
      debugs[set] = function() {
        var msg = format.apply(null, arguments);
        console.error('%s %d: %s', set, pid, msg);
      };
    } else {
      debugs[set] = function() {};
    }
  }
  return debugs[set];
}

/**
 * Echos the value of a value. Trys to print the value out
 * in the best way possible given the different types.
 *
 * @param {Object} obj The object to print out.
 * @param {Object} opts Optional options object that alters the output.
 */
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
  // default options
  var ctx = {
    seen: [],
    stylize: stylizeNoColor
  };
  // legacy...
  if (arguments.length >= 3) ctx.depth = arguments[2];
  if (arguments.length >= 4) ctx.colors = arguments[3];
  if (isBoolean$1(opts)) {
    // legacy...
    ctx.showHidden = opts;
  } else if (opts) {
    // got an "options" object
    _extend(ctx, opts);
  }
  // set default options
  if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
  if (isUndefined(ctx.depth)) ctx.depth = 2;
  if (isUndefined(ctx.colors)) ctx.colors = false;
  if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
  if (ctx.colors) ctx.stylize = stylizeWithColor;
  return formatValue(ctx, obj, ctx.depth);
}

// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
  'bold' : [1, 22],
  'italic' : [3, 23],
  'underline' : [4, 24],
  'inverse' : [7, 27],
  'white' : [37, 39],
  'grey' : [90, 39],
  'black' : [30, 39],
  'blue' : [34, 39],
  'cyan' : [36, 39],
  'green' : [32, 39],
  'magenta' : [35, 39],
  'red' : [31, 39],
  'yellow' : [33, 39]
};

// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
  'special': 'cyan',
  'number': 'yellow',
  'boolean': 'yellow',
  'undefined': 'grey',
  'null': 'bold',
  'string': 'green',
  'date': 'magenta',
  // "name": intentionally not styling
  'regexp': 'red'
};


function stylizeWithColor(str, styleType) {
  var style = inspect.styles[styleType];

  if (style) {
    return '\u001b[' + inspect.colors[style][0] + 'm' + str +
           '\u001b[' + inspect.colors[style][1] + 'm';
  } else {
    return str;
  }
}


function stylizeNoColor(str, styleType) {
  return str;
}


function arrayToHash(array) {
  var hash = {};

  array.forEach(function(val, idx) {
    hash[val] = true;
  });

  return hash;
}


function formatValue(ctx, value, recurseTimes) {
  // Provide a hook for user-specified inspect functions.
  // Check that value is an object with an inspect function on it
  if (ctx.customInspect &&
      value &&
      isFunction$1(value.inspect) &&
      // Filter out the util module, it's inspect function is special
      value.inspect !== inspect &&
      // Also filter out any prototype objects using the circular check.
      !(value.constructor && value.constructor.prototype === value)) {
    var ret = value.inspect(recurseTimes, ctx);
    if (!isString$1(ret)) {
      ret = formatValue(ctx, ret, recurseTimes);
    }
    return ret;
  }

  // Primitive types cannot have properties
  var primitive = formatPrimitive(ctx, value);
  if (primitive) {
    return primitive;
  }

  // Look up the keys of the object.
  var keys = Object.keys(value);
  var visibleKeys = arrayToHash(keys);

  if (ctx.showHidden) {
    keys = Object.getOwnPropertyNames(value);
  }

  // IE doesn't make error fields non-enumerable
  // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
  if (isError(value)
      && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
    return formatError(value);
  }

  // Some type of object without properties can be shortcutted.
  if (keys.length === 0) {
    if (isFunction$1(value)) {
      var name = value.name ? ': ' + value.name : '';
      return ctx.stylize('[Function' + name + ']', 'special');
    }
    if (isRegExp(value)) {
      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
    }
    if (isDate(value)) {
      return ctx.stylize(Date.prototype.toString.call(value), 'date');
    }
    if (isError(value)) {
      return formatError(value);
    }
  }

  var base = '', array = false, braces = ['{', '}'];

  // Make Array say that they are Array
  if (isArray(value)) {
    array = true;
    braces = ['[', ']'];
  }

  // Make functions say that they are functions
  if (isFunction$1(value)) {
    var n = value.name ? ': ' + value.name : '';
    base = ' [Function' + n + ']';
  }

  // Make RegExps say that they are RegExps
  if (isRegExp(value)) {
    base = ' ' + RegExp.prototype.toString.call(value);
  }

  // Make dates with properties first say the date
  if (isDate(value)) {
    base = ' ' + Date.prototype.toUTCString.call(value);
  }

  // Make error with message first say the error
  if (isError(value)) {
    base = ' ' + formatError(value);
  }

  if (keys.length === 0 && (!array || value.length == 0)) {
    return braces[0] + base + braces[1];
  }

  if (recurseTimes < 0) {
    if (isRegExp(value)) {
      return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
    } else {
      return ctx.stylize('[Object]', 'special');
    }
  }

  ctx.seen.push(value);

  var output;
  if (array) {
    output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
  } else {
    output = keys.map(function(key) {
      return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
    });
  }

  ctx.seen.pop();

  return reduceToSingleString(output, base, braces);
}


function formatPrimitive(ctx, value) {
  if (isUndefined(value))
    return ctx.stylize('undefined', 'undefined');
  if (isString$1(value)) {
    var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
                                             .replace(/'/g, "\\'")
                                             .replace(/\\"/g, '"') + '\'';
    return ctx.stylize(simple, 'string');
  }
  if (isNumber$1(value))
    return ctx.stylize('' + value, 'number');
  if (isBoolean$1(value))
    return ctx.stylize('' + value, 'boolean');
  // For some reason typeof null is "object", so special case here.
  if (isNull(value))
    return ctx.stylize('null', 'null');
}


function formatError(value) {
  return '[' + Error.prototype.toString.call(value) + ']';
}


function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
  var output = [];
  for (var i = 0, l = value.length; i < l; ++i) {
    if (hasOwnProperty(value, String(i))) {
      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
          String(i), true));
    } else {
      output.push('');
    }
  }
  keys.forEach(function(key) {
    if (!key.match(/^\d+$/)) {
      output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
          key, true));
    }
  });
  return output;
}


function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
  var name, str, desc;
  desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
  if (desc.get) {
    if (desc.set) {
      str = ctx.stylize('[Getter/Setter]', 'special');
    } else {
      str = ctx.stylize('[Getter]', 'special');
    }
  } else {
    if (desc.set) {
      str = ctx.stylize('[Setter]', 'special');
    }
  }
  if (!hasOwnProperty(visibleKeys, key)) {
    name = '[' + key + ']';
  }
  if (!str) {
    if (ctx.seen.indexOf(desc.value) < 0) {
      if (isNull(recurseTimes)) {
        str = formatValue(ctx, desc.value, null);
      } else {
        str = formatValue(ctx, desc.value, recurseTimes - 1);
      }
      if (str.indexOf('\n') > -1) {
        if (array) {
          str = str.split('\n').map(function(line) {
            return '  ' + line;
          }).join('\n').substr(2);
        } else {
          str = '\n' + str.split('\n').map(function(line) {
            return '   ' + line;
          }).join('\n');
        }
      }
    } else {
      str = ctx.stylize('[Circular]', 'special');
    }
  }
  if (isUndefined(name)) {
    if (array && key.match(/^\d+$/)) {
      return str;
    }
    name = JSON.stringify('' + key);
    if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
      name = name.substr(1, name.length - 2);
      name = ctx.stylize(name, 'name');
    } else {
      name = name.replace(/'/g, "\\'")
                 .replace(/\\"/g, '"')
                 .replace(/(^"|"$)/g, "'");
      name = ctx.stylize(name, 'string');
    }
  }

  return name + ': ' + str;
}


function reduceToSingleString(output, base, braces) {
  var length = output.reduce(function(prev, cur) {
    if (cur.indexOf('\n') >= 0) ;
    return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
  }, 0);

  if (length > 60) {
    return braces[0] +
           (base === '' ? '' : base + '\n ') +
           ' ' +
           output.join(',\n  ') +
           ' ' +
           braces[1];
  }

  return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}


// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
  return Array.isArray(ar);
}

function isBoolean$1(arg) {
  return typeof arg === 'boolean';
}

function isNull(arg) {
  return arg === null;
}

function isNullOrUndefined(arg) {
  return arg == null;
}

function isNumber$1(arg) {
  return typeof arg === 'number';
}

function isString$1(arg) {
  return typeof arg === 'string';
}

function isSymbol(arg) {
  return typeof arg === 'symbol';
}

function isUndefined(arg) {
  return arg === void 0;
}

function isRegExp(re) {
  return isObject(re) && objectToString(re) === '[object RegExp]';
}

function isObject(arg) {
  return typeof arg === 'object' && arg !== null;
}

function isDate(d) {
  return isObject(d) && objectToString(d) === '[object Date]';
}

function isError(e) {
  return isObject(e) &&
      (objectToString(e) === '[object Error]' || e instanceof Error);
}

function isFunction$1(arg) {
  return typeof arg === 'function';
}

function isPrimitive(arg) {
  return arg === null ||
         typeof arg === 'boolean' ||
         typeof arg === 'number' ||
         typeof arg === 'string' ||
         typeof arg === 'symbol' ||  // ES6 symbol
         typeof arg === 'undefined';
}

function isBuffer(maybeBuf) {
  return Buffer.isBuffer(maybeBuf);
}

function objectToString(o) {
  return Object.prototype.toString.call(o);
}


function pad$1(n) {
  return n < 10 ? '0' + n.toString(10) : n.toString(10);
}


var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
              'Oct', 'Nov', 'Dec'];

// 26 Feb 16:19:34
function timestamp() {
  var d = new Date();
  var time = [pad$1(d.getHours()),
              pad$1(d.getMinutes()),
              pad$1(d.getSeconds())].join(':');
  return [d.getDate(), months[d.getMonth()], time].join(' ');
}


// log is just a thin wrapper to console.log that prepends a timestamp
function log$2() {
  console.log('%s - %s', timestamp(), format.apply(null, arguments));
}

function _extend(origin, add) {
  // Don't do anything if add isn't an object
  if (!add || !isObject(add)) return origin;

  var keys = Object.keys(add);
  var i = keys.length;
  while (i--) {
    origin[keys[i]] = add[keys[i]];
  }
  return origin;
}
function hasOwnProperty(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

var util = {
  inherits: inherits$1,
  _extend: _extend,
  log: log$2,
  isBuffer: isBuffer,
  isPrimitive: isPrimitive,
  isFunction: isFunction$1,
  isError: isError,
  isDate: isDate,
  isObject: isObject,
  isRegExp: isRegExp,
  isUndefined: isUndefined,
  isSymbol: isSymbol,
  isString: isString$1,
  isNumber: isNumber$1,
  isNullOrUndefined: isNullOrUndefined,
  isNull: isNull,
  isBoolean: isBoolean$1,
  isArray: isArray,
  inspect: inspect,
  deprecate: deprecate,
  format: format,
  debuglog: debuglog
};

var util$1 = /*#__PURE__*/Object.freeze({
	__proto__: null,
	format: format,
	deprecate: deprecate,
	debuglog: debuglog,
	inspect: inspect,
	isArray: isArray,
	isBoolean: isBoolean$1,
	isNull: isNull,
	isNullOrUndefined: isNullOrUndefined,
	isNumber: isNumber$1,
	isString: isString$1,
	isSymbol: isSymbol,
	isUndefined: isUndefined,
	isRegExp: isRegExp,
	isObject: isObject,
	isDate: isDate,
	isError: isError,
	isFunction: isFunction$1,
	isPrimitive: isPrimitive,
	isBuffer: isBuffer,
	log: log$2,
	inherits: inherits$1,
	_extend: _extend,
	'default': util
});

var require$$1 = /*@__PURE__*/getAugmentedNamespace(util$1);

/**
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */
Object.defineProperty(partial_bundle_ml,"__esModule",{value:true});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const EPSILON_FLOAT32$1=1e-7;const EPSILON_FLOAT16$1=1e-4;class DataStorage{constructor(e,t){this.backend=e;this.dataMover=t;this.data=new WeakMap;this.dataIdsCount=0;}get(e){if(!this.data.has(e)){this.dataMover.moveData(this.backend,e);}return this.data.get(e)}set(e,t){this.dataIdsCount++;this.data.set(e,t);}has(e){return this.data.has(e)}delete(e){this.dataIdsCount--;return this.data.delete(e)}numDataIds(){return this.dataIdsCount}}class KernelBackend{refCount(e){return notYetImplemented("refCount")}incRef(e){return notYetImplemented("incRef")}timerAvailable(){return true}time(e){return notYetImplemented("time")}read(e){return notYetImplemented("read")}readSync(e){return notYetImplemented("readSync")}numDataIds(){return notYetImplemented("numDataIds")}disposeData(e,t){return notYetImplemented("disposeData")}write(e,t,n){return notYetImplemented("write")}move(e,t,n,r,s){return notYetImplemented("move")}memory(){return notYetImplemented("memory")}floatPrecision(){return notYetImplemented("floatPrecision")}epsilon(){return this.floatPrecision()===32?EPSILON_FLOAT32$1:EPSILON_FLOAT16$1}dispose(){return notYetImplemented("dispose")}}function notYetImplemented(e){throw new Error(`'${e}' not yet implemented or not found in the registry. `+`This kernel may not be supported by the tfjs backend you have chosen`)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function clamp(e,t,n){return Math.max(e,Math.min(t,n))}function nearestLargerEven(e){return e%2===0?e:e+1}function sum$2(e){let t=0;for(let n=0;n<e.length;n++){t+=e[n];}return t}function assert(e,t){if(!e){throw new Error(typeof t==="string"?t:t())}}function assertShapesMatch(e,t,n=""){assert(arraysEqual(e,t),(()=>n+` Shapes ${e} and ${t} must match`));}function assertNonNull(e){assert(e!=null,(()=>`The input to the tensor constructor must be a non-null value.`));}function flatten(e,t=[],n=false){if(t==null){t=[];}if(Array.isArray(e)||isTypedArray(e)&&!n){for(let r=0;r<e.length;++r){flatten(e[r],t,n);}}else {t.push(e);}return t}function sizeFromShape(e){if(e.length===0){return 1}let t=e[0];for(let n=1;n<e.length;n++){t*=e[n];}return t}function arraysEqual(e,t){if(e===t){return true}if(e==null||t==null){return false}if(e.length!==t.length){return false}for(let n=0;n<e.length;n++){if(e[n]!==t[n]){return false}}return true}function isInt(e){return e%1===0}function sizeToSquarishShape(e){const t=Math.ceil(Math.sqrt(e));return [t,Math.ceil(e/t)]}function rightPad(e,t){if(t<=e.length){return e}return e+" ".repeat(t-e.length)}function repeatedTry(e,t=(e=>0),n){return new Promise(((r,s)=>{let a=0;const o=()=>{if(e()){r();return}a++;const i=t(a);if(n!=null&&a>=n){s();return}setTimeout(o,i);};o();}))}function inferFromImplicitShape(e,t){let n=1;let r=-1;for(let t=0;t<e.length;++t){if(e[t]>=0){n*=e[t];}else if(e[t]===-1){if(r!==-1){throw Error(`Shapes can only have 1 implicit size. `+`Found -1 at dim ${r} and dim ${t}`)}r=t;}else if(e[t]<0){throw Error(`Shapes can not be < 0. Found ${e[t]} at dim ${t}`)}}if(r===-1){if(t>0&&t!==n){throw Error(`Size(${t}) must match the product of shape ${e}`)}return e}if(n===0){throw Error(`Cannot infer the missing size in [${e}] when `+`there are 0 elements`)}if(t%n!==0){throw Error(`The implicit shape can't be a fractional number. `+`Got ${t} / ${n}`)}const s=e.slice();s[r]=t/n;return s}function parseAxisParam(e,t){const n=t.length;e=e==null?t.map(((e,t)=>t)):[].concat(e);assert(e.every((e=>e>=-n&&e<n)),(()=>`All values in axis param must be in range [-${n}, ${n}) but `+`got axis ${e}`));assert(e.every((e=>isInt(e))),(()=>`All values in axis param must be integers but `+`got axis ${e}`));return e.map((e=>e<0?n+e:e))}function squeezeShape(e,t){const n=[];const r=[];const s=t!=null&&Array.isArray(t)&&t.length===0;const a=t==null||s?null:parseAxisParam(t,e).sort();let o=0;for(let t=0;t<e.length;++t){if(a!=null){if(a[o]===t&&e[t]!==1){throw new Error(`Can't squeeze axis ${t} since its dim '${e[t]}' is not 1`)}if((a[o]==null||a[o]>t)&&e[t]===1){n.push(e[t]);r.push(t);}if(a[o]<=t){o++;}}if(e[t]!==1){n.push(e[t]);r.push(t);}}return {newShape:n,keptDims:r}}function getTypedArrayFromDType(e,t){let n=null;if(e==null||e==="float32"){n=new Float32Array(t);}else if(e==="int32"){n=new Int32Array(t);}else if(e==="bool"){n=new Uint8Array(t);}else {throw new Error(`Unknown data type ${e}`)}return n}function getArrayFromDType(e,t){let n=null;if(e==null||e==="float32"){n=new Float32Array(t);}else if(e==="int32"){n=new Int32Array(t);}else if(e==="bool"){n=new Uint8Array(t);}else if(e==="string"){n=new Array(t);}else {throw new Error(`Unknown data type ${e}`)}return n}function checkConversionForErrors(e,t){for(let n=0;n<e.length;n++){const r=e[n];if(isNaN(r)||!isFinite(r)){throw Error(`A tensor of type ${t} being uploaded contains ${r}.`)}}}function isValidDtype(e){return e==="bool"||e==="complex64"||e==="float32"||e==="int32"||e==="string"}function hasEncodingLoss(e,t){if(t==="complex64"){return false}if(t==="float32"&&e!=="complex64"){return false}if(t==="int32"&&e!=="float32"&&e!=="complex64"){return false}if(t==="bool"&&e==="bool"){return false}return true}function isTypedArray(e){return e instanceof Float32Array||e instanceof Int32Array||e instanceof Uint8Array}function bytesPerElement(e){if(e==="float32"||e==="int32"){return 4}else if(e==="complex64"){return 8}else if(e==="bool"){return 1}else {throw new Error(`Unknown dtype ${e}`)}}function bytesFromStringArray(e){if(e==null){return 0}let t=0;e.forEach((e=>t+=e.length));return t}function isString(e){return typeof e==="string"||e instanceof String}function isBoolean(e){return typeof e==="boolean"}function isNumber(e){return typeof e==="number"}function inferDtype(e){if(Array.isArray(e)){return inferDtype(e[0])}if(e instanceof Float32Array){return "float32"}else if(e instanceof Int32Array||e instanceof Uint8Array){return "int32"}else if(isNumber(e)){return "float32"}else if(isString(e)){return "string"}else if(isBoolean(e)){return "bool"}return "float32"}function isFunction(e){return !!(e&&e.constructor&&e.call&&e.apply)}function nearestDivisor(e,t){for(let n=t;n<e;++n){if(e%n===0){return n}}return e}function computeStrides(e){const t=e.length;if(t<2){return []}const n=new Array(t-1);n[t-2]=e[t-1];for(let r=t-3;r>=0;--r){n[r]=n[r+1]*e[r+1];}return n}function createNestedArray(e,t,n,r=false){const s=new Array;if(t.length===1){const a=t[0]*(r?2:1);for(let t=0;t<a;t++){s[t]=n[e+t];}}else {const a=t[0];const o=t.slice(1);const i=o.reduce(((e,t)=>e*t))*(r?2:1);for(let t=0;t<a;t++){s[t]=createNestedArray(e+t*i,o,n,r);}}return s}function toNestedArray(e,t,n=false){if(e.length===0){return t[0]}const r=e.reduce(((e,t)=>e*t))*(n?2:1);if(r===0){return []}if(r!==t.length){throw new Error(`[${e}] does not match the input size ${t.length}${n?" for a complex tensor":""}.`)}return createNestedArray(0,e,t,n)}function makeOnesTypedArray(e,t){const n=makeZerosTypedArray(e,t);for(let e=0;e<n.length;e++){n[e]=1;}return n}function makeZerosTypedArray(e,t){if(t==null||t==="float32"||t==="complex64"){return new Float32Array(e)}else if(t==="int32"){return new Int32Array(e)}else if(t==="bool"){return new Uint8Array(e)}else {throw new Error(`Unknown data type ${t}`)}}function assertNonNegativeIntegerDimensions(e){e.forEach((t=>{assert(Number.isInteger(t)&&t>=0,(()=>`Tensor must have a shape comprised of positive integers but got `+`shape [${e}].`));}));}function locToIndex(e,t,n){if(t===0){return 0}else if(t===1){return e[0]}let r=e[e.length-1];for(let t=0;t<e.length-1;++t){r+=n[t]*e[t];}return r}function indexToLoc(e,t,n){if(t===0){return []}else if(t===1){return [e]}const r=new Array(t);for(let t=0;t<r.length-1;++t){r[t]=Math.floor(e/n[t]);e-=r[t]*n[t];}r[r.length-1]=e;return r}function isPromise(e){return e&&e.then&&typeof e.then==="function"}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const TENSORFLOWJS_FLAGS_PREFIX="tfjsflags";class Environment{constructor(e){this.global=e;this.flags={};this.flagRegistry={};this.urlFlags={};this.getQueryParams=getQueryParams;this.populateURLFlags();}setPlatform(e,t){if(this.platform!=null){console.warn(`Platform ${this.platformName} has already been set. `+`Overwriting the platform with ${t}.`);}this.platformName=e;this.platform=t;}registerFlag(e,t,n){this.flagRegistry[e]={evaluationFn:t,setHook:n};if(this.urlFlags[e]!=null){const t=this.urlFlags[e];console.warn(`Setting feature override from URL ${e}: ${t}.`);this.set(e,t);}}async getAsync(e){if(e in this.flags){return this.flags[e]}this.flags[e]=await this.evaluateFlag(e);return this.flags[e]}get(e){if(e in this.flags){return this.flags[e]}const t=this.evaluateFlag(e);if(isPromise(t)){throw new Error(`Flag ${e} cannot be synchronously evaluated. `+`Please use getAsync() instead.`)}this.flags[e]=t;return this.flags[e]}getNumber(e){return this.get(e)}getBool(e){return this.get(e)}getFlags(){return this.flags}get features(){return this.flags}set(e,t){if(this.flagRegistry[e]==null){throw new Error(`Cannot set flag ${e} as it has not been registered.`)}this.flags[e]=t;if(this.flagRegistry[e].setHook!=null){this.flagRegistry[e].setHook(t);}}evaluateFlag(e){if(this.flagRegistry[e]==null){throw new Error(`Cannot evaluate flag '${e}': no evaluation function found.`)}return this.flagRegistry[e].evaluationFn()}setFlags(e){this.flags=Object.assign({},e);}reset(){this.flags={};this.urlFlags={};this.populateURLFlags();}populateURLFlags(){if(typeof this.global==="undefined"||typeof this.global.location==="undefined"||typeof this.global.location.search==="undefined"){return}const e=this.getQueryParams(this.global.location.search);if(TENSORFLOWJS_FLAGS_PREFIX in e){const t=e[TENSORFLOWJS_FLAGS_PREFIX].split(",");t.forEach((e=>{const[t,n]=e.split(":");this.urlFlags[t]=parseValue(t,n);}));}}}function getQueryParams(e){const t={};e.replace(/[?&]([^=?&]+)(?:=([^&]*))?/g,((e,...n)=>{decodeParam(t,n[0],n[1]);return n.join("=")}));return t}function decodeParam(e,t,n){e[decodeURIComponent(t)]=decodeURIComponent(n||"");}function parseValue(e,t){t=t.toLowerCase();if(t==="true"||t==="false"){return t==="true"}else if(`${+t}`===t){return +t}throw new Error(`Could not parse value flag value ${t} for flag ${e}.`)}function env(){return ENV$2}let ENV$2=null;function setEnvironmentGlobal(e){ENV$2=e;}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */let globalNameSpace;function getGlobalNamespace(){if(globalNameSpace==null){let e;if(typeof window!=="undefined"){e=window;}else if(typeof commonjsGlobal$1!=="undefined"){e=commonjsGlobal$1;}else if(typeof process!=="undefined"){e=process;}else if(typeof self!=="undefined"){e=self;}else {throw new Error("Could not find a global object")}globalNameSpace=e;}return globalNameSpace}function getGlobalMap(){const e=getGlobalNamespace();if(e._tfGlobals==null){e._tfGlobals=new Map;}return e._tfGlobals}function getGlobal(e,t){const n=getGlobalMap();if(n.has(e)){return n.get(e)}else {const r=t();n.set(e,r);return n.get(e)}}const Abs="Abs";const Acos="Acos";const Acosh="Acosh";const Add="Add";const AddN="AddN";const All="All";const Any="Any";const ArgMax="ArgMax";const ArgMin="ArgMin";const Asin="Asin";const Asinh="Asinh";const Atan="Atan";const Atanh="Atanh";const Atan2="Atan2";const AvgPool="AvgPool";const AvgPool3D="AvgPool3D";const BatchMatMul="BatchMatMul";const BatchToSpaceND="BatchToSpaceND";const Bincount="Bincount";const Cast="Cast";const Ceil="Ceil";const ClipByValue="ClipByValue";const Complex="Complex";const ComplexAbs="ComplexAbs";const Concat="Concat";const Conv2D="Conv2D";const Conv2DBackpropFilter="Conv2DBackpropFilter";const Conv2DBackpropInput="Conv2DBackpropInput";const Conv3D="Conv3D";const Cos="Cos";const Cosh="Cosh";const Cumsum="Cumsum";const CropAndResize="CropAndResize";const DenseBincount="DenseBincount";const DepthToSpace="DepthToSpace";const DepthwiseConv2dNative="DepthwiseConv2dNative";const DepthwiseConv2dNativeBackpropFilter="DepthwiseConv2dNativeBackpropFilter";const DepthwiseConv2dNativeBackpropInput="DepthwiseConv2dNativeBackpropInput";const Dilation2D="Dilation2D";const RealDiv="RealDiv";const Einsum="Einsum";const Elu="Elu";const Erf="Erf";const Equal="Equal";const Exp="Exp";const ExpandDims="ExpandDims";const Expm1="Expm1";const FFT="FFT";const Fill="Fill";const FlipLeftRight="FlipLeftRight";const Floor="Floor";const FloorDiv="FloorDiv";const FusedBatchNorm="FusedBatchNorm";const GatherV2="GatherV2";const GatherNd="GatherNd";const Greater="Greater";const GreaterEqual="GreaterEqual";const Identity="Identity";const IFFT="IFFT";const Imag="Imag";const IsFinite="IsFinite";const IsNan="IsNan";const LeakyRelu="LeakyRelu";const Less="Less";const LessEqual="LessEqual";const LinSpace="LinSpace";const Log="Log";const Log1p="Log1p";const LogicalAnd="LogicalAnd";const LogicalNot="LogicalNot";const LogicalOr="LogicalOr";const LRN="LRN";const Max="Max";const Maximum="Maximum";const MaxPool="MaxPool";const MaxPool3D="MaxPool3D";const MaxPoolWithArgmax="MaxPoolWithArgmax";const Mean="Mean";const Min="Min";const Minimum="Minimum";const MirrorPad="MirrorPad";const Mod="Mod";const Multinomial="Multinomial";const Multiply="Multiply";const Neg="Neg";const NotEqual="NotEqual";const NonMaxSuppressionV3="NonMaxSuppressionV3";const NonMaxSuppressionV4="NonMaxSuppressionV4";const NonMaxSuppressionV5="NonMaxSuppressionV5";const OnesLike="OnesLike";const OneHot="OneHot";const Pack="Pack";const PadV2="PadV2";const Pow="Pow";const Prelu="Prelu";const Prod="Prod";const Range="Range";const Real="Real";const Reciprocal="Reciprocal";const Relu="Relu";const Reshape="Reshape";const ResizeNearestNeighbor="ResizeNearestNeighbor";const ResizeBilinear="ResizeBilinear";const Relu6="Relu6";const Reverse="Reverse";const Round="Round";const Rsqrt="Rsqrt";const ScatterNd="ScatterNd";const Select="Select";const Selu="Selu";const Slice="Slice";const Sin="Sin";const Sinh="Sinh";const Sign="Sign";const Sigmoid="Sigmoid";const Softplus="Softplus";const Sqrt="Sqrt";const Sum="Sum";const SpaceToBatchND="SpaceToBatchND";const SplitV="SplitV";const Softmax="Softmax";const SparseFillEmptyRows="SparseFillEmptyRows";const SparseReshape="SparseReshape";const SparseSegmentMean="SparseSegmentMean";const SparseSegmentSum="SparseSegmentSum";const SparseToDense="SparseToDense";const SquaredDifference="SquaredDifference";const StridedSlice="StridedSlice";const StringNGrams="StringNGrams";const StringSplit="StringSplit";const StringToHashBucketFast="StringToHashBucketFast";const Sub="Sub";const Tan="Tan";const Tanh="Tanh";const Tile="Tile";const TopK="TopK";const Transform="Transform";const Transpose="Transpose";const Unique="Unique";const Unpack="Unpack";const ZerosLike="ZerosLike";const Step="Step";const RotateWithOffset="RotateWithOffset";const _FusedMatMul="_FusedMatMul";const FusedConv2D="FusedConv2D";const FusedDepthwiseConv2D="FusedDepthwiseConv2D";
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const kernelRegistry=getGlobal("kernelRegistry",(()=>new Map));const gradRegistry=getGlobal("gradRegistry",(()=>new Map));function getKernel(e,t){const n=makeKey(e,t);return kernelRegistry.get(n)}function getGradient(e){return gradRegistry.get(e)}function getKernelsForBackend(e){const t=kernelRegistry.entries();const n=[];while(true){const{done:r,value:s}=t.next();if(r){break}const[a,o]=s;const[i]=a.split("_");if(i===e){n.push(o);}}return n}function registerKernel(e){const{kernelName:t,backendName:n}=e;const r=makeKey(t,n);if(kernelRegistry.has(r)){console.warn(`The kernel '${t}' for backend `+`'${n}' is already registered`);}kernelRegistry.set(r,e);}function makeKey(e,t){return `${t}_${e}`}var commonjsGlobal=typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:typeof commonjsGlobal$1!=="undefined"?commonjsGlobal$1:typeof self!=="undefined"?self:{};var long=Long$1;var wasm=null;try{wasm=new WebAssembly.Instance(new WebAssembly.Module(new Uint8Array([0,97,115,109,1,0,0,0,1,13,2,96,0,1,127,96,4,127,127,127,127,1,127,3,7,6,0,1,1,1,1,1,6,6,1,127,1,65,0,11,7,50,6,3,109,117,108,0,1,5,100,105,118,95,115,0,2,5,100,105,118,95,117,0,3,5,114,101,109,95,115,0,4,5,114,101,109,95,117,0,5,8,103,101,116,95,104,105,103,104,0,0,10,191,1,6,4,0,35,0,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,126,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,127,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,128,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,129,34,4,66,32,135,167,36,0,32,4,167,11,36,1,1,126,32,0,173,32,1,173,66,32,134,132,32,2,173,32,3,173,66,32,134,132,130,34,4,66,32,135,167,36,0,32,4,167,11])),{}).exports;}catch(e){}function Long$1(e,t,n){this.low=e|0;this.high=t|0;this.unsigned=!!n;}Long$1.prototype.__isLong__;Object.defineProperty(Long$1.prototype,"__isLong__",{value:true});function isLong(e){return (e&&e["__isLong__"])===true}Long$1.isLong=isLong;var INT_CACHE={};var UINT_CACHE={};function fromInt(e,t){var n,r,s;if(t){e>>>=0;if(s=0<=e&&e<256){r=UINT_CACHE[e];if(r)return r}n=fromBits(e,(e|0)<0?-1:0,true);if(s)UINT_CACHE[e]=n;return n}else {e|=0;if(s=-128<=e&&e<128){r=INT_CACHE[e];if(r)return r}n=fromBits(e,e<0?-1:0,false);if(s)INT_CACHE[e]=n;return n}}Long$1.fromInt=fromInt;function fromNumber(e,t){if(isNaN(e))return t?UZERO:ZERO;if(t){if(e<0)return UZERO;if(e>=TWO_PWR_64_DBL)return MAX_UNSIGNED_VALUE}else {if(e<=-TWO_PWR_63_DBL)return MIN_VALUE;if(e+1>=TWO_PWR_63_DBL)return MAX_VALUE}if(e<0)return fromNumber(-e,t).neg();return fromBits(e%TWO_PWR_32_DBL|0,e/TWO_PWR_32_DBL|0,t)}Long$1.fromNumber=fromNumber;function fromBits(e,t,n){return new Long$1(e,t,n)}Long$1.fromBits=fromBits;var pow_dbl=Math.pow;function fromString(e,t,n){if(e.length===0)throw Error("empty string");if(e==="NaN"||e==="Infinity"||e==="+Infinity"||e==="-Infinity")return ZERO;if(typeof t==="number"){n=t,t=false;}else {t=!!t;}n=n||10;if(n<2||36<n)throw RangeError("radix");var r;if((r=e.indexOf("-"))>0)throw Error("interior hyphen");else if(r===0){return fromString(e.substring(1),t,n).neg()}var s=fromNumber(pow_dbl(n,8));var a=ZERO;for(var o=0;o<e.length;o+=8){var i=Math.min(8,e.length-o),u=parseInt(e.substring(o,o+i),n);if(i<8){var c=fromNumber(pow_dbl(n,i));a=a.mul(c).add(fromNumber(u));}else {a=a.mul(s);a=a.add(fromNumber(u));}}a.unsigned=t;return a}Long$1.fromString=fromString;function fromValue(e,t){if(typeof e==="number")return fromNumber(e,t);if(typeof e==="string")return fromString(e,t);return fromBits(e.low,e.high,typeof t==="boolean"?t:e.unsigned)}Long$1.fromValue=fromValue;var TWO_PWR_16_DBL=1<<16;var TWO_PWR_24_DBL=1<<24;var TWO_PWR_32_DBL=TWO_PWR_16_DBL*TWO_PWR_16_DBL;var TWO_PWR_64_DBL=TWO_PWR_32_DBL*TWO_PWR_32_DBL;var TWO_PWR_63_DBL=TWO_PWR_64_DBL/2;var TWO_PWR_24=fromInt(TWO_PWR_24_DBL);var ZERO=fromInt(0);Long$1.ZERO=ZERO;var UZERO=fromInt(0,true);Long$1.UZERO=UZERO;var ONE=fromInt(1);Long$1.ONE=ONE;var UONE=fromInt(1,true);Long$1.UONE=UONE;var NEG_ONE=fromInt(-1);Long$1.NEG_ONE=NEG_ONE;var MAX_VALUE=fromBits(4294967295|0,2147483647|0,false);Long$1.MAX_VALUE=MAX_VALUE;var MAX_UNSIGNED_VALUE=fromBits(4294967295|0,4294967295|0,true);Long$1.MAX_UNSIGNED_VALUE=MAX_UNSIGNED_VALUE;var MIN_VALUE=fromBits(0,2147483648|0,false);Long$1.MIN_VALUE=MIN_VALUE;var LongPrototype=Long$1.prototype;LongPrototype.toInt=function e(){return this.unsigned?this.low>>>0:this.low};LongPrototype.toNumber=function e(){if(this.unsigned)return (this.high>>>0)*TWO_PWR_32_DBL+(this.low>>>0);return this.high*TWO_PWR_32_DBL+(this.low>>>0)};LongPrototype.toString=function e(t){t=t||10;if(t<2||36<t)throw RangeError("radix");if(this.isZero())return "0";if(this.isNegative()){if(this.eq(MIN_VALUE)){var n=fromNumber(t),r=this.div(n),s=r.mul(n).sub(this);return r.toString(t)+s.toInt().toString(t)}else return "-"+this.neg().toString(t)}var a=fromNumber(pow_dbl(t,6),this.unsigned),o=this;var i="";while(true){var u=o.div(a),c=o.sub(u.mul(a)).toInt()>>>0,l=c.toString(t);o=u;if(o.isZero())return l+i;else {while(l.length<6)l="0"+l;i=""+l+i;}}};LongPrototype.getHighBits=function e(){return this.high};LongPrototype.getHighBitsUnsigned=function e(){return this.high>>>0};LongPrototype.getLowBits=function e(){return this.low};LongPrototype.getLowBitsUnsigned=function e(){return this.low>>>0};LongPrototype.getNumBitsAbs=function e(){if(this.isNegative())return this.eq(MIN_VALUE)?64:this.neg().getNumBitsAbs();var t=this.high!=0?this.high:this.low;for(var n=31;n>0;n--)if((t&1<<n)!=0)break;return this.high!=0?n+33:n+1};LongPrototype.isZero=function e(){return this.high===0&&this.low===0};LongPrototype.eqz=LongPrototype.isZero;LongPrototype.isNegative=function e(){return !this.unsigned&&this.high<0};LongPrototype.isPositive=function e(){return this.unsigned||this.high>=0};LongPrototype.isOdd=function e(){return (this.low&1)===1};LongPrototype.isEven=function e(){return (this.low&1)===0};LongPrototype.equals=function e(t){if(!isLong(t))t=fromValue(t);if(this.unsigned!==t.unsigned&&this.high>>>31===1&&t.high>>>31===1)return false;return this.high===t.high&&this.low===t.low};LongPrototype.eq=LongPrototype.equals;LongPrototype.notEquals=function e(t){return !this.eq(t)};LongPrototype.neq=LongPrototype.notEquals;LongPrototype.ne=LongPrototype.notEquals;LongPrototype.lessThan=function e(t){return this.comp(t)<0};LongPrototype.lt=LongPrototype.lessThan;LongPrototype.lessThanOrEqual=function e(t){return this.comp(t)<=0};LongPrototype.lte=LongPrototype.lessThanOrEqual;LongPrototype.le=LongPrototype.lessThanOrEqual;LongPrototype.greaterThan=function e(t){return this.comp(t)>0};LongPrototype.gt=LongPrototype.greaterThan;LongPrototype.greaterThanOrEqual=function e(t){return this.comp(t)>=0};LongPrototype.gte=LongPrototype.greaterThanOrEqual;LongPrototype.ge=LongPrototype.greaterThanOrEqual;LongPrototype.compare=function e(t){if(!isLong(t))t=fromValue(t);if(this.eq(t))return 0;var n=this.isNegative(),r=t.isNegative();if(n&&!r)return -1;if(!n&&r)return 1;if(!this.unsigned)return this.sub(t).isNegative()?-1:1;return t.high>>>0>this.high>>>0||t.high===this.high&&t.low>>>0>this.low>>>0?-1:1};LongPrototype.comp=LongPrototype.compare;LongPrototype.negate=function e(){if(!this.unsigned&&this.eq(MIN_VALUE))return MIN_VALUE;return this.not().add(ONE)};LongPrototype.neg=LongPrototype.negate;LongPrototype.add=function e(t){if(!isLong(t))t=fromValue(t);var n=this.high>>>16;var r=this.high&65535;var s=this.low>>>16;var a=this.low&65535;var o=t.high>>>16;var i=t.high&65535;var u=t.low>>>16;var c=t.low&65535;var l=0,p=0,d=0,h=0;h+=a+c;d+=h>>>16;h&=65535;d+=s+u;p+=d>>>16;d&=65535;p+=r+i;l+=p>>>16;p&=65535;l+=n+o;l&=65535;return fromBits(d<<16|h,l<<16|p,this.unsigned)};LongPrototype.subtract=function e(t){if(!isLong(t))t=fromValue(t);return this.add(t.neg())};LongPrototype.sub=LongPrototype.subtract;LongPrototype.multiply=function e(t){if(this.isZero())return ZERO;if(!isLong(t))t=fromValue(t);if(wasm){var n=wasm.mul(this.low,this.high,t.low,t.high);return fromBits(n,wasm.get_high(),this.unsigned)}if(t.isZero())return ZERO;if(this.eq(MIN_VALUE))return t.isOdd()?MIN_VALUE:ZERO;if(t.eq(MIN_VALUE))return this.isOdd()?MIN_VALUE:ZERO;if(this.isNegative()){if(t.isNegative())return this.neg().mul(t.neg());else return this.neg().mul(t).neg()}else if(t.isNegative())return this.mul(t.neg()).neg();if(this.lt(TWO_PWR_24)&&t.lt(TWO_PWR_24))return fromNumber(this.toNumber()*t.toNumber(),this.unsigned);var r=this.high>>>16;var s=this.high&65535;var a=this.low>>>16;var o=this.low&65535;var i=t.high>>>16;var u=t.high&65535;var c=t.low>>>16;var l=t.low&65535;var p=0,d=0,h=0,m=0;m+=o*l;h+=m>>>16;m&=65535;h+=a*l;d+=h>>>16;h&=65535;h+=o*c;d+=h>>>16;h&=65535;d+=s*l;p+=d>>>16;d&=65535;d+=a*c;p+=d>>>16;d&=65535;d+=o*u;p+=d>>>16;d&=65535;p+=r*l+s*c+a*u+o*i;p&=65535;return fromBits(h<<16|m,p<<16|d,this.unsigned)};LongPrototype.mul=LongPrototype.multiply;LongPrototype.divide=function e(t){if(!isLong(t))t=fromValue(t);if(t.isZero())throw Error("division by zero");if(wasm){if(!this.unsigned&&this.high===-2147483648&&t.low===-1&&t.high===-1){return this}var n=(this.unsigned?wasm.div_u:wasm.div_s)(this.low,this.high,t.low,t.high);return fromBits(n,wasm.get_high(),this.unsigned)}if(this.isZero())return this.unsigned?UZERO:ZERO;var r,s,a;if(!this.unsigned){if(this.eq(MIN_VALUE)){if(t.eq(ONE)||t.eq(NEG_ONE))return MIN_VALUE;else if(t.eq(MIN_VALUE))return ONE;else {var o=this.shr(1);r=o.div(t).shl(1);if(r.eq(ZERO)){return t.isNegative()?ONE:NEG_ONE}else {s=this.sub(t.mul(r));a=r.add(s.div(t));return a}}}else if(t.eq(MIN_VALUE))return this.unsigned?UZERO:ZERO;if(this.isNegative()){if(t.isNegative())return this.neg().div(t.neg());return this.neg().div(t).neg()}else if(t.isNegative())return this.div(t.neg()).neg();a=ZERO;}else {if(!t.unsigned)t=t.toUnsigned();if(t.gt(this))return UZERO;if(t.gt(this.shru(1)))return UONE;a=UZERO;}s=this;while(s.gte(t)){r=Math.max(1,Math.floor(s.toNumber()/t.toNumber()));var i=Math.ceil(Math.log(r)/Math.LN2),u=i<=48?1:pow_dbl(2,i-48),c=fromNumber(r),l=c.mul(t);while(l.isNegative()||l.gt(s)){r-=u;c=fromNumber(r,this.unsigned);l=c.mul(t);}if(c.isZero())c=ONE;a=a.add(c);s=s.sub(l);}return a};LongPrototype.div=LongPrototype.divide;LongPrototype.modulo=function e(t){if(!isLong(t))t=fromValue(t);if(wasm){var n=(this.unsigned?wasm.rem_u:wasm.rem_s)(this.low,this.high,t.low,t.high);return fromBits(n,wasm.get_high(),this.unsigned)}return this.sub(this.div(t).mul(t))};LongPrototype.mod=LongPrototype.modulo;LongPrototype.rem=LongPrototype.modulo;LongPrototype.not=function e(){return fromBits(~this.low,~this.high,this.unsigned)};LongPrototype.and=function e(t){if(!isLong(t))t=fromValue(t);return fromBits(this.low&t.low,this.high&t.high,this.unsigned)};LongPrototype.or=function e(t){if(!isLong(t))t=fromValue(t);return fromBits(this.low|t.low,this.high|t.high,this.unsigned)};LongPrototype.xor=function e(t){if(!isLong(t))t=fromValue(t);return fromBits(this.low^t.low,this.high^t.high,this.unsigned)};LongPrototype.shiftLeft=function e(t){if(isLong(t))t=t.toInt();if((t&=63)===0)return this;else if(t<32)return fromBits(this.low<<t,this.high<<t|this.low>>>32-t,this.unsigned);else return fromBits(0,this.low<<t-32,this.unsigned)};LongPrototype.shl=LongPrototype.shiftLeft;LongPrototype.shiftRight=function e(t){if(isLong(t))t=t.toInt();if((t&=63)===0)return this;else if(t<32)return fromBits(this.low>>>t|this.high<<32-t,this.high>>t,this.unsigned);else return fromBits(this.high>>t-32,this.high>=0?0:-1,this.unsigned)};LongPrototype.shr=LongPrototype.shiftRight;LongPrototype.shiftRightUnsigned=function e(t){if(isLong(t))t=t.toInt();t&=63;if(t===0)return this;else {var n=this.high;if(t<32){var r=this.low;return fromBits(r>>>t|n<<32-t,n>>>t,this.unsigned)}else if(t===32)return fromBits(n,0,this.unsigned);else return fromBits(n>>>t-32,0,this.unsigned)}};LongPrototype.shru=LongPrototype.shiftRightUnsigned;LongPrototype.shr_u=LongPrototype.shiftRightUnsigned;LongPrototype.toSigned=function e(){if(!this.unsigned)return this;return fromBits(this.low,this.high,false)};LongPrototype.toUnsigned=function e(){if(this.unsigned)return this;return fromBits(this.low,this.high,true)};LongPrototype.toBytes=function e(t){return t?this.toBytesLE():this.toBytesBE()};LongPrototype.toBytesLE=function e(){var t=this.high,n=this.low;return [n&255,n>>>8&255,n>>>16&255,n>>>24,t&255,t>>>8&255,t>>>16&255,t>>>24]};LongPrototype.toBytesBE=function e(){var t=this.high,n=this.low;return [t>>>24,t>>>16&255,t>>>8&255,t&255,n>>>24,n>>>16&255,n>>>8&255,n&255]};Long$1.fromBytes=function e(t,n,r){return r?Long$1.fromBytesLE(t,n):Long$1.fromBytesBE(t,n)};Long$1.fromBytesLE=function e(t,n){return new Long$1(t[0]|t[1]<<8|t[2]<<16|t[3]<<24,t[4]|t[5]<<8|t[6]<<16|t[7]<<24,n)};Long$1.fromBytesBE=function e(t,n){return new Long$1(t[4]<<24|t[5]<<16|t[6]<<8|t[7],t[0]<<24|t[1]<<16|t[2]<<8|t[3],n)};var LongExports=Object.freeze(Object.assign(Object.create(null),long,{default:long}));
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const Long=long||LongExports;function hexToLong(e){return Long.fromString(e,true,16)}const k0=hexToLong("c3a5c85c97cb3127");const k1=hexToLong("b492b66fbe98f273");const k2=hexToLong("9ae16a3b2f90404f");function shiftMix(e){return e.xor(e.shru(47))}function fetch$1(e,t,n){const r=e.slice(t,t+n);return Long.fromBytes(Array.from(r),true,true)}function fetch64(e,t){return fetch$1(e,t,8)}function fetch32(e,t){return fetch$1(e,t,4)}function rotate64(e,t){return t===0?e:e.shru(t).or(e.shl(64-t))}function hashLen16(e,t,n=hexToLong("9ddfea08eb382d69")){let r=e.xor(t).mul(n);r=r.xor(r.shru(47));let s=t.xor(r).mul(n);s=s.xor(s.shru(47));s=s.mul(n);return s}function weakHashLen32WithSeeds(e,t,n,r,s,a){s=s.add(e);a=rotate64(a.add(s).add(r),21);const o=s;s=s.add(t);s=s.add(n);a=a.add(rotate64(s,44));return [s.add(r),a.add(o)]}function weakHashLen32WithSeedsStr(e,t,n,r){return weakHashLen32WithSeeds(fetch64(e,t),fetch64(e,t+8),fetch64(e,t+16),fetch64(e,t+24),n,r)}function hashLen0to16(e,t=e.length){if(t>=8){const n=k2.add(t*2);const r=fetch64(e,0).add(k2);const s=fetch64(e,t-8);const a=rotate64(s,37).mul(n).add(r);const o=rotate64(r,25).add(s).mul(n);return hashLen16(a,o,n)}if(t>=4){const n=k2.add(t*2);const r=fetch32(e,0);return hashLen16(r.shl(3).add(t),fetch32(e,t-4),n)}if(t>0){const n=e[0];const r=e[t>>1];const s=e[t-1];const a=n+(r<<8);const o=t+(s<<2);return shiftMix(k2.mul(a).xor(k0.mul(o))).mul(k2)}return k2}function hashLen17to32(e,t=e.length){const n=k2.add(t*2);const r=fetch64(e,0).mul(k1);const s=fetch64(e,8);const a=fetch64(e,t-8).mul(n);const o=fetch64(e,t-16).mul(k2);return hashLen16(rotate64(r.add(s),43).add(rotate64(a,30)).add(o),r.add(rotate64(s.add(k2),18)).add(a),n)}function hashLen33to64(e,t=e.length){const n=k2.add(t*2);const r=fetch64(e,0).mul(k2);const s=fetch64(e,8);const a=fetch64(e,t-8).mul(n);const o=fetch64(e,t-16).mul(k2);const i=rotate64(r.add(s),43).add(rotate64(a,30)).add(o);const u=hashLen16(i,r.add(rotate64(s.add(k2),18)).add(a),n);const c=fetch64(e,16).mul(n);const l=fetch64(e,24);const p=i.add(fetch64(e,t-32)).mul(n);const d=u.add(fetch64(e,t-24)).mul(n);return hashLen16(rotate64(c.add(l),43).add(rotate64(p,30)).add(d),c.add(rotate64(l.add(r),18)).add(p),n)}function fingerPrint64(e,t=e.length){const n=Long.fromNumber(81,true);if(t<=32){if(t<=16){return hashLen0to16(e,t)}else {return hashLen17to32(e,t)}}else if(t<=64){return hashLen33to64(e,t)}let r=n;let s=n.mul(k1).add(113);let a=shiftMix(s.mul(k2).add(113)).mul(k2);let o=[Long.UZERO,Long.UZERO];let i=[Long.UZERO,Long.UZERO];r=r.mul(k2).add(fetch64(e,0));let u=0;const c=(t-1>>6)*64;const l=c+(t-1&63)-63;do{r=rotate64(r.add(s).add(o[0]).add(fetch64(e,u+8)),37).mul(k1);s=rotate64(s.add(o[1]).add(fetch64(e,u+48)),42).mul(k1);r=r.xor(i[1]);s=s.add(o[0]).add(fetch64(e,u+40));a=rotate64(a.add(i[0]),33).mul(k1);o=weakHashLen32WithSeedsStr(e,u,o[1].mul(k1),r.add(i[0]));i=weakHashLen32WithSeedsStr(e,u+32,a.add(i[1]),s.add(fetch64(e,u+16)));[a,r]=[r,a];u+=64;}while(u!==c);const p=k1.add(a.and(255).shl(1));u=l;i[0]=i[0].add(t-1&63);o[0]=o[0].add(i[0]);i[0]=i[0].add(o[0]);r=rotate64(r.add(s).add(o[0]).add(fetch64(e,u+8)),37).mul(p);s=rotate64(s.add(o[1]).add(fetch64(e,u+48)),42).mul(p);r=r.xor(i[1].mul(9));s=s.add(o[0].mul(9).add(fetch64(e,u+40)));a=rotate64(a.add(i[0]),33).mul(p);o=weakHashLen32WithSeedsStr(e,u,o[1].mul(p),r.add(i[0]));i=weakHashLen32WithSeedsStr(e,u+32,a.add(i[1]),s.add(fetch64(e,u+16)));[a,r]=[r,a];return hashLen16(hashLen16(o[0],i[0],p).add(shiftMix(s).mul(k0)).add(a),hashLen16(o[1],i[1],p).add(r),p)}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function createScalarValue(e,t){if(t==="string"){return encodeString(e)}return toTypedArray([e],t)}function noConversionNeeded(e,t){return e instanceof Float32Array&&t==="float32"||e instanceof Int32Array&&t==="int32"||e instanceof Uint8Array&&t==="bool"}function toTypedArray(e,t){if(t==="string"){throw new Error("Cannot convert a string[] to a TypedArray")}if(Array.isArray(e)){e=flatten(e);}if(env().getBool("DEBUG")){checkConversionForErrors(e,t);}if(noConversionNeeded(e,t)){return e}if(t==null||t==="float32"||t==="complex64"){return new Float32Array(e)}else if(t==="int32"){return new Int32Array(e)}else if(t==="bool"){const t=new Uint8Array(e.length);for(let n=0;n<t.length;++n){if(Math.round(e[n])!==0){t[n]=1;}}return t}else {throw new Error(`Unknown data type ${t}`)}}function now(){return env().platform.now()}function encodeString(e,t="utf-8"){t=t||"utf-8";return env().platform.encode(e,t)}function decodeString(e,t="utf-8"){t=t||"utf-8";return env().platform.decode(e,t)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class Profiler{constructor(e,t){this.backendTimer=e;this.logger=t;if(t==null){this.logger=new Logger;}}profileKernel(e,t,n){let r;const s=()=>{r=n();};let a;const o=now();if(this.backendTimer.timerAvailable()){a=this.backendTimer.time(s);}else {s();for(const e of r){e.dataSync();}a=Promise.resolve({kernelMs:now()-o});}if(env().getBool("CHECK_COMPUTATION_FOR_ERRORS")){for(let t=0;t<r.length;t++){const n=r[t];n.data().then((t=>{checkComputationForErrors(t,n.dtype,e);}));}}const i={kernelName:e,outputs:r,inputs:t,timeMs:a.then((e=>e.kernelMs)),extraInfo:a.then((e=>e.getExtraProfileInfo!=null?e.getExtraProfileInfo():""))};return i}logKernelProfile(e){const{kernelName:t,outputs:n,timeMs:r,inputs:s,extraInfo:a}=e;n.forEach((e=>{Promise.all([e.data(),r,a]).then((n=>{this.logger.logKernelProfile(t,e,n[0],n[1],s,n[2]);}));}));}}function checkComputationForErrors(e,t,n){if(t!=="float32"){return false}for(let t=0;t<e.length;t++){const r=e[t];if(isNaN(r)||!isFinite(r)){console.warn(`Found ${r} in the result of '${n}'`);return true}}return false}class Logger{logKernelProfile(e,t,n,r,s,a){const o=typeof r==="number"?rightPad(`${r}ms`,9):r["error"];const i=rightPad(e,25);const u=t.rank;const c=t.size;const l=rightPad(t.shape.toString(),14);let p="";for(const e in s){const n=s[e];if(n!=null){const r=n.shape||t.shape;const s=r.length;p+=`${e}: ${s}D ${s>0?r:""} `;}}console.log(`%c${i}\t%c${o}\t%c${u}D ${l}\t%c${c}\t%c${p}\t%c${a}`,"font-weight:bold","color:red","color:blue","color: orange","color: green","color: steelblue");}}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getFilteredNodesXToY(e,t,n){const r={};const s={};for(let e=0;e<t.length;e++){r[t[e].id]=true;}for(let n=0;n<e.length;n++){const a=e[n];const o=a.inputs;for(const e in o){const n=o[e];let i=false;for(let e=0;e<t.length;e++){if(r[n.id]){a.outputs.forEach((e=>r[e.id]=true));i=true;s[a.id]=true;break}}if(i){break}}}const a={};a[n.id]=true;const o={};for(let t=e.length-1;t>=0;t--){const n=e[t];const r=n.inputs;for(let e=0;e<n.outputs.length;e++){if(a[n.outputs[e].id]){for(const e in r){a[r[e].id]=true;o[n.id]=true;}break}}}const i=[];for(let t=0;t<e.length;t++){const n=e[t];if(s[n.id]&&o[n.id]){const e={};for(const t in n.inputs){const s=n.inputs[t];if(r[s.id]){e[t]=s;}}const t=Object.assign({},n);t.inputs=e;t.outputs=n.outputs;i.push(t);}}return i}function backpropagateGradients(e,t,n,r){for(let s=t.length-1;s>=0;s--){const a=t[s];const o=[];a.outputs.forEach((t=>{const n=e[t.id];if(n!=null){o.push(n);}else {o.push(null);}}));if(a.gradient==null){throw new Error(`Cannot compute gradient: gradient function not found `+`for ${a.kernelName}.`)}const i=a.gradient(o);for(const t in a.inputs){if(!(t in i)){throw new Error(`Cannot backprop through input ${t}. `+`Available gradients found: ${Object.keys(i)}.`)}const s=n((()=>i[t]()));if(s.dtype!=="float32"){throw new Error(`Error in gradient for op ${a.kernelName}. The gradient of input `+`${t} must have 'float32' dtype, but has '${s.dtype}'`)}const o=a.inputs[t];if(!arraysEqual(s.shape,o.shape)){throw new Error(`Error in gradient for op ${a.kernelName}. The gradient of input `+`'${t}' has shape '${s.shape}', which does not match `+`the shape of the input '${o.shape}'`)}if(e[o.id]==null){e[o.id]=s;}else {const t=e[o.id];e[o.id]=r(t,s);t.dispose();}}}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const FORMAT_LIMIT_NUM_VALS=20;const FORMAT_NUM_FIRST_LAST_VALS=3;const FORMAT_NUM_SIG_DIGITS=7;function tensorToString(e,t,n,r){const s=computeStrides(t);const a=computeMaxSizePerColumn(e,t,n,s);const o=t.length;const i=subTensorToString(e,t,n,s,a);const u=["Tensor"];if(r){u.push(`  dtype: ${n}`);u.push(`  rank: ${o}`);u.push(`  shape: [${t}]`);u.push(`  values:`);}u.push(i.map((e=>"    "+e)).join("\n"));return u.join("\n")}function computeMaxSizePerColumn(e,t,n,r){const s=sizeFromShape(t);const a=r[r.length-1];const o=new Array(a).fill(0);const i=t.length;const u=n==="complex64"?createComplexTuples(e):e;if(i>1){for(let e=0;e<s/a;e++){const t=e*a;for(let e=0;e<a;e++){o[e]=Math.max(o[e],valToString(u[t+e],0,n).length);}}}return o}function valToString(e,t,n){let r;if(Array.isArray(e)){r=`${parseFloat(e[0].toFixed(FORMAT_NUM_SIG_DIGITS))} + `+`${parseFloat(e[1].toFixed(FORMAT_NUM_SIG_DIGITS))}j`;}else if(isString(e)){r=`'${e}'`;}else if(n==="bool"){r=boolNumToString(e);}else {r=parseFloat(e.toFixed(FORMAT_NUM_SIG_DIGITS)).toString();}return rightPad(r,t)}function boolNumToString(e){return e===0?"false":"true"}function subTensorToString(e,t,n,r,s,a=true){const o=n==="complex64"?2:1;const i=t[0];const u=t.length;if(u===0){if(n==="complex64"){const t=createComplexTuples(e);return [valToString(t[0],0,n)]}if(n==="bool"){return [boolNumToString(e[0])]}return [e[0].toString()]}if(u===1){if(i>FORMAT_LIMIT_NUM_VALS){const t=FORMAT_NUM_FIRST_LAST_VALS*o;let r=Array.from(e.slice(0,t));let a=Array.from(e.slice((i-FORMAT_NUM_FIRST_LAST_VALS)*o,i*o));if(n==="complex64"){r=createComplexTuples(r);a=createComplexTuples(a);}return ["["+r.map(((e,t)=>valToString(e,s[t],n))).join(", ")+", ..., "+a.map(((e,t)=>valToString(e,s[i-FORMAT_NUM_FIRST_LAST_VALS+t],n))).join(", ")+"]"]}const t=n==="complex64"?createComplexTuples(e):Array.from(e);return ["["+t.map(((e,t)=>valToString(e,s[t],n))).join(", ")+"]"]}const c=t.slice(1);const l=r.slice(1);const p=r[0]*o;const d=[];if(i>FORMAT_LIMIT_NUM_VALS){for(let t=0;t<FORMAT_NUM_FIRST_LAST_VALS;t++){const r=t*p;const a=r+p;d.push(...subTensorToString(e.slice(r,a),c,n,l,s,false));}d.push("...");for(let t=i-FORMAT_NUM_FIRST_LAST_VALS;t<i;t++){const r=t*p;const a=r+p;d.push(...subTensorToString(e.slice(r,a),c,n,l,s,t===i-1));}}else {for(let t=0;t<i;t++){const r=t*p;const a=r+p;d.push(...subTensorToString(e.slice(r,a),c,n,l,s,t===i-1));}}const h=u===2?",":"";d[0]="["+d[0]+h;for(let e=1;e<d.length-1;e++){d[e]=" "+d[e]+h;}let m=",\n";for(let e=2;e<u;e++){m+="\n";}d[d.length-1]=" "+d[d.length-1]+"]"+(a?"":m);return d}function createComplexTuples(e){const t=[];for(let n=0;n<e.length;n+=2){t.push([e[n],e[n+1]]);}return t}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class TensorBuffer{constructor(e,t,n){this.dtype=t;this.shape=e.slice();this.size=sizeFromShape(e);if(n!=null){const e=n.length;assert(e===this.size,(()=>`Length of values '${e}' does not match the size `+`inferred by the shape '${this.size}'.`));}if(t==="complex64"){throw new Error(`complex64 dtype TensorBuffers are not supported. Please create `+`a TensorBuffer for the real and imaginary parts separately and `+`call tf.complex(real, imag).`)}this.values=n||getArrayFromDType(t,this.size);this.strides=computeStrides(e);}set(e,...t){if(t.length===0){t=[0];}assert(t.length===this.rank,(()=>`The number of provided coordinates (${t.length}) must `+`match the rank (${this.rank})`));const n=this.locToIndex(t);this.values[n]=e;}get(...e){if(e.length===0){e=[0];}let t=0;for(const n of e){if(n<0||n>=this.shape[t]){const t=`Requested out of range element at ${e}. `+`  Buffer shape=${this.shape}`;throw new Error(t)}t++;}let n=e[e.length-1];for(let t=0;t<e.length-1;++t){n+=this.strides[t]*e[t];}return this.values[n]}locToIndex(e){if(this.rank===0){return 0}else if(this.rank===1){return e[0]}let t=e[e.length-1];for(let n=0;n<e.length-1;++n){t+=this.strides[n]*e[n];}return t}indexToLoc(e){if(this.rank===0){return []}else if(this.rank===1){return [e]}const t=new Array(this.shape.length);for(let n=0;n<t.length-1;++n){t[n]=Math.floor(e/this.strides[n]);e-=t[n]*this.strides[n];}t[t.length-1]=e;return t}get rank(){return this.shape.length}toTensor(){return trackerFn().makeTensor(this.values,this.shape,this.dtype)}}let trackerFn=null;let opHandler$1=null;function setTensorTracker(e){trackerFn=e;}function setOpHandler(e){opHandler$1=e;}class Tensor{constructor(e,t,n,r){this.kept=false;this.isDisposedInternal=false;this.shape=e.slice();this.dtype=t||"float32";this.size=sizeFromShape(e);this.strides=computeStrides(e);this.dataId=n;this.id=r;this.rankType=this.rank<5?this.rank.toString():"higher";}get rank(){return this.shape.length}async buffer(){const e=await this.data();return opHandler$1.buffer(this.shape,this.dtype,e)}bufferSync(){return opHandler$1.buffer(this.shape,this.dtype,this.dataSync())}async array(){const e=await this.data();return toNestedArray(this.shape,e,this.dtype==="complex64")}arraySync(){return toNestedArray(this.shape,this.dataSync(),this.dtype==="complex64")}async data(){this.throwIfDisposed();const e=trackerFn().read(this.dataId);if(this.dtype==="string"){const t=await e;try{return t.map((e=>decodeString(e)))}catch(e){throw new Error("Failed to decode the string bytes into utf-8. "+"To get the original bytes, call tensor.bytes().")}}return e}dataSync(){this.throwIfDisposed();const e=trackerFn().readSync(this.dataId);if(this.dtype==="string"){try{return e.map((e=>decodeString(e)))}catch(e){throw new Error("Failed to decode the string bytes into utf-8. "+"To get the original bytes, call tensor.bytes().")}}return e}async bytes(){this.throwIfDisposed();const e=await trackerFn().read(this.dataId);if(this.dtype==="string"){return e}else {return new Uint8Array(e.buffer)}}dispose(){if(this.isDisposed){return}trackerFn().disposeTensor(this);this.isDisposedInternal=true;}get isDisposed(){return this.isDisposedInternal}throwIfDisposed(){if(this.isDisposed){throw new Error(`Tensor is disposed.`)}}print(e=false){return opHandler$1.print(this,e)}clone(){this.throwIfDisposed();return opHandler$1.clone(this)}toString(e=false){const t=this.dataSync();return tensorToString(t,this.shape,this.dtype,e)}cast(e){this.throwIfDisposed();return opHandler$1.cast(this,e)}variable(e=true,t,n){this.throwIfDisposed();return trackerFn().makeVariable(this,e,t,n)}}Object.defineProperty(Tensor,Symbol.hasInstance,{value:e=>!!e&&e.data!=null&&e.dataSync!=null&&e.throwIfDisposed!=null});function getGlobalTensorClass(){return getGlobal("Tensor",(()=>Tensor))}getGlobalTensorClass();class Variable extends Tensor{constructor(e,t,n,r){super(e.shape,e.dtype,e.dataId,r);this.trainable=t;this.name=n;}assign(e){if(e.dtype!==this.dtype){throw new Error(`dtype of the new value (${e.dtype}) and `+`previous value (${this.dtype}) must match`)}if(!arraysEqual(e.shape,this.shape)){throw new Error(`shape of the new value (${e.shape}) and `+`previous value (${this.shape}) must match`)}trackerFn().disposeTensor(this);this.dataId=e.dataId;trackerFn().incRef(this,null);}dispose(){trackerFn().disposeVariable(this);this.isDisposedInternal=true;}}Object.defineProperty(Variable,Symbol.hasInstance,{value:e=>e instanceof Tensor&&e.assign!=null&&e.assign instanceof Function});
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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 Rank;(function(e){e["R0"]="R0";e["R1"]="R1";e["R2"]="R2";e["R3"]="R3";e["R4"]="R4";e["R5"]="R5";e["R6"]="R6";})(Rank||(Rank={}));var UpcastInt32AndMap;(function(e){e["float32"]="float32";e["int32"]="int32";e["bool"]="int32";e["complex64"]="complex64";})(UpcastInt32AndMap||(UpcastInt32AndMap={}));var UpcastBoolAndMap;(function(e){e["float32"]="float32";e["int32"]="int32";e["bool"]="bool";e["complex64"]="complex64";})(UpcastBoolAndMap||(UpcastBoolAndMap={}));var UpcastFloat32AndMap;(function(e){e["float32"]="float32";e["int32"]="float32";e["bool"]="float32";e["complex64"]="complex64";})(UpcastFloat32AndMap||(UpcastFloat32AndMap={}));var UpcastComplex64AndMap;(function(e){e["float32"]="complex64";e["int32"]="complex64";e["bool"]="complex64";e["complex64"]="complex64";})(UpcastComplex64AndMap||(UpcastComplex64AndMap={}));const upcastTypeMap={float32:UpcastFloat32AndMap,int32:UpcastInt32AndMap,bool:UpcastBoolAndMap,complex64:UpcastComplex64AndMap};function upcastType(e,t){if(e==="string"||t==="string"){if(e==="string"&&t==="string"){return "string"}throw new Error(`Can not upcast ${e} with ${t}`)}return upcastTypeMap[e][t]}function sumOutType(e){return upcastType(e,"int32")}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function makeTypesMatch(e,t){if(e.dtype===t.dtype){return [e,t]}const n=upcastType(e.dtype,t.dtype);return [e.cast(n),t.cast(n)]}function getTensorsInContainer(e){const t=[];const n=new Set;walkTensorContainer(e,t,n);return t}function walkTensorContainer(e,t,n){if(e==null){return}if(e instanceof Tensor){t.push(e);return}if(!isIterable(e)){return}const r=e;for(const e in r){const s=r[e];if(!n.has(s)){n.add(s);walkTensorContainer(s,t,n);}}}function isIterable(e){return Array.isArray(e)||typeof e==="object"}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function isRegisteredKernelInvocation(e){return e.kernelName!=null}class EngineState{constructor(){this.registeredVariables={};this.nextTapeNodeId=0;this.numBytes=0;this.numTensors=0;this.numStringTensors=0;this.numDataBuffers=0;this.gradientDepth=0;this.kernelDepth=0;this.scopeStack=[];this.numDataMovesStack=[];this.nextScopeId=0;this.tensorInfo=new WeakMap;this.profiling=false;this.activeProfile={newBytes:0,newTensors:0,peakBytes:0,kernels:[],result:null,get kernelNames(){return Array.from(new Set(this.kernels.map((e=>e.name))))}};}dispose(){for(const e in this.registeredVariables){this.registeredVariables[e].dispose();}}}class Engine{constructor(e){this.ENV=e;this.registry={};this.registryFactory={};this.pendingBackendInitId=0;this.state=new EngineState;}async ready(){if(this.pendingBackendInit!=null){return this.pendingBackendInit.then((()=>{}))}if(this.backendInstance!=null){return}const e=this.getSortedBackends();for(let t=0;t<e.length;t++){const n=e[t];const r=await this.initializeBackend(n).success;if(r){await this.setBackend(n);return}}throw new Error(`Could not initialize any backends, all backend initializations `+`failed.`)}get backend(){if(this.pendingBackendInit!=null){throw new Error(`Backend '${this.backendName}' has not yet been initialized. Make `+`sure to await tf.ready() or await tf.setBackend() before calling `+`other methods`)}if(this.backendInstance==null){const{name:e,asyncInit:t}=this.initializeBackendsAndReturnBest();if(t){throw new Error(`The highest priority backend '${e}' has not yet been `+`initialized. Make sure to await tf.ready() or `+`await tf.setBackend() before calling other methods`)}this.setBackend(e);}return this.backendInstance}backendNames(){return Object.keys(this.registryFactory)}findBackend(e){if(!(e in this.registry)){if(e in this.registryFactory){const{asyncInit:t}=this.initializeBackend(e);if(t){return null}}else {return null}}return this.registry[e]}findBackendFactory(e){if(!(e in this.registryFactory)){return null}return this.registryFactory[e].factory}registerBackend(e,t,n=1){if(e in this.registryFactory){console.warn(`${e} backend was already registered. `+`Reusing existing backend factory.`);return false}this.registryFactory[e]={factory:t,priority:n};return true}async setBackend(e){if(this.registryFactory[e]==null){throw new Error(`Backend name '${e}' not found in registry`)}this.backendName=e;if(this.registry[e]==null){this.backendInstance=null;const{success:t,asyncInit:n}=this.initializeBackend(e);const r=n?await t:t;if(!r){return false}}this.backendInstance=this.registry[e];this.setupRegisteredKernels();this.profiler=new Profiler(this.backendInstance);return true}setupRegisteredKernels(){const e=getKernelsForBackend(this.backendName);e.forEach((e=>{if(e.setupFunc!=null){e.setupFunc(this.backendInstance);}}));}disposeRegisteredKernels(e){const t=getKernelsForBackend(e);t.forEach((t=>{if(t.disposeFunc!=null){t.disposeFunc(this.registry[e]);}}));}initializeBackend(e){const t=this.registryFactory[e];if(t==null){throw new Error(`Cannot initialize backend ${e}, no registration found.`)}try{const n=t.factory();if(n&&!(n instanceof KernelBackend)&&typeof n.then==="function"){const t=++this.pendingBackendInitId;const r=n.then((n=>{if(t<this.pendingBackendInitId){return false}this.registry[e]=n;this.pendingBackendInit=null;return true})).catch((n=>{if(t<this.pendingBackendInitId){return false}this.pendingBackendInit=null;console.warn(`Initialization of backend ${e} failed`);console.warn(n.stack||n.message);return false}));this.pendingBackendInit=r;return {success:r,asyncInit:true}}else {this.registry[e]=n;return {success:true,asyncInit:false}}}catch(t){console.warn(`Initialization of backend ${e} failed`);console.warn(t.stack||t.message);return {success:false,asyncInit:false}}}removeBackend(e){if(!(e in this.registryFactory)){throw new Error(`${e} backend not found in registry`)}if(this.backendName===e&&this.pendingBackendInit!=null){this.pendingBackendInitId++;}if(e in this.registry){this.disposeRegisteredKernels(e);this.registry[e].dispose();delete this.registry[e];}delete this.registryFactory[e];if(this.backendName===e){this.pendingBackendInit=null;this.backendName=null;this.backendInstance=null;}}getSortedBackends(){if(Object.keys(this.registryFactory).length===0){throw new Error("No backend found in registry.")}return Object.keys(this.registryFactory).sort(((e,t)=>this.registryFactory[t].priority-this.registryFactory[e].priority))}initializeBackendsAndReturnBest(){const e=this.getSortedBackends();for(let t=0;t<e.length;t++){const n=e[t];const{success:r,asyncInit:s}=this.initializeBackend(n);if(s||r){return {name:n,asyncInit:s}}}throw new Error(`Could not initialize any backends, all backend initializations `+`failed.`)}moveData(e,t){const n=this.state.tensorInfo.get(t);const r=n.backend;const s=this.readSync(t);const a=r.refCount(t);r.disposeData(t,true);n.backend=e;e.move(t,s,n.shape,n.dtype,a);if(this.shouldCheckForMemLeaks()){this.state.numDataMovesStack[this.state.numDataMovesStack.length-1]++;}}tidy(e,t){let n=null;if(t==null){if(typeof e!=="function"){throw new Error("Please provide a function to tidy()")}t=e;}else {if(typeof e!=="string"&&!(e instanceof String)){throw new Error("When calling with two arguments, the first argument "+"to tidy() must be a string")}if(typeof t!=="function"){throw new Error("When calling with two arguments, the 2nd argument "+"to tidy() must be a function")}n=e;}let r;return this.scopedRun((()=>this.startScope(n)),(()=>this.endScope(r)),(()=>{r=t();if(r instanceof Promise){console.error("Cannot return a Promise inside of tidy.");}return r}))}scopedRun(e,t,n){e();try{const e=n();t();return e}catch(e){t();throw e}}nextTensorId(){return Engine.nextTensorId++}nextVariableId(){return Engine.nextVariableId++}clone(e){const t=ENGINE.runKernel(Identity,{x:e});const n={x:e};const r=e=>({x:()=>{const t="float32";const n={x:e};const r={dtype:t};return ENGINE.runKernel(Cast,n,r)}});const s=[];this.addTapeNode(this.state.activeScope.name,n,[t],r,s,{});return t}runKernel(e,t,n){const r=getKernel(e,this.backendName)!=null;if(!r){throw new Error(`Kernel '${e}' not registered for backend '${this.backendName}'`)}return this.runKernelFunc({kernelName:e,inputs:t,attrs:n})}shouldCheckForMemLeaks(){return this.ENV.getBool("IS_TEST")}checkKernelForMemLeak(e,t,n){const r=this.backend.numDataIds();let s=0;n.forEach((e=>{s+=e.dtype==="complex64"?3:1;}));const a=this.state.numDataMovesStack[this.state.numDataMovesStack.length-1];const o=r-t-s-a;if(o>0){throw new Error(`Backend '${this.backendName}' has an internal memory leak `+`(${o} data ids) after running '${e}'`)}}runKernelFunc(e){let t;let n=[];const r=this.isTapeOn();const s=this.state.numBytes;const a=this.state.numTensors;if(this.shouldCheckForMemLeaks()){this.state.numDataMovesStack.push(0);}let o;if(this.backendName==null){this.backend;}let i;const u=isRegisteredKernelInvocation(e)?e.kernelName:this.state.activeScope!=null?this.state.activeScope.name:"";if(isRegisteredKernelInvocation(e)){const{kernelName:t,inputs:s,attrs:a}=e;if(this.backendName==null){this.backend;}const u=getKernel(t,this.backendName);assert(u!=null,(()=>`Cannot find registered kernel '${t}' for backend '${this.backendName}'`));o=()=>{const e=this.backend.numDataIds();i=u.kernelFunc({inputs:s,attrs:a,backend:this.backend});const o=Array.isArray(i)?i:[i];if(this.shouldCheckForMemLeaks()){this.checkKernelForMemLeak(t,e,o);}const c=o.map((e=>{if(e.rank!=null){return e}const{dataId:t,shape:n,dtype:r}=e;return this.makeTensorFromDataId(t,n,r)}));if(r){const e=this.getTensorsForGradient(t,s,c);n=this.saveTensorsForBackwardMode(e);}return c};}else {const{forwardFunc:t}=e;const s=e=>{if(!r){return}n=e.map((e=>this.keep(this.clone(e))));};o=()=>{const e=this.backend.numDataIds();i=this.tidy((()=>t(this.backend,s)));const n=Array.isArray(i)?i:[i];if(this.shouldCheckForMemLeaks()){this.checkKernelForMemLeak(u,e,n);}return n};}const{inputs:c,attrs:l}=e;const p=isRegisteredKernelInvocation(e)?null:e.backwardsFunc;let d;this.scopedRun((()=>this.state.kernelDepth++),(()=>this.state.kernelDepth--),(()=>{if(!this.ENV.getBool("DEBUG")&&!this.state.profiling){t=o();}else {d=this.profiler.profileKernel(u,c,(()=>o()));if(this.ENV.getBool("DEBUG")){this.profiler.logKernelProfile(d);}t=d.outputs;}}));if(r){this.addTapeNode(u,c,t,p,n,l);}if(this.state.profiling){this.state.activeProfile.kernels.push({name:u,bytesAdded:this.state.numBytes-s,totalBytesSnapshot:this.state.numBytes,tensorsAdded:this.state.numTensors-a,totalTensorsSnapshot:this.state.numTensors,inputShapes:Object.keys(c).map((e=>c[e]!=null?c[e].shape:null)),outputShapes:t.map((e=>e.shape)),kernelTimeMs:d.timeMs,extraInfo:d.extraInfo});}return Array.isArray(i)?t:t[0]}saveTensorsForBackwardMode(e){const t=e.map((e=>this.keep(this.clone(e))));return t}getTensorsForGradient(e,t,n){const r=getGradient(e);if(r!=null){const e=r.inputsToSave||[];const s=r.outputsToSave||[];let a;if(r.saveAllInputs){assert(Array.isArray(t),(()=>"saveAllInputs is true, expected inputs to be an array."));a=Object.keys(t).map((e=>t[e]));}else {a=e.map((e=>t[e]));}const o=n.filter(((e,t)=>s[t]));return a.concat(o)}return []}makeTensor(e,t,n,r){if(e==null){throw new Error("Values passed to engine.makeTensor() are null")}n=n||"float32";r=r||this.backend;let s=e;if(n==="string"&&isString(e[0])){s=e.map((e=>encodeString(e)));}const a=r.write(s,t,n);const o=new Tensor(t,n,a,this.nextTensorId());this.trackTensor(o,r);if(n==="string"){const e=this.state.tensorInfo.get(a);const t=bytesFromStringArray(s);this.state.numBytes+=t-e.bytes;e.bytes=t;}return o}makeTensorFromDataId(e,t,n,r){n=n||"float32";const s=new Tensor(t,n,e,this.nextTensorId());this.trackTensor(s,r);return s}makeVariable(e,t=true,n,r){n=n||this.nextVariableId().toString();if(r!=null&&r!==e.dtype){e=e.cast(r);}const s=new Variable(e,t,n,this.nextTensorId());if(this.state.registeredVariables[s.name]!=null){throw new Error(`Variable with name ${s.name} was already registered`)}this.state.registeredVariables[s.name]=s;this.incRef(s,this.backend);return s}trackTensor(e,t){this.state.numTensors++;if(e.dtype==="string"){this.state.numStringTensors++;}let n=0;if(e.dtype!=="complex64"&&e.dtype!=="string"){n=e.size*bytesPerElement(e.dtype);}this.state.numBytes+=n;if(!this.state.tensorInfo.has(e.dataId)){this.state.numDataBuffers++;this.state.tensorInfo.set(e.dataId,{backend:t||this.backend,dtype:e.dtype,shape:e.shape,bytes:n});}if(!(e instanceof Variable)){this.track(e);}}incRef(e,t){this.trackTensor(e,t);this.backend.incRef(e.dataId);}removeDataId(e,t){if(this.state.tensorInfo.has(e)&&this.state.tensorInfo.get(e).backend===t){this.state.tensorInfo.delete(e);this.state.numDataBuffers--;}}disposeTensor(e){if(!this.state.tensorInfo.has(e.dataId)){return}const t=this.state.tensorInfo.get(e.dataId);this.state.numTensors--;if(e.dtype==="string"){this.state.numStringTensors--;this.state.numBytes-=t.bytes;}if(e.dtype!=="complex64"&&e.dtype!=="string"){const t=e.size*bytesPerElement(e.dtype);this.state.numBytes-=t;}if(t.backend.disposeData(e.dataId)){this.removeDataId(e.dataId,t.backend);}}disposeVariables(){for(const e in this.state.registeredVariables){const t=this.state.registeredVariables[e];this.disposeVariable(t);}}disposeVariable(e){this.disposeTensor(e);if(this.state.registeredVariables[e.name]!=null){delete this.state.registeredVariables[e.name];}}memory(){const e=this.backend.memory();e.numTensors=this.state.numTensors;e.numDataBuffers=this.state.numDataBuffers;e.numBytes=this.state.numBytes;if(this.state.numStringTensors>0){e.unreliable=true;if(e.reasons==null){e.reasons=[];}e.reasons.push("Memory usage by string tensors is approximate "+"(2 bytes per character)");}return e}async profile(e){this.state.profiling=true;const t=this.state.numBytes;const n=this.state.numTensors;this.state.activeProfile.kernels=[];this.state.activeProfile.result=await e();this.state.profiling=false;this.state.activeProfile.peakBytes=Math.max(...this.state.activeProfile.kernels.map((e=>e.totalBytesSnapshot)));this.state.activeProfile.newBytes=this.state.numBytes-t;this.state.activeProfile.newTensors=this.state.numTensors-n;for(const e of this.state.activeProfile.kernels){e.kernelTimeMs=await e.kernelTimeMs;e.extraInfo=await e.extraInfo;}return this.state.activeProfile}isTapeOn(){return this.state.gradientDepth>0&&this.state.kernelDepth===0}addTapeNode(e,t,n,r,s,a){const o={id:this.state.nextTapeNodeId++,kernelName:e,inputs:t,outputs:n,saved:s};const i=getGradient(e);if(i!=null){r=i.gradFunc;}if(r!=null){o.gradient=e=>{e=e.map(((e,t)=>{if(e==null){const e=n[t];const r=makeZerosTypedArray(e.size,e.dtype);return this.makeTensor(r,e.shape,e.dtype)}return e}));return r(e.length>1?e:e[0],s,a)};}this.state.activeTape.push(o);}keep(e){e.kept=true;return e}startTape(){if(this.state.gradientDepth===0){this.state.activeTape=[];}this.state.gradientDepth++;}endTape(){this.state.gradientDepth--;}startScope(e){const t={track:[],name:"unnamed scope",id:this.state.nextScopeId++};if(e){t.name=e;}this.state.scopeStack.push(t);this.state.activeScope=t;}endScope(e){const t=getTensorsInContainer(e);const n=new Set(t.map((e=>e.id)));for(let e=0;e<this.state.activeScope.track.length;e++){const t=this.state.activeScope.track[e];if(!t.kept&&!n.has(t.id)){t.dispose();}}const r=this.state.scopeStack.pop();this.state.activeScope=this.state.scopeStack.length===0?null:this.state.scopeStack[this.state.scopeStack.length-1];t.forEach((e=>{if(!e.kept&&e.scopeId===r.id){this.track(e);}}));}gradients(e,t,n,r=false){assert(t.length>0,(()=>"gradients() received an empty list of xs."));if(n!=null&&n.dtype!=="float32"){throw new Error(`dy must have 'float32' dtype, but has '${n.dtype}'`)}const s=this.scopedRun((()=>this.startTape()),(()=>this.endTape()),(()=>this.tidy("forward",e)));assert(s instanceof Tensor,(()=>"The result y returned by f() must be a tensor."));const a=getFilteredNodesXToY(this.state.activeTape,t,s);if(!r&&a.length===0&&t.length>0){throw new Error("Cannot compute gradient of y=f(x) with respect to x. Make sure "+"that the f you passed encloses all operations that lead from x "+"to y.")}return this.tidy("backward",(()=>{const e={};e[s.id]=n==null?ones$1(s.shape):n;backpropagateGradients(e,a,(e=>this.tidy(e)),add$1);const r=t.map((t=>e[t.id]));if(this.state.gradientDepth===0){this.state.activeTape.forEach((e=>{for(const t of e.saved){t.dispose();}}));this.state.activeTape=null;}return {value:s,grads:r}}))}customGrad(e){assert(isFunction(e),(()=>"The f passed in customGrad(f) must be a function."));return (...t)=>{assert(t.every((e=>e instanceof Tensor)),(()=>"The args passed in customGrad(f)(x1, x2,...) must all be "+"tensors"));let n;const r={};t.forEach(((e,t)=>{r[t]=e;}));const s=(r,s)=>{n=e(...[...t,s]);assert(n.value instanceof Tensor,(()=>"The function f passed in customGrad(f) must return an "+"object where `obj.value` is a tensor"));assert(isFunction(n.gradFunc),(()=>"The function f passed in customGrad(f) must return an "+"object where `obj.gradFunc` is a function."));return n.value};const a=(e,r)=>{const s=n.gradFunc(e,r);const a=Array.isArray(s)?s:[s];assert(a.length===t.length,(()=>"The function f passed in customGrad(f) must return an "+"object where `obj.gradFunc` is a function that returns "+"the same number of tensors as inputs passed to f(...)."));assert(a.every((e=>e instanceof Tensor)),(()=>"The function f passed in customGrad(f) must return an "+"object where `obj.gradFunc` is a function that returns "+"a list of only tensors."));const o={};a.forEach(((e,t)=>{o[t]=()=>e;}));return o};return this.runKernelFunc({forwardFunc:s,backwardsFunc:a,inputs:r})}}readSync(e){const t=this.state.tensorInfo.get(e);return t.backend.readSync(e)}read(e){const t=this.state.tensorInfo.get(e);return t.backend.read(e)}async time(e){const t=now();const n=await this.backend.time(e);n.wallMs=now()-t;return n}track(e){if(this.state.activeScope!=null){e.scopeId=this.state.activeScope.id;this.state.activeScope.track.push(e);}return e}get registeredVariables(){return this.state.registeredVariables}reset(){this.pendingBackendInitId++;this.state.dispose();this.ENV.reset();this.state=new EngineState;for(const e in this.registry){this.disposeRegisteredKernels(e);this.registry[e].dispose();delete this.registry[e];}this.backendName=null;this.backendInstance=null;this.pendingBackendInit=null;}}Engine.nextTensorId=0;Engine.nextVariableId=0;function ones$1(e){const t=makeOnesTypedArray(sizeFromShape(e),"float32");return ENGINE.makeTensor(t,e,"float32")}function getOrMakeEngine(){const e=getGlobalNamespace();if(e._tfengine==null){const t=new Environment(e);e._tfengine=new Engine(t);}setEnvironmentGlobal(e._tfengine.ENV);setTensorTracker((()=>e._tfengine));return e._tfengine}const ENGINE=getOrMakeEngine();function add$1(e,t){const n={a:e,b:t};return ENGINE.runKernel(Add,n)}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function _isNavigatorDefined(){return typeof navigator!=="undefined"&&navigator!=null}function isMobile(e){if(e||_isNavigatorDefined()){if(!e){e=navigator;}if(e.product==="ReactNative"){return true}const t=e.userAgent||e.vendor||window.opera;return /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(t)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(t.substr(0,4))}return false}function isBrowser(){return typeof window!=="undefined"&&window.document!=null||typeof WorkerGlobalScope!=="undefined"}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const ENV$1=env();ENV$1.registerFlag("DEBUG",(()=>false),(e=>{if(e){console.warn("Debugging mode is ON. The output of every math call will "+"be downloaded to CPU and checked for NaNs. "+"This significantly impacts performance.");}}));ENV$1.registerFlag("IS_BROWSER",(()=>isBrowser()));ENV$1.registerFlag("IS_NODE",(()=>typeof process!=="undefined"&&typeof process.versions!=="undefined"&&typeof process.versions.node!=="undefined"));ENV$1.registerFlag("IS_CHROME",(()=>typeof navigator!=="undefined"&&navigator!=null&&navigator.userAgent!=null&&/Chrome/.test(navigator.userAgent)&&/Google Inc/.test(navigator.vendor)));ENV$1.registerFlag("PROD",(()=>false));ENV$1.registerFlag("TENSORLIKE_CHECK_SHAPE_CONSISTENCY",(()=>ENV$1.getBool("DEBUG")));ENV$1.registerFlag("DEPRECATION_WARNINGS_ENABLED",(()=>true));ENV$1.registerFlag("IS_TEST",(()=>false));ENV$1.registerFlag("CHECK_COMPUTATION_FOR_ERRORS",(()=>true));ENV$1.registerFlag("WRAP_TO_IMAGEBITMAP",(()=>false));
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function inferShape(e,t){let n=e;if(isTypedArray(e)){return t==="string"?[]:[e.length]}if(!Array.isArray(e)){return []}const r=[];while(Array.isArray(n)||isTypedArray(n)&&t!=="string"){r.push(n.length);n=n[0];}if(Array.isArray(e)&&env().getBool("TENSORLIKE_CHECK_SHAPE_CONSISTENCY")){deepAssertShapeConsistency(e,r,[]);}return r}function deepAssertShapeConsistency(e,t,n){n=n||[];if(!Array.isArray(e)&&!isTypedArray(e)){assert(t.length===0,(()=>`Element arr[${n.join("][")}] is a primitive, `+`but should be an array/TypedArray of ${t[0]} elements`));return}assert(t.length>0,(()=>`Element arr[${n.join("][")}] should be a primitive, `+`but is an array of ${e.length} elements`));assert(e.length===t[0],(()=>`Element arr[${n.join("][")}] should have ${t[0]} `+`elements, but has ${e.length} elements`));const r=t.slice(1);for(let t=0;t<e.length;++t){deepAssertShapeConsistency(e[t],r,n.concat(t));}}function assertDtype(e,t,n,r){if(e==="string_or_numeric"){return}if(e==null){throw new Error(`Expected dtype cannot be null.`)}if(e!=="numeric"&&e!==t||e==="numeric"&&t==="string"){throw new Error(`Argument '${n}' passed to '${r}' must `+`be ${e} tensor, but got ${t} tensor`)}}function convertToTensor(e,t,n,r="numeric"){if(e instanceof Tensor){assertDtype(r,e.dtype,t,n);return e}let s=inferDtype(e);if(s!=="string"&&["bool","int32","float32"].indexOf(r)>=0){s=r;}assertDtype(r,s,t,n);if(e==null||!isTypedArray(e)&&!Array.isArray(e)&&typeof e!=="number"&&typeof e!=="boolean"&&typeof e!=="string"){const r=e==null?"null":e.constructor.name;throw new Error(`Argument '${t}' passed to '${n}' must be a `+`Tensor or TensorLike, but got '${r}'`)}const a=inferShape(e,s);if(!isTypedArray(e)&&!Array.isArray(e)){e=[e];}const o=true;const i=s!=="string"?toTypedArray(e,s):flatten(e,[],o);return ENGINE.makeTensor(i,a,s)}function convertToTensorArray(e,t,n,r="numeric"){if(!Array.isArray(e)){throw new Error(`Argument ${t} passed to ${n} must be a `+"`Tensor[]` or `TensorLike[]`")}const s=e;return s.map(((e,s)=>convertToTensor(e,`${t}[${s}]`,n,r)))}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const OP_SCOPE_SUFFIX="__op";function op(e){const t=Object.keys(e);if(t.length!==1){throw new Error(`Please provide an object with a single key `+`(operation name) mapping to a function. Got an object with `+`${t.length} keys.`)}let n=t[0];const r=e[n];if(n.endsWith("_")){n=n.substring(0,n.length-1);}n=n+OP_SCOPE_SUFFIX;const s=(...e)=>{ENGINE.startScope(n);try{const t=r(...e);if(isPromise(t)){console.error("Cannot return a Promise inside of tidy.");}ENGINE.endScope(t);return t}catch(e){ENGINE.endScope(null);throw e}};Object.defineProperty(s,"name",{value:n,configurable:true});return s}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function complex_(e,t){const n=convertToTensor(e,"real","complex");const r=convertToTensor(t,"imag","complex");assertShapesMatch(n.shape,r.shape,`real and imag shapes, ${n.shape} and ${r.shape}, `+`must match in call to tf.complex().`);const s={real:n,imag:r};return ENGINE.runKernel(Complex,s)}const complex$1=op({complex_:complex_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function makeTensor(e,t,n,r){if(r==null){r=inferDtype(e);}if(r==="complex64"){throw new Error(`Cannot construct a complex64 tensor directly. `+`Please use tf.complex(real, imag).`)}if(!isTypedArray(e)&&!Array.isArray(e)&&typeof e!=="number"&&typeof e!=="boolean"&&typeof e!=="string"){throw new Error("values passed to tensor(values) must be a number/boolean/string or "+"an array of numbers/booleans/strings, or a TypedArray")}if(t!=null){assertNonNegativeIntegerDimensions(t);const e=sizeFromShape(t);const r=sizeFromShape(n);assert(e===r,(()=>`Based on the provided shape, [${t}], the tensor should have `+`${e} values but has ${r}`));for(let e=0;e<n.length;++e){const r=n[e];const s=e===n.length-1?r!==sizeFromShape(t.slice(e)):true;assert(n[e]===t[e]||!s,(()=>`Error creating a new Tensor. Inferred shape `+`(${n}) does not match the provided `+`shape (${t}). `));}}if(!isTypedArray(e)&&!Array.isArray(e)){e=[e];}t=t||n;e=r!=="string"?toTypedArray(e,r):flatten(e,[],true);return ENGINE.makeTensor(e,t,r)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function tensor(e,t,n){const r=inferShape(e,n);return makeTensor(e,t,r,n)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const DTYPE_VALUE_SIZE_MAP={float32:4,float16:2,int32:4,uint16:2,uint8:1,bool:1,complex64:8};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const NUM_BYTES_STRING_LENGTH=4;function decodeWeights(e,t){const n={};let r;let s=0;for(const a of t){const t=a.name;const o=a.dtype;const i=a.shape;const u=sizeFromShape(i);let c;if("quantization"in a){const n=a.quantization;if(n.dtype==="uint8"||n.dtype==="uint16"){if(!("min"in n&&"scale"in n)){throw new Error(`Weight ${a.name} with quantization ${n.dtype} `+`doesn't have corresponding metadata min and scale.`)}}else if(n.dtype==="float16"){if(o!=="float32"){throw new Error(`Weight ${a.name} is quantized with ${n.dtype} `+`which only supports weights of type float32 not ${o}.`)}}else {throw new Error(`Weight ${a.name} has unknown `+`quantization dtype ${n.dtype}. `+`Supported quantization dtypes are: `+`'uint8', 'uint16', and 'float16'.`)}const i=DTYPE_VALUE_SIZE_MAP[n.dtype];const l=e.slice(s,s+u*i);const p=n.dtype==="uint8"?new Uint8Array(l):new Uint16Array(l);if(o==="float32"){if(n.dtype==="uint8"||n.dtype==="uint16"){c=new Float32Array(p.length);for(let e=0;e<p.length;e++){const t=p[e];c[e]=t*n.scale+n.min;}}else if(n.dtype==="float16"){if(r===undefined){r=getFloat16Decoder();}c=r(p);}else {throw new Error(`Unsupported quantization type ${n.dtype} `+`for weight type float32.`)}}else if(o==="int32"){if(n.dtype!=="uint8"&&n.dtype!=="uint16"){throw new Error(`Unsupported quantization type ${n.dtype} `+`for weight type int32.`)}c=new Int32Array(p.length);for(let e=0;e<p.length;e++){const t=p[e];c[e]=Math.round(t*n.scale+n.min);}}else {throw new Error(`Unsupported dtype in weight '${t}': ${o}`)}s+=u*i;}else if(o==="string"){const t=sizeFromShape(a.shape);c=[];for(let n=0;n<t;n++){const t=new Uint32Array(e.slice(s,s+NUM_BYTES_STRING_LENGTH))[0];s+=NUM_BYTES_STRING_LENGTH;const n=new Uint8Array(e.slice(s,s+t));c.push(n);s+=t;}}else {const r=DTYPE_VALUE_SIZE_MAP[o];const a=e.slice(s,s+u*r);if(o==="float32"){c=new Float32Array(a);}else if(o==="int32"){c=new Int32Array(a);}else if(o==="bool"){c=new Uint8Array(a);}else if(o==="complex64"){c=new Float32Array(a);const e=new Float32Array(c.length/2);const r=new Float32Array(c.length/2);for(let t=0;t<e.length;t++){e[t]=c[t*2];r[t]=c[t*2+1];}const s=tensor(e,i,"float32");const o=tensor(r,i,"float32");n[t]=complex$1(s,o);s.dispose();o.dispose();}else {throw new Error(`Unsupported dtype in weight '${t}': ${o}`)}s+=u*r;}if(o!=="complex64"){n[t]=tensor(c,i,o);}}return n}const useNodeBuffer=typeof Buffer!=="undefined"&&(typeof Blob==="undefined"||typeof atob==="undefined"||typeof btoa==="undefined");function stringByteLength(e){if(useNodeBuffer){return Buffer.byteLength(e)}return new Blob([e]).size}function arrayBufferToBase64String(e){if(useNodeBuffer){return Buffer.from(e).toString("base64")}const t=new Uint8Array(e);let n="";for(let e=0,r=t.length;e<r;e++){n+=String.fromCharCode(t[e]);}return btoa(n)}function base64StringToArrayBuffer(e){if(useNodeBuffer){const t=Buffer.from(e,"base64");return t.buffer.slice(t.byteOffset,t.byteOffset+t.byteLength)}const t=atob(e);const n=new Uint8Array(t.length);for(let e=0;e<t.length;++e){n.set([t.charCodeAt(e)],e);}return n.buffer}function concatenateArrayBuffers(e){if(e.length===1){return e[0]}let t=0;e.forEach((e=>{t+=e.byteLength;}));const n=new Uint8Array(t);let r=0;e.forEach((e=>{n.set(new Uint8Array(e),r);r+=e.byteLength;}));return n.buffer}function getModelArtifactsInfoForJSON(e){if(e.modelTopology instanceof ArrayBuffer){throw new Error("Expected JSON model topology, received ArrayBuffer.")}return {dateSaved:new Date,modelTopologyType:"JSON",modelTopologyBytes:e.modelTopology==null?0:stringByteLength(JSON.stringify(e.modelTopology)),weightSpecsBytes:e.weightSpecs==null?0:stringByteLength(JSON.stringify(e.weightSpecs)),weightDataBytes:e.weightData==null?0:e.weightData.byteLength}}function computeFloat16MantisaTable(){const e=e=>{let t=e<<13;let n=0;while((t&8388608)===0){n-=8388608;t<<=1;}t&=~8388608;n+=947912704;return t|n};const t=new Uint32Array(2048);t[0]=0;for(let n=1;n<1024;n++){t[n]=e(n);}for(let e=1024;e<2048;e++){t[e]=939524096+(e-1024<<13);}return t}function computeFloat16ExponentTable(){const e=new Uint32Array(64);e[0]=0;e[31]=1199570944;e[32]=2147483648;e[63]=3347054592;for(let t=1;t<31;t++){e[t]=t<<23;}for(let t=33;t<63;t++){e[t]=2147483648+(t-32<<23);}return e}function computeFloat16OffsetTable(){const e=new Uint32Array(64);for(let t=0;t<64;t++){e[t]=1024;}e[0]=e[32]=0;return e}function getFloat16Decoder(){const e=computeFloat16MantisaTable();const t=computeFloat16ExponentTable();const n=computeFloat16OffsetTable();return r=>{const s=new ArrayBuffer(4*r.length);const a=new Uint32Array(s);for(let s=0;s<r.length;s++){const o=r[s];const i=e[n[o>>10]+(o&1023)]+t[o>>10];a[s]=i;}return new Float32Array(s)}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class IORouterRegistry{constructor(){this.saveRouters=[];this.loadRouters=[];}static getInstance(){if(IORouterRegistry.instance==null){IORouterRegistry.instance=new IORouterRegistry;}return IORouterRegistry.instance}static registerSaveRouter(e){IORouterRegistry.getInstance().saveRouters.push(e);}static registerLoadRouter(e){IORouterRegistry.getInstance().loadRouters.push(e);}static getSaveHandlers(e){return IORouterRegistry.getHandlers(e,"save")}static getLoadHandlers(e,t){return IORouterRegistry.getHandlers(e,"load",t)}static getHandlers(e,t,n){const r=[];const s=t==="load"?IORouterRegistry.getInstance().loadRouters:IORouterRegistry.getInstance().saveRouters;s.forEach((t=>{const s=t(e,n);if(s!==null){r.push(s);}}));return r}}const getSaveHandlers=e=>IORouterRegistry.getSaveHandlers(e);const getLoadHandlers=(e,t)=>IORouterRegistry.getLoadHandlers(e,t)
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */;const DATABASE_NAME="tensorflowjs";const DATABASE_VERSION=1;const MODEL_STORE_NAME="models_store";const INFO_STORE_NAME="model_info_store";function getIndexedDBFactory(){if(!env().getBool("IS_BROWSER")){throw new Error("Failed to obtain IndexedDB factory because the current environment"+"is not a web browser.")}const e=typeof window==="undefined"?self:window;const t=e.indexedDB||e.mozIndexedDB||e.webkitIndexedDB||e.msIndexedDB||e.shimIndexedDB;if(t==null){throw new Error("The current browser does not appear to support IndexedDB.")}return t}function setUpDatabase(e){const t=e.result;t.createObjectStore(MODEL_STORE_NAME,{keyPath:"modelPath"});t.createObjectStore(INFO_STORE_NAME,{keyPath:"modelPath"});}class BrowserIndexedDB{constructor(e){this.indexedDB=getIndexedDBFactory();if(e==null||!e){throw new Error("For IndexedDB, modelPath must not be null, undefined or empty.")}this.modelPath=e;}async save(e){if(e.modelTopology instanceof ArrayBuffer){throw new Error("BrowserLocalStorage.save() does not support saving model topology "+"in binary formats yet.")}return this.databaseAction(this.modelPath,e)}async load(){return this.databaseAction(this.modelPath)}databaseAction(e,t){return new Promise(((e,n)=>{const r=this.indexedDB.open(DATABASE_NAME,DATABASE_VERSION);r.onupgradeneeded=()=>setUpDatabase(r);r.onsuccess=()=>{const s=r.result;if(t==null){const t=s.transaction(MODEL_STORE_NAME,"readonly");const r=t.objectStore(MODEL_STORE_NAME);const a=r.get(this.modelPath);a.onsuccess=()=>{if(a.result==null){s.close();return n(new Error(`Cannot find model with path '${this.modelPath}' `+`in IndexedDB.`))}else {e(a.result.modelArtifacts);}};a.onerror=e=>{s.close();return n(a.error)};t.oncomplete=()=>s.close();}else {const r=getModelArtifactsInfoForJSON(t);const a=s.transaction(INFO_STORE_NAME,"readwrite");let o=a.objectStore(INFO_STORE_NAME);const i=o.put({modelPath:this.modelPath,modelArtifactsInfo:r});let u;i.onsuccess=()=>{u=s.transaction(MODEL_STORE_NAME,"readwrite");const i=u.objectStore(MODEL_STORE_NAME);const c=i.put({modelPath:this.modelPath,modelArtifacts:t,modelArtifactsInfo:r});c.onsuccess=()=>e({modelArtifactsInfo:r});c.onerror=e=>{o=a.objectStore(INFO_STORE_NAME);const t=o.delete(this.modelPath);t.onsuccess=()=>{s.close();return n(c.error)};t.onerror=e=>{s.close();return n(c.error)};};};i.onerror=e=>{s.close();return n(i.error)};a.oncomplete=()=>{if(u==null){s.close();}else {u.oncomplete=()=>s.close();}};}};r.onerror=e=>n(r.error);}))}}BrowserIndexedDB.URL_SCHEME="indexeddb://";const indexedDBRouter=e=>{if(!env().getBool("IS_BROWSER")){return null}else {if(!Array.isArray(e)&&e.startsWith(BrowserIndexedDB.URL_SCHEME)){return browserIndexedDB(e.slice(BrowserIndexedDB.URL_SCHEME.length))}else {return null}}};IORouterRegistry.registerSaveRouter(indexedDBRouter);IORouterRegistry.registerLoadRouter(indexedDBRouter);function browserIndexedDB(e){return new BrowserIndexedDB(e)}function maybeStripScheme$1(e){return e.startsWith(BrowserIndexedDB.URL_SCHEME)?e.slice(BrowserIndexedDB.URL_SCHEME.length):e}class BrowserIndexedDBManager{constructor(){this.indexedDB=getIndexedDBFactory();}async listModels(){return new Promise(((e,t)=>{const n=this.indexedDB.open(DATABASE_NAME,DATABASE_VERSION);n.onupgradeneeded=()=>setUpDatabase(n);n.onsuccess=()=>{const r=n.result;const s=r.transaction(INFO_STORE_NAME,"readonly");const a=s.objectStore(INFO_STORE_NAME);const o=a.getAll();o.onsuccess=()=>{const t={};for(const e of o.result){t[e.modelPath]=e.modelArtifactsInfo;}e(t);};o.onerror=e=>{r.close();return t(o.error)};s.oncomplete=()=>r.close();};n.onerror=e=>t(n.error);}))}async removeModel(e){e=maybeStripScheme$1(e);return new Promise(((t,n)=>{const r=this.indexedDB.open(DATABASE_NAME,DATABASE_VERSION);r.onupgradeneeded=()=>setUpDatabase(r);r.onsuccess=()=>{const s=r.result;const a=s.transaction(INFO_STORE_NAME,"readwrite");const o=a.objectStore(INFO_STORE_NAME);const i=o.get(e);let u;i.onsuccess=()=>{if(i.result==null){s.close();return n(new Error(`Cannot find model with path '${e}' `+`in IndexedDB.`))}else {const r=o.delete(e);const a=()=>{u=s.transaction(MODEL_STORE_NAME,"readwrite");const r=u.objectStore(MODEL_STORE_NAME);const a=r.delete(e);a.onsuccess=()=>t(i.result.modelArtifactsInfo);a.onerror=e=>n(i.error);};r.onsuccess=a;r.onerror=e=>{a();s.close();return n(i.error)};}};i.onerror=e=>{s.close();return n(i.error)};a.oncomplete=()=>{if(u==null){s.close();}else {u.oncomplete=()=>s.close();}};};r.onerror=e=>n(r.error);}))}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const PATH_SEPARATOR="/";const PATH_PREFIX="tensorflowjs_models";const INFO_SUFFIX="info";const MODEL_TOPOLOGY_SUFFIX="model_topology";const WEIGHT_SPECS_SUFFIX="weight_specs";const WEIGHT_DATA_SUFFIX="weight_data";const MODEL_METADATA_SUFFIX="model_metadata";function getModelKeys(e){return {info:[PATH_PREFIX,e,INFO_SUFFIX].join(PATH_SEPARATOR),topology:[PATH_PREFIX,e,MODEL_TOPOLOGY_SUFFIX].join(PATH_SEPARATOR),weightSpecs:[PATH_PREFIX,e,WEIGHT_SPECS_SUFFIX].join(PATH_SEPARATOR),weightData:[PATH_PREFIX,e,WEIGHT_DATA_SUFFIX].join(PATH_SEPARATOR),modelMetadata:[PATH_PREFIX,e,MODEL_METADATA_SUFFIX].join(PATH_SEPARATOR)}}function getModelPathFromKey(e){const t=e.split(PATH_SEPARATOR);if(t.length<3){throw new Error(`Invalid key format: ${e}`)}return t.slice(1,t.length-1).join(PATH_SEPARATOR)}function maybeStripScheme(e){return e.startsWith(BrowserLocalStorage.URL_SCHEME)?e.slice(BrowserLocalStorage.URL_SCHEME.length):e}class BrowserLocalStorage{constructor(e){if(!env().getBool("IS_BROWSER")||typeof window==="undefined"||typeof window.localStorage==="undefined"){throw new Error("The current environment does not support local storage.")}this.LS=window.localStorage;if(e==null||!e){throw new Error("For local storage, modelPath must not be null, undefined or empty.")}this.modelPath=e;this.keys=getModelKeys(this.modelPath);}async save(e){if(e.modelTopology instanceof ArrayBuffer){throw new Error("BrowserLocalStorage.save() does not support saving model topology "+"in binary formats yet.")}else {const t=JSON.stringify(e.modelTopology);const n=JSON.stringify(e.weightSpecs);const r=getModelArtifactsInfoForJSON(e);try{this.LS.setItem(this.keys.info,JSON.stringify(r));this.LS.setItem(this.keys.topology,t);this.LS.setItem(this.keys.weightSpecs,n);this.LS.setItem(this.keys.weightData,arrayBufferToBase64String(e.weightData));const s={format:e.format,generatedBy:e.generatedBy,convertedBy:e.convertedBy};if(e.signature!=null){s.signature=e.signature;}if(e.userDefinedMetadata!=null){s.userDefinedMetadata=e.userDefinedMetadata;}if(e.modelInitializer!=null){s.modelInitializer=e.modelInitializer;}this.LS.setItem(this.keys.modelMetadata,JSON.stringify(s));return {modelArtifactsInfo:r}}catch(e){this.LS.removeItem(this.keys.info);this.LS.removeItem(this.keys.topology);this.LS.removeItem(this.keys.weightSpecs);this.LS.removeItem(this.keys.weightData);this.LS.removeItem(this.keys.modelMetadata);throw new Error(`Failed to save model '${this.modelPath}' to local storage: `+`size quota being exceeded is a possible cause of this failure: `+`modelTopologyBytes=${r.modelTopologyBytes}, `+`weightSpecsBytes=${r.weightSpecsBytes}, `+`weightDataBytes=${r.weightDataBytes}.`)}}}async load(){const e=JSON.parse(this.LS.getItem(this.keys.info));if(e==null){throw new Error(`In local storage, there is no model with name '${this.modelPath}'`)}if(e.modelTopologyType!=="JSON"){throw new Error("BrowserLocalStorage does not support loading non-JSON model "+"topology yet.")}const t={};const n=JSON.parse(this.LS.getItem(this.keys.topology));if(n==null){throw new Error(`In local storage, the topology of model '${this.modelPath}' `+`is missing.`)}t.modelTopology=n;const r=JSON.parse(this.LS.getItem(this.keys.weightSpecs));if(r==null){throw new Error(`In local storage, the weight specs of model '${this.modelPath}' `+`are missing.`)}t.weightSpecs=r;const s=this.LS.getItem(this.keys.modelMetadata);if(s!=null){const e=JSON.parse(s);t.format=e["format"];t.generatedBy=e["generatedBy"];t.convertedBy=e["convertedBy"];if(e["signature"]!=null){t.signature=e["signature"];}if(e["userDefinedMetadata"]!=null){t.userDefinedMetadata=e["userDefinedMetadata"];}if(e["modelInitializer"]!=null){t.modelInitializer=e["modelInitializer"];}}const a=this.LS.getItem(this.keys.weightData);if(a==null){throw new Error(`In local storage, the binary weight values of model `+`'${this.modelPath}' are missing.`)}t.weightData=base64StringToArrayBuffer(a);return t}}BrowserLocalStorage.URL_SCHEME="localstorage://";const localStorageRouter=e=>{if(!env().getBool("IS_BROWSER")){return null}else {if(!Array.isArray(e)&&e.startsWith(BrowserLocalStorage.URL_SCHEME)){return browserLocalStorage(e.slice(BrowserLocalStorage.URL_SCHEME.length))}else {return null}}};IORouterRegistry.registerSaveRouter(localStorageRouter);IORouterRegistry.registerLoadRouter(localStorageRouter);function browserLocalStorage(e){return new BrowserLocalStorage(e)}class BrowserLocalStorageManager{constructor(){assert(env().getBool("IS_BROWSER"),(()=>"Current environment is not a web browser"));assert(typeof window==="undefined"||typeof window.localStorage!=="undefined",(()=>"Current browser does not appear to support localStorage"));this.LS=window.localStorage;}async listModels(){const e={};const t=PATH_PREFIX+PATH_SEPARATOR;const n=PATH_SEPARATOR+INFO_SUFFIX;for(let r=0;r<this.LS.length;++r){const s=this.LS.key(r);if(s.startsWith(t)&&s.endsWith(n)){const t=getModelPathFromKey(s);e[t]=JSON.parse(this.LS.getItem(s));}}return e}async removeModel(e){e=maybeStripScheme(e);const t=getModelKeys(e);if(this.LS.getItem(t.info)==null){throw new Error(`Cannot find model at path '${e}'`)}const n=JSON.parse(this.LS.getItem(t.info));this.LS.removeItem(t.info);this.LS.removeItem(t.topology);this.LS.removeItem(t.weightSpecs);this.LS.removeItem(t.weightData);return n}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const URL_SCHEME_SUFFIX="://";class ModelStoreManagerRegistry{constructor(){this.managers={};}static getInstance(){if(ModelStoreManagerRegistry.instance==null){ModelStoreManagerRegistry.instance=new ModelStoreManagerRegistry;}return ModelStoreManagerRegistry.instance}static registerManager(e,t){assert(e!=null,(()=>"scheme must not be undefined or null."));if(e.endsWith(URL_SCHEME_SUFFIX)){e=e.slice(0,e.indexOf(URL_SCHEME_SUFFIX));}assert(e.length>0,(()=>"scheme must not be an empty string."));const n=ModelStoreManagerRegistry.getInstance();assert(n.managers[e]==null,(()=>`A model store manager is already registered for scheme '${e}'.`));n.managers[e]=t;}static getManager(e){const t=this.getInstance().managers[e];if(t==null){throw new Error(`Cannot find model manager for scheme '${e}'`)}return t}static getSchemes(){return Object.keys(this.getInstance().managers)}}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class PlatformBrowser{fetch(e,t){return fetch(e,t)}now(){return performance.now()}encode(e,t){if(t!=="utf-8"&&t!=="utf8"){throw new Error(`Browser's encoder only supports utf-8, but got ${t}`)}if(this.textEncoder==null){this.textEncoder=new TextEncoder;}return this.textEncoder.encode(e)}decode(e,t){return new TextDecoder(t).decode(e)}}if(env().get("IS_BROWSER")){env().setPlatform("browser",new PlatformBrowser);try{ModelStoreManagerRegistry.registerManager(BrowserLocalStorage.URL_SCHEME,new BrowserLocalStorageManager);}catch(e){}try{ModelStoreManagerRegistry.registerManager(BrowserIndexedDB.URL_SCHEME,new BrowserIndexedDBManager);}catch(e){}}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const getNodeFetch={importFetch:()=>node_fetch__WEBPACK_IMPORTED_MODULE_0__};let systemFetch;class PlatformNode{constructor(){this.util=require$$1;this.textEncoder=new this.util.TextEncoder;}fetch(e,t){if(env().global.fetch!=null){return env().global.fetch(e,t)}if(systemFetch==null){systemFetch=getNodeFetch.importFetch();}return systemFetch(e,t)}now(){const e=process.hrtime();return e[0]*1e3+e[1]/1e6}encode(e,t){if(t!=="utf-8"&&t!=="utf8"){throw new Error(`Node built-in encoder only supports utf-8, but got ${t}`)}return this.textEncoder.encode(e)}decode(e,t){if(e.length===0){return ""}return new this.util.TextDecoder(t).decode(e)}}if(env().get("IS_NODE")){env().setPlatform("node",new PlatformNode);}
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function buffer(e,t="float32",n){t=t||"float32";assertNonNegativeIntegerDimensions(e);return new TensorBuffer(e,t,n)}
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function cast_(e,t){const n=convertToTensor(e,"x","cast");if(!isValidDtype(t)){throw new Error(`Failed to cast to unknown dtype ${t}`)}if(t==="string"&&n.dtype!=="string"||t!=="string"&&n.dtype==="string"){throw new Error("Only strings can be casted to strings")}const r={x:n};const s={dtype:t};return ENGINE.runKernel(Cast,r,s)}const cast$1=op({cast_:cast_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function clone_(e){const t=convertToTensor(e,"x","clone","string_or_numeric");const n={x:t};return ENGINE.runKernel(Identity,n)}const clone=op({clone_:clone_});
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function print(e,t=false){console.log(e.toString(t));}
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */getOrMakeEngine();const opHandler={buffer:buffer,cast:cast$1,clone:clone,print:print};setOpHandler(opHandler);
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const DEFAULT_FILE_NAME_PREFIX="model";const DEFAULT_JSON_EXTENSION_NAME=".json";const DEFAULT_WEIGHT_DATA_EXTENSION_NAME=".weights.bin";function defer(e){return new Promise((e=>setTimeout(e))).then(e)}class BrowserDownloads{constructor(e){if(!env().getBool("IS_BROWSER")){throw new Error("browserDownloads() cannot proceed because the current environment "+"is not a browser.")}if(e.startsWith(BrowserDownloads.URL_SCHEME)){e=e.slice(BrowserDownloads.URL_SCHEME.length);}if(e==null||e.length===0){e=DEFAULT_FILE_NAME_PREFIX;}this.modelTopologyFileName=e+DEFAULT_JSON_EXTENSION_NAME;this.weightDataFileName=e+DEFAULT_WEIGHT_DATA_EXTENSION_NAME;}async save(e){if(typeof document==="undefined"){throw new Error("Browser downloads are not supported in "+"this environment since `document` is not present")}const t=window.URL.createObjectURL(new Blob([e.weightData],{type:"application/octet-stream"}));if(e.modelTopology instanceof ArrayBuffer){throw new Error("BrowserDownloads.save() does not support saving model topology "+"in binary formats yet.")}else {const n=[{paths:["./"+this.weightDataFileName],weights:e.weightSpecs}];const r={modelTopology:e.modelTopology,format:e.format,generatedBy:e.generatedBy,convertedBy:e.convertedBy,weightsManifest:n};if(e.signature!=null){r.signature=e.signature;}if(e.userDefinedMetadata!=null){r.userDefinedMetadata=e.userDefinedMetadata;}if(e.modelInitializer!=null){r.modelInitializer=e.modelInitializer;}const s=window.URL.createObjectURL(new Blob([JSON.stringify(r)],{type:"application/json"}));const a=this.jsonAnchor==null?document.createElement("a"):this.jsonAnchor;a.download=this.modelTopologyFileName;a.href=s;await defer((()=>a.dispatchEvent(new MouseEvent("click"))));if(e.weightData!=null){const e=this.weightDataAnchor==null?document.createElement("a"):this.weightDataAnchor;e.download=this.weightDataFileName;e.href=t;await defer((()=>e.dispatchEvent(new MouseEvent("click"))));}return {modelArtifactsInfo:getModelArtifactsInfoForJSON(e)}}}}BrowserDownloads.URL_SCHEME="downloads://";const browserDownloadsRouter=e=>{if(!env().getBool("IS_BROWSER")){return null}else {if(!Array.isArray(e)&&e.startsWith(BrowserDownloads.URL_SCHEME)){return browserDownloads(e.slice(BrowserDownloads.URL_SCHEME.length))}else {return null}}};IORouterRegistry.registerSaveRouter(browserDownloadsRouter);function browserDownloads(e="model"){return new BrowserDownloads(e)}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function monitorPromisesProgress(e,t,n,r){o(e);n=n==null?0:n;r=r==null?1:r;i(n,r);let s=0;const a=a=>{a.then((a=>{const o=n+ ++s/e.length*(r-n);t(o);return a}));return a};function o(e){assert(e!=null&&Array.isArray(e)&&e.length>0,(()=>"promises must be a none empty array"));}function i(e,t){assert(e>=0&&e<=1,(()=>`Progress fraction must be in range [0, 1], but `+`got startFraction ${e}`));assert(t>=0&&t<=1,(()=>`Progress fraction must be in range [0, 1], but `+`got endFraction ${t}`));assert(t>=e,(()=>`startFraction must be no more than endFraction, but `+`got startFraction ${e} and endFraction `+`${t}`));}return Promise.all(e.map(a))}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */async function loadWeightsAsArrayBuffer(e,t){if(t==null){t={};}const n=t.fetchFunc==null?env().platform.fetch:t.fetchFunc;const r=e.map((e=>n(e,t.requestInit,{isBinary:true})));const s=0;const a=.5;const o=t.onProgress==null?await Promise.all(r):await monitorPromisesProgress(r,t.onProgress,s,a);const i=o.map((e=>e.arrayBuffer()));const u=.5;const c=1;const l=t.onProgress==null?await Promise.all(i):await monitorPromisesProgress(i,t.onProgress,u,c);return l}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const OCTET_STREAM_MIME_TYPE="application/octet-stream";const JSON_TYPE="application/json";class HTTPRequest{constructor(e,t){this.DEFAULT_METHOD="POST";if(t==null){t={};}this.weightPathPrefix=t.weightPathPrefix;this.onProgress=t.onProgress;this.weightUrlConverter=t.weightUrlConverter;if(t.fetchFunc!=null){assert(typeof t.fetchFunc==="function",(()=>"Must pass a function that matches the signature of "+"`fetch` (see "+"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)"));this.fetch=t.fetchFunc;}else {this.fetch=env().platform.fetch;}assert(e!=null&&e.length>0,(()=>"URL path for http must not be null, undefined or "+"empty."));if(Array.isArray(e)){assert(e.length===2,(()=>"URL paths for http must have a length of 2, "+`(actual length is ${e.length}).`));}this.path=e;if(t.requestInit!=null&&t.requestInit.body!=null){throw new Error("requestInit is expected to have no pre-existing body, but has one.")}this.requestInit=t.requestInit||{};}async save(e){if(e.modelTopology instanceof ArrayBuffer){throw new Error("BrowserHTTPRequest.save() does not support saving model topology "+"in binary formats yet.")}const t=Object.assign({method:this.DEFAULT_METHOD},this.requestInit);t.body=new FormData;const n=[{paths:["./model.weights.bin"],weights:e.weightSpecs}];const r={modelTopology:e.modelTopology,format:e.format,generatedBy:e.generatedBy,convertedBy:e.convertedBy,weightsManifest:n};if(e.signature!=null){r.signature=e.signature;}if(e.userDefinedMetadata!=null){r.userDefinedMetadata=e.userDefinedMetadata;}if(e.modelInitializer!=null){r.modelInitializer=e.modelInitializer;}t.body.append("model.json",new Blob([JSON.stringify(r)],{type:JSON_TYPE}),"model.json");if(e.weightData!=null){t.body.append("model.weights.bin",new Blob([e.weightData],{type:OCTET_STREAM_MIME_TYPE}),"model.weights.bin");}const s=await this.fetch(this.path,t);if(s.ok){return {modelArtifactsInfo:getModelArtifactsInfoForJSON(e),responses:[s]}}else {throw new Error(`BrowserHTTPRequest.save() failed due to HTTP response status `+`${s.status}.`)}}async load(){const e=await this.fetch(this.path,this.requestInit);if(!e.ok){throw new Error(`Request to ${this.path} failed with status code `+`${e.status}. Please verify this URL points to `+`the model JSON of the model to load.`)}let t;try{t=await e.json();}catch(e){let t=`Failed to parse model JSON of response from ${this.path}.`;if(this.path.endsWith(".pb")){t+=" Your path contains a .pb file extension. "+"Support for .pb models have been removed in TensorFlow.js 1.0 "+"in favor of .json models. You can re-convert your Python "+"TensorFlow model using the TensorFlow.js 1.0 conversion scripts "+"or you can convert your.pb models with the 'pb2json'"+"NPM script in the tensorflow/tfjs-converter repository.";}else {t+=" Please make sure the server is serving valid "+"JSON for this request.";}throw new Error(t)}const n=t.modelTopology;const r=t.weightsManifest;const s=t.generatedBy;const a=t.convertedBy;const o=t.format;const i=t.signature;const u=t.userDefinedMetadata;if(n==null&&r==null){throw new Error(`The JSON from HTTP path ${this.path} contains neither model `+`topology or manifest for weights.`)}let c;let l;if(r!=null){const e=await this.loadWeights(r);[c,l]=e;}const p={modelTopology:n,weightSpecs:c,weightData:l,generatedBy:s,convertedBy:a,format:o};if(i!=null){p.signature=i;}if(u!=null){p.userDefinedMetadata=u;}const d=t.modelInitializer;if(d){p.modelInitializer=d;}return p}async loadWeights(e){const t=Array.isArray(this.path)?this.path[1]:this.path;const[n,r]=parseUrl(t);const s=this.weightPathPrefix||n;const a=[];for(const t of e){a.push(...t.weights);}const o=[];const i=[];for(const t of e){for(const e of t.paths){if(this.weightUrlConverter!=null){i.push(this.weightUrlConverter(e));}else {o.push(s+e+r);}}}if(this.weightUrlConverter){o.push(...await Promise.all(i));}const u=await loadWeightsAsArrayBuffer(o,{requestInit:this.requestInit,fetchFunc:this.fetch,onProgress:this.onProgress});return [a,concatenateArrayBuffers(u)]}}HTTPRequest.URL_SCHEME_REGEX=/^https?:\/\//;function parseUrl(e){const t=e.lastIndexOf("/");const n=e.lastIndexOf("?");const r=e.substring(0,t);const s=n>t?e.substring(n):"";return [r+"/",s]}function isHTTPScheme(e){return e.match(HTTPRequest.URL_SCHEME_REGEX)!=null}const httpRouter=(e,t)=>{if(typeof fetch==="undefined"&&(t==null||t.fetchFunc==null)){return null}else {let n=true;if(Array.isArray(e)){n=e.every((e=>isHTTPScheme(e)));}else {n=isHTTPScheme(e);}if(n){return http(e,t)}}return null};IORouterRegistry.registerSaveRouter(httpRouter);IORouterRegistry.registerLoadRouter(httpRouter);function http(e,t){return new HTTPRequest(e,t)}function browserHTTPRequest(e,t){return http(e,t)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function matMul_(e,t,n=false,r=false){let s=convertToTensor(e,"a","matMul");let a=convertToTensor(t,"b","matMul");[s,a]=makeTypesMatch(s,a);const o={a:s,b:a};const i={transposeA:n,transposeB:r};return ENGINE.runKernel(BatchMatMul,o,i)}const matMul$1=op({matMul_:matMul_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function oneHot_(e,t,n=1,r=0){if(t<2){throw new Error(`Error in oneHot: depth must be >=2, but it is ${t}`)}const s=convertToTensor(e,"indices","oneHot","int32");const a={indices:s};const o={depth:t,onValue:n,offValue:r};return ENGINE.runKernel(OneHot,a,o)}const oneHot=op({oneHot_:oneHot_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function transpose_(e,t){const n=convertToTensor(e,"x","transpose");if(t==null){t=n.shape.map(((e,t)=>t)).reverse();}assert(n.rank===t.length,(()=>`Error in transpose: rank of input ${n.rank} `+`must match length of perm ${t}.`));t.forEach((e=>{assert(e>=0&&e<n.rank,(()=>`All entries in 'perm' must be between 0 and ${n.rank-1}`+` but got ${t}`));}));if(n.rank<=1){return n.clone()}const r={x:n};const s={perm:t};return ENGINE.runKernel(Transpose,r,s)}const transpose$1=op({transpose_:transpose_});function prepareAndValidate(e,t){const n=e.shape.length;const r=t.shape.length;if(n<1){throw new Error("tf.gatherND() expects the input to be rank 1 or higher,"+` but the rank was ${n}.`)}if(r<1){throw new Error("tf.gatherND() expects the indices to be rank 1 or higher,"+` but the rank was ${r}.`)}if(t.dtype!=="int32"){throw new Error("tf.gatherND() expects the indices to be int32 type,"+` but the dtype was ${t.dtype}.`)}if(t.shape[r-1]>n){throw new Error("index innermost dimension length must be <= tensor rank; saw: "+`${t.shape[r-1]} vs. ${n}`)}if(sizeFromShape(e.shape)===0){throw new Error("Requested more than 0 entries, but input is empty."+` Input shape: ${e.shape}.`)}const s=t.shape;const a=s[s.length-1];let o=1;for(let e=0;e<s.length-1;++e){o*=s[e];}const i=e.shape;const u=s.slice();u.pop();let c=1;for(let e=a;e<n;++e){c*=i[e];u.push(i[e]);}const l=[...computeStrides(e.shape).map((e=>e/c)),1].slice(0,a);return [u,o,c,l]}function validateUpdateShape(e,t,n){const r=t.rank>1?t.shape[t.rank-1]:1;const s=t.rank>1?t.rank-1:1;const a="Must have updates.shape = indices.shape[:batchDim] + "+`shape[sliceDim:], got updates.shape: ${n.shape}`+`, indices.shape: ${t.shape}, shape: ${e}`+`, sliceDim: ${r}, and batchDim: ${s}.`;if(n.rank<s){throw new Error(a+` update.rank < ${s}. `)}if(e.length<r+(n.rank-s)){throw new Error(a+` Output shape length < ${r+(n.rank-s)}`)}if(n.rank!==s+e.length-r){throw new Error(a+` update.rank != ${s+e.length-r}`)}for(let e=0;e<s;++e){if(n.shape[e]!==t.shape[e]){throw new Error(a+` updates.shape[${e}] (${n.shape[e]}) != indices.shape[${e}] (${t.shape[e]}).`)}}for(let t=0;t<n.rank-s;++t){if(n.shape[t+s]!==e[t+r]){throw new Error(a+` updates.shape[${t+s}] (${n.shape[t+s]}) != shape[${t+s}] (${e[t+s]})`)}}}function validateInput$1(e,t,n){if(t.rank<1){throw new Error("tf.scatterND() expects the indices to be rank 1 or higher,"+` but the rank was ${t.rank}.`)}if(e.rank<1){throw new Error("tf.scatterND() expects the updates to be rank 1 or higher,"+` but the rank was ${e.rank}.`)}if(t.dtype!=="int32"){throw new Error(`The dtype of 'indices' should be int32, but got dtype: ${t.dtype}`)}if(n.length<1){throw new Error(`Output rank must be greater or equal to 1, but got shape: ${n}`)}if(n.length===0){if(t.size===0){throw new Error(`Indices specified for empty output. indices shape: ${t.shape}`)}if(e.size===0){throw new Error(`Updates specified for empty output. updates shape: ${e.shape}`)}}validateUpdateShape(n,t,e);}function calculateShapes(e,t,n){const r=t.shape.length;const s=r>1?t.shape[r-1]:1;const a=n.length;let o=1;for(let e=s;e<a;++e){o*=n[e];}const i=s<1?1:s;const u=sizeFromShape(t.shape)/i;const c=[...computeStrides(n.slice(0,s)),1];const l=sizeFromShape(n);return {sliceRank:s,numUpdates:u,sliceSize:o,strides:c,outputSize:l}}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function assertParamsValid(e,t,n){const r=e.shape.length;assert(r===t.length,(()=>`Error in slice${r}D: Length of begin ${t} must `+`match the rank of the array (${r}).`));assert(r===n.length,(()=>`Error in slice${r}D: Length of size ${n} must `+`match the rank of the array (${r}).`));for(let s=0;s<r;++s){assert(t[s]+n[s]<=e.shape[s],(()=>`Error in slice${r}D: begin[${s}] + size[${s}] `+`(${t[s]+n[s]}) would overflow input.shape[${s}] (${e.shape[s]})`));}}function maskToAxes(e){const t=[];let n=0;while(e>0){if(e&1){t.push(n);}e/=2;n++;}return t}function computeOutShape$2(e,t,n){const r=[];for(let s=0;s<e.length;s++){r[s]=Math.ceil((t[s]-e[s])/n[s]);}return r}function stridesWithElidedDims(e,t,n,r){const s=[...e];for(let e=s.length;e<r.length;e++){s.push(1);}for(let e=0;e<n;e++){if(e===0){s[t]=1;}else {s.splice(t,0,1);s.pop();}}return s}function unnormalizeAxis(e,t,n){if(n<=e){return n}return n-(t-1)}function getElidedAxes(e,t){const n=[];for(let r=0;r<e;r++){n.push(t+r);}return n}function getNormalizedAxes(e,t,n,r,s,a,o,i,u){const c=e.length;let l=new Array(c),p=new Array(c),d=new Array(c);if(t.length&&n>0){const u=t[0];const c=n+1;l=startIndicesWithElidedDims(o,u,c,r,e);p=stopIndicesWithElidedDims(i,u,c,s,e);d=stridesWithElidedDims(a,u,c,e);}else {for(let t=0;t<c;t++){l[t]=startForAxis(o,r,a,e,t,u);p[t]=stopForAxis(i,s,a,e,t,u);d[t]=stridesForAxis(a,t,u);}}return {begin:l,end:p,strides:d}}function startIndicesWithElidedDims(e,t,n,r,s){const a=[...s];const o=getElidedAxes(n,t);for(let s=0;s<a.length;s++){if(o.indexOf(s)>-1){a[s]=0;}else {const o=unnormalizeAxis(t,n,s);let i=r[o];if(e&1<<o){i=0;}a[s]=i;}}return a}function stopIndicesWithElidedDims(e,t,n,r,s){const a=[...s];const o=getElidedAxes(n,t);for(let s=0;s<a.length;s++){if(o.indexOf(s)>-1){a[s]=Number.MAX_SAFE_INTEGER;}else {const o=unnormalizeAxis(t,n,s);let i=r[o];if(e&1<<o){i=Number.MAX_SAFE_INTEGER;}a[s]=i;}}for(let e=0;e<a.length;e++){const t=s[e];if(a[e]<0){a[e]+=t;}a[e]=clamp(0,a[e],s[e]);}return a}function stridesForAxis(e,t,n){let r=e[t];if(n&1<<t||r==null){r=1;}return r}function startForAxis(e,t,n,r,s,a){let o=t[s];const i=n[s]||1;if(e&1<<s||a&1<<s||o==null){if(i>0){o=Number.MIN_SAFE_INTEGER;}else {o=Number.MAX_SAFE_INTEGER;}}const u=r[s];if(o<0){o+=u;}o=clamp(0,o,u-1);return o}function stopForAxis(e,t,n,r,s,a){let o=t[s];const i=n[s]||1;if(e&1<<s||a&1<<s||o==null){if(i>0){o=Number.MAX_SAFE_INTEGER;}else {o=Number.MIN_SAFE_INTEGER;}}const u=r[s];if(o<0){o+=u;}if(i>0){o=clamp(0,o,u);}else {o=clamp(-1,o,u-1);}return o}function isSliceContinous(e,t,n){let r=n.length;for(let e=0;e<n.length;e++){if(n[e]>1){r=e;break}}for(let s=r+1;s<n.length;s++){if(t[s]>0||n[s]!==e[s]){return false}}return true}function computeFlatOffset(e,t){let n=e.length>0?e[e.length-1]:1;for(let r=0;r<e.length-1;r++){n+=e[r]*t[r];}return n}function parseSliceParams(e,t,n){let r;const s=e.shape.length;if(typeof t==="number"){r=[t,...new Array(s-1).fill(0)];}else if(t.length<s){r=t.concat(new Array(s-t.length).fill(0));}else {r=t.slice();}r.forEach((e=>{assert(e!==-1,(()=>"slice() does not support negative begin indexing."));}));let a;if(n==null){a=new Array(s).fill(-1);}else if(typeof n==="number"){a=[n,...new Array(s-1).fill(-1)];}else if(n.length<s){a=n.concat(new Array(s-n.length).fill(-1));}else {a=n;}a=a.map(((t,n)=>{if(t>=0){return t}else {assert(t===-1,(()=>`Negative size values should be exactly -1 but got `+`${t} for the slice() size at index ${n}.`));return e.shape[n]-r[n]}}));return [r,a]}function sliceInfo(e,t,n,r,s,a,o,i,u){let c=t.slice();let l=n.slice();let p=r;if(r==null){p=new Array(c.length);}const d=maskToAxes(o);if(d.length>1){throw new Error("Multiple ellipses in slice is not allowed.")}if(o!==0&&i!==0){throw new Error("Using both ellipsisMask and newAxisMask is not yet supported.")}if(o!==0&&u!==0){throw new Error("Using both ellipsisMask and shrinkAxisMask is not yet supported.")}const h=e.length-c.length;const m=maskToAxes(i);const f=e.slice();m.forEach((e=>{c[e]=0;l[e]=1;f.splice(e,0,1);}));const{begin:g,end:y,strides:x}=getNormalizedAxes(f,d,h,c,l,p,s,a,o);c=g;l=y;p=x;const T=maskToAxes(u);T.forEach((e=>{l[e]=c[e]+1;p[e]=1;}));const E=computeOutShape$2(c,l,p);const b=E.filter(((e,t)=>T.indexOf(t)===-1));const N=p.every((e=>e===1));return {nonStrided:N,$begin:c,$end:l,$strides:p,size:E,newShape:f,outShape:b}}var slice_util=Object.freeze({__proto__:null,assertParamsValid:assertParamsValid,maskToAxes:maskToAxes,computeOutShape:computeOutShape$2,stridesWithElidedDims:stridesWithElidedDims,getNormalizedAxes:getNormalizedAxes,startIndicesWithElidedDims:startIndicesWithElidedDims,stopIndicesWithElidedDims:stopIndicesWithElidedDims,stridesForAxis:stridesForAxis,startForAxis:startForAxis,stopForAxis:stopForAxis,isSliceContinous:isSliceContinous,computeFlatOffset:computeFlatOffset,parseSliceParams:parseSliceParams,sliceInfo:sliceInfo});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function enableProdMode(){env().set("PROD",true);}function engine(){return ENGINE}function tidy(e,t){return ENGINE.tidy(e,t)}function dispose(e){const t=getTensorsInContainer(e);t.forEach((e=>e.dispose()));}function keep(e){return ENGINE.keep(e)}function registerBackend(e,t,n=1){return ENGINE.registerBackend(e,t,n)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function add_(e,t){let n=convertToTensor(e,"a","add");let r=convertToTensor(t,"b","add");[n,r]=makeTypesMatch(n,r);const s={a:n,b:r};return ENGINE.runKernel(Add,s)}const add=op({add_:add_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function floorDiv_(e,t){let n=convertToTensor(e,"a","floorDiv");let r=convertToTensor(t,"b","floorDiv");[n,r]=makeTypesMatch(n,r);const s={a:n,b:r};return ENGINE.runKernel(FloorDiv,s)}const floorDiv=op({floorDiv_:floorDiv_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function div_(e,t){let n=convertToTensor(e,"a","div");let r=convertToTensor(t,"b","div");[n,r]=makeTypesMatch(n,r);if(n.dtype==="int32"&&r.dtype==="int32"){return floorDiv(n,r)}const s={a:n,b:r};const a={};return ENGINE.runKernel(RealDiv,s,a)}const div=op({div_:div_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function mul_(e,t){let n=convertToTensor(e,"a","mul");let r=convertToTensor(t,"b","mul");[n,r]=makeTypesMatch(n,r);const s={a:n,b:r};return ENGINE.runKernel(Multiply,s)}const mul=op({mul_:mul_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function abs_(e){const t=convertToTensor(e,"x","abs");if(t.dtype==="complex64"){const e={x:t};return ENGINE.runKernel(ComplexAbs,e)}else {const e={x:t};return ENGINE.runKernel(Abs,e)}}const abs=op({abs_:abs_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function acos_(e){const t=convertToTensor(e,"x","acos");const n={x:t};return ENGINE.runKernel(Acos,n)}const acos=op({acos_:acos_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function acosh_(e){const t=convertToTensor(e,"x","acosh");const n={x:t};return ENGINE.runKernel(Acosh,n)}const acosh=op({acosh_:acosh_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function addN_(e){assert(Array.isArray(e),(()=>"The argument passed to tf.addN() must be a list of tensors"));assert(e.length>=1,(()=>`Must pass at least one tensor to tf.addN(), but got `+`${e.length}`));const t=e.map(((e,t)=>convertToTensor(e,`tensors${t}`,"addN")));const n=t[0];t.forEach((e=>{if(e.dtype!==n.dtype){throw new Error("All tensors passed to tf.addN() must have the same dtype")}}));t.forEach((e=>{if(!arraysEqual(e.shape,n.shape)){throw new Error("All tensors passed to tf.addN() must have the same shape")}}));const r=t;return ENGINE.runKernel(AddN,r)}const addN=op({addN_:addN_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function all_(e,t=null,n=false){const r=convertToTensor(e,"x","all","bool");const s={x:r};const a={axis:t,keepDims:n};return ENGINE.runKernel(All,s,a)}const all=op({all_:all_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function any_(e,t=null,n=false){const r=convertToTensor(e,"x","any","bool");const s={x:r};const a={axis:t,keepDims:n};return ENGINE.runKernel(Any,s,a)}const any=op({any_:any_});
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function argMax_(e,t=0){const n=convertToTensor(e,"x","argMax");const r={x:n};const s={axis:t};return ENGINE.runKernel(ArgMax,r,s)}const argMax=op({argMax_:argMax_});
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function argMin_(e,t=0){const n=convertToTensor(e,"x","argMin");const r={x:n};const s={axis:t};return ENGINE.runKernel(ArgMin,r,s)}const argMin=op({argMin_:argMin_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function asin_(e){const t=convertToTensor(e,"x","asin");const n={x:t};return ENGINE.runKernel(Asin,n)}const asin=op({asin_:asin_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function asinh_(e){const t=convertToTensor(e,"x","asinh");const n={x:t};return ENGINE.runKernel(Asinh,n)}const asinh=op({asinh_:asinh_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function atan_(e){const t=convertToTensor(e,"x","atan");const n={x:t};return ENGINE.runKernel(Atan,n)}const atan=op({atan_:atan_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function atan2_(e,t){let n=convertToTensor(e,"a","atan2");let r=convertToTensor(t,"b","atan2");[n,r]=makeTypesMatch(n,r);const s={a:n,b:r};return ENGINE.runKernel(Atan2,s)}const atan2=op({atan2_:atan2_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function atanh_(e){const t=convertToTensor(e,"x","atanh");const n={x:t};return ENGINE.runKernel(Atanh,n)}const atanh=op({atanh_:atanh_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function computeDilation2DInfo(e,t,n,r,s="NHWC",a){const o=e[3];const i=[...t,o];const u=convertConv2DDataFormat(s);return computeConv2DInfo(e,i,n,a,r,null,null,u)}function computePool2DInfo(e,t,n,r,s,a,o="channelsLast"){const[i,u]=parseTupleParam(t);let c;if(o==="channelsLast"){c=[i,u,e[3],e[3]];}else if(o==="channelsFirst"){c=[i,u,e[1],e[1]];}else {throw new Error(`Unknown dataFormat ${o}`)}return computeConv2DInfo(e,c,n,r,s,a,false,o)}function computePool3DInfo(e,t,n,r,s,a,o="NDHWC"){const[i,u,c]=parse3TupleParam(t);let l;let p;if(o==="NDHWC"){p="channelsLast";l=[i,u,c,e[4],e[4]];}else if(o==="NCDHW"){p="channelsFirst";l=[i,u,c,e[1],e[1]];}else {throw new Error(`Unknown dataFormat ${o}`)}return computeConv3DInfo(e,l,n,r,s,false,p,a)}function computeConv2DInfo(e,t,n,r,s,a,o=false,i="channelsLast"){let[u,c,l,p]=[-1,-1,-1,-1];if(i==="channelsLast"){[u,c,l,p]=e;}else if(i==="channelsFirst"){[u,p,c,l]=e;}else {throw new Error(`Unknown dataFormat ${i}`)}const[d,h,,m]=t;const[f,g]=parseTupleParam(n);const[y,x]=parseTupleParam(r);const T=getEffectiveFilterSize(d,y);const E=getEffectiveFilterSize(h,x);const{padInfo:b,outHeight:N,outWidth:S}=getPadAndOutInfo(s,c,l,f,g,T,E,a,i);const I=o?m*p:m;let v;if(i==="channelsFirst"){v=[u,I,N,S];}else if(i==="channelsLast"){v=[u,N,S,I];}return {batchSize:u,dataFormat:i,inHeight:c,inWidth:l,inChannels:p,outHeight:N,outWidth:S,outChannels:I,padInfo:b,strideHeight:f,strideWidth:g,filterHeight:d,filterWidth:h,effectiveFilterHeight:T,effectiveFilterWidth:E,dilationHeight:y,dilationWidth:x,inShape:e,outShape:v,filterShape:t}}function computeConv3DInfo(e,t,n,r,s,a=false,o="channelsLast",i){let[u,c,l,p,d]=[-1,-1,-1,-1,-1];if(o==="channelsLast"){[u,c,l,p,d]=e;}else if(o==="channelsFirst"){[u,d,c,l,p]=e;}else {throw new Error(`Unknown dataFormat ${o}`)}const[h,m,f,,g]=t;const[y,x,T]=parse3TupleParam(n);const[E,b,N]=parse3TupleParam(r);const S=getEffectiveFilterSize(h,E);const I=getEffectiveFilterSize(m,b);const v=getEffectiveFilterSize(f,N);const{padInfo:_,outDepth:w,outHeight:A,outWidth:$}=get3DPadAndOutInfo(s,c,l,p,y,x,T,S,I,v,i);const P=a?g*d:g;let k;if(o==="channelsFirst"){k=[u,P,w,A,$];}else if(o==="channelsLast"){k=[u,w,A,$,P];}return {batchSize:u,dataFormat:o,inDepth:c,inHeight:l,inWidth:p,inChannels:d,outDepth:w,outHeight:A,outWidth:$,outChannels:P,padInfo:_,strideDepth:y,strideHeight:x,strideWidth:T,filterDepth:h,filterHeight:m,filterWidth:f,effectiveFilterDepth:S,effectiveFilterHeight:I,effectiveFilterWidth:v,dilationDepth:E,dilationHeight:b,dilationWidth:N,inShape:e,outShape:k,filterShape:t}}function computeOutputShape2D(e,t,n,r,s){if(r==null){r=computeDefaultPad(e,t,n);}const a=e[0];const o=e[1];const i=round$1((a-t+2*r)/n+1,s);const u=round$1((o-t+2*r)/n+1,s);return [i,u]}function computeOutputShape4D(e,t,n,r,s,a){if(s==null){s=computeDefaultPad(e,t,r);}const o=e[0];const i=e[1];const u=e[2];const c=round$1((o-t+2*s)/r+1,a);const l=round$1((i-t+2*s)/r+1,a);const p=round$1((u-t+2*s)/r+1,a);return [c,l,p,n]}function computeDefaultPad(e,t,n,r=1){const s=getEffectiveFilterSize(t,r);return Math.floor((e[0]*(n-1)-n+s)/2)}function parseTupleParam(e){if(typeof e==="number"){return [e,e,e]}if(e.length===2){return [e[0],e[1],1]}return e}function parse3TupleParam(e){return typeof e==="number"?[e,e,e]:e}function getEffectiveFilterSize(e,t){if(t<=1){return e}return e+(e-1)*(t-1)}function getPadAndOutInfo(e,t,n,r,s,a,o,i,u){let c;let l;let p;if(typeof e==="number"){const s=e===0?"VALID":"NUMBER";c={top:e,bottom:e,left:e,right:e,type:s};const o=computeOutputShape2D([t,n],a,r,e,i);l=o[0];p=o[1];}else if(e==="same"){l=Math.ceil(t/r);p=Math.ceil(n/s);const e=Math.max(0,(l-1)*r+a-t);const i=Math.max(0,(p-1)*s+o-n);const u=Math.floor(e/2);const d=e-u;const h=Math.floor(i/2);const m=i-h;c={top:u,bottom:d,left:h,right:m,type:"SAME"};}else if(e==="valid"){c={top:0,bottom:0,left:0,right:0,type:"VALID"};l=Math.ceil((t-a+1)/r);p=Math.ceil((n-o+1)/s);}else if(typeof e==="object"){const d=u==="channelsLast"?e[1][0]:e[2][0];const h=u==="channelsLast"?e[1][1]:e[2][1];const m=u==="channelsLast"?e[2][0]:e[3][0];const f=u==="channelsLast"?e[2][1]:e[3][1];const g=d===0&&h===0&&m===0&&f===0?"VALID":"EXPLICIT";c={top:d,bottom:h,left:m,right:f,type:g};l=round$1((t-a+d+h)/r+1,i);p=round$1((n-o+m+f)/s+1,i);}else {throw Error(`Unknown padding parameter: ${e}`)}return {padInfo:c,outHeight:l,outWidth:p}}function get3DPadAndOutInfo(e,t,n,r,s,a,o,i,u,c,l){let p;let d;let h;let m;if(typeof e==="number"){const a=e===0?"VALID":"NUMBER";p={top:e,bottom:e,left:e,right:e,front:e,back:e,type:a};const o=computeOutputShape4D([t,n,r,1],i,1,s,e,l);d=o[0];h=o[1];m=o[2];}else if(e==="same"){d=Math.ceil(t/s);h=Math.ceil(n/a);m=Math.ceil(r/o);const e=(d-1)*s+i-t;const l=(h-1)*a+u-n;const f=(m-1)*o+c-r;const g=Math.floor(e/2);const y=e-g;const x=Math.floor(l/2);const T=l-x;const E=Math.floor(f/2);const b=f-E;p={top:x,bottom:T,left:E,right:b,front:g,back:y,type:"SAME"};}else if(e==="valid"){p={top:0,bottom:0,left:0,right:0,front:0,back:0,type:"VALID"};d=Math.ceil((t-i+1)/s);h=Math.ceil((n-u+1)/a);m=Math.ceil((r-c+1)/o);}else {throw Error(`Unknown padding parameter: ${e}`)}return {padInfo:p,outDepth:d,outHeight:h,outWidth:m}}function round$1(e,t){if(!t){return Math.trunc(e)}switch(t){case"round":return Math.round(e);case"ceil":return Math.ceil(e);case"floor":return Math.floor(e);default:throw new Error(`Unknown roundingMode ${t}`)}}function tupleValuesAreOne(e){const[t,n,r]=parseTupleParam(e);return t===1&&n===1&&r===1}function eitherStridesOrDilationsAreOne(e,t){return tupleValuesAreOne(e)||tupleValuesAreOne(t)}function convertConv2DDataFormat(e){if(e==="NHWC"){return "channelsLast"}else if(e==="NCHW"){return "channelsFirst"}else {throw new Error(`Unknown dataFormat ${e}`)}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function reshape_(e,t){const n=convertToTensor(e,"x","reshape","string_or_numeric");const r={x:n};const s={shape:t};return ENGINE.runKernel(Reshape,r,s)}const reshape$1=op({reshape_:reshape_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function avgPool_(e,t,n,r,s){const a=convertToTensor(e,"x","avgPool","float32");const o=1;assert(eitherStridesOrDilationsAreOne(n,o),(()=>"Error in avgPool: Either strides or dilations must be 1. "+`Got strides ${n} and dilations '${o}'`));let i=a;let u=false;if(a.rank===3){u=true;i=reshape$1(a,[1,a.shape[0],a.shape[1],a.shape[2]]);}assert(i.rank===4,(()=>`Error in avgPool: x must be rank 4 but got rank ${i.rank}.`));if(s!=null){assert(isInt(r),(()=>`Error in avgPool: pad must be an integer when using, `+`dimRoundingMode ${s} but got pad ${r}.`));}const c={x:i};const l={filterSize:t,strides:n,pad:r,dimRoundingMode:s};let p=ENGINE.runKernel(AvgPool,c,l);p=cast$1(p,a.dtype);if(u){return reshape$1(p,[p.shape[1],p.shape[2],p.shape[3]])}return p}const avgPool=op({avgPool_:avgPool_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function avgPool3d_(e,t,n,r,s,a="NDHWC"){const o=convertToTensor(e,"x","avgPool3d","float32");let i=o;let u=false;if(o.rank===4){u=true;i=reshape$1(o,[1,o.shape[0],o.shape[1],o.shape[2],o.shape[3]]);}assert(i.rank===5,(()=>`Error in avgPool3d: x must be rank 5 but got rank ${i.rank}.`));assert(a==="NDHWC",(()=>`Error in avgPool3d: Only NDHWC is currently supported, `+`but got dataFormat of ${a}`));if(s!=null){assert(isInt(r),(()=>`Error in avgPool3d: pad must be an integer when using, `+`dimRoundingMode ${s} but got pad ${r}.`));}const c={x:i};const l={filterSize:t,strides:n,pad:r,dimRoundingMode:s,dataFormat:a};let p=ENGINE.runKernel(AvgPool3D,c,l);p=cast$1(p,i.dtype);if(u){return reshape$1(p,[p.shape[1],p.shape[2],p.shape[3],p.shape[4]])}return p}const avgPool3d=op({avgPool3d_:avgPool3d_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function concat_(e,t=0){assert(e.length>=1,(()=>"Pass at least one tensor to concat"));const n=convertToTensorArray(e,"tensors","concat","string_or_numeric");if(n[0].dtype==="complex64"){n.forEach((e=>{if(e.dtype!=="complex64"){throw new Error(`Cannot concatenate complex64 tensors with a tensor\n          with dtype ${e.dtype}. `)}}));}if(n.length===1){return clone(n[0])}const r=n;const s={axis:t};return ENGINE.runKernel(Concat,r,s)}const concat$1=op({concat_:concat_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sigmoid_(e){const t=convertToTensor(e,"x","sigmoid");const n={x:t};return ENGINE.runKernel(Sigmoid,n)}const sigmoid$1=op({sigmoid_:sigmoid_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function slice_(e,t,n){const r=convertToTensor(e,"x","slice","string_or_numeric");if(r.rank===0){throw new Error("Slicing scalar is not possible")}const s={x:r};const a={begin:t,size:n};return ENGINE.runKernel(Slice,s,a)}const slice$1=op({slice_:slice_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function tanh_(e){const t=convertToTensor(e,"x","tanh");const n={x:t};return ENGINE.runKernel(Tanh,n)}const tanh=op({tanh_:tanh_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function batchToSpaceND_(e,t,n){const r=convertToTensor(e,"x","batchToSpaceND");const s=t.reduce(((e,t)=>e*t));assert(r.rank>=1+t.length,(()=>`input rank is ${r.rank} but should be > than blockShape.length ${t.length}`));assert(n.length===t.length,(()=>`crops.length is ${n.length} but should be equal to blockShape.length  ${t.length}`));assert(r.shape[0]%s===0,(()=>`input tensor batch is ${r.shape[0]} but is not divisible by the product of `+`the elements of blockShape ${t.join(" * ")} === ${s}`));const a={x:r};const o={blockShape:t,crops:n};return ENGINE.runKernel(BatchToSpaceND,a,o)}const batchToSpaceND=op({batchToSpaceND_:batchToSpaceND_});function xAs4D(e){let t;if(e.rank===0||e.rank===1){t=reshape$1(e,[1,1,1,e.size]);}else if(e.rank===2){t=reshape$1(e,[1,1,e.shape[0],e.shape[1]]);}else if(e.rank===3){t=reshape$1(e,[1,e.shape[0],e.shape[1],e.shape[2]]);}else {t=e;}return t}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function batchNorm_(e,t,n,r,s,a){if(a==null){a=.001;}const o=convertToTensor(e,"x","batchNorm");const i=convertToTensor(t,"mean","batchNorm");const u=convertToTensor(n,"variance","batchNorm");let c;if(s!=null){c=convertToTensor(s,"scale","batchNorm");}let l;if(r!=null){l=convertToTensor(r,"offset","batchNorm");}assert(i.rank===u.rank,(()=>"Batch normalization gradient requires mean and variance to have "+"equal ranks."));assert(l==null||i.rank===l.rank,(()=>"Batch normalization gradient requires mean and offset to have "+"equal ranks."));assert(c==null||i.rank===c.rank,(()=>"Batch normalization gradient requires mean and scale to have "+"equal ranks."));const p=xAs4D(o);const d={x:p,scale:c,offset:l,mean:i,variance:u};const h={varianceEpsilon:a};const m=ENGINE.runKernel(FusedBatchNorm,d,h);return reshape$1(m,o.shape)}const batchNorm=op({batchNorm_:batchNorm_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function bincount_(e,t,n){const r=convertToTensor(e,"x","bincount");const s=convertToTensor(t,"weights","bincount");assert(r.dtype==="int32",(()=>`Error in bincount: input `+`dtype must be int32, but got ${r.dtype}`));assert(n>=0,(()=>`size must be non-negative, but got ${n}.`));assert(s.size===r.size||s.size===0,(()=>`Error in bincount: weights must have the same size as input or`+`0-length, but got input shape: ${r.shape}, weights shape: `+`${s.shape}.`));const a={x:r,weights:s};const o={size:n};return ENGINE.runKernel(Bincount,a,o)}const bincount=op({bincount_:bincount_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function broadcastTo_(e,t){let n=convertToTensor(e,"broadcastTo","x");const r=n.shape;if(t.some((e=>!(e>0)||e%1!==0))){throw new Error(`broadcastTo(): Invalid broadcast shape [${t}].`)}if(t.length<n.rank){throw new Error(`broadcastTo(): shape.length=${t.length} < input.rank=${n.rank}.`)}if(t.length>n.rank){const e=n.shape.slice();while(e.length<t.length){e.unshift(1);}n=reshape$1(n,e);}const s=n.shape;const a=Array.from(t);for(let e=t.length-1;e>=0;e--){if(s[e]===t[e]){a[e]=1;}else if(n.shape[e]!==1){throw new Error(`broadcastTo(): [${r}] cannot be broadcast to [${t}].`)}}const o=a.map(((e,t)=>e>1?t:-1)).filter((e=>e>=0));if(o.length===0){return clone(n)}const i={x:n};const u={reps:a};return ENGINE.runKernel(Tile,i,u)}const broadcastTo=op({broadcastTo_:broadcastTo_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function ceil_(e){const t=convertToTensor(e,"x","ceil");const n={x:t};return ENGINE.runKernel(Ceil,n)}const ceil=op({ceil_:ceil_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function clipByValue_(e,t,n){const r=convertToTensor(e,"x","clipByValue");assert(t<=n,(()=>`Error in clip: min (${t}) must be `+`less than or equal to max (${n}).`));const s={x:r};const a={clipValueMin:t,clipValueMax:n};return ENGINE.runKernel(ClipByValue,s,a)}const clipByValue=op({clipByValue_:clipByValue_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function conv2d_(e,t,n,r,s="NHWC",a=[1,1],o){const i=convertToTensor(e,"x","conv2d");const u=convertToTensor(t,"filter","conv2d");let c=i;let l=false;if(i.rank===3){l=true;c=reshape$1(i,[1,i.shape[0],i.shape[1],i.shape[2]]);}assert(c.rank===4,(()=>`Error in conv2d: input must be rank 4, but got rank ${c.rank}.`));assert(u.rank===4,(()=>`Error in conv2d: filter must be rank 4, but got rank `+`${u.rank}.`));if(o!=null){assert(isInt(r),(()=>`Error in conv2d: pad must be an integer when using, `+`dimRoundingMode ${o} but got pad ${r}.`));}const p=s==="NHWC"?c.shape[3]:c.shape[1];assert(p===u.shape[2],(()=>`Error in conv2d: depth of input (${p}) must match `+`input depth for filter ${u.shape[2]}.`));assert(eitherStridesOrDilationsAreOne(n,a),(()=>"Error in conv2D: Either strides or dilations must be 1. "+`Got strides ${n} and dilations '${a}'`));const d={x:c,filter:u};const h={strides:n,pad:r,dataFormat:s,dilations:a,dimRoundingMode:o};const m=ENGINE.runKernel(Conv2D,d,h);if(l){return reshape$1(m,[m.shape[1],m.shape[2],m.shape[3]])}return m}const conv2d$1=op({conv2d_:conv2d_});function conv1d_(e,t,n,r,s="NWC",a=1,o){const i=convertToTensor(e,"x","conv1d");const u=convertToTensor(t,"filter","conv1d");let c=i;let l=false;if(i.rank===2){l=true;c=reshape$1(i,[1,i.shape[0],i.shape[1]]);}assert(c.rank===3,(()=>`Error in conv1d: input must be rank 3, but got rank ${c.rank}.`));assert(u.rank===3,(()=>`Error in conv1d: filter must be rank 3, but got rank `+`${u.rank}.`));if(o!=null){assert(isInt(r),(()=>`Error in conv1d: pad must be an integer when using, `+`dimRoundingMode ${o} but got pad ${r}.`));}assert(c.shape[2]===u.shape[1],(()=>`Error in conv1d: depth of input (${c.shape[2]}) must match `+`input depth for filter ${u.shape[1]}.`));assert(eitherStridesOrDilationsAreOne(n,a),(()=>"Error in conv1D: Either stride or dilation must be 1. "+`Got stride ${n} and dilation '${a}'`));assert(s==="NWC",(()=>`Error in conv1d: got dataFormat of ${s} but only NWC is currently supported.`));const p=reshape$1(u,[1,u.shape[0],u.shape[1],u.shape[2]]);const d=reshape$1(c,[c.shape[0],1,c.shape[1],c.shape[2]]);const h=[1,n];const m=[1,a];const f="NHWC";const g=conv2d$1(d,p,h,r,f,m,o);if(l){return reshape$1(g,[g.shape[2],g.shape[3]])}return reshape$1(g,[g.shape[0],g.shape[2],g.shape[3]])}const conv1d=op({conv1d_:conv1d_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function conv2DBackpropInput_(e,t,n,r,s,a="NHWC",o){assert(e.length===t.rank,(()=>`Length of inShape `+`(${e.length}) and rank of dy (${t.rank}) must match`));let i=e;let u=t;let c=false;if(t.rank===3){c=true;u=reshape$1(t,[1,t.shape[0],t.shape[1],t.shape[2]]);i=[1,e[0],e[1],e[2]];}assert(i.length===4,(()=>`Error in conv2dDerInput: inShape must be length 4, but got length `+`${i.length}.`));assert(u.rank===4,(()=>`Error in conv2dDerInput: dy must be rank 4, but got `+`rank ${u.rank}`));assert(n.rank===4,(()=>`Error in conv2dDerInput: filter must be rank 4, but got `+`rank ${n.rank}`));const l=a==="NHWC"?i[3]:i[1];const p=a==="NHWC"?u.shape[3]:u.shape[1];assert(l===n.shape[2],(()=>`Error in conv2dDerInput: depth of input (${l}) must `+`match input depth for filter ${n.shape[2]}.`));assert(p===n.shape[3],(()=>`Error in conv2dDerInput: depth of output (${p}) must `+`match output depth for filter ${n.shape[3]}.`));if(o!=null){assert(isInt(s),(()=>`Error in conv2dDerInput: pad must be an integer when using, `+`dimRoundingMode ${o} but got pad ${s}.`));}const d={dy:u,filter:n};const h={strides:r,pad:s,dataFormat:a,dimRoundingMode:o,inputShape:i};const m=ENGINE.runKernel(Conv2DBackpropInput,d,h);if(c){return reshape$1(m,[m.shape[1],m.shape[2],m.shape[3]])}return m}const conv2DBackpropInput=op({conv2DBackpropInput_:conv2DBackpropInput_});function conv2dTranspose_(e,t,n,r,s,a){const o=convertToTensor(e,"x","conv2dTranspose");const i=convertToTensor(t,"filter","conv2dTranspose");return conv2DBackpropInput(n,o,i,r,s,"NHWC",a)}const conv2dTranspose=op({conv2dTranspose_:conv2dTranspose_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function conv3d_(e,t,n,r,s="NDHWC",a=[1,1,1]){const o=convertToTensor(e,"x","conv3d");const i=convertToTensor(t,"filter","conv3d");let u=o;let c=false;if(o.rank===4){c=true;u=reshape$1(o,[1,o.shape[0],o.shape[1],o.shape[2],o.shape[3]]);}assert(u.rank===5,(()=>`Error in conv3d: input must be rank 5, but got rank ${u.rank}.`));assert(i.rank===5,(()=>`Error in conv3d: filter must be rank 5, but got rank `+`${i.rank}.`));assert(u.shape[4]===i.shape[3],(()=>`Error in conv3d: depth of input (${u.shape[4]}) must match `+`input depth for filter ${i.shape[3]}.`));assert(eitherStridesOrDilationsAreOne(n,a),(()=>"Error in conv3D: Either strides or dilations must be 1. "+`Got strides ${n} and dilations '${a}'`));assert(s==="NDHWC",(()=>`Error in conv3d: got dataFormat of ${s} but only NDHWC is currently supported.`));const l={x:u,filter:i};const p={strides:n,pad:r,dataFormat:s,dilations:a};const d=ENGINE.runKernel(Conv3D,l,p);if(c){return reshape$1(d,[d.shape[1],d.shape[2],d.shape[3],d.shape[4]])}return d}const conv3d=op({conv3d_:conv3d_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function cos_(e){const t=convertToTensor(e,"x","cos");const n={x:t};return ENGINE.runKernel(Cos,n)}const cos=op({cos_:cos_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function cosh_(e){const t=convertToTensor(e,"x","cosh");const n={x:t};return ENGINE.runKernel(Cosh,n)}const cosh=op({cosh_:cosh_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function cumsum_(e,t=0,n=false,r=false){const s=convertToTensor(e,"x","cumsum");const a={x:s};const o={axis:t,exclusive:n,reverse:r};return ENGINE.runKernel(Cumsum,a,o)}const cumsum=op({cumsum_:cumsum_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function denseBincount_(e,t,n,r=false){const s=convertToTensor(e,"x","denseBincount");const a=convertToTensor(t,"weights","denseBincount");assert(s.dtype==="int32",(()=>`Error in denseBincount: input `+`dtype must be int32, but got ${s.dtype}`));assert(s.rank<=2,(()=>`Error in denseBincount: input must be at most rank 2, but got `+`rank ${s.rank}.`));assert(n>=0,(()=>`size must be non-negative, but got ${n}.`));assert(a.size===s.size||a.size===0,(()=>`Error in denseBincount: weights must have the same shape as x or `+`0-length, but got x shape: ${s.shape}, weights shape: `+`${a.shape}.`));const o={x:s,weights:a};const i={size:n,binaryOutput:r};return ENGINE.runKernel(DenseBincount,o,i)}const denseBincount=op({denseBincount_:denseBincount_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function depthToSpace_(e,t,n="NHWC"){const r=convertToTensor(e,"x","depthToSpace");const s=n==="NHWC"?r.shape[1]:r.shape[2];const a=n==="NHWC"?r.shape[2]:r.shape[3];const o=n==="NHWC"?r.shape[3]:r.shape[1];assert(s*t>=0,(()=>`Negative dimension size caused by overflow when multiplying\n    ${s} and ${t}  for depthToSpace with input shape\n    ${r.shape}`));assert(a*t>=0,(()=>`Negative dimension size caused by overflow when multiplying\n    ${a} and ${t} for depthToSpace with input shape\n        ${r.shape}`));assert(o%(t*t)===0,(()=>`Dimension size must be evenly divisible by ${t*t} but is ${o} for depthToSpace with input shape ${r.shape}`));const i={x:r};const u={blockSize:t,dataFormat:n};return ENGINE.runKernel(DepthToSpace,i,u)}const depthToSpace=op({depthToSpace_:depthToSpace_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function depthwiseConv2d_(e,t,n,r,s="NHWC",a=[1,1],o){const i=convertToTensor(e,"x","depthwiseConv2d");const u=convertToTensor(t,"filter","depthwiseConv2d");let c=i;let l=false;if(i.rank===3){l=true;c=reshape$1(i,[1,i.shape[0],i.shape[1],i.shape[2]]);}assert(c.rank===4,(()=>`Error in depthwiseConv2d: input must be rank 4, but got `+`rank ${c.rank}.`));assert(u.rank===4,(()=>`Error in depthwiseConv2d: filter must be rank 4, but got rank `+`${u.rank}.`));assert(c.shape[3]===u.shape[2],(()=>`Error in depthwiseConv2d: number of input channels `+`(${c.shape[3]}) must match the inChannels dimension in `+`filter ${u.shape[2]}.`));if(o!=null){assert(isInt(r),(()=>`Error in depthwiseConv2d: pad must be an integer when using, `+`dimRoundingMode ${o} but got pad ${r}.`));}const p={x:c,filter:u};const d={strides:n,pad:r,dataFormat:s,dilations:a,dimRoundingMode:o};const h=ENGINE.runKernel(DepthwiseConv2dNative,p,d);if(l){return reshape$1(h,[h.shape[1],h.shape[2],h.shape[3]])}return h}const depthwiseConv2d$1=op({depthwiseConv2d_:depthwiseConv2d_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function dilation2d_(e,t,n,r,s=[1,1],a="NHWC"){const o=convertToTensor(e,"x","dilation2d");const i=convertToTensor(t,"filter","dilation2d");assert(o.rank===3||o.rank===4,(()=>`Error in dilation2d: input must be rank 3 or 4, but got rank `+`${o.rank}.`));assert(i.rank===3,(()=>`Error in dilation2d: filter must be rank 3, but got rank `+`${i.rank}.`));assert(a==="NHWC",(()=>`Error in dilation2d: Only NHWC is currently supported, `+`but got dataFormat of ${a}`));let u=o;let c=false;if(o.rank===3){u=reshape$1(o,[1,o.shape[0],o.shape[1],o.shape[2]]);c=true;}const l={x:u,filter:i};const p={strides:n,pad:r,dilations:s};const d=ENGINE.runKernel(Dilation2D,l,p);if(c){return reshape$1(d,[d.shape[1],d.shape[2],d.shape[3]])}return d}const dilation2d=op({dilation2d_:dilation2d_});
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getBroadcastDims$1(e,t){const n=e.length;const r=[];for(let s=0;s<n;s++){const a=n-1-s;const o=e[a]||1;const i=t[t.length-1-s]||1;if(i>1&&o===1){r.unshift(a);}}return r}function getReductionAxes(e,t){const n=[];for(let r=0;r<t.length;r++){const s=e[e.length-r-1];const a=t.length-r-1;const o=t[a];if(s==null||s===1&&o>1){n.unshift(a);}}return n}function assertAndGetBroadcastShape(e,t){const n=[];const r=Math.max(e.length,t.length);for(let s=0;s<r;s++){let r=e[e.length-s-1];if(r==null){r=1;}let a=t[t.length-s-1];if(a==null){a=1;}if(r===1){n.unshift(a);}else if(a===1){n.unshift(r);}else if(r!==a){const n=`Operands could not be broadcast together with shapes `+`${e} and ${t}.`;throw Error(n)}else {n.unshift(r);}}return n}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function equal_(e,t){let n=convertToTensor(e,"a","equal","string_or_numeric");let r=convertToTensor(t,"b","equal","string_or_numeric");[n,r]=makeTypesMatch(n,r);assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(Equal,s)}const equal=op({equal_:equal_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function where_(e,t,n){const r=convertToTensor(t,"a","where");const s=convertToTensor(n,"b","where");const a=convertToTensor(e,"condition","where","bool");const o=assertAndGetBroadcastShape(assertAndGetBroadcastShape(a.shape,r.shape),s.shape);const i=broadcastTo(a,o);const u=broadcastTo(r,o);const c=broadcastTo(s,o);const l={condition:i,t:u,e:c};return ENGINE.runKernel(Select,l)}const where=op({where_:where_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function zerosLike_(e){const t=convertToTensor(e,"x","zerosLike");const n={x:t};return ENGINE.runKernel(ZerosLike,n)}const zerosLike=op({zerosLike_:zerosLike_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function divNoNan_(e,t){let n=convertToTensor(e,"a","div");let r=convertToTensor(t,"b","div");[n,r]=makeTypesMatch(n,r);const s=div(n,r);const a=zerosLike(s);const o=equal(r,a);return where(o,a,s)}const divNoNan=op({divNoNan_:divNoNan_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function dot_(e,t){const n=convertToTensor(e,"t1","dot");const r=convertToTensor(t,"t2","dot");assert((n.rank===1||n.rank===2)&&(r.rank===1||r.rank===2),(()=>`Error in dot: inputs must all be rank 1 or 2, but got ranks `+`${n.rank} and ${r.rank}.`));const s=n.rank===1?n.size:n.shape[1];const a=r.rank===1?r.size:r.shape[0];assert(s===a,(()=>`Error in dot: inner dimensions of inputs must match, but got `+`${s} and ${a}.`));if(n.rank===1&&r.rank===1){const e=reshape$1(n,[1,-1]);const t=reshape$1(r,[-1,1]);const s=matMul$1(e,t);return reshape$1(s,[])}else if(n.rank===1&&r.rank===2){const e=reshape$1(n,[1,-1]);const t=reshape$1(r,[r.shape[0],r.shape[1]]);const s=matMul$1(e,t);return reshape$1(s,[s.size])}else if(n.rank===2&&r.rank===1){const e=reshape$1(r,[-1,1]);const t=matMul$1(n,e);return reshape$1(t,[t.size])}else {const e=reshape$1(r,[r.shape[0],r.shape[1]]);const t=matMul$1(n,e);return t}}const dot=op({dot_:dot_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function einsum_(e,...t){const n=t.map(((e,t)=>convertToTensor(e,`tensors${t}`,"einsum")));const r={equation:e};return ENGINE.runKernel(Einsum,n,r)}const einsum=op({einsum_:einsum_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function elu_(e){const t=convertToTensor(e,"x","elu");const n={x:t};return ENGINE.runKernel(Elu,n)}const elu=op({elu_:elu_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function erf_(e){let t=convertToTensor(e,"x","erf");assert(t.dtype==="int32"||t.dtype==="float32",(()=>"Input dtype must be `int32` or `float32`."));if(t.dtype==="int32"){t=cast$1(t,"float32");}const n={x:t};return ENGINE.runKernel(Erf,n)}const erf=op({erf_:erf_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function exp_(e){const t=convertToTensor(e,"x","exp");const n={x:t};return ENGINE.runKernel(Exp,n)}const exp=op({exp_:exp_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function expandDims_(e,t=0){const n=convertToTensor(e,"x","expandDims","string_or_numeric");assert(t<=n.rank,(()=>"Axis must be <= rank of the tensor"));const r={input:n};const s={dim:t};return ENGINE.runKernel(ExpandDims,r,s)}const expandDims$1=op({expandDims_:expandDims_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function expm1_(e){const t=convertToTensor(e,"x","expm1");const n={x:t};return ENGINE.runKernel(Expm1,n)}const expm1=op({expm1_:expm1_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function tile_(e,t){const n=convertToTensor(e,"x","tile","string_or_numeric");assert(n.rank===t.length,(()=>`Error in transpose: rank of input ${n.rank} `+`must match length of reps ${t}.`));const r={x:n};const s={reps:t};return ENGINE.runKernel(Tile,r,s)}const tile=op({tile_:tile_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function eye_(e,t,n,r="float32"){if(t==null){t=e;}const s=buffer([e,t],r);const a=e<=t?e:t;for(let e=0;e<a;++e){s.set(1,e,e);}const o=reshape$1(s.toTensor(),[e,t]);if(n==null){return o}else {if(n.length===1){return tile(expandDims$1(o,0),[n[0],1,1])}else if(n.length===2){return tile(expandDims$1(expandDims$1(o,0),0),[n[0],n[1],1,1])}else if(n.length===3){return tile(expandDims$1(expandDims$1(expandDims$1(o,0),0),0),[n[0],n[1],n[2],1,1])}else {throw new Error(`eye() currently supports only 1D and 2D `+`batchShapes, but received ${n.length}D.`)}}}const eye=op({eye_:eye_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function fill(e,t,n){const r={shape:e,value:t,dtype:n};return ENGINE.runKernel(Fill,{},r)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function floor_(e){const t=convertToTensor(e,"x","floor");const n={x:t};return ENGINE.runKernel(Floor,n)}const floor=op({floor_:floor_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function gather_(e,t,n=0,r=0){const s=convertToTensor(e,"x","gather");const a=convertToTensor(t,"indices","gather","int32");const o={x:s,indices:a};const i={axis:n,batchDims:r};return ENGINE.runKernel(GatherV2,o,i)}const gather=op({gather_:gather_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function greater_(e,t){let n=convertToTensor(e,"a","greater","string_or_numeric");let r=convertToTensor(t,"b","greater","string_or_numeric");[n,r]=makeTypesMatch(n,r);assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(Greater,s)}const greater=op({greater_:greater_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function greaterEqual_(e,t){let n=convertToTensor(e,"a","greaterEqual","string_or_numeric");let r=convertToTensor(t,"b","greaterEqual","string_or_numeric");[n,r]=makeTypesMatch(n,r);assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(GreaterEqual,s)}const greaterEqual=op({greaterEqual_:greaterEqual_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function imag_(e){const t=convertToTensor(e,"input","imag");const n={input:t};return ENGINE.runKernel(Imag,n)}const imag$1=op({imag_:imag_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function isFinite_(e){const t=convertToTensor(e,"x","isFinite");const n={x:t};return ENGINE.runKernel(IsFinite,n)}const isFinite$2=op({isFinite_:isFinite_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function isNaN_(e){const t=convertToTensor(e,"x","isNaN");const n={x:t};return ENGINE.runKernel(IsNan,n)}const isNaN$1=op({isNaN_:isNaN_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function leakyRelu_(e,t=.2){const n=convertToTensor(e,"x","leakyRelu");const r={x:n};const s={alpha:t};return ENGINE.runKernel(LeakyRelu,r,s)}const leakyRelu=op({leakyRelu_:leakyRelu_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function less_(e,t){let n=convertToTensor(e,"a","less","string_or_numeric");let r=convertToTensor(t,"b","less","string_or_numeric");[n,r]=makeTypesMatch(n,r);assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(Less,s)}const less=op({less_:less_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function lessEqual_(e,t){let n=convertToTensor(e,"a","lessEqual","string_or_numeric");let r=convertToTensor(t,"b","lessEqual","string_or_numeric");[n,r]=makeTypesMatch(n,r);assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(LessEqual,s)}const lessEqual=op({lessEqual_:lessEqual_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function linspace(e,t,n){if(n<=0){throw new Error("The number of values should be positive.")}const r={start:e,stop:t,num:n};return ENGINE.runKernel(LinSpace,{},r)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function localResponseNormalization_(e,t=5,n=1,r=1,s=.5){const a=convertToTensor(e,"x","localResponseNormalization");assert(a.rank===4||a.rank===3,(()=>`Error in localResponseNormalization: x must be rank 3 or 4 but got\n               rank ${a.rank}.`));assert(isInt(t),(()=>`Error in localResponseNormalization: depthRadius must be an `+`integer but got depthRadius ${t}.`));let o=a;let i=false;if(a.rank===3){i=true;o=reshape$1(a,[1,a.shape[0],a.shape[1],a.shape[2]]);}const u={x:o};const c={depthRadius:t,bias:n,alpha:r,beta:s};const l=ENGINE.runKernel(LRN,u,c);if(i){return reshape$1(l,[l.shape[1],l.shape[2],l.shape[3]])}else {return l}}const localResponseNormalization=op({localResponseNormalization_:localResponseNormalization_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function log_(e){const t=convertToTensor(e,"x","log");const n={x:t};return ENGINE.runKernel(Log,n)}const log$1=op({log_:log_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function log1p_(e){const t=convertToTensor(e,"x","log1p");const n={x:t};return ENGINE.runKernel(Log1p,n)}const log1p=op({log1p_:log1p_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function customGrad(e){return ENGINE.customGrad(e)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function neg_(e){const t=convertToTensor(e,"x","neg");const n={x:t};return ENGINE.runKernel(Neg,n)}const neg=op({neg_:neg_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function softplus_(e){const t=convertToTensor(e,"x","softplus");const n={x:t};return ENGINE.runKernel(Softplus,n)}const softplus=op({softplus_:softplus_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function max_(e,t=null,n=false){const r=convertToTensor(e,"x","max");const s={x:r};const a={reductionIndices:t,keepDims:n};return ENGINE.runKernel(Max,s,a)}const max=op({max_:max_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sub_(e,t){let n=convertToTensor(e,"a","sub");let r=convertToTensor(t,"b","sub");[n,r]=makeTypesMatch(n,r);const s={a:n,b:r};return ENGINE.runKernel(Sub,s)}const sub=op({sub_:sub_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sum_(e,t=null,n=false){let r=convertToTensor(e,"x","sum");if(r.dtype==="bool"){r=cast$1(r,"int32");}const s={x:r};const a={axis:t,keepDims:n};return ENGINE.runKernel(Sum,s,a)}const sum$1=op({sum_:sum_});
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function logSoftmax_(e,t=-1){const n=convertToTensor(e,"logits","logSoftmax");if(t===-1){t=n.rank-1;}if(t!==n.rank-1){throw Error("Log Softmax along a non-last dimension is not yet supported. "+`Logits was rank ${n.rank} and axis was ${t}`)}const r=customGrad(((e,n)=>{const r=true;const s=max(e,t,true);const a=sub(e,s);const o=sub(cast$1(a,"float32"),log$1(sum$1(exp(a),t,r)));n([o]);const i=(e,n)=>{const[r]=n;const s=true;const a=exp(r);return sub(e,mul(sum$1(e,t,s),a))};return {value:o,gradFunc:i}}));return r(n)}const logSoftmax=op({logSoftmax_:logSoftmax_});
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function axesAreInnerMostDims(e,t){for(let n=0;n<e.length;++n){if(e[e.length-n-1]!==t-1-n){return false}}return true}function combineLocations(e,t,n){const r=e.length+t.length;const s=[];let a=0;let o=0;for(let i=0;i<r;i++){if(n.indexOf(i)===-1){s.push(e[a++]);}else {s.push(t[o++]);}}return s}function computeOutAndReduceShapes(e,t){const n=[];const r=e.length;for(let s=0;s<r;s++){if(t.indexOf(s)===-1){n.push(e[s]);}}const s=t.map((t=>e[t]));return [n,s]}function expandShapeToKeepDim(e,t){const n=t.map((e=>1));return combineLocations(e,n,t)}function assertAxesAreInnerMostDims(e,t,n){assert(axesAreInnerMostDims(t,n),(()=>`${e} supports only inner-most axes for now. `+`Got axes ${t} and rank-${n} input.`));}function getAxesPermutation(e,t){if(axesAreInnerMostDims(e,t)){return null}const n=[];for(let r=0;r<t;++r){if(e.indexOf(r)===-1){n.push(r);}}e.forEach((e=>n.push(e)));return n}function getUndoAxesPermutation(e){return e.map(((e,t)=>[t,e])).sort(((e,t)=>e[1]-t[1])).map((e=>e[0]))}function getInnerMostAxes(e,t){const n=[];for(let r=t-e;r<t;++r){n.push(r);}return n}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function logSumExp_(e,t=null,n=false){const r=convertToTensor(e,"x","logSumExp");const s=parseAxisParam(t,r.shape);const a=max(r,s,true);const o=sub(r,a);const i=exp(o);const u=sum$1(i,s);const c=log$1(u);const l=add(reshape$1(a,c.shape),c);if(n){const e=expandShapeToKeepDim(l.shape,s);return reshape$1(l,e)}return l}const logSumExp=op({logSumExp_:logSumExp_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function logicalAnd_(e,t){const n=convertToTensor(e,"a","logicalAnd","bool");const r=convertToTensor(t,"b","logicalAnd","bool");assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(LogicalAnd,s)}const logicalAnd=op({logicalAnd_:logicalAnd_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function logicalNot_(e){const t=convertToTensor(e,"x","logicalNot","bool");const n={x:t};return ENGINE.runKernel(LogicalNot,n)}const logicalNot=op({logicalNot_:logicalNot_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function logicalOr_(e,t){const n=convertToTensor(e,"a","logicalOr","bool");const r=convertToTensor(t,"b","logicalOr","bool");assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(LogicalOr,s)}const logicalOr=op({logicalOr_:logicalOr_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function maxPool_(e,t,n,r,s){const a=convertToTensor(e,"x","maxPool");const o=1;let i=a;let u=false;if(a.rank===3){u=true;i=reshape$1(a,[1,a.shape[0],a.shape[1],a.shape[2]]);}assert(i.rank===4,(()=>`Error in maxPool: input must be rank 4 but got rank ${i.rank}.`));assert(eitherStridesOrDilationsAreOne(n,o),(()=>"Error in maxPool: Either strides or dilations must be 1. "+`Got strides ${n} and dilations '${o}'`));if(s!=null){assert(isInt(r),(()=>`Error in maxPool: pad must be an integer when using, `+`dimRoundingMode ${s} but got pad ${r}.`));}const c={x:i};const l={filterSize:t,strides:n,pad:r,dimRoundingMode:s};const p=ENGINE.runKernel(MaxPool,c,l);if(u){return reshape$1(p,[p.shape[1],p.shape[2],p.shape[3]])}return p}const maxPool=op({maxPool_:maxPool_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function maxPool3d_(e,t=[1,1,1],n,r,s,a="NDHWC"){const o=convertToTensor(e,"x","maxPool3d");let i=o;let u=false;if(o.rank===4){u=true;i=reshape$1(o,[1,o.shape[0],o.shape[1],o.shape[2],o.shape[3]]);}assert(i.rank===5,(()=>`Error in maxPool3d: x must be rank 5 but got rank ${i.rank}.`));assert(a==="NDHWC",(()=>`Error in maxPool3d: Only NDHWC is currently supported, `+`but got dataFormat of ${a}`));if(s!=null){assert(isInt(r),(()=>`Error in maxPool3d: pad must be an integer when using, `+`dimRoundingMode ${s} but got pad ${r}.`));}const c={x:i};const l={filterSize:t,strides:n,pad:r,dimRoundingMode:s,dataFormat:a};const p=ENGINE.runKernel(MaxPool3D,c,l);if(u){return reshape$1(p,[p.shape[1],p.shape[2],p.shape[3],p.shape[4]])}return p}const maxPool3d=op({maxPool3d_:maxPool3d_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function maxPoolWithArgmax_(e,t,n,r,s=false){const a=convertToTensor(e,"x","maxPoolWithArgmax");const o={x:a};const i={filterSize:t,strides:n,pad:r,includeBatchInIndex:s};const u=ENGINE.runKernel(MaxPoolWithArgmax,o,i);return {result:u[0],indexes:u[1]}}const maxPoolWithArgmax=op({maxPoolWithArgmax_:maxPoolWithArgmax_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function maximum_(e,t){let n=convertToTensor(e,"a","maximum");let r=convertToTensor(t,"b","maximum");[n,r]=makeTypesMatch(n,r);if(n.dtype==="bool"){n=cast$1(n,"int32");r=cast$1(r,"int32");}assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(Maximum,s)}const maximum=op({maximum_:maximum_});
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function mean_(e,t=null,n=false){const r=convertToTensor(e,"x","mean");const s={x:r};const a={axis:t,keepDims:n};return ENGINE.runKernel(Mean,s,a)}const mean=op({mean_:mean_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function zeros(e,t="float32"){if(t==="complex64"){const t=zeros(e,"float32");const n=zeros(e,"float32");return complex$1(t,n)}const n=makeZerosTypedArray(sizeFromShape(e),t);return ENGINE.makeTensor(n,e,t)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function ones(e,t="float32"){if(t==="complex64"){const t=ones(e,"float32");const n=zeros(e,"float32");return complex$1(t,n)}const n=makeOnesTypedArray(sizeFromShape(e),t);return ENGINE.makeTensor(n,e,t)}
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */function min_(e,t=null,n=false){const r=convertToTensor(e,"x","min");const s={x:r};const a={axis:t,keepDims:n};return ENGINE.runKernel(Min,s,a)}const min=op({min_:min_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function minimum_(e,t){let n=convertToTensor(e,"a","minimum");let r=convertToTensor(t,"b","minimum");[n,r]=makeTypesMatch(n,r);if(n.dtype==="bool"){n=cast$1(n,"int32");r=cast$1(r,"int32");}assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(Minimum,s)}const minimum=op({minimum_:minimum_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function mirrorPad_(e,t,n){assert(n==="reflect"||n==="symmetric",(()=>`Invalid mode. Mode must be either reflect or symmetric. `+`Got ${n}.`));const r=convertToTensor(e,"x","mirrorPad");if(r.rank===0){throw new Error("mirrorPad(scalar) is not defined. "+"Pass non-scalar to mirrorPad")}assert(t.length===r.rank,(()=>`Padding doesn't match input. Must be ${r.rank}. `+`Got ${t.length}.`));const s=n==="reflect"?1:0;for(let e=0;e<r.rank;e++){assert(t[e].length===2,(()=>`Invalid number of paddings. Must be length of 2 each.`));assert(t[e][0]>=0&&t[e][0]<=r.shape[e]-s&&t[e][1]>=0&&t[e][1]<=r.shape[e]-s,(()=>`Padding in dimension ${e} cannot be greater than or equal `+`to ${r.shape[e]-s} or less than 0 for input of `+`shape ${r.shape}`));}const a={paddings:t,mode:n};const o={x:r};return ENGINE.runKernel(MirrorPad,o,a)}const mirrorPad=op({mirrorPad_:mirrorPad_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function mod_(e,t){let n=convertToTensor(e,"a","mod");let r=convertToTensor(t,"b","mod");[n,r]=makeTypesMatch(n,r);const s={a:n,b:r};return ENGINE.runKernel(Mod,s)}const mod=op({mod_:mod_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function square_(e){const t=convertToTensor(e,"x","square");const n={};return ENGINE.runKernel("Square",{x:t},n)}const square=op({square_:square_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function multinomial_(e,t,n,r=false){const s=convertToTensor(e,"logits","multinomial");const a=s.size;const o=s.rank;if(a<2){throw new Error(`Error in multinomial: you need at least 2 outcomes, but got `+`${a}.`)}if(o>2){throw new Error(`Rank of probabilities must be 1 or 2, but is ${o}`)}n=n||Math.random();const i=o===1?reshape$1(s,[1,-1]):s;const u={logits:i};const c={numSamples:t,seed:n,normalized:r};const l=ENGINE.runKernel(Multinomial,u,c);return o===1?reshape$1(l,[l.size]):l}const multinomial=op({multinomial_:multinomial_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function notEqual_(e,t){let n=convertToTensor(e,"a","notEqual","string_or_numeric");let r=convertToTensor(t,"b","notEqual","string_or_numeric");[n,r]=makeTypesMatch(n,r);assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};return ENGINE.runKernel(NotEqual,s)}const notEqual$1=op({notEqual_:notEqual_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function onesLike_(e){const t=convertToTensor(e,"x","onesLike");const n={x:t};return ENGINE.runKernel(OnesLike,n)}const onesLike=op({onesLike_:onesLike_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function pad_(e,t,n=0){const r=convertToTensor(e,"x","pad");if(r.rank===0){throw new Error("pad(scalar) is not defined. Pass non-scalar to pad")}const s={paddings:t,constantValue:n};const a={x:r};return ENGINE.runKernel(PadV2,a,s)}const pad=op({pad_:pad_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function spaceToBatchND_(e,t,n){const r=convertToTensor(e,"x","spaceToBatchND");assert(r.rank>=1+t.length,(()=>`input rank ${r.rank} should be > than [blockShape] ${t.length}`));assert(n.length===t.length,(()=>`paddings.shape[0] ${n.length} must be equal to [blockShape] ${t.length}`));assert(r.shape.reduce(((e,r,s)=>{if(s>0&&s<=t.length){return e&&(r+n[s-1][0]+n[s-1][1])%t[s-1]===0}return e}),true),(()=>`input spatial dimensions ${r.shape.slice(1)} with paddings ${n.toString()} must be divisible by blockShapes ${t.toString()}`));const s={x:r};const a={blockShape:t,paddings:n};return ENGINE.runKernel(SpaceToBatchND,s,a)}const spaceToBatchND=op({spaceToBatchND_:spaceToBatchND_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function pow_(e,t){let n=convertToTensor(e,"base","pow");let r=convertToTensor(t,"exp","pow");[n,r]=makeTypesMatch(n,r);const s={a:n,b:r};return ENGINE.runKernel(Pow,s)}const pow$1=op({pow_:pow_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function prelu_(e,t){const n=convertToTensor(e,"x","prelu");const r=convertToTensor(t,"alpha","prelu");const s={x:n,alpha:r};return ENGINE.runKernel(Prelu,s)}const prelu=op({prelu_:prelu_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function prod_(e,t=null,n=false){let r=convertToTensor(e,"x","prod");if(r.dtype==="bool"){r=cast$1(r,"int32");}const s={x:r};const a={axis:t,keepDims:n};return ENGINE.runKernel(Prod,s,a)}const prod$1=op({prod_:prod_});var alea$1={exports:{}};(function(e){(function(e,t,n){function r(e){var t=this,n=o();t.next=function(){var e=2091639*t.s0+t.c*2.3283064365386963e-10;t.s0=t.s1;t.s1=t.s2;return t.s2=e-(t.c=e|0)};t.c=1;t.s0=n(" ");t.s1=n(" ");t.s2=n(" ");t.s0-=n(e);if(t.s0<0){t.s0+=1;}t.s1-=n(e);if(t.s1<0){t.s1+=1;}t.s2-=n(e);if(t.s2<0){t.s2+=1;}n=null;}function s(e,t){t.c=e.c;t.s0=e.s0;t.s1=e.s1;t.s2=e.s2;return t}function a(e,t){var n=new r(e),a=t&&t.state,o=n.next;o.int32=function(){return n.next()*4294967296|0};o.double=function(){return o()+(o()*2097152|0)*11102230246251565e-32};o.quick=o;if(a){if(typeof a=="object")s(a,n);o.state=function(){return s(n,{})};}return o}function o(){var e=4022871197;var t=function(t){t=t.toString();for(var n=0;n<t.length;n++){e+=t.charCodeAt(n);var r=.02519603282416938*e;e=r>>>0;r-=e;r*=e;e=r>>>0;r-=e;e+=r*4294967296;}return (e>>>0)*2.3283064365386963e-10};return t}if(t&&t.exports){t.exports=a;}else if(n&&n.amd){n((function(){return a}));}else {this.alea=a;}})(commonjsGlobal,e,typeof undefined=="function");})(alea$1);var xor128$1={exports:{}};(function(e){(function(e,t,n){function r(e){var t=this,n="";t.x=0;t.y=0;t.z=0;t.w=0;t.next=function(){var e=t.x^t.x<<11;t.x=t.y;t.y=t.z;t.z=t.w;return t.w^=t.w>>>19^e^e>>>8};if(e===(e|0)){t.x=e;}else {n+=e;}for(var r=0;r<n.length+64;r++){t.x^=n.charCodeAt(r)|0;t.next();}}function s(e,t){t.x=e.x;t.y=e.y;t.z=e.z;t.w=e.w;return t}function a(e,t){var n=new r(e),a=t&&t.state,o=function(){return (n.next()>>>0)/4294967296};o.double=function(){do{var e=n.next()>>>11,t=(n.next()>>>0)/4294967296,r=(e+t)/(1<<21);}while(r===0);return r};o.int32=n.next;o.quick=o;if(a){if(typeof a=="object")s(a,n);o.state=function(){return s(n,{})};}return o}if(t&&t.exports){t.exports=a;}else if(n&&n.amd){n((function(){return a}));}else {this.xor128=a;}})(commonjsGlobal,e,typeof undefined=="function");})(xor128$1);var xorwow$1={exports:{}};(function(e){(function(e,t,n){function r(e){var t=this,n="";t.next=function(){var e=t.x^t.x>>>2;t.x=t.y;t.y=t.z;t.z=t.w;t.w=t.v;return (t.d=t.d+362437|0)+(t.v=t.v^t.v<<4^(e^e<<1))|0};t.x=0;t.y=0;t.z=0;t.w=0;t.v=0;if(e===(e|0)){t.x=e;}else {n+=e;}for(var r=0;r<n.length+64;r++){t.x^=n.charCodeAt(r)|0;if(r==n.length){t.d=t.x<<10^t.x>>>4;}t.next();}}function s(e,t){t.x=e.x;t.y=e.y;t.z=e.z;t.w=e.w;t.v=e.v;t.d=e.d;return t}function a(e,t){var n=new r(e),a=t&&t.state,o=function(){return (n.next()>>>0)/4294967296};o.double=function(){do{var e=n.next()>>>11,t=(n.next()>>>0)/4294967296,r=(e+t)/(1<<21);}while(r===0);return r};o.int32=n.next;o.quick=o;if(a){if(typeof a=="object")s(a,n);o.state=function(){return s(n,{})};}return o}if(t&&t.exports){t.exports=a;}else if(n&&n.amd){n((function(){return a}));}else {this.xorwow=a;}})(commonjsGlobal,e,typeof undefined=="function");})(xorwow$1);var xorshift7$1={exports:{}};(function(e){(function(e,t,n){function r(e){var t=this;t.next=function(){var e=t.x,n=t.i,r,s;r=e[n];r^=r>>>7;s=r^r<<24;r=e[n+1&7];s^=r^r>>>10;r=e[n+3&7];s^=r^r>>>3;r=e[n+4&7];s^=r^r<<7;r=e[n+7&7];r=r^r<<13;s^=r^r<<9;e[n]=s;t.i=n+1&7;return s};function n(e,t){var n,r=[];if(t===(t|0)){r[0]=t;}else {t=""+t;for(n=0;n<t.length;++n){r[n&7]=r[n&7]<<15^t.charCodeAt(n)+r[n+1&7]<<13;}}while(r.length<8)r.push(0);for(n=0;n<8&&r[n]===0;++n);if(n==8)r[7]=-1;e.x=r;e.i=0;for(n=256;n>0;--n){e.next();}}n(t,e);}function s(e,t){t.x=e.x.slice();t.i=e.i;return t}function a(e,t){if(e==null)e=+new Date;var n=new r(e),a=t&&t.state,o=function(){return (n.next()>>>0)/4294967296};o.double=function(){do{var e=n.next()>>>11,t=(n.next()>>>0)/4294967296,r=(e+t)/(1<<21);}while(r===0);return r};o.int32=n.next;o.quick=o;if(a){if(a.x)s(a,n);o.state=function(){return s(n,{})};}return o}if(t&&t.exports){t.exports=a;}else if(n&&n.amd){n((function(){return a}));}else {this.xorshift7=a;}})(commonjsGlobal,e,typeof undefined=="function");})(xorshift7$1);var xor4096$1={exports:{}};(function(e){(function(e,t,n){function r(e){var t=this;t.next=function(){var e=t.w,n=t.X,r=t.i,s,a;t.w=e=e+1640531527|0;a=n[r+34&127];s=n[r=r+1&127];a^=a<<13;s^=s<<17;a^=a>>>15;s^=s>>>12;a=n[r]=a^s;t.i=r;return a+(e^e>>>16)|0};function n(e,t){var n,r,s,a,o,i=[],u=128;if(t===(t|0)){r=t;t=null;}else {t=t+"\0";r=0;u=Math.max(u,t.length);}for(s=0,a=-32;a<u;++a){if(t)r^=t.charCodeAt((a+32)%t.length);if(a===0)o=r;r^=r<<10;r^=r>>>15;r^=r<<4;r^=r>>>13;if(a>=0){o=o+1640531527|0;n=i[a&127]^=r+o;s=0==n?s+1:0;}}if(s>=128){i[(t&&t.length||0)&127]=-1;}s=127;for(a=4*128;a>0;--a){r=i[s+34&127];n=i[s=s+1&127];r^=r<<13;n^=n<<17;r^=r>>>15;n^=n>>>12;i[s]=r^n;}e.w=o;e.X=i;e.i=s;}n(t,e);}function s(e,t){t.i=e.i;t.w=e.w;t.X=e.X.slice();return t}function a(e,t){if(e==null)e=+new Date;var n=new r(e),a=t&&t.state,o=function(){return (n.next()>>>0)/4294967296};o.double=function(){do{var e=n.next()>>>11,t=(n.next()>>>0)/4294967296,r=(e+t)/(1<<21);}while(r===0);return r};o.int32=n.next;o.quick=o;if(a){if(a.X)s(a,n);o.state=function(){return s(n,{})};}return o}if(t&&t.exports){t.exports=a;}else if(n&&n.amd){n((function(){return a}));}else {this.xor4096=a;}})(commonjsGlobal,e,typeof undefined=="function");})(xor4096$1);var tychei$1={exports:{}};(function(e){(function(e,t,n){function r(e){var t=this,n="";t.next=function(){var e=t.b,n=t.c,r=t.d,s=t.a;e=e<<25^e>>>7^n;n=n-r|0;r=r<<24^r>>>8^s;s=s-e|0;t.b=e=e<<20^e>>>12^n;t.c=n=n-r|0;t.d=r<<16^n>>>16^s;return t.a=s-e|0};t.a=0;t.b=0;t.c=2654435769|0;t.d=1367130551;if(e===Math.floor(e)){t.a=e/4294967296|0;t.b=e|0;}else {n+=e;}for(var r=0;r<n.length+20;r++){t.b^=n.charCodeAt(r)|0;t.next();}}function s(e,t){t.a=e.a;t.b=e.b;t.c=e.c;t.d=e.d;return t}function a(e,t){var n=new r(e),a=t&&t.state,o=function(){return (n.next()>>>0)/4294967296};o.double=function(){do{var e=n.next()>>>11,t=(n.next()>>>0)/4294967296,r=(e+t)/(1<<21);}while(r===0);return r};o.int32=n.next;o.quick=o;if(a){if(typeof a=="object")s(a,n);o.state=function(){return s(n,{})};}return o}if(t&&t.exports){t.exports=a;}else if(n&&n.amd){n((function(){return a}));}else {this.tychei=a;}})(commonjsGlobal,e,typeof undefined=="function");})(tychei$1);var seedrandom$1={exports:{}};(function(e){(function(t,n){var r=this,s=256,a=6,o=52,i="random",u=n.pow(s,a),c=n.pow(2,o),l=c*2,p=s-1,d;function h(e,r,o){var p=[];r=r==true?{entropy:true}:r||{};var d=y(g(r.entropy?[e,T(t)]:e==null?x():e,3),p);var h=new m(p);var E=function(){var e=h.g(a),t=u,n=0;while(e<c){e=(e+n)*s;t*=s;n=h.g(1);}while(e>=l){e/=2;t/=2;n>>>=1;}return (e+n)/t};E.int32=function(){return h.g(4)|0};E.quick=function(){return h.g(4)/4294967296};E.double=E;y(T(h.S),t);return (r.pass||o||function(e,t,r,s){if(s){if(s.S){f(s,h);}e.state=function(){return f(h,{})};}if(r){n[i]=e;return t}else return e})(E,d,"global"in r?r.global:this==n,r.state)}n["seed"+i]=h;function m(e){var t,n=e.length,r=this,a=0,o=r.i=r.j=0,i=r.S=[];if(!n){e=[n++];}while(a<s){i[a]=a++;}for(a=0;a<s;a++){i[a]=i[o=p&o+e[a%n]+(t=i[a])];i[o]=t;}(r.g=function(e){var t,n=0,a=r.i,o=r.j,i=r.S;while(e--){t=i[a=p&a+1];n=n*s+i[p&(i[a]=i[o=p&o+t])+(i[o]=t)];}r.i=a;r.j=o;return n})(s);}function f(e,t){t.i=e.i;t.j=e.j;t.S=e.S.slice();return t}function g(e,t){var n=[],r=typeof e,s;if(t&&r=="object"){for(s in e){try{n.push(g(e[s],t-1));}catch(e){}}}return n.length?n:r=="string"?e:e+"\0"}function y(e,t){var n=e+"",r,s=0;while(s<n.length){t[p&s]=p&(r^=t[p&s]*19)+n.charCodeAt(s++);}return T(t)}function x(){try{var e;if(d&&(e=d.randomBytes)){e=e(s);}else {e=new Uint8Array(s);(r.crypto||r.msCrypto).getRandomValues(e);}return T(e)}catch(e){var n=r.navigator,a=n&&n.plugins;return [+new Date,r,a,r.screen,T(t)]}}function T(e){return String.fromCharCode.apply(0,e)}y(n.random(),t);if(e.exports){e.exports=h;try{d=require("crypto");}catch(e){}}})([],Math);})(seedrandom$1);var alea=alea$1.exports;var xor128=xor128$1.exports;var xorwow=xorwow$1.exports;var xorshift7=xorshift7$1.exports;var xor4096=xor4096$1.exports;var tychei=tychei$1.exports;var sr=seedrandom$1.exports;sr.alea=alea;sr.xor128=xor128;sr.xorwow=xorwow;sr.xorshift7=xorshift7;sr.xor4096=xor4096;sr.tychei=tychei;var seedrandom=sr;
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class MPRandGauss{constructor(e,t,n,r,s){this.mean=e;this.stdDev=t;this.dtype=n;this.nextVal=NaN;this.truncated=r;if(this.truncated){this.upper=this.mean+this.stdDev*2;this.lower=this.mean-this.stdDev*2;}const a=s?s:Math.random();this.random=seedrandom.alea(a.toString());}nextValue(){if(!isNaN(this.nextVal)){const e=this.nextVal;this.nextVal=NaN;return e}let e,t;let n=false;while(!n){let r,s,a;do{r=2*this.random()-1;s=2*this.random()-1;a=r*r+s*s;}while(a>=1||a===0);const o=Math.sqrt(-2*Math.log(a)/a);e=this.mean+this.stdDev*r*o;t=this.mean+this.stdDev*s*o;if(!this.truncated||this.isValidTruncated(e)){n=true;}}if(!this.truncated||this.isValidTruncated(t)){this.nextVal=this.convertValue(t);}return this.convertValue(e)}convertValue(e){if(this.dtype==null||this.dtype==="float32"){return e}return Math.round(e)}isValidTruncated(e){return e<=this.upper&&e>=this.lower}}class UniformRandom{constructor(e=0,t=1,n,r){this.canReturnFloat=()=>this.dtype==null||this.dtype==="float32";this.min=e;this.range=t-e;this.dtype=n;if(r==null){r=Math.random();}if(typeof r==="number"){r=r.toString();}if(!this.canReturnFloat()&&this.range<=1){throw new Error(`The difference between ${e} - ${t} <= 1 and dtype is not float`)}this.random=seedrandom.alea(r);}convertValue(e){if(this.canReturnFloat()){return e}return Math.round(e)}nextValue(){return this.convertValue(this.min+this.range*this.random())}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function randomUniform_(e,t=0,n=1,r="float32",s){const a=buffer(e,r);const o=new UniformRandom(t,n,null,s);for(let e=0;e<a.values.length;e++){a.values[e]=o.nextValue();}return a.toTensor()}const randomUniform=op({randomUniform_:randomUniform_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function range(e,t,n=1,r="float32"){if(n===0){throw new Error("Cannot have a step of zero")}const s={start:e,stop:t,step:n,dtype:r};return ENGINE.runKernel(Range,{},s)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function real_(e){const t=convertToTensor(e,"input","real");const n={input:t};return ENGINE.runKernel(Real,n)}const real$1=op({real_:real_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function reciprocal_(e){const t=convertToTensor(e,"x","reciprocal");const n={x:t};return ENGINE.runKernel(Reciprocal,n)}const reciprocal=op({reciprocal_:reciprocal_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function relu_(e){const t=convertToTensor(e,"x","relu");const n={x:t};return ENGINE.runKernel(Relu,n)}const relu$1=op({relu_:relu_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function relu6_(e){const t=convertToTensor(e,"x","relu6");const n={x:t};return ENGINE.runKernel(Relu6,n)}const relu6=op({relu6_:relu6_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function reverse_(e,t){const n=convertToTensor(e,"x","reverse");const r={x:n};const s={dims:t};return ENGINE.runKernel(Reverse,r,s)}const reverse=op({reverse_:reverse_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function round_(e){const t=convertToTensor(e,"x","round");const n={x:t};return ENGINE.runKernel(Round,n)}const round=op({round_:round_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function rsqrt_(e){const t=convertToTensor(e,"x","rsqrt");const n={x:t};return ENGINE.runKernel(Rsqrt,n)}const rsqrt=op({rsqrt_:rsqrt_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function scalar(e,t){if((isTypedArray(e)&&t!=="string"||Array.isArray(e))&&t!=="complex64"){throw new Error("Error creating a new Scalar: value must be a primitive "+"(number|boolean|string)")}if(t==="string"&&isTypedArray(e)&&!(e instanceof Uint8Array)){throw new Error("When making a scalar from encoded string, "+"the value must be `Uint8Array`.")}const n=[];const r=[];return makeTensor(e,n,r,t)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function selu_(e){const t=convertToTensor(e,"x","selu");const n={x:t};return ENGINE.runKernel(Selu,n)}const selu=op({selu_:selu_});
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */async function setdiff1dAsync_(e,t){const n=convertToTensor(e,"x","setdiff1d");const r=convertToTensor(t,"y","setdiff1d");assert(n.dtype===r.dtype,(()=>`x and y should have the same dtype, but got x (${n.dtype}) and y (${r.dtype}).`));assert(n.rank===1,(()=>`x should be 1D tensor, but got x (${n.shape}).`));assert(r.rank===1,(()=>`y should be 1D tensor, but got y (${r.shape}).`));const s=await n.data();const a=await r.data();const o=new Set(a);let i=0;for(let e=0;e<s.length;e++){if(!o.has(s[e])){i++;}}const u=new TensorBuffer([i],n.dtype);const c=new TensorBuffer([i],"int32");for(let e=0,t=0;e<s.length;e++){if(!o.has(s[e])){u.values[t]=s[e];c.values[t]=e;t++;}}return [u.toTensor(),c.toTensor()]}const setdiff1dAsync=setdiff1dAsync_;
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sign_(e){const t=convertToTensor(e,"x","sign");const n={x:t};return ENGINE.runKernel(Sign,n)}const sign=op({sign_:sign_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sin_(e){const t=convertToTensor(e,"x","sin");const n={x:t};return ENGINE.runKernel(Sin,n)}const sin=op({sin_:sin_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sinh_(e){const t=convertToTensor(e,"x","sinh");const n={x:t};return ENGINE.runKernel(Sinh,n)}const sinh=op({sinh_:sinh_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function softmax_(e,t=-1){const n=convertToTensor(e,"logits","softmax","float32");if(t===-1){t=n.rank-1;}if(t!==n.rank-1){throw Error("Softmax along a non-last dimension is not yet supported. "+`Logits was rank ${n.rank} and dim was ${t}`)}const r={logits:n};const s={dim:t};return ENGINE.runKernel(Softmax,r,s)}const softmax=op({softmax_:softmax_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function fft_(e){assert(e.dtype==="complex64",(()=>`The dtype for tf.spectral.fft() must be complex64 `+`but got ${e.dtype}.`));const t={input:e};return ENGINE.runKernel(FFT,t)}const fft=op({fft_:fft_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function ifft_(e){assert(e.dtype==="complex64",(()=>`The dtype for tf.spectral.ifft() must be complex64 `+`but got ${e.dtype}.`));const t={input:e};return ENGINE.runKernel(IFFT,t)}const ifft=op({ifft_:ifft_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function irfft_(e){const t=e.shape[e.shape.length-1];const n=e.size/t;let r;if(t<=2){const s=reshape$1(e,[n,t]);r=ifft(s);}else {const s=[n,2*(t-1)];const a=reshape$1(real$1(e),[n,t]);const o=reshape$1(imag$1(e),[n,t]);const i=reverse(slice$1(a,[0,1],[n,t-2]),1);const u=mul(reverse(slice$1(o,[0,1],[n,t-2]),1),scalar(-1));const c=concat$1([a,i],1);const l=concat$1([o,u],1);const p=reshape$1(complex$1(c,l),[s[0],s[1]]);r=ifft(p);}r=real$1(r);if(e.rank===3&&e.shape[0]!==0){const t=r;const n=e.shape[0];r=reshape$1(r,[n,r.shape[0]/n,r.shape[1]]);t.dispose();}return r}const irfft=op({irfft_:irfft_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function split_(e,t,n=0){const r=convertToTensor(e,"x","split");const s={x:r};const a={numOrSizeSplits:t,axis:n};return ENGINE.runKernel(SplitV,s,a)}const split$2=op({split_:split_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function rfft_(e,t){assert(e.dtype==="float32",(()=>`The dtype for rfft() must be real value but got ${e.dtype}`));let n=e.shape[e.shape.length-1];const r=e.size/n;let s;if(t!=null&&t<n){const r=e.shape.map((e=>0));const a=e.shape.map((e=>e));a[e.shape.length-1]=t;s=slice$1(e,r,a);n=t;}else if(t!=null&&t>n){const r=e.shape.map((e=>e));r[e.shape.length-1]=t-n;s=concat$1([e,zeros(r)],e.shape.length-1);n=t;}else {s=e;}const a=zerosLike(s);const o=reshape$1(complex$1(s,a),[r,n]);const i=fft(o);const u=Math.floor(n/2)+1;const c=real$1(i);const l=imag$1(i);const p=split$2(c,[u,n-u],c.shape.length-1);const d=split$2(l,[u,n-u],l.shape.length-1);const h=s.shape.slice();h[s.shape.length-1]=u;return reshape$1(complex$1(p[0],d[0]),h)}const rfft=op({rfft_:rfft_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sqrt_(e){const t=convertToTensor(e,"x","sqrt");const n={x:t};return ENGINE.runKernel(Sqrt,n)}const sqrt=op({sqrt_:sqrt_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function squaredDifference_(e,t){let n=convertToTensor(e,"a","squaredDifference");let r=convertToTensor(t,"b","squaredDifference");[n,r]=makeTypesMatch(n,r);assertAndGetBroadcastShape(n.shape,r.shape);const s={a:n,b:r};const a={};return ENGINE.runKernel(SquaredDifference,s,a)}const squaredDifference=op({squaredDifference_:squaredDifference_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function squeeze_(e,t){const n=convertToTensor(e,"x","squeeze");return reshape$1(n,squeezeShape(n.shape,t).newShape)}const squeeze=op({squeeze_:squeeze_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stack_(e,t=0){const n=convertToTensorArray(e,"tensors","stack","string_or_numeric");assert(n.length>=1,(()=>"Pass at least one tensor to tf.stack"));if(n.length>0){assert(t<=n[0].rank,(()=>"Axis must be <= rank of the tensor"));}const r=n;const s={axis:t};return ENGINE.runKernel(Pack,r,s)}const stack=op({stack_:stack_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function step_(e,t=0){const n=convertToTensor(e,"x","step");const r={x:n};const s={alpha:t};return ENGINE.runKernel(Step,r,s)}const step=op({step_:step_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stridedSlice_(e,t,n,r,s=0,a=0,o=0,i=0,u=0){const c=convertToTensor(e,"x","stridedSlice","string_or_numeric");const l={x:c};const p={begin:t,end:n,strides:r,beginMask:s,endMask:a,ellipsisMask:o,newAxisMask:i,shrinkAxisMask:u};return ENGINE.runKernel(StridedSlice,l,p)}const stridedSlice=op({stridedSlice_:stridedSlice_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function tan_(e){const t=convertToTensor(e,"x","tan");const n={x:t};return ENGINE.runKernel(Tan,n)}const tan=op({tan_:tan_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function tensor1d(e,t){assertNonNull(e);const n=inferShape(e,t);if(n.length!==1){throw new Error("tensor1d() requires values to be a flat/TypedArray")}const r=null;return makeTensor(e,r,n,t)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function tensor2d(e,t,n){assertNonNull(e);if(t!=null&&t.length!==2){throw new Error("tensor2d() requires shape to have two numbers")}const r=inferShape(e,n);if(r.length!==2&&r.length!==1){throw new Error("tensor2d() requires values to be number[][] or flat/TypedArray")}if(r.length===1&&t==null){throw new Error("tensor2d() requires shape to be provided when `values` "+"are a flat/TypedArray")}return makeTensor(e,t,r,n)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function topk_(e,t=1,n=true){const r=convertToTensor(e,"x","topk");if(r.rank===0){throw new Error("topk() expects the input to be of rank 1 or higher")}const s=r.shape[r.shape.length-1];if(t>s){throw new Error(`'k' passed to topk() must be <= the last dimension (${s}) `+`but got ${t}`)}const a={x:r};const o={k:t,sorted:n};const[i,u]=ENGINE.runKernel(TopK,a,o);return {values:i,indices:u}}const topk=op({topk_:topk_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function truncatedNormal_(e,t=0,n=1,r,s){if(r!=null&&r==="bool"){throw new Error(`Unsupported data type $ { dtype }`)}const a=new MPRandGauss(t,n,r,true,s);const o=buffer(e,r);for(let e=0;e<o.values.length;e++){o.values[e]=a.nextValue();}return o.toTensor()}const truncatedNormal=op({truncatedNormal_:truncatedNormal_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function unique_(e,t=0){const n=convertToTensor(e,"x","unique","string_or_numeric");assert(n.rank>0,(()=>"The input tensor must be at least 1D"));const r={x:n};const s={axis:t};const[a,o]=ENGINE.runKernel(Unique,r,s);return {values:a,indices:o}}const unique=op({unique_:unique_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function unstack_(e,t=0){const n=convertToTensor(e,"x","unstack","string_or_numeric");assert(t>=-n.shape.length&&t<n.shape.length,(()=>`Axis = ${t} is not in [-${n.shape.length}, ${n.shape.length})`));const r={value:n};const s={axis:t};return ENGINE.runKernel(Unpack,r,s)}const unstack=op({unstack_:unstack_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function whereImpl$1(e,t){const n=[];for(let e=0;e<t.length;e++){if(t[e]){n.push(e);}}const r=buffer(e,"int32");const s=buffer([n.length,e.length],"int32");for(let t=0;t<n.length;t++){const a=r.indexToLoc(n[t]);const o=t*e.length;s.values.set(a,o);}return s.toTensor()}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */async function whereAsync_(e){const t=convertToTensor(e,"condition","whereAsync","bool");const n=await t.data();const r=whereImpl$1(t.shape,n);if(e!==t){t.dispose();}return r}const whereAsync=whereAsync_;
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function norm_(e,t="euclidean",n=null,r=false){e=convertToTensor(e,"x","norm");const s=normImpl(e,t,n);let a=s.shape;if(r){const t=parseAxisParam(n,e.shape);a=expandShapeToKeepDim(s.shape,t);}return reshape$1(s,a)}function normImpl(e,t,n=null){if(e.rank===0){return abs(e)}if(e.rank!==1&&n===null){return normImpl(reshape$1(e,[-1]),t,n)}if(e.rank===1||typeof n==="number"||Array.isArray(n)&&n.length===1){if(t===1){return sum$1(abs(e),n)}if(t===Infinity){return max(abs(e),n)}if(t===-Infinity){return min(abs(e),n)}if(t==="euclidean"||t===2){return sqrt(sum$1(pow$1(abs(e),scalar(2,"int32")),n))}throw new Error(`Error in norm: invalid ord value: ${t}`)}if(Array.isArray(n)&&n.length===2){if(t===1){return max(sum$1(abs(e),n[0]),n[1]-1)}if(t===Infinity){return max(sum$1(abs(e),n[1]),n[0])}if(t===-Infinity){return min(sum$1(abs(e),n[1]),n[0])}if(t==="fro"||t==="euclidean"){return sqrt(sum$1(square(e),n))}throw new Error(`Error in norm: invalid ord value: ${t}`)}throw new Error(`Error in norm: invalid axis: ${n}`)}const norm=op({norm_:norm_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function scatterND_(e,t,n){const r=convertToTensor(e,"indices","scatterND","int32");const s=convertToTensor(t,"updates","scatterND");validateInput$1(s,r,n);const a={indices:r,updates:s};const o={shape:n};return ENGINE.runKernel(ScatterNd,a,o)}const scatterND=op({scatterND_:scatterND_});function validateInput(e,t,n,r){if(e.dtype!=="int32"){throw new Error("tf.sparseToDense() expects the indices to be int32 type,"+` but the dtype was ${e.dtype}.`)}if(e.rank>2){throw new Error("sparseIndices should be a scalar, vector, or matrix,"+` but got shape ${e.shape}.`)}const s=e.rank>0?e.shape[0]:1;const a=e.rank>1?e.shape[1]:1;if(n.length!==a){throw new Error("outputShape has incorrect number of elements:,"+` ${n.length}, should be: ${a}.`)}const o=t.size;if(!(t.rank===0||t.rank===1&&o===s)){throw new Error("sparseValues has incorrect shape "+`${t.shape}, should be [] or [${s}]`)}if(t.dtype!==r.dtype){throw new Error("sparseValues.dtype must match defaultValues.dtype")}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseToDense_(e,t,n,r=0){const s=convertToTensor(e,"sparseIndices","sparseToDense","int32");const a=convertToTensor(t,"sparseValues","sparseToDense");const o=convertToTensor(r,"defaultValue","sparseToDense",a.dtype);validateInput(s,a,n,o);const i={sparseIndices:s,sparseValues:a,defaultValue:o};const u={outputShape:n};return ENGINE.runKernel(SparseToDense,i,u)}const sparseToDense=op({sparseToDense_:sparseToDense_});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function gatherND_(e,t){const n=convertToTensor(t,"indices","gatherND","int32");const r=convertToTensor(e,"x","gatherND","string_or_numeric");const s={params:r,indices:n};return ENGINE.runKernel(GatherNd,s)}const gatherND=op({gatherND_:gatherND_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function enclosingPowerOfTwo(e){return Math.floor(Math.pow(2,Math.ceil(Math.log(e)/Math.log(2))))}function cosineWindow(e,t,n){const r=1-e%2;const s=new Float32Array(e);for(let a=0;a<e;++a){const o=2*Math.PI*a/(e+r-1);s[a]=t-n*Math.cos(o);}return tensor1d(s,"float32")}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function conv2DBackpropFilter_(e,t,n,r,s,a="NHWC",o){let i=e;if(e.rank===3){i=reshape$1(e,[1,e.shape[0],e.shape[1],e.shape[2]]);}let u=t;if(u.rank===3){u=reshape$1(t,[1,t.shape[0],t.shape[1],t.shape[2]]);}assert(i.rank===4,(()=>`Error in conv2dDerFilter: input must be rank 4, but got shape `+`${i.shape}.`));assert(u.rank===4,(()=>`Error in conv2dDerFilter: dy must be rank 4, but got shape `+`${u.shape}.`));assert(n.length===4,(()=>`Error in conv2dDerFilter: filterShape must be length 4, but got `+`${n}.`));const c=a==="NHWC"?i.shape[3]:i.shape[1];const l=a==="NHWC"?u.shape[3]:u.shape[1];assert(c===n[2],(()=>`Error in conv2dDerFilter: depth of input ${c}) must `+`match input depth in filter (${n[2]}.`));assert(l===n[3],(()=>`Error in conv2dDerFilter: depth of dy (${l}) must `+`match output depth for filter (${n[3]}).`));if(o!=null){assert(isInt(s),(()=>`Error in conv2dDerFilter: pad must be an integer when using, `+`dimRoundingMode ${o} but got pad ${s}.`));}const p={x:i,dy:u};const d={strides:r,pad:s,dataFormat:a,dimRoundingMode:o,filterShape:n};return ENGINE.runKernel(Conv2DBackpropFilter,p,d)}const conv2DBackpropFilter=op({conv2DBackpropFilter_:conv2DBackpropFilter_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getFusedDyActivation(e,t,n){if(n==null||n==="linear"){return e}if(n==="relu"){return mul(e,step(t))}throw new Error(`Cannot compute gradient for fused activation ${n}.`)}function getFusedBiasGradient(e,t){let n=t;const r=getReductionAxes(e.shape,t.shape);if(r.length>0){n=sum$1(n,r);}return reshape$1(n,e.shape)}function applyActivation(e,t,n,r){if(t==="linear"){return e}else if(t==="relu"){return relu$1(e)}else if(t==="elu"){return elu(e)}else if(t==="relu6"){return relu6(e)}else if(t==="prelu"){return prelu(e,n)}else if(t==="leakyrelu"){return leakyRelu(e,r)}else if(t==="sigmoid"){return sigmoid$1(e)}throw new Error(`Unknown fused activation ${t}.`)}const shouldFuse=(e,t)=>{const n=e>0;return !n||t==="linear"};
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function fusedConv2d_({x:e,filter:t,strides:n,pad:r,dataFormat:s="NHWC",dilations:a=[1,1],dimRoundingMode:o,bias:i,activation:u="linear",preluActivationWeights:c,leakyreluAlpha:l}){u=u||"linear";if(shouldFuse(ENGINE.state.gradientDepth,u)===false){let p=conv2d$1(e,t,n,r,s,a,o);if(i!=null){p=add(p,i);}return applyActivation(p,u,c,l)}const p=convertToTensor(e,"x","conv2d");const d=convertToTensor(t,"filter","conv2d");let h=p;let m=false;if(p.rank===3){m=true;h=reshape$1(p,[1,p.shape[0],p.shape[1],p.shape[2]]);}assert(h.rank===4,(()=>`Error in fused conv2d: input must be rank 4, but got rank `+`${h.rank}.`));assert(d.rank===4,(()=>`Error in fused conv2d: filter must be rank 4, but got rank `+`${d.rank}.`));if(o!=null){assert(isInt(r),(()=>`Error in fused conv2d: pad must be an integer when using, `+`dimRoundingMode ${o} but got pad ${r}.`));}assert(h.shape[3]===d.shape[2],(()=>`Error in conv2d: depth of input (${h.shape[3]}) must match `+`input depth for filter ${d.shape[2]}.`));assert(eitherStridesOrDilationsAreOne(n,a),(()=>"Error in conv2D: Either strides or dilations must be 1. "+`Got strides ${n} and dilations '${a}'`));assert(s==="NHWC",(()=>`Error in conv2d: got dataFormat of ${s} but only NHWC is currently supported.`));const f=computeConv2DInfo(h.shape,d.shape,n,a,r,o);let g;if(i!=null){g=convertToTensor(i,"bias","fused conv2d");[g]=makeTypesMatch(g,p);assertAndGetBroadcastShape(f.outShape,g.shape);}let y;if(c!=null){y=convertToTensor(c,"prelu weights","fused conv2d");}const x=(e,t)=>{const[s,o,i,c]=t;const l=getFusedDyActivation(e,i,u);assert(tupleValuesAreOne(a),(()=>"Error in gradient of fused conv2D: "+`dilation rates greater than 1 `+`are not yet supported in gradients. Got dilations '${a}'`));const p=conv2DBackpropInput(o.shape,l,s,n,r);const d=conv2DBackpropFilter(o,l,s.shape,n,r);const h=[p,d];if(c!=null){const e=getFusedBiasGradient(c,l);h.push(e);}return h};const T={x:h,filter:d,bias:g,preluActivationWeights:y};const E={strides:n,pad:r,dataFormat:s,dilations:a,dimRoundingMode:o,activation:u,leakyreluAlpha:l};if(i==null){const e=customGrad(((e,t,n)=>{let r=ENGINE.runKernel(FusedConv2D,T,E);n([t,e,r]);if(m){r=reshape$1(r,[r.shape[1],r.shape[2],r.shape[3]]);}return {value:r,gradFunc:x}}));return e(h,d)}else {const e=customGrad(((e,t,n,r)=>{let s=ENGINE.runKernel(FusedConv2D,T,E);r([t,e,s,n]);if(m){s=reshape$1(s,[s.shape[1],s.shape[2],s.shape[3]]);}return {value:s,gradFunc:x}}));return e(h,d,g)}}const conv2d=op({fusedConv2d_:fusedConv2d_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function depthwiseConv2dNativeBackpropFilter_(e,t,n,r,s,a=[1,1],o){let i=e;if(e.rank===3){i=reshape$1(e,[1,e.shape[0],e.shape[1],e.shape[2]]);}let u=t;if(u.rank===3){u=reshape$1(t,[1,t.shape[0],t.shape[1],t.shape[2]]);}const c={x:i,dy:u};const l={strides:r,pad:s,dimRoundingMode:o,dilations:a,filterShape:n};return ENGINE.runKernel(DepthwiseConv2dNativeBackpropFilter,c,l)}const depthwiseConv2dNativeBackpropFilter=op({depthwiseConv2dNativeBackpropFilter_:depthwiseConv2dNativeBackpropFilter_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function depthwiseConv2dNativeBackpropInput_(e,t,n,r,s,a=[1,1],o){let i=t;let u=false;if(t.rank===3){u=true;i=reshape$1(t,[1,t.shape[0],t.shape[1],t.shape[2]]);}const c={dy:i,filter:n};const l={strides:r,pad:s,dimRoundingMode:o,dilations:a,inputShape:e};const p=ENGINE.runKernel(DepthwiseConv2dNativeBackpropInput,c,l);if(u){return reshape$1(p,[p.shape[1],p.shape[2],p.shape[3]])}return p}const depthwiseConv2dNativeBackpropInput=op({depthwiseConv2dNativeBackpropInput_:depthwiseConv2dNativeBackpropInput_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function fusedDepthwiseConv2d_({x:e,filter:t,strides:n,pad:r,dataFormat:s="NHWC",dilations:a=[1,1],dimRoundingMode:o,bias:i,activation:u="linear",preluActivationWeights:c,leakyreluAlpha:l}){if(shouldFuse(ENGINE.state.gradientDepth,u)===false){let p=depthwiseConv2d$1(e,t,n,r,s,a,o);if(i!=null){p=add(p,i);}return applyActivation(p,u,c,l)}const p=convertToTensor(e,"x","depthwiseConv2d");const d=convertToTensor(t,"filter","depthwiseConv2d");let h=p;let m=false;if(p.rank===3){m=true;h=reshape$1(p,[1,p.shape[0],p.shape[1],p.shape[2]]);}assert(h.rank===4,(()=>`Error in fused depthwiseConv2d: input must be rank 4, but got `+`rank ${h.rank}.`));assert(d.rank===4,(()=>`Error in fused depthwiseConv2d: filter must be rank 4, `+`but got rank ${d.rank}.`));assert(h.shape[3]===d.shape[2],(()=>`Error in fused depthwiseConv2d: number of input channels `+`(${h.shape[3]}) must match the inChannels dimension in `+`filter ${d.shape[2]}.`));if(a==null){a=[1,1];}assert(eitherStridesOrDilationsAreOne(n,a),(()=>"Error in fused depthwiseConv2d: Either strides or dilations must "+`be 1. Got strides ${n} and dilations '${a}'`));if(o!=null){assert(isInt(r),(()=>`Error in fused depthwiseConv2d: pad must be an integer when `+`using dimRoundingMode ${o} but got pad ${r}.`));}const f=computeConv2DInfo(h.shape,d.shape,n,a,r,o,true);let g;if(i!=null){g=convertToTensor(i,"bias","fused conv2d");[g]=makeTypesMatch(g,p);assertAndGetBroadcastShape(f.outShape,g.shape);}let y;if(c!=null){y=convertToTensor(c,"prelu weights","fused depthwiseConv2d");}const x=(e,t)=>{assert(tupleValuesAreOne(a),(()=>"Error in gradient of fused depthwiseConv2d: dilation rates "+`greater than 1 are not yet supported. Got dilations `+`'${a}'`));const[s,i,c,l]=t;const p=getFusedDyActivation(e,c,u);const d=depthwiseConv2dNativeBackpropInput(i.shape,p,s,n,r,a,o);const h=depthwiseConv2dNativeBackpropFilter(i,p,s.shape,n,r,a,o);if(l!=null){const e=getFusedBiasGradient(g,p);return [d,h,e]}return [d,h]};const T={x:h,filter:d,bias:g,preluActivationWeights:y};const E={strides:n,pad:r,dataFormat:s,dilations:a,dimRoundingMode:o,activation:u,leakyreluAlpha:l};if(i==null){const e=customGrad(((e,t,n)=>{let r=ENGINE.runKernel(FusedDepthwiseConv2D,T,E);n([t,e,r]);if(m){r=reshape$1(r,[r.shape[1],r.shape[2],r.shape[3]]);}return {value:r,gradFunc:x}}));return e(h,d)}else {const e=customGrad(((e,t,n,r)=>{let s=ENGINE.runKernel(FusedDepthwiseConv2D,T,E);r([t,e,s,n]);if(m){s=reshape$1(s,[s.shape[1],s.shape[2],s.shape[3]]);}return {value:s,gradFunc:x}}));return e(h,d,g)}}const depthwiseConv2d=op({fusedDepthwiseConv2d_:fusedDepthwiseConv2d_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function fusedMatMul_({a:e,b:t,transposeA:n=false,transposeB:r=false,bias:s,activation:a="linear",preluActivationWeights:o,leakyreluAlpha:i}){if(shouldFuse(ENGINE.state.gradientDepth,a)===false){let u=matMul$1(e,t,n,r);if(s!=null){u=add(u,s);}return applyActivation(u,a,o,i)}let u=convertToTensor(e,"a","fused matMul");let c=convertToTensor(t,"b","fused matMul");[u,c]=makeTypesMatch(u,c);const l=n?u.shape[u.rank-2]:u.shape[u.rank-1];const p=r?c.shape[c.rank-1]:c.shape[c.rank-2];const d=n?u.shape[u.rank-1]:u.shape[u.rank-2];const h=r?c.shape[c.rank-2]:c.shape[c.rank-1];const m=u.shape.slice(0,-2);const f=c.shape.slice(0,-2);const g=sizeFromShape(m);const y=sizeFromShape(f);assert(u.rank>=2&&c.rank>=2&&u.rank===c.rank,(()=>`Error in fused matMul: inputs must have the same rank of at `+`least 2, got ranks ${u.rank} and ${c.rank}.`));assert(arraysEqual(m,f),(()=>`Error in fused matMul: outer dimensions (${m}) and (`+`${f}) of Tensors with shapes ${u.shape} and `+`${c.shape} must match.`));assert(l===p,(()=>`Error in fused matMul: inner shapes (${l}) and (`+`${p}) of Tensors with shapes ${u.shape} and `+`${c.shape} and transposeA=${n}`+` and transposeB=${r} must match.`));const x=u.shape.slice(0,-2).concat([d,h]);const T=n?reshape$1(u,[g,l,d]):reshape$1(u,[g,d,l]);const E=r?reshape$1(c,[y,h,p]):reshape$1(c,[y,p,h]);let b;if(s!=null){b=convertToTensor(s,"bias","fused matMul");[b]=makeTypesMatch(b,u);assertAndGetBroadcastShape(x,b.shape);}let N;if(o!=null){N=convertToTensor(o,"prelu weights","fused matMul");}const S=(e,t)=>{const[o,i,u,c]=t;const l=getFusedDyActivation(reshape$1(e,u.shape),u,a);let p;let d;if(!n&&!r){p=matMul$1(l,i,false,true);d=matMul$1(o,l,true,false);}else if(!n&&r){p=matMul$1(l,i,false,false);d=matMul$1(l,o,true,false);}else if(n&&!r){p=matMul$1(i,l,false,true);d=matMul$1(o,l,false,false);}else {p=matMul$1(i,l,true,true);d=matMul$1(l,o,true,true);}if(s!=null){const e=getFusedBiasGradient(c,l);return [p,d,e]}else {return [p,d]}};const I={a:T,b:E,bias:b,preluActivationWeights:N};const v={transposeA:n,transposeB:r,activation:a,leakyreluAlpha:i};if(s==null){const e=customGrad(((e,t,n)=>{const r=ENGINE.runKernel(_FusedMatMul,I,v);n([e,t,r]);return {value:reshape$1(r,x),gradFunc:S}}));return e(T,E)}else {const e=customGrad(((e,t,n,r)=>{const s=ENGINE.runKernel(_FusedMatMul,I,v);r([e,t,s,n]);return {value:reshape$1(s,x),gradFunc:S}}));return e(T,E,b)}}const matMul=op({fusedMatMul_:fusedMatMul_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function hammingWindow_(e){return cosineWindow(e,.54,.46)}op({hammingWindow_:hammingWindow_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function hannWindow_(e){return cosineWindow(e,.5,.5)}const hannWindow=op({hannWindow_:hannWindow_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function frame_(e,t,n,r=false,s=0){let a=0;const o=[];while(a+t<=e.size){o.push(slice$1(e,a,t));a+=n;}if(r){while(a<e.size){const r=a+t-e.size;const i=concat$1([slice$1(e,a,t-r),fill([r],s)]);o.push(i);a+=n;}}if(o.length===0){return tensor2d([],[0,t])}return reshape$1(concat$1(o),[o.length,t])}const frame=op({frame_:frame_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stft_(e,t,n,r,s=hannWindow){if(r==null){r=enclosingPowerOfTwo(t);}const a=frame(e,t,n);const o=mul(a,s(t));return rfft(o,r)}op({stft_:stft_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function cropAndResize_(e,t,n,r,s="bilinear",a=0){const o=convertToTensor(e,"image","cropAndResize");const i=convertToTensor(t,"boxes","cropAndResize","float32");const u=convertToTensor(n,"boxInd","cropAndResize","int32");const c=i.shape[0];assert(o.rank===4,(()=>"Error in cropAndResize: image must be rank 4,"+`but got rank ${o.rank}.`));assert(i.rank===2&&i.shape[1]===4,(()=>`Error in cropAndResize: boxes must be have size [${c},4] `+`but had shape ${i.shape}.`));assert(u.rank===1&&u.shape[0]===c,(()=>`Error in cropAndResize: boxInd must be have size [${c}] `+`but had shape ${i.shape}.`));assert(r.length===2,(()=>`Error in cropAndResize: cropSize must be of length 2, but got `+`length ${r.length}.`));assert(r[0]>=1&&r[1]>=1,(()=>`cropSize must be atleast [1,1], but was ${r}`));assert(s==="bilinear"||s==="nearest",(()=>`method must be bilinear or nearest, but was ${s}`));const l={image:o,boxes:i,boxInd:u};const p={method:s,extrapolationValue:a,cropSize:r};const d=ENGINE.runKernel(CropAndResize,l,p);return d}const cropAndResize=op({cropAndResize_:cropAndResize_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function flipLeftRight_(e){const t=convertToTensor(e,"image","flipLeftRight","float32");assert(t.rank===4,(()=>"Error in flipLeftRight: image must be rank 4,"+`but got rank ${t.rank}.`));const n={image:t};const r=ENGINE.runKernel(FlipLeftRight,n,{});return r}const flipLeftRight=op({flipLeftRight_:flipLeftRight_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function rotateWithOffset_(e,t,n=0,r=.5){const s=convertToTensor(e,"image","rotateWithOffset","float32");assert(s.rank===4,(()=>"Error in rotateWithOffset: image must be rank 4,"+`but got rank ${s.rank}.`));const a={image:s};const o={radians:t,fillValue:n,center:r};const i=ENGINE.runKernel(RotateWithOffset,a,o);return i}const rotateWithOffset=op({rotateWithOffset_:rotateWithOffset_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function nonMaxSuppSanityCheck(e,t,n,r,s,a){if(r==null){r=.5;}if(s==null){s=Number.NEGATIVE_INFINITY;}if(a==null){a=0;}const o=e.shape[0];n=Math.min(n,o);assert(0<=r&&r<=1,(()=>`iouThreshold must be in [0, 1], but was '${r}'`));assert(e.rank===2,(()=>`boxes must be a 2D tensor, but was of rank '${e.rank}'`));assert(e.shape[1]===4,(()=>`boxes must have 4 columns, but 2nd dimension was ${e.shape[1]}`));assert(t.rank===1,(()=>"scores must be a 1D tensor"));assert(t.shape[0]===o,(()=>`scores has incompatible shape with boxes. Expected ${o}, `+`but was ${t.shape[0]}`));assert(0<=a&&a<=1,(()=>`softNmsSigma must be in [0, 1], but was '${a}'`));return {maxOutputSize:n,iouThreshold:r,scoreThreshold:s,softNmsSigma:a}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function nonMaxSuppression_(e,t,n,r=.5,s=Number.NEGATIVE_INFINITY){const a=convertToTensor(e,"boxes","nonMaxSuppression");const o=convertToTensor(t,"scores","nonMaxSuppression");const i=nonMaxSuppSanityCheck(a,o,n,r,s);n=i.maxOutputSize;r=i.iouThreshold;s=i.scoreThreshold;const u={maxOutputSize:n,iouThreshold:r,scoreThreshold:s};return ENGINE.runKernel(NonMaxSuppressionV3,{boxes:a,scores:o},u)}const nonMaxSuppression=op({nonMaxSuppression_:nonMaxSuppression_});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function binaryInsert(e,t,n){const r=binarySearch(e,t,n);const s=r<0?-(r+1):r;e.splice(s,0,t);}function binarySearch(e,t,n){return binarySearch_(e,t,n||defaultComparator)}function defaultComparator(e,t){return e>t?1:e<t?-1:0}function binarySearch_(e,t,n){let r=0;let s=e.length;let a=0;let o=false;while(r<s){a=r+(s-r>>>1);const i=n(t,e[a]);if(i>0){r=a+1;}else {s=a;o=!i;}}return o?r:-r-1}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function nonMaxSuppressionV3Impl(e,t,n,r,s){return nonMaxSuppressionImpl_(e,t,n,r,s,0)}function nonMaxSuppressionV4Impl(e,t,n,r,s,a){return nonMaxSuppressionImpl_(e,t,n,r,s,0,false,a,true)}function nonMaxSuppressionV5Impl(e,t,n,r,s,a){return nonMaxSuppressionImpl_(e,t,n,r,s,a,true)}function nonMaxSuppressionImpl_(e,t,n,r,s,a,o=false,i=false,u=false){const c=[];for(let e=0;e<t.length;e++){if(t[e]>s){c.push({score:t[e],boxIndex:e,suppressBeginIndex:0});}}c.sort(ascendingComparator);const l=a>0?-.5/a:0;const p=[];const d=[];while(p.length<n&&c.length>0){const t=c.pop();const{score:n,boxIndex:a,suppressBeginIndex:o}=t;if(n<s){break}let i=false;for(let n=p.length-1;n>=o;--n){const o=intersectionOverUnion(e,a,p[n]);if(o>=r){i=true;break}t.score=t.score*suppressWeight(r,l,o);if(t.score<=s){break}}t.suppressBeginIndex=p.length;if(!i){if(t.score===n){p.push(a);d.push(t.score);}else if(t.score>s){binaryInsert(c,t,ascendingComparator);}}}const h=p.length;const m=n-h;if(i&&m>0){p.push(...new Array(m).fill(0));d.push(...new Array(m).fill(0));}const f={selectedIndices:p};if(o){f["selectedScores"]=d;}if(u){f["validOutputs"]=h;}return f}function intersectionOverUnion(e,t,n){const r=e.subarray(t*4,t*4+4);const s=e.subarray(n*4,n*4+4);const a=Math.min(r[0],r[2]);const o=Math.min(r[1],r[3]);const i=Math.max(r[0],r[2]);const u=Math.max(r[1],r[3]);const c=Math.min(s[0],s[2]);const l=Math.min(s[1],s[3]);const p=Math.max(s[0],s[2]);const d=Math.max(s[1],s[3]);const h=(i-a)*(u-o);const m=(p-c)*(d-l);if(h<=0||m<=0){return 0}const f=Math.max(a,c);const g=Math.max(o,l);const y=Math.min(i,p);const x=Math.min(u,d);const T=Math.max(y-f,0)*Math.max(x-g,0);return T/(h+m-T)}function suppressWeight(e,t,n){const r=Math.exp(t*n*n);return n<=e?r:0}function ascendingComparator(e,t){return e.score-t.score||e.score===t.score&&t.boxIndex-e.boxIndex}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */async function nonMaxSuppressionAsync_(e,t,n,r=.5,s=Number.NEGATIVE_INFINITY){const a=convertToTensor(e,"boxes","nonMaxSuppressionAsync");const o=convertToTensor(t,"scores","nonMaxSuppressionAsync");const i=nonMaxSuppSanityCheck(a,o,n,r,s);n=i.maxOutputSize;r=i.iouThreshold;s=i.scoreThreshold;const u=await Promise.all([a.data(),o.data()]);const c=u[0];const l=u[1];const{selectedIndices:p}=nonMaxSuppressionV3Impl(c,l,n,r,s);if(a!==e){a.dispose();}if(o!==t){o.dispose();}return tensor1d(p,"int32")}const nonMaxSuppressionAsync=nonMaxSuppressionAsync_;
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function nonMaxSuppressionWithScore_(e,t,n,r=.5,s=Number.NEGATIVE_INFINITY,a=0){const o=convertToTensor(e,"boxes","nonMaxSuppression");const i=convertToTensor(t,"scores","nonMaxSuppression");const u=nonMaxSuppSanityCheck(o,i,n,r,s,a);n=u.maxOutputSize;r=u.iouThreshold;s=u.scoreThreshold;a=u.softNmsSigma;const c={boxes:o,scores:i};const l={maxOutputSize:n,iouThreshold:r,scoreThreshold:s,softNmsSigma:a};const p=ENGINE.runKernel(NonMaxSuppressionV5,c,l);return {selectedIndices:p[0],selectedScores:p[1]}}const nonMaxSuppressionWithScore=op({nonMaxSuppressionWithScore_:nonMaxSuppressionWithScore_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */async function nonMaxSuppressionWithScoreAsync_(e,t,n,r=.5,s=Number.NEGATIVE_INFINITY,a=0){const o=convertToTensor(e,"boxes","nonMaxSuppressionAsync");const i=convertToTensor(t,"scores","nonMaxSuppressionAsync");const u=nonMaxSuppSanityCheck(o,i,n,r,s,a);n=u.maxOutputSize;r=u.iouThreshold;s=u.scoreThreshold;a=u.softNmsSigma;const c=await Promise.all([o.data(),i.data()]);const l=c[0];const p=c[1];const{selectedIndices:d,selectedScores:h}=nonMaxSuppressionV5Impl(l,p,n,r,s,a);if(o!==e){o.dispose();}if(i!==t){i.dispose();}return {selectedIndices:tensor1d(d,"int32"),selectedScores:tensor1d(h)}}const nonMaxSuppressionWithScoreAsync=nonMaxSuppressionWithScoreAsync_;
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function nonMaxSuppressionPadded_(e,t,n,r=.5,s=Number.NEGATIVE_INFINITY,a=false){const o=convertToTensor(e,"boxes","nonMaxSuppression");const i=convertToTensor(t,"scores","nonMaxSuppression");const u=nonMaxSuppSanityCheck(o,i,n,r,s,null);const c=u.maxOutputSize;const l=u.iouThreshold;const p=u.scoreThreshold;const d={boxes:o,scores:i};const h={maxOutputSize:c,iouThreshold:l,scoreThreshold:p,padToMaxOutputSize:a};const m=ENGINE.runKernel(NonMaxSuppressionV4,d,h);return {selectedIndices:m[0],validOutputs:m[1]}}const nonMaxSuppressionPadded=op({nonMaxSuppressionPadded_:nonMaxSuppressionPadded_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */async function nonMaxSuppressionPaddedAsync_(e,t,n,r=.5,s=Number.NEGATIVE_INFINITY,a=false){const o=convertToTensor(e,"boxes","nonMaxSuppressionAsync");const i=convertToTensor(t,"scores","nonMaxSuppressionAsync");const u=nonMaxSuppSanityCheck(o,i,n,r,s,null);const c=u.maxOutputSize;const l=u.iouThreshold;const p=u.scoreThreshold;const[d,h]=await Promise.all([o.data(),i.data()]);const{selectedIndices:m,validOutputs:f}=nonMaxSuppressionV4Impl(d,h,c,l,p,a);if(o!==e){o.dispose();}if(i!==t){i.dispose();}return {selectedIndices:tensor1d(m,"int32"),validOutputs:scalar(f,"int32")}}const nonMaxSuppressionPaddedAsync=nonMaxSuppressionPaddedAsync_;
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function resizeBilinear_(e,t,n=false,r=false){const s=convertToTensor(e,"images","resizeBilinear");assert(s.rank===3||s.rank===4,(()=>`Error in resizeBilinear: x must be rank 3 or 4, but got `+`rank ${s.rank}.`));assert(t.length===2,(()=>`Error in resizeBilinear: new shape must 2D, but got shape `+`${t}.`));assert(r===false||n===false,(()=>`Error in resizeBilinear: If halfPixelCenters is true, `+`alignCorners must be false.`));let a=s;let o=false;if(s.rank===3){o=true;a=reshape$1(s,[1,s.shape[0],s.shape[1],s.shape[2]]);}const i={images:a};const u={alignCorners:n,halfPixelCenters:r,size:t};const c=ENGINE.runKernel(ResizeBilinear,i,u);if(o){return reshape$1(c,[c.shape[1],c.shape[2],c.shape[3]])}return c}const resizeBilinear=op({resizeBilinear_:resizeBilinear_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function resizeNearestNeighbor_(e,t,n=false,r=false){const s=convertToTensor(e,"images","resizeNearestNeighbor");assert(s.rank===3||s.rank===4,(()=>`Error in resizeNearestNeighbor: x must be rank 3 or 4, but got `+`rank ${s.rank}.`));assert(t.length===2,(()=>`Error in resizeNearestNeighbor: new shape must 2D, but got shape `+`${t}.`));assert(s.dtype==="float32"||s.dtype==="int32",(()=>"`images` must have `int32` or `float32` as dtype"));assert(r===false||n===false,(()=>`Error in resizeNearestNeighbor: If halfPixelCenters is true, `+`alignCorners must be false.`));let a=s;let o=false;if(s.rank===3){o=true;a=reshape$1(s,[1,s.shape[0],s.shape[1],s.shape[2]]);}const i={images:a};const u={alignCorners:n,halfPixelCenters:r,size:t};const c=ENGINE.runKernel(ResizeNearestNeighbor,i,u);if(o){return reshape$1(c,[c.shape[1],c.shape[2],c.shape[3]])}return c}const resizeNearestNeighbor=op({resizeNearestNeighbor_:resizeNearestNeighbor_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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
 *
 * https://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.
 * =============================================================================
 */function threshold_(e,t="binary",n=false,r=.5){const s=convertToTensor(e,"image","threshold");const a=.2989;const o=.587;const i=.114;const u=s.shape[0]*s.shape[1];let c=mul(tensor1d([r]),255);let l,p,d,h;assert(s.rank===3,(()=>"Error in threshold: image must be rank 3,"+`but got rank ${s.rank}.`));assert(s.shape[2]===3||s.shape[2]===1,(()=>"Error in threshold: "+"image color channel must be equal to 3 or 1"+`but got ${s.shape[2]}.`));assert(s.dtype==="int32"||s.dtype==="float32",(()=>"Error in dtype: image dtype must be int32 or float32,"+`but got dtype ${s.dtype}.`));assert(t==="otsu"||t==="binary",(()=>`Method must be binary or otsu, but was ${t}`));if(s.shape[2]===3){[l,p,d]=split$2(s,[1,1,1],-1);const e=mul(l,a);const t=mul(p,o);const n=mul(d,i);h=add(add(e,t),n);}else {h=e;}if(t==="otsu"){const e=bincount(cast$1(round(h),"int32"),tensor([]),256);c=otsu(e,u);}const m=n?lessEqual(h,c):greater(h,c);const f=cast$1(mul(m,255),"int32");return f}function otsu(e,t){let n=tensor1d([-1]);let r=tensor1d([0]);let s=tensor1d([0]);let a,o,i,u,c,l;for(let p=0;p<e.size-1;p++){a=slice$1(e,0,p+1);o=slice$1(e,p+1);c=div(sum$1(a),t);l=div(sum$1(o),t);const d=sum$1(mul(a,range(0,a.size)));i=div(d,sum$1(a));const h=fill(o.shape,a.size);const m=add(range(0,o.size),h);const f=mul(o,m);u=div(sum$1(f),sum$1(o));const g=sub(i,u);const y=sub(i,u);const x=mul(c,l);s=mul(mul(x,g),y);const T=greater(s,r);r=where(T,s,r);n=where(T,tensor1d([p]),n);}return n}const threshold=op({threshold_:threshold_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function transform_(e,t,n="nearest",r="constant",s=0,a){const o=convertToTensor(e,"image","transform","float32");const i=convertToTensor(t,"transforms","transform","float32");assert(o.rank===4,(()=>"Error in transform: image must be rank 4,"+`but got rank ${o.rank}.`));assert(i.rank===2&&(i.shape[0]===o.shape[0]||i.shape[0]===1)&&i.shape[1]===8,(()=>`Error in transform: Input transform should be batch x 8 or 1 x 8`));assert(a==null||a.length===2,(()=>"Error in transform: outputShape must be [height, width] or null, "+`but got ${a}.`));const u={image:o,transforms:i};const c={interpolation:n,fillMode:r,fillValue:s,outputShape:a};return ENGINE.runKernel(Transform,u,c)}const transform=op({transform_:transform_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function bandPart_(e,t,n){assert(t%1===0,(()=>`bandPart(): numLower must be an integer, got ${t}.`));assert(n%1===0,(()=>`bandPart(): numUpper must be an integer, got ${n}.`));const r=convertToTensor(e,"a","bandPart");assert(r.rank>=2,(()=>`bandPart(): Rank must be at least 2, got ${r.rank}.`));const s=r.shape;const[a,o]=r.shape.slice(-2);if(!(t<=a)){throw new Error(`bandPart(): numLower (${t})`+` must not be greater than the number of rows (${a}).`)}if(!(n<=o)){throw new Error(`bandPart(): numUpper (${n})`+` must not be greater than the number of columns (${o}).`)}if(t<0){t=a;}if(n<0){n=o;}const i=reshape$1(range(0,a,1,"int32"),[-1,1]);const u=range(0,o,1,"int32");const c=sub(i,u);const l=logicalAnd(lessEqual(c,scalar(+t,"int32")),greaterEqual(c,scalar(-n,"int32")));const p=zeros([a,o],r.dtype);return reshape$1(stack(unstack(reshape$1(r,[-1,a,o])).map((e=>where(l,e,p)))),s)}op({bandPart_:bandPart_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function gramSchmidt_(e){let t;if(Array.isArray(e)){t=false;assert(e!=null&&e.length>0,(()=>"Gram-Schmidt process: input must not be null, undefined, or "+"empty"));const n=e[0].shape[0];for(let t=1;t<e.length;++t){assert(e[t].shape[0]===n,(()=>"Gram-Schmidt: Non-unique lengths found in the input vectors: "+`(${e[t].shape[0]} vs. ${n})`));}}else {t=true;e=split$2(e,e.shape[0],0).map((e=>squeeze(e,[0])));}assert(e.length<=e[0].shape[0],(()=>`Gram-Schmidt: Number of vectors (${e.length}) exceeds `+`number of dimensions (${e[0].shape[0]}).`));const n=[];const r=e;for(let t=0;t<e.length;++t){n.push(ENGINE.tidy((()=>{let e=r[t];if(t>0){for(let r=0;r<t;++r){const t=mul(sum$1(mul(n[r],e)),n[r]);e=sub(e,t);}}return div(e,norm(e,"euclidean"))})));}if(t){return stack(n,0)}else {return n}}op({gramSchmidt_:gramSchmidt_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function qr_(e,t=false){assert(e.rank>=2,(()=>`qr() requires input tensor to have a rank >= 2, but got rank ${e.rank}`));if(e.rank===2){return qr2d(e,t)}else {const n=e.shape.slice(0,e.shape.length-2).reduce(((e,t)=>e*t));const r=unstack(reshape$1(e,[n,e.shape[e.shape.length-2],e.shape[e.shape.length-1]]),0);const s=[];const a=[];r.forEach((e=>{const[n,r]=qr2d(e,t);s.push(n);a.push(r);}));const o=reshape$1(stack(s,0),e.shape);const i=reshape$1(stack(a,0),e.shape);return [o,i]}}function qr2d(e,t=false){return ENGINE.tidy((()=>{assert(e.shape.length===2,(()=>`qr2d() requires a 2D Tensor, but got a ${e.shape.length}D Tensor.`));const n=e.shape[0];const r=e.shape[1];let s=eye(n);let a=clone(e);const o=tensor2d([[1]],[1,1]);let i=clone(o);const u=n>=r?r:n;for(let e=0;e<u;++e){const t=a;const u=i;const c=s;[i,a,s]=ENGINE.tidy((()=>{const t=slice$1(a,[e,e],[n-e,1]);const u=norm(t);const c=slice$1(a,[e,e],[1,1]);const l=where(greater(c,0),tensor2d([[-1]]),tensor2d([[1]]));const p=sub(c,mul(l,u));const d=div(t,p);if(d.shape[0]===1){i=clone(o);}else {i=concat$1([o,slice$1(d,[1,0],[d.shape[0]-1,d.shape[1]])],0);}const h=neg(div(matMul$1(l,p),u));const m=slice$1(a,[e,0],[n-e,r]);const f=mul(h,i);const g=transpose$1(i);if(e===0){a=sub(m,matMul$1(f,matMul$1(g,m)));}else {const t=sub(m,matMul$1(f,matMul$1(g,m)));a=concat$1([slice$1(a,[0,0],[e,r]),t],0);}const y=transpose$1(f);const x=slice$1(s,[0,e],[n,s.shape[1]-e]);if(e===0){s=sub(x,matMul$1(matMul$1(x,i),y));}else {const t=sub(x,matMul$1(matMul$1(x,i),y));s=concat$1([slice$1(s,[0,0],[n,e]),t],1);}return [i,a,s]}));dispose([t,u,c]);}if(!t&&n>r){s=slice$1(s,[0,0],[n,r]);a=slice$1(a,[0,0],[r,r]);}return [s,a]}))}op({qr_:qr_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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 Reduction;(function(e){e[e["NONE"]=0]="NONE";e[e["MEAN"]=1]="MEAN";e[e["SUM"]=2]="SUM";e[e["SUM_BY_NONZERO_WEIGHTS"]=3]="SUM_BY_NONZERO_WEIGHTS";})(Reduction||(Reduction={}));function computeWeightedLoss_(e,t,n=Reduction.SUM_BY_NONZERO_WEIGHTS){const r=convertToTensor(e,"losses","computeWeightedLoss");let s=null;if(t!=null){s=convertToTensor(t,"weights","computeWeightedLoss");}const a=s==null?r:mul(r,s);if(n===Reduction.NONE){return a}if(n===Reduction.SUM){return sum$1(a)}if(n===Reduction.MEAN){if(s==null){return mean(a)}else {const e=r.size/s.size;const t=div(sum$1(a),sum$1(s));return e>1?div(t,scalar(e)):t}}if(n===Reduction.SUM_BY_NONZERO_WEIGHTS){if(s==null){return div(sum$1(a),scalar(r.size))}else {const e=mul(s,ones(r.shape));const t=cast$1(sum$1(notEqual$1(e,scalar(0))),"float32");return div(sum$1(a),t)}}throw Error(`Unknown reduction: ${n}`)}const computeWeightedLoss=op({computeWeightedLoss_:computeWeightedLoss_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function absoluteDifference_(e,t,n,r=Reduction.SUM_BY_NONZERO_WEIGHTS){const s=convertToTensor(e,"labels","absoluteDifference");const a=convertToTensor(t,"predictions","absoluteDifference");let o=null;if(n!=null){o=convertToTensor(n,"weights","absoluteDifference");}assertShapesMatch(s.shape,a.shape,"Error in absoluteDifference: ");const i=abs(sub(s,a));return computeWeightedLoss(i,o,r)}op({absoluteDifference_:absoluteDifference_});function cosineDistance_(e,t,n,r,s=Reduction.SUM_BY_NONZERO_WEIGHTS){const a=convertToTensor(e,"labels","cosineDistance");const o=convertToTensor(t,"predictions","cosineDistance");let i=null;if(r!=null){i=convertToTensor(r,"weights","cosineDistance");}assertShapesMatch(a.shape,o.shape,"Error in cosineDistance: ");const u=scalar(1);const c=sub(u,sum$1(mul(a,o),n,true));return computeWeightedLoss(c,i,s)}op({cosineDistance_:cosineDistance_});function hingeLoss_(e,t,n,r=Reduction.SUM_BY_NONZERO_WEIGHTS){let s=convertToTensor(e,"labels","hingeLoss");const a=convertToTensor(t,"predictions","hingeLoss");let o=null;if(n!=null){o=convertToTensor(n,"weights","hingeLoss");}assertShapesMatch(s.shape,a.shape,"Error in hingeLoss: ");const i=scalar(1);s=sub(mul(scalar(2),s),i);const u=relu$1(sub(i,mul(s,a)));return computeWeightedLoss(u,o,r)}op({hingeLoss_:hingeLoss_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function huberLoss_(e,t,n,r=1,s=Reduction.SUM_BY_NONZERO_WEIGHTS){const a=convertToTensor(e,"labels","huberLoss");const o=convertToTensor(t,"predictions","huberLoss");let i=null;if(n!=null){i=convertToTensor(n,"weights","huberLoss");}assertShapesMatch(a.shape,o.shape,"Error in huberLoss: ");const u=scalar(r);const c=abs(sub(o,a));const l=minimum(c,u);const p=sub(c,l);const d=add(mul(scalar(.5),square(l)),mul(u,p));return computeWeightedLoss(d,i,s)}op({huberLoss_:huberLoss_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function logLoss_(e,t,n,r=1e-7,s=Reduction.SUM_BY_NONZERO_WEIGHTS){const a=convertToTensor(e,"labels","logLoss");const o=convertToTensor(t,"predictions","logLoss");let i=null;if(n!=null){i=convertToTensor(n,"weights","logLoss");}assertShapesMatch(a.shape,o.shape,"Error in logLoss: ");const u=scalar(1);const c=scalar(r);const l=neg(mul(a,log$1(add(o,c))));const p=mul(sub(u,a),log$1(add(sub(u,o),c)));const d=sub(l,p);return computeWeightedLoss(d,i,s)}op({logLoss_:logLoss_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function meanSquaredError_(e,t,n,r=Reduction.SUM_BY_NONZERO_WEIGHTS){const s=convertToTensor(e,"labels","meanSquaredError");const a=convertToTensor(t,"predictions","meanSquaredError");let o=null;if(n!=null){o=convertToTensor(n,"weights","meanSquaredError");}assertShapesMatch(s.shape,a.shape,"Error in meanSquaredError: ");const i=squaredDifference(s,a);return computeWeightedLoss(i,o,r)}op({meanSquaredError_:meanSquaredError_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sigmoidCrossEntropyWithLogits_(e,t){const n=convertToTensor(e,"labels","sigmoidCrossEntropyWithLogits");const r=convertToTensor(t,"logits","sigmoidCrossEntropyWithLogits");assertShapesMatch(n.shape,r.shape,"Error in sigmoidCrossEntropyWithLogits: ");const s=relu$1(r);const a=mul(r,n);const o=log1p(exp(neg(abs(r))));return add(sub(s,a),o)}function sigmoidCrossEntropy_(e,t,n,r=0,s=Reduction.SUM_BY_NONZERO_WEIGHTS){let a=convertToTensor(e,"multiClassLabels","sigmoidCrossEntropy");const o=convertToTensor(t,"logits","sigmoidCrossEntropy");let i=null;if(n!=null){i=convertToTensor(n,"weights","sigmoidCrossEntropy");}assertShapesMatch(a.shape,o.shape,"Error in sigmoidCrossEntropy: ");if(r>0){const e=scalar(r);const t=scalar(1);const n=scalar(.5);a=add(mul(a,sub(t,e)),mul(n,e));}const u=sigmoidCrossEntropyWithLogits_(a,o);return computeWeightedLoss(u,i,s)}op({sigmoidCrossEntropy_:sigmoidCrossEntropy_});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function softmaxCrossEntropyWithLogits_(e,t,n=-1){if(n===-1){n=t.rank-1;}if(n!==t.rank-1){throw Error(`Softmax cross entropy along a non-last dimension is not yet `+`supported. Labels / logits was rank ${t.rank} `+`and dim was ${n}`)}const r=customGrad(((e,t,r)=>{const s=true;const a=logSumExp(t,[n],s);const o=sub(cast$1(t,"float32"),a);r([e,o]);const i=neg(mul(o,e));const u=sum$1(i,[n]);const c=(e,t)=>{const[r,s]=t;const a=expandShapeToKeepDim(e.shape,[n]);return [mul(reshape$1(e,a),sub(cast$1(r,"float32"),exp(s))),mul(reshape$1(e,a),sub(exp(s),cast$1(r,"float32")))]};return {value:u,gradFunc:c}}));return r(e,t)}function softmaxCrossEntropy_(e,t,n,r=0,s=Reduction.SUM_BY_NONZERO_WEIGHTS){let a=convertToTensor(e,"onehotLabels","softmaxCrossEntropy");const o=convertToTensor(t,"logits","softmaxCrossEntropy");let i=null;if(n!=null){i=convertToTensor(n,"weights","softmaxCrossEntropy");}assertShapesMatch(a.shape,o.shape,"Error in softmaxCrossEntropy: ");if(r>0){const e=scalar(r);const t=scalar(1);const n=scalar(a.shape[1]);a=add(mul(a,sub(t,e)),div(e,n));}const u=softmaxCrossEntropyWithLogits_(a,o);return computeWeightedLoss(u,i,s)}op({softmaxCrossEntropy_:softmaxCrossEntropy_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseFillEmptyRows_(e,t,n,r){const s=convertToTensor(e,"indices","sparseFillEmptyRows");const a=convertToTensor(t,"values","sparseFillEmptyRows");const o=convertToTensor(n,"denseShape","sparseFillEmptyRows");const i=convertToTensor(r,"defaultValue","sparseFillEmptyRows",a.dtype);if(s.rank!==2){throw new Error(`Indices should be Tensor2D but received shape\n        ${s.shape}`)}if(a.rank!==1){throw new Error(`Values should be Tensor1D but received shape ${a.shape}`)}if(o.rank!==1){throw new Error(`Dense shape should be Tensor1D but received shape ${o.shape}`)}if(i.rank!==0){throw new Error(`Default value should be a scalar but received shape ${i.shape}`)}const u={indices:s,values:a,denseShape:o,defaultValue:i};const c=ENGINE.runKernel(SparseFillEmptyRows,u);return {outputIndices:c[0],outputValues:c[1],emptyRowIndicator:c[2],reverseIndexMap:c[3]}}const sparseFillEmptyRows=op({sparseFillEmptyRows_:sparseFillEmptyRows_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseReshape_(e,t,n){const r=convertToTensor(e,"inputIndices","sparseReshape");const s=convertToTensor(t,"inputShape","sparseReshape");const a=convertToTensor(n,"newShape","sparseReshape");if(r.rank!==2){throw new Error(`Input indices should be Tensor2D but received shape\n        ${r.shape}`)}if(s.rank!==1){throw new Error(`Input shape should be Tensor1D but received shape ${s.shape}`)}if(a.rank!==1){throw new Error(`New shape should be Tensor1D but received shape ${a.shape}`)}const o={inputIndices:r,inputShape:s,newShape:a};const i=ENGINE.runKernel(SparseReshape,o);return {outputIndices:i[0],outputShape:i[1]}}const sparseReshape=op({sparseReshape_:sparseReshape_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseSegmentMean_(e,t,n){const r=convertToTensor(e,"data","sparseSegmentMean");const s=convertToTensor(t,"indices","sparseSegmentMean");const a=convertToTensor(n,"segmentIds","sparseSegmentMean");if(r.rank<1){throw new Error(`Data should be at least 1 dimensional but received scalar`)}if(s.rank!==1){throw new Error(`Indices should be Tensor1D but received shape\n          ${s.shape}`)}if(a.rank!==1){throw new Error(`Segment ids should be Tensor1D but received shape\n          ${a.shape}`)}const o={data:r,indices:s,segmentIds:a};return ENGINE.runKernel(SparseSegmentMean,o)}const sparseSegmentMean=op({sparseSegmentMean_:sparseSegmentMean_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseSegmentSum_(e,t,n){const r=convertToTensor(e,"data","sparseSegmentSum");const s=convertToTensor(t,"indices","sparseSegmentSum");const a=convertToTensor(n,"segmentIds","sparseSegmentSum");if(r.rank<1){throw new Error(`Data should be at least 1 dimensional but received scalar`)}if(s.rank!==1){throw new Error(`Indices should be Tensor1D but received shape\n         ${s.shape}`)}if(a.rank!==1){throw new Error(`Segment ids should be Tensor1D but received shape\n         ${a.shape}`)}const o={data:r,indices:s,segmentIds:a};return ENGINE.runKernel(SparseSegmentSum,o)}const sparseSegmentSum=op({sparseSegmentSum_:sparseSegmentSum_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stringNGrams_(e,t,n,r,s,a,o,i){const u=convertToTensor(e,"data","stringNGrams","string");if(u.dtype!=="string"){throw new Error("Data must be of datatype string")}if(u.shape.length!==1){throw new Error(`Data must be a vector, saw: ${u.shape}`)}const c=convertToTensor(t,"dataSplits","stringNGrams");if(c.dtype!=="int32"){throw new Error("Data splits must be of datatype int32")}const l={separator:n,nGramWidths:r,leftPad:s,rightPad:a,padWidth:o,preserveShortSequences:i};const p={data:u,dataSplits:c};const d=ENGINE.runKernel(StringNGrams,p,l);return {nGrams:d[0],nGramsSplits:d[1]}}const stringNGrams=op({stringNGrams_:stringNGrams_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stringSplit_(e,t,n=true){const r=convertToTensor(e,"input","stringSplit","string");const s=convertToTensor(t,"delimiter","stringSplit","string");if(r.rank!==1){throw new Error(`Input should be Tensor1D but received shape ${r.shape}`)}if(s.rank!==0){throw new Error(`Delimiter should be a scalar but received shape ${s.shape}`)}const a={skipEmpty:n};const o={input:r,delimiter:s};const i=ENGINE.runKernel(StringSplit,o,a);return {indices:i[0],values:i[1],shape:i[2]}}const stringSplit=op({stringSplit_:stringSplit_});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stringToHashBucketFast_(e,t){const n=convertToTensor(e,"input","stringToHashBucketFast","string");const r={numBuckets:t};if(t<=0){throw new Error(`Number of buckets must be at least 1`)}const s={input:n};return ENGINE.runKernel(StringToHashBucketFast,s,r)}const stringToHashBucketFast=op({stringToHashBucketFast_:stringToHashBucketFast_});
const image$1={flipLeftRight:flipLeftRight,resizeNearestNeighbor:resizeNearestNeighbor,resizeBilinear:resizeBilinear,rotateWithOffset:rotateWithOffset,cropAndResize:cropAndResize,nonMaxSuppression:nonMaxSuppression,nonMaxSuppressionAsync:nonMaxSuppressionAsync,nonMaxSuppressionWithScore:nonMaxSuppressionWithScore,nonMaxSuppressionWithScoreAsync:nonMaxSuppressionWithScoreAsync,nonMaxSuppressionPadded:nonMaxSuppressionPadded,nonMaxSuppressionPaddedAsync:nonMaxSuppressionPaddedAsync,threshold:threshold,transform:transform};const sparse$1={sparseFillEmptyRows:sparseFillEmptyRows,sparseReshape:sparseReshape,sparseSegmentMean:sparseSegmentMean,sparseSegmentSum:sparseSegmentSum};const string$1={stringNGrams:stringNGrams,stringSplit:stringSplit,stringToHashBucketFast:stringToHashBucketFast};
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function assertParamsConsistent(e,t){const n=e[0].length;e.forEach(((e,t)=>{assert(e.length===n,(()=>`Error in concat${n}D: rank of tensors[${t}] must be the same `+`as the rank of the rest (${n})`));}));assert(t>=0&&t<n,(()=>`Error in concat${n}D: axis must be between 0 and ${n-1}.`));const r=e[0];e.forEach(((e,s)=>{for(let a=0;a<n;a++){assert(a===t||e[a]===r[a],(()=>`Error in concat${n}D: Shape of tensors[${s}] (${e}) `+`does not match the shape of the rest (${r}) `+`along the non-concatenated axis ${s}.`));}}));}function computeOutShape$1(e,t){const n=e[0].slice();for(let r=1;r<e.length;r++){n[t]+=e[r][t];}return n}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const PARALLELIZE_THRESHOLD=30;function computeOptimalWindowSize(e){if(e<=PARALLELIZE_THRESHOLD){return e}return nearestDivisor(e,Math.floor(Math.sqrt(e)))}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getImageCenter(e,t,n){const r=n*(typeof e==="number"?e:e[0]);const s=t*(typeof e==="number"?e:e[1]);return [r,s]}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getReshaped(e,t,n,r=true){let s=[];if(r){s=s.concat(t.slice(0));s.push(e[0]/n);s=s.concat(e.slice(1));}else {s=s.concat(e[0]);const n=t.length;for(let r=0;r<n;++r){s=s.concat([e[r+1]/t[r],t[r]]);}s=s.concat(e.slice(n+1));}return s}function getPermuted(e,t,n=true){const r=[];if(n){r.push(t);for(let n=t+1;n<e;++n){if(n<=2*t){r.push(n);r.push(n-(t+1));}else {r.push(n);}}}else {const n=[];const s=[];for(let r=1;r<e;++r){if(r>=t*2+1||r%2===1){s.push(r);}else {n.push(r);}}r.push(...n);r.push(0);r.push(...s);}return r}function getReshapedPermuted(e,t,n,r=true){const s=[];if(r){s.push(e[0]/n);}else {s.push(e[0]*n);}for(let n=1;n<e.length;++n){if(n<=t.length){if(r){s.push(t[n-1]*e[n]);}else {s.push(e[n]/t[n-1]);}}else {s.push(e[n]);}}return s}function getSliceBeginCoords(e,t){const n=[0];for(let r=0;r<t;++r){n.push(e[r][0]);}return n}function getSliceSize(e,t,n){const r=e.slice(0,1);for(let s=0;s<n;++s){r.push(e[s+1]-t[s][0]-t[s][1]);}return r}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const SELU_SCALEALPHA=1.7580993408473768;const SELU_SCALE=1.0507009873554805;
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const ERF_P=.3275911;const ERF_A1=.254829592;const ERF_A2=-.284496736;const ERF_A3=1.421413741;const ERF_A4=-1.453152027;const ERF_A5=1.061405429;
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function warn(...e){if(!env().getBool("IS_TEST")){console.warn(...e);}}function log(...e){if(!env().getBool("IS_TEST")){console.log(...e);}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function mergeRealAndImagArrays(e,t){if(e.length!==t.length){throw new Error(`Cannot merge real and imag arrays of different lengths. real:`+`${e.length}, imag: ${t.length}.`)}const n=new Float32Array(e.length*2);for(let r=0;r<n.length;r+=2){n[r]=e[r/2];n[r+1]=t[r/2];}return n}function splitRealAndImagArrays(e){const t=new Float32Array(e.length/2);const n=new Float32Array(e.length/2);for(let r=0;r<e.length;r+=2){t[r/2]=e[r];n[r/2]=e[r+1];}return {real:t,imag:n}}function complexWithEvenIndex(e){const t=Math.ceil(e.length/4);const n=new Float32Array(t);const r=new Float32Array(t);for(let t=0;t<e.length;t+=4){n[Math.floor(t/4)]=e[t];r[Math.floor(t/4)]=e[t+1];}return {real:n,imag:r}}function complexWithOddIndex(e){const t=Math.floor(e.length/4);const n=new Float32Array(t);const r=new Float32Array(t);for(let t=2;t<e.length;t+=4){n[Math.floor(t/4)]=e[t];r[Math.floor(t/4)]=e[t+1];}return {real:n,imag:r}}function getComplexWithIndex(e,t){const n=e[t*2];const r=e[t*2+1];return {real:n,imag:r}}function assignToTypedArray(e,t,n,r){e[r*2]=t;e[r*2+1]=n;}function exponents(e,t){const n=new Float32Array(e/2);const r=new Float32Array(e/2);for(let s=0;s<Math.ceil(e/2);s++){const a=(t?2:-2)*Math.PI*(s/e);n[s]=Math.cos(a);r[s]=Math.sin(a);}return {real:n,imag:r}}function exponent(e,t,n){const r=(n?2:-2)*Math.PI*(e/t);const s=Math.cos(r);const a=Math.sin(r);return {real:s,imag:a}}
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const ARROW="->";const ARROW_REGEX=/->/g;const COMMA=",";const ELLIPSIS="...";function decodeEinsumEquation(e,t){e=e.replace(/\s/g,"");const n=(e.length-e.replace(ARROW_REGEX,"").length)/ARROW.length;if(n<1){throw new Error("Equations without an arrow are not supported.")}else if(n>1){throw new Error(`Equation must contain exactly one arrow ("${ARROW}").`)}const[r,s]=e.split(ARROW);assert(r.indexOf(ELLIPSIS)===-1,(()=>`The ellipsis notation ("${ELLIPSIS}") is not supported yet.`));const a=r.split(COMMA);const o=a.length;if(t!==o){throw new Error(`Expected ${o} input tensors, received ${t}`)}if(o>2){throw new Error("Support for more than 2 input tensors is not implemented yet.")}const i=[];for(let e=0;e<s.length;++e){const t=s[e];if(!a.some((e=>e.indexOf(t)!==-1))){throw new Error(`Output subscripts contain the label ${t} `+`not present in the input subscripts.`)}if(i.indexOf(t)===-1){i.push(t);}}for(let e=0;e<r.length;++e){const t=r[e];if(i.indexOf(t)===-1&&t!==COMMA){i.push(t);}}const u=new Array(a.length);for(let e=0;e<o;++e){if(new Set(a[e].split("")).size!==a[e].length){throw new Error(`Found duplicate axes in input component ${a[e]}. `+`Support for duplicate axes in input is not implemented yet.`)}u[e]=[];for(let t=0;t<a[e].length;++t){u[e].push(i.indexOf(a[e][t]));}}const c=i.length;const l=s.length;const p=[];for(let e=l;e<c;++e){p.push(e);}return {allDims:i,summedDims:p,idDims:u}}function getEinsumPermutation(e,t){let n=new Array(e);n.fill(-1);for(let e=0;e<t.length;++e){n[t[e]]=e;}const r=[];for(let t=0;t<e;++t){if(n[t]===-1){r.push(t);}}n=n.filter((e=>e!==-1));return {permutationIndices:n,expandDims:r}}function checkEinsumDimSizes(e,t,n){const r=new Array(e);for(let e=0;e<n.length;++e){const s=n[e].shape;for(let n=0;n<t[e].length;++n){if(r[t[e][n]]===undefined){r[t[e][n]]=s[n];}else {assert(r[t[e][n]]===s[n],(()=>`Expected dimension ${r[t[e][n]]} at axis ${n} `+`of input shaped ${JSON.stringify(s)}, `+`but got dimension ${s[n]}`));}}}}function getEinsumComputePath(e,t){const n=e;const r=[];let s=0;if(e.length===0){n.push(-1);}s=e.length+1;for(let e=0;e<s;++e){r.push([]);}const a=[];for(let e=0;e<n.length;++e){const s=n[e];const o=findTermsWithDim(t,s);for(const t of o){if(a.indexOf(t)===-1){r[e].push(t);a.push(t);}}}return {path:n,steps:r}}function isIdentityPermutation(e){return e.every(((e,t)=>e===t))}function findTermsWithDim(e,t){const n=[];for(let r=0;r<e.length;++r){if(e[r].length===0||e[r].indexOf(t)!==-1||t===-1){n.push(r);}}return n}function prepareSplitSize(e,t,n=0){let r=[];if(typeof t==="number"){assert(e.shape[n]%t===0,(()=>"Number of splits must evenly divide the axis."));r=new Array(t).fill(e.shape[n]/t);}else {const s=t.reduce(((e,t)=>{if(t===-1){e+=1;}return e}),0);assert(s<=1,(()=>"There should be only one negative value in split array."));const a=t.indexOf(-1);if(a!==-1){const r=t.reduce(((e,t)=>t>0?e+t:e));t[a]=e.shape[n]-r;}assert(e.shape[n]===t.reduce(((e,t)=>e+t)),(()=>"The sum of sizes must match the size of the axis dimension."));r=t;}return r}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function segOpComputeOptimalWindowSize(e,t){let n=false;let r;if(e<=PARALLELIZE_THRESHOLD){r=e;n=true;}else {r=nearestDivisor(e,Math.floor(Math.sqrt(e)));}while(!n){if(r>t||r===e){n=true;}else {r=nearestDivisor(e,r+1);}}return r}function computeOutShape(e,t,n){const r=[];const s=e.length;for(let a=0;a<s;a++){if(a!==t){r.push(e[a]);}else {r.push(n);}}return r}function collectGatherOpShapeInfo(e,t,n,r){const s=t.shape.length;const a=e.shape.length;if(r!==0){if(r<-s||r>s){throw new Error(`Expect batchDims in the range of [-${s}, ${s}], but got ${r}`)}}if(r<0){r+=s;}if(r>a){throw new Error(`batchDims (${r}) must be less than rank(x) (\n    ${a}).`)}if(n<r){throw new Error(`batchDims (${r}) must be less than or equal to axis (${n}).`)}for(let n=0;n<r;++n){if(e.shape[n]!==t.shape[n]){throw new Error(`x.shape[${n}]: ${e.shape[n]} should be equal to indices.shape[${n}]: ${t.shape[n]}.`)}}const o=e.shape[n];const i=[];let u=1;let c=1;let l=1;for(let t=0;t<r;++t){i.push(e.shape[t]);u*=e.shape[t];}for(let t=r;t<n;t++){i.push(e.shape[t]);c*=e.shape[t];}for(let e=r;e<s;e++){i.push(t.shape[e]);}for(let t=n+1;t<a;t++){i.push(e.shape[t]);l*=e.shape[t];}return {batchSize:u,sliceSize:l,outerSize:c,dimSize:o,outputShape:i}}var segment_util=Object.freeze({__proto__:null,segOpComputeOptimalWindowSize:segOpComputeOptimalWindowSize,computeOutShape:computeOutShape,collectGatherOpShapeInfo:collectGatherOpShapeInfo});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function fromUint8ToStringArray(e){try{return e.map((e=>decodeString(e)))}catch(e){throw new Error(`Failed to decode encoded string bytes into utf-8, error: ${e}`)}}function fromStringArrayToUint8(e){return e.map((e=>encodeString(e)))}var backend_util=Object.freeze({__proto__:null,slice_util:slice_util,segment_util:segment_util,fromUint8ToStringArray:fromUint8ToStringArray,fromStringArrayToUint8:fromStringArrayToUint8,upcastType:upcastType,axesAreInnerMostDims:axesAreInnerMostDims,combineLocations:combineLocations,computeOutAndReduceShapes:computeOutAndReduceShapes,expandShapeToKeepDim:expandShapeToKeepDim,assertAxesAreInnerMostDims:assertAxesAreInnerMostDims,getAxesPermutation:getAxesPermutation,getUndoAxesPermutation:getUndoAxesPermutation,getInnerMostAxes:getInnerMostAxes,getBroadcastDims:getBroadcastDims$1,getReductionAxes:getReductionAxes,assertAndGetBroadcastShape:assertAndGetBroadcastShape,assertParamsConsistent:assertParamsConsistent,computeOutShape:computeOutShape$1,computeDilation2DInfo:computeDilation2DInfo,computePool2DInfo:computePool2DInfo,computePool3DInfo:computePool3DInfo,computeConv2DInfo:computeConv2DInfo,computeConv3DInfo:computeConv3DInfo,computeDefaultPad:computeDefaultPad,tupleValuesAreOne:tupleValuesAreOne,eitherStridesOrDilationsAreOne:eitherStridesOrDilationsAreOne,convertConv2DDataFormat:convertConv2DDataFormat,getFusedDyActivation:getFusedDyActivation,getFusedBiasGradient:getFusedBiasGradient,applyActivation:applyActivation,shouldFuse:shouldFuse,PARALLELIZE_THRESHOLD:PARALLELIZE_THRESHOLD,computeOptimalWindowSize:computeOptimalWindowSize,getImageCenter:getImageCenter,getReshaped:getReshaped,getPermuted:getPermuted,getReshapedPermuted:getReshapedPermuted,getSliceBeginCoords:getSliceBeginCoords,getSliceSize:getSliceSize,prepareAndValidate:prepareAndValidate,validateUpdateShape:validateUpdateShape,validateInput:validateInput$1,calculateShapes:calculateShapes,SELU_SCALEALPHA:SELU_SCALEALPHA,SELU_SCALE:SELU_SCALE,ERF_P:ERF_P,ERF_A1:ERF_A1,ERF_A2:ERF_A2,ERF_A3:ERF_A3,ERF_A4:ERF_A4,ERF_A5:ERF_A5,warn:warn,log:log,mergeRealAndImagArrays:mergeRealAndImagArrays,splitRealAndImagArrays:splitRealAndImagArrays,complexWithEvenIndex:complexWithEvenIndex,complexWithOddIndex:complexWithOddIndex,getComplexWithIndex:getComplexWithIndex,assignToTypedArray:assignToTypedArray,exponents:exponents,exponent:exponent,decodeEinsumEquation:decodeEinsumEquation,getEinsumPermutation:getEinsumPermutation,checkEinsumDimSizes:checkEinsumDimSizes,getEinsumComputePath:getEinsumComputePath,isIdentityPermutation:isIdentityPermutation,prepareSplitSize:prepareSplitSize});
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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 DataType;(function(e){e[e["DT_INVALID"]=0]="DT_INVALID";e[e["DT_FLOAT"]=1]="DT_FLOAT";e[e["DT_DOUBLE"]=2]="DT_DOUBLE";e[e["DT_INT32"]=3]="DT_INT32";e[e["DT_UINT8"]=4]="DT_UINT8";e[e["DT_INT16"]=5]="DT_INT16";e[e["DT_INT8"]=6]="DT_INT8";e[e["DT_STRING"]=7]="DT_STRING";e[e["DT_COMPLEX64"]=8]="DT_COMPLEX64";e[e["DT_INT64"]=9]="DT_INT64";e[e["DT_BOOL"]=10]="DT_BOOL";e[e["DT_QINT8"]=11]="DT_QINT8";e[e["DT_QUINT8"]=12]="DT_QUINT8";e[e["DT_QINT32"]=13]="DT_QINT32";e[e["DT_BFLOAT16"]=14]="DT_BFLOAT16";e[e["DT_FLOAT_REF"]=101]="DT_FLOAT_REF";e[e["DT_DOUBLE_REF"]=102]="DT_DOUBLE_REF";e[e["DT_INT32_REF"]=103]="DT_INT32_REF";e[e["DT_UINT8_REF"]=104]="DT_UINT8_REF";e[e["DT_INT16_REF"]=105]="DT_INT16_REF";e[e["DT_INT8_REF"]=106]="DT_INT8_REF";e[e["DT_STRING_REF"]=107]="DT_STRING_REF";e[e["DT_COMPLEX64_REF"]=108]="DT_COMPLEX64_REF";e[e["DT_INT64_REF"]=109]="DT_INT64_REF";e[e["DT_BOOL_REF"]=110]="DT_BOOL_REF";e[e["DT_QINT8_REF"]=111]="DT_QINT8_REF";e[e["DT_QUINT8_REF"]=112]="DT_QUINT8_REF";e[e["DT_QINT32_REF"]=113]="DT_QINT32_REF";e[e["DT_BFLOAT16_REF"]=114]="DT_BFLOAT16_REF";})(DataType||(DataType={}));var SaverDef;(function(e){(function(e){e[e["LEGACY"]=0]="LEGACY";e[e["V1"]=1]="V1";e[e["V2"]=2]="V2";})(e.CheckpointFormatVersion||(e.CheckpointFormatVersion={}));})(SaverDef||(SaverDef={}));
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const CUSTOM_OPS={};function getRegisteredOp(e){return CUSTOM_OPS[e]}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getParamValue(e,t,n,r,s){const a=t.inputParams[e];if(a&&a.inputIndexStart!==undefined){const e=a.inputIndexStart;const o=a.inputIndexEnd===0?undefined:a.inputIndexEnd===undefined?e+1:a.inputIndexEnd;if(a.type==="tensor"){return getTensor(t.inputNames[a.inputIndexStart],n,r,s)}if(a.type==="tensors"){const a=t.inputNames.slice(e,o);return a.map((e=>getTensor(e,n,r,s)))}const i=getTensor(t.inputNames.slice(e)[0],n,r,s);const u=i.dataSync();return a.type==="number"?u[0]:toNestedArray(i.shape,u)}const o=t.attrParams[e];return o&&o.value}function getTensor(e,t,n,r){const[s,a]=parseNodeName(e);if(r!=null){const e=r.getHashTableHandleByName(s);if(e!=null){return e}}const o=n.currentContextIds.find((e=>!!t[getNodeNameWithContextId(s,e)]));return o!==undefined?t[getNodeNameWithContextId(s,o)][a]:undefined}function getTensorsForCurrentContenxt(e,t,n){return t[getNodeNameWithContextId(e,n.currentContextId)]}function getNodeNameAndIndex(e,t){const[n,r,s]=parseNodeName(e);return [getNodeNameWithContextId(n,t&&t.currentContextId),r,s]}function getNodeNameWithContextId(e,t){return !!t?`${e}-${t}`:e}function parseNodeName(e){const t=e.split(":");if(t.length===1){return [e,0,undefined]}const n=t[0];const r=t.length===3?t[1]:undefined;const s=Number(t[t.length-1]);return [n,s,r]}function getPadding(e,t,n){let r=getParamValue("pad",e,t,n);if(r==="explicit"){r=getParamValue("explicitPaddings",e,t,n);const s=[[0,0],[0,0],[0,0],[0,0]];for(let e=0;e<4;e++){s[e][0]=r[e*2];s[e][1]=r[e*2+1];}return s}return r}function cloneTensor(e){return e.kept?e:clone(e)}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$i=[{tfOpName:"Add",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"AddV2",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"AddN",category:"arithmetic",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}]},{tfOpName:"BiasAdd",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true}]},{tfOpName:"Sub",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"RealDiv",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Div",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"DivNoNan",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"FloorDiv",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Mul",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Maximum",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Minimum",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Pow",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"SquaredDifference",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Mod",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"FloorMod",category:"arithmetic",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]}];var arithmetic=Object.freeze({__proto__:null,json:json$i});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$h=[{tfOpName:"Abs",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Acos",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Asin",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Atan",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Atan2",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"y",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Ceil",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"ClipByValue",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"clipValueMin",type:"number"},{start:2,name:"clipValueMax",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Complex",category:"basic_math",inputs:[{start:0,name:"real",type:"tensor"},{start:1,name:"imag",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"ComplexAbs",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Cos",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Cosh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Elu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Exp",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Floor",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Log",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Imag",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"Tout",name:"outputType",type:"dtype",notSupported:true}]},{tfOpName:"Neg",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Real",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"Tout",name:"outputType",type:"dtype",notSupported:true}]},{tfOpName:"Prelu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"alpha",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Relu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Relu6",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Selu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Sigmoid",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Sin",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Sinh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Sqrt",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Rsqrt",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Square",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Tan",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Tanh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Sign",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Round",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Expm1",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Log1p",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Reciprocal",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Softplus",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Asinh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Acosh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Atanh",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Erf",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Prod",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axes",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool",notSupported:true},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"LeakyRelu",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"alpha",name:"alpha",type:"number",defaultValue:.2},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"IsNan",category:"basic_math",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]}];var basicMath=Object.freeze({__proto__:null,json:json$h});const json$g=[{tfOpName:"EmptyTensorList",category:"control",inputs:[{start:0,name:"elementShape",type:"shape"},{start:1,name:"maxNumElements",type:"number"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"LoopCond",category:"control",inputs:[{start:0,name:"pred",type:"tensor"}]},{tfOpName:"Switch",category:"control",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"pred",type:"tensor"}]},{tfOpName:"Merge",category:"control",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}]},{tfOpName:"Enter",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"frame_name",name:"frameName",type:"string"},{tfName:"is_constant",name:"isConstant",type:"bool"}]},{tfOpName:"Exit",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"NextIteration",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"TensorArrayV3",category:"control",inputs:[{start:0,name:"size",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"element_shape",name:"elementShape",type:"shape"},{tfName:"dynamic_size",name:"dynamicSize",type:"bool"},{tfName:"clear_after_read",name:"clearAfterRead",type:"bool"},{tfName:"identical_element_shapes",name:"identicalElementShapes",type:"bool"},{tfName:"tensor_array_name",name:"name",type:"string"}]},{tfOpName:"TensorArrayWriteV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"tensor",type:"tensor"},{start:3,name:"flowIn",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"TensorArrayReadV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"flowIn",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"TensorArrayGatherV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"flowIn",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"element_shape",name:"elementShape",type:"shape"}]},{tfOpName:"TensorArrayScatterV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"tensor",type:"tensor"},{start:3,name:"flowIn",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"TensorArrayConcatV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"flowIn",type:"number"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"element_shape_except0",name:"elementShapeExcept0",type:"shape",notSupported:true}]},{tfOpName:"TensorArraySplitV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"tensor",type:"tensor"},{start:2,name:"lengths",type:"number[]"},{start:3,name:"flowIn",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"TensorArraySizeV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"},{start:1,name:"flowIn",type:"number"}]},{tfOpName:"TensorArrayCloseV3",category:"control",inputs:[{start:0,name:"tensorArrayId",type:"tensor"}]},{tfOpName:"StatelessIf",category:"control",inputs:[{start:0,name:"cond",type:"tensor"},{start:1,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"then_branch",name:"thenBranch",type:"func"},{tfName:"else_branch",name:"elseBranch",type:"func"}]},{tfOpName:"If",category:"control",inputs:[{start:0,name:"cond",type:"tensor"},{start:1,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"then_branch",name:"thenBranch",type:"func"},{tfName:"else_branch",name:"elseBranch",type:"func"}]},{tfOpName:"StatelessWhile",category:"control",inputs:[{start:0,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"cond",name:"cond",type:"func"},{tfName:"body",name:"body",type:"func"}]},{tfOpName:"While",category:"control",inputs:[{start:0,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"cond",name:"cond",type:"func"},{tfName:"body",name:"body",type:"func"}]},{tfOpName:"TensorListScatter",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListScatterV2",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"elementShape",type:"shape"},{start:3,name:"numElements",type:"number"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListGather",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"indices",type:"number[]"},{start:2,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListGetItem",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListSetItem",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"index",type:"number"},{start:2,name:"tensor",type:"tensor"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListReserve",category:"control",inputs:[{start:0,name:"elementShape",type:"shape"},{start:1,name:"numElements",type:"number"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListFromTensor",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListStack",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"},{tfName:"num_elements",name:"numElements",type:"dtype"}]},{tfOpName:"TensorListSplit",category:"control",inputs:[{start:0,name:"tensor",type:"tensor"},{start:1,name:"elementShape",type:"shape"},{start:2,name:"lengths",type:"number[]"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListConcat",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"}],attrs:[{tfName:"element_shape",name:"elementShape",type:"shape"},{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListPopBack",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"elementShape",type:"shape"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]},{tfOpName:"TensorListPushBack",category:"control",inputs:[{start:0,name:"tensorListId",type:"tensor"},{start:1,name:"tensor",type:"tensor"}],attrs:[{tfName:"element_dtype",name:"elementDType",type:"dtype"}]}];var control=Object.freeze({__proto__:null,json:json$g});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$f=[{tfOpName:"AvgPool",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"MaxPool",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[],notSupported:true},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"MaxPoolWithArgmax",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"include_batch_in_index",name:"includeBatchInIndex",type:"bool"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"AvgPool3D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"MaxPool3D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true},{tfName:"ksize",name:"kernelSize",type:"number[]"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Conv1D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"stride",name:"stride",type:"number"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NWC"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"dilation",name:"dilation",type:"number",defaultValue:1}]},{tfOpName:"Conv2D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"useCudnnOnGpu",name:"useCudnnOnGpu",type:"bool"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"_FusedConv2D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"},{start:2,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"num_args",name:"numArgs",type:"number"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"use_cudnn_on_gpu",name:"useCudnnOnGpu",type:"bool",defaultValue:true},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"dilations",name:"dilations",type:"number[]",defaultValue:[1,1,1,1]},{tfName:"fused_ops",name:"fusedOps",type:"string[]",defaultValue:[]},{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:1e-4},{tfName:"leakyrelu_alpha",name:"leakyreluAlpha",type:"number"}]},{tfOpName:"Conv2DBackpropInput",category:"convolution",inputs:[{start:2,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"},{start:0,name:"outputShape",type:"number[]"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]",notSupported:true}]},{tfOpName:"DepthwiseConv2d",category:"convolution",inputs:[{start:0,name:"input",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"DepthwiseConv2dNative",category:"convolution",inputs:[{start:0,name:"input",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"FusedDepthwiseConv2dNative",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"},{start:2,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"num_args",name:"numArgs",type:"number"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"dilations",name:"dilations",type:"number[]",defaultValue:[1,1,1,1]},{tfName:"fused_ops",name:"fusedOps",type:"string[]",defaultValue:[]},{tfName:"explicit_paddings",name:"explicitPaddings",type:"number[]",defaultValue:[]}]},{tfOpName:"Conv3D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"padding",name:"pad",type:"string"},{tfName:"data_format",name:"dataFormat",type:"string",defaultValue:"NHWC"},{tfName:"dilations",name:"dilations",type:"number[]"}]},{tfOpName:"Dilation2D",category:"convolution",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"filter",type:"tensor"}],attrs:[{tfName:"strides",name:"strides",type:"number[]"},{tfName:"rates",name:"dilations",type:"number[]"},{tfName:"padding",name:"pad",type:"string"}]}];var convolution=Object.freeze({__proto__:null,json:json$f});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$e=[{tfOpName:"Fill",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"},{start:1,name:"value",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"LinSpace",category:"creation",inputs:[{start:0,name:"start",type:"number"},{start:1,name:"stop",type:"number"},{start:2,name:"num",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"OneHot",category:"creation",inputs:[{start:0,name:"indices",type:"tensor"},{start:1,name:"depth",type:"number"},{start:2,name:"onValue",type:"number",defaultValue:1},{start:3,name:"offValue",type:"number",defaultValue:0}],attrs:[{tfName:"axis",name:"axis",type:"number",notSupported:true},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Ones",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"OnesLike",category:"creation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"dtype",name:"dtype",type:"dtype"}]},{tfOpName:"RandomUniform",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"minval",name:"minval",type:"number",defaultValue:0},{tfName:"maxval",name:"maxval",type:"number",defaultValue:1},{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"seed",name:"seed",type:"number",defaultValue:0},{tfName:"seed2",name:"seed2",type:"number",defaultValue:0,notSupported:true},{tfName:"T",name:"T",type:"number",notSupported:true}]},{tfOpName:"Range",category:"creation",inputs:[{start:0,name:"start",type:"number"},{start:1,name:"stop",type:"number"},{start:2,name:"step",type:"number",defaultValue:0}],attrs:[{tfName:"Tidx",name:"dtype",type:"dtype"}]},{tfOpName:"TruncatedNormal",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"means",name:"mean",type:"number",defaultValue:0},{tfName:"stddev",name:"stdDev",type:"number",defaultValue:1},{tfName:"seed",name:"seed",type:"number"},{tfName:"seed2",name:"seed2",type:"number",defaultValue:0,notSupported:true},{tfName:"dtype",name:"dtype",type:"dtype"},{tfName:"T",name:"T",type:"number",notSupported:true}]},{tfOpName:"Zeros",category:"creation",inputs:[{start:0,name:"shape",type:"number[]"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"ZerosLike",category:"creation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype"}]},{tfOpName:"Multinomial",category:"creation",inputs:[{start:0,name:"logits",type:"tensor"},{start:1,name:"numSamples",type:"number"}],attrs:[{tfName:"seed",name:"seed",type:"number"},{tfName:"seed2",name:"seed2",type:"number"},{tfName:"T",name:"dtype",type:"dtype"},{tfName:"output_dtype",name:"output_dtype",type:"dtype"}]}];var creation=Object.freeze({__proto__:null,json:json$e});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$d=[{tfOpName:"NonMaxSuppressionV2",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"}]},{tfOpName:"NonMaxSuppressionV3",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"},{start:4,name:"scoreThreshold",type:"number"}]},{tfOpName:"NonMaxSuppressionV4",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"},{start:4,name:"scoreThreshold",type:"number"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true},{tfName:"T_threshold",name:"threshold",type:"dtype",notSupported:true},{tfName:"pad_to_max_output_size",name:"padToMaxOutputSize",type:"bool"}]},{tfOpName:"NonMaxSuppressionV5",category:"dynamic",inputs:[{start:0,name:"boxes",type:"tensor"},{start:1,name:"scores",type:"tensor"},{start:2,name:"maxOutputSize",type:"number"},{start:3,name:"iouThreshold",type:"number"},{start:4,name:"scoreThreshold",type:"number"},{start:5,name:"softNmsSigma",type:"number"}]},{tfOpName:"Where",category:"dynamic",inputs:[{start:0,name:"condition",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"ListDiff",category:"dynamic",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"y",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]}];var dynamic=Object.freeze({__proto__:null,json:json$d});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$c=[{tfOpName:"TopKV2",category:"evaluation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"k",type:"number"}],attrs:[{tfName:"sorted",name:"sorted",type:"bool"}]},{tfOpName:"Unique",category:"evaluation",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"UniqueV2",category:"evaluation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]}];var evaluation=Object.freeze({__proto__:null,json:json$c});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$b=[{tfOpName:"PlaceholderWithDefault",category:"graph",inputs:[{start:0,name:"default",type:"tensor"}],attrs:[{tfName:"shape",name:"shape",type:"shape"},{tfName:"dtype",name:"dtype",type:"dtype"}]},{tfOpName:"Placeholder",category:"graph",attrs:[{tfName:"shape",name:"shape",type:"shape"},{tfName:"dtype",name:"dtype",type:"dtype"}]},{tfOpName:"Const",category:"graph"},{tfOpName:"Identity",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"IdentityN",category:"graph",inputs:[{start:0,end:0,name:"x",type:"tensors"}]},{tfOpName:"Snapshot",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"Rank",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"Size",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"Shape",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"ShapeN",category:"graph",inputs:[{start:0,end:0,name:"x",type:"tensors"}]},{tfOpName:"Print",category:"graph",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"data",type:"tensors"}],attrs:[{tfName:"message",name:"message",type:"string"},{tfName:"first_n",name:"firstN",type:"number",notSupported:true},{tfName:"summarize",name:"summarize",type:"number",defaultValue:3}]},{tfOpName:"NoOp",category:"graph",inputs:[]},{tfOpName:"StopGradient",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"FakeQuantWithMinMaxVars",category:"graph",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"min",name:"min",type:"number"},{tfName:"max",name:"max",type:"number"}]}];var graph=Object.freeze({__proto__:null,json:json$b});const json$a=[{tfOpName:"HashTable",category:"hash_table",inputs:[],attrs:[{tfName:"shared_name",name:"sharedName",type:"string"},{tfName:"use_node_name_sharing",name:"useNodeNameSharing",type:"bool"},{tfName:"key_dtype",name:"keyDType",type:"dtype"},{tfName:"value_dtype",name:"valueDType",type:"dtype"}]},{tfOpName:"HashTableV2",category:"hash_table",inputs:[],attrs:[{tfName:"shared_name",name:"sharedName",type:"string"},{tfName:"use_node_name_sharing",name:"useNodeNameSharing",type:"bool"},{tfName:"key_dtype",name:"keyDType",type:"dtype"},{tfName:"value_dtype",name:"valueDType",type:"dtype"}]},{tfOpName:"LookupTableImport",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"values",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:true},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:true}]},{tfOpName:"LookupTableImportV2",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"values",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:true},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:true}]},{tfOpName:"LookupTableFind",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:true},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:true}]},{tfOpName:"LookupTableFindV2",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"},{start:1,name:"keys",type:"tensor"},{start:2,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"Tin",name:"tIn",type:"dtype",notSupported:true},{tfName:"Tout",name:"tOut",type:"dtype",notSupported:true}]},{tfOpName:"LookupTableSize",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"}]},{tfOpName:"LookupTableSizeV2",category:"hash_table",inputs:[{start:0,name:"tableHandle",type:"tensor"}]}];var hashTable=Object.freeze({__proto__:null,json:json$a});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$9=[{tfOpName:"ResizeBilinear",category:"image",inputs:[{start:0,name:"images",type:"tensor"},{start:1,name:"size",type:"number[]"}],attrs:[{tfName:"align_corners",name:"alignCorners",type:"bool"},{tfName:"half_pixel_centers",name:"halfPixelCenters",type:"bool"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"ResizeNearestNeighbor",category:"image",inputs:[{start:0,name:"images",type:"tensor"},{start:1,name:"size",type:"number[]"}],attrs:[{tfName:"align_corners",name:"alignCorners",type:"bool"},{tfName:"half_pixel_centers",name:"halfPixelCenters",type:"bool"},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"CropAndResize",category:"image",inputs:[{start:0,name:"image",type:"tensor"},{start:1,name:"boxes",type:"tensor"},{start:2,name:"boxInd",type:"tensor"},{start:3,name:"cropSize",type:"number[]"}],attrs:[{tfName:"method",name:"method",type:"string"},{tfName:"extrapolation_value",name:"extrapolationValue",type:"number"}]}];var image=Object.freeze({__proto__:null,json:json$9});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$8=[{tfOpName:"Equal",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"NotEqual",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Greater",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"GreaterEqual",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Less",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"LessEqual",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"LogicalAnd",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"LogicalNot",category:"logical",inputs:[{start:0,name:"a",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"LogicalOr",category:"logical",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Select",category:"logical",inputs:[{start:0,name:"condition",type:"tensor"},{start:1,name:"a",type:"tensor"},{start:2,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"SelectV2",category:"logical",inputs:[{start:0,name:"condition",type:"tensor"},{start:1,name:"a",type:"tensor"},{start:2,name:"b",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]}];var logical=Object.freeze({__proto__:null,json:json$8});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$7=[{tfOpName:"_FusedMatMul",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"},{start:2,end:0,name:"args",type:"tensors"}],attrs:[{tfName:"num_args",name:"numArgs",type:"number"},{tfName:"fused_ops",name:"fusedOps",type:"string[]",defaultValue:[]},{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:1e-4},{tfName:"transpose_a",name:"transposeA",type:"bool",defaultValue:false},{tfName:"transpose_b",name:"transposeB",type:"bool",defaultValue:false},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"MatMul",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"transpose_a",name:"transposeA",type:"bool",defaultValue:false},{tfName:"transpose_b",name:"transposeB",type:"bool",defaultValue:false},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"BatchMatMul",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"adj_x",name:"transposeA",type:"bool",defaultValue:false},{tfName:"adj_y",name:"transposeB",type:"bool",defaultValue:false},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"BatchMatMulV2",category:"matrices",inputs:[{start:0,name:"a",type:"tensor"},{start:1,name:"b",type:"tensor"}],attrs:[{tfName:"adj_x",name:"transposeA",type:"bool",defaultValue:false},{tfName:"adj_y",name:"transposeB",type:"bool",defaultValue:false},{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Transpose",category:"matrices",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"perm",type:"number[]"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"Einsum",category:"matrices",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}],attrs:[{tfName:"equation",name:"equation",type:"string"},{tfName:"N",name:"n",type:"number",defaultValue:2},{tfName:"T",name:"dtype",type:"dtype"}]}];var matrices=Object.freeze({__proto__:null,json:json$7});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$6=[{tfOpName:"FusedBatchNorm",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"scale",type:"tensor"},{start:2,name:"offset",type:"tensor"},{start:3,name:"mean",type:"tensor"},{start:4,name:"variance",type:"tensor"}],attrs:[{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:.001},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true}]},{tfOpName:"FusedBatchNormV2",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"scale",type:"tensor"},{start:2,name:"offset",type:"tensor"},{start:3,name:"mean",type:"tensor"},{start:4,name:"variance",type:"tensor"}],attrs:[{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:.001},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true}]},{tfOpName:"FusedBatchNormV3",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"scale",type:"tensor"},{start:2,name:"offset",type:"tensor"},{start:3,name:"mean",type:"tensor"},{start:4,name:"variance",type:"tensor"}],attrs:[{tfName:"epsilon",name:"epsilon",type:"number",defaultValue:.001},{tfName:"data_format",name:"dataFormat",type:"string",notSupported:true}]},{tfOpName:"LRN",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"depth_radius",name:"radius",type:"number",defaultValue:5},{tfName:"bias",name:"bias",type:"number",defaultValue:1},{tfName:"alpha",name:"alpha",type:"number",defaultValue:1},{tfName:"beta",name:"beta",type:"number",defaultValue:.5}]},{tfOpName:"Softmax",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"LogSoftmax",category:"normalization",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"SparseToDense",category:"normalization",inputs:[{start:0,name:"sparseIndices",type:"tensor"},{start:1,name:"outputShape",type:"number[]"},{start:2,name:"sparseValues",type:"tensor"},{start:3,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"validate_indices",name:"validateIndices",type:"bool",defaultValue:true,notSupported:true}]}];var normalization=Object.freeze({__proto__:null,json:json$6});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$5=[{tfOpName:"Bincount",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"size",type:"number"},{start:2,name:"weights",type:"tensor"}]},{tfOpName:"DenseBincount",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"size",type:"number"},{start:2,name:"weights",type:"tensor"}],attrs:[{tfName:"binary_output",name:"binaryOutput",type:"bool"}]},{tfOpName:"Max",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Mean",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Min",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Sum",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"All",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Any",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"ArgMax",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]},{tfOpName:"ArgMin",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]},{tfOpName:"Prod",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}],attrs:[{tfName:"keep_dims",name:"keepDims",type:"bool"}]},{tfOpName:"Cumsum",category:"reduction",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}],attrs:[{tfName:"exclusive",name:"exclusive",type:"bool"},{tfName:"reverse",name:"reverse",type:"bool"}]}];var reduction=Object.freeze({__proto__:null,json:json$5});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$4=[{tfOpName:"ConcatV2",category:"slice_join",inputs:[{start:0,end:-1,name:"tensors",type:"tensors"},{start:-1,name:"axis",type:"number"}],attrs:[{tfName:"N",name:"n",type:"number",defaultValue:2}]},{tfOpName:"Concat",category:"slice_join",inputs:[{start:1,end:0,name:"tensors",type:"tensors"},{start:0,name:"axis",type:"number"}],attrs:[{tfName:"N",name:"n",type:"number",defaultValue:2}]},{tfOpName:"GatherV2",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"indices",type:"tensor"},{start:2,name:"axis",type:"number",defaultValue:0}],attrs:[{tfName:"batch_dims",name:"batchDims",type:"number",defaultValue:0}]},{tfOpName:"Gather",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"indices",type:"tensor"}],attrs:[{tfName:"validate_indices",name:"validateIndices",type:"bool",notSupported:true}]},{tfOpName:"Reverse",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"dims",type:"bool[]"}]},{tfOpName:"ReverseV2",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number[]"}]},{tfOpName:"Slice",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"begin",type:"number[]"},{start:2,name:"size",type:"number[]"}]},{tfOpName:"StridedSlice",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"begin",type:"number[]"},{start:2,name:"end",type:"number[]"},{start:3,name:"strides",type:"number[]"}],attrs:[{tfName:"begin_mask",name:"beginMask",type:"number",defaultValue:0},{tfName:"end_mask",name:"endMask",type:"number",defaultValue:0},{tfName:"new_axis_mask",name:"newAxisMask",type:"number",defaultValue:0},{tfName:"ellipsis_mask",name:"ellipsisMask",type:"number",defaultValue:0},{tfName:"shrink_axis_mask",name:"shrinkAxisMask",type:"number",defaultValue:0}]},{tfOpName:"Pack",category:"slice_join",inputs:[{start:0,end:0,name:"tensors",type:"tensors"}],attrs:[{tfName:"axis",name:"axis",type:"number",defaultValue:0}]},{tfOpName:"Unpack",category:"slice_join",inputs:[{start:0,name:"tensor",type:"tensor"}],attrs:[{tfName:"axis",name:"axis",type:"number",defaultValue:0},{tfName:"num",name:"num",type:"number",defaultValue:0,notSupported:true}]},{tfOpName:"Tile",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"reps",type:"number[]"}]},{tfOpName:"Split",category:"slice_join",inputs:[{start:0,name:"axis",type:"number",defaultValue:0},{start:1,name:"x",type:"tensor"}],attrs:[{tfName:"num_split",name:"numOrSizeSplits",type:"number",defaultValue:1}]},{tfOpName:"SplitV",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"numOrSizeSplits",type:"number[]"},{start:2,name:"axis",type:"number",defaultValue:0}]},{tfOpName:"ScatterNd",category:"slice_join",inputs:[{start:0,name:"indices",type:"tensor"},{start:1,name:"values",type:"tensor"},{start:2,name:"shape",type:"number[]"}]},{tfOpName:"GatherNd",category:"slice_join",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"indices",type:"tensor"}]},{tfOpName:"SparseToDense",category:"slice_join",inputs:[{start:0,name:"sparseIndices",type:"tensor"},{start:1,name:"outputShape",type:"number[]"},{start:2,name:"sparseValues",type:"tensor"},{start:3,name:"defaultValue",type:"tensor"}],attrs:[{tfName:"validate_indices",name:"validateIndices",type:"bool",defaultValue:false,notSupported:true}]}];var sliceJoin=Object.freeze({__proto__:null,json:json$4});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$3=[{tfOpName:"SparseFillEmptyRows",category:"sparse",inputs:[{start:0,name:"indices",type:"tensor"},{start:1,name:"values",type:"tensor"},{start:2,name:"denseShape",type:"tensor"},{start:3,name:"defaultValue",type:"tensor"}]},{tfOpName:"SparseReshape",category:"sparse",inputs:[{start:0,name:"inputIndices",type:"tensor"},{start:1,name:"inputShape",type:"tensor"},{start:2,name:"newShape",type:"tensor"}],attrs:[{tfName:"T",name:"dtype",type:"dtype",notSupported:true}]},{tfOpName:"SparseSegmentMean",category:"sparse",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"indices",type:"tensor"},{start:2,name:"segmentIds",type:"tensor"}]},{tfOpName:"SparseSegmentSum",category:"sparse",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"indices",type:"tensor"},{start:2,name:"segmentIds",type:"tensor"}]}];var sparse=Object.freeze({__proto__:null,json:json$3});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$2=[{tfOpName:"FFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"IFFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"}]},{tfOpName:"RFFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"fft_length",type:"number",notSupported:true}]},{tfOpName:"IRFFT",category:"spectral",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"fft_length",type:"number",notSupported:true}]}];var spectral=Object.freeze({__proto__:null,json:json$2});
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json$1=[{tfOpName:"StringNGrams",category:"string",inputs:[{start:0,name:"data",type:"tensor"},{start:1,name:"dataSplits",type:"tensor"}],attrs:[{tfName:"separator",name:"separator",type:"string"},{tfName:"ngram_widths",name:"nGramWidths",type:"number[]"},{tfName:"left_pad",name:"leftPad",type:"string"},{tfName:"right_pad",name:"rightPad",type:"string"},{tfName:"pad_width",name:"padWidth",type:"number"},{tfName:"preserve_short_sequences",name:"preserveShortSequences",type:"bool"}],outputs:["ngrams","ngrams_splits"]},{tfOpName:"StringSplit",category:"string",inputs:[{start:0,name:"input",type:"tensor"},{start:1,name:"delimiter",type:"tensor"}],attrs:[{tfName:"skip_empty",name:"skipEmpty",type:"bool"}],outputs:["indices","values","shape"]},{tfOpName:"StringToHashBucketFast",category:"string",inputs:[{start:0,name:"input",type:"tensor"}],attrs:[{tfName:"num_buckets",name:"numBuckets",type:"number"}]}];var string=Object.freeze({__proto__:null,json:json$1});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const json=[{tfOpName:"Cast",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"SrcT",name:"sdtype",type:"dtype",notSupported:true},{tfName:"DstT",name:"dtype",type:"dtype"}]},{tfOpName:"ExpandDims",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"axis",type:"number"}]},{tfOpName:"MirrorPad",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"padding",type:"number[]"}],attrs:[{tfName:"mode",name:"mode",type:"string"}]},{tfOpName:"Pad",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"padding",type:"number[]"}],attrs:[{tfName:"constant_value",name:"constantValue",type:"number",defaultValue:0}]},{tfOpName:"PadV2",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"padding",type:"number[]"},{start:2,name:"constantValue",type:"number",defaultValue:0}]},{tfOpName:"Reshape",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"shape",type:"number[]"}]},{tfOpName:"Squeeze",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"axis",tfDeprecatedName:"squeeze_dims",name:"axis",type:"number[]"}]},{tfOpName:"SpaceToBatchND",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"blockShape",type:"number[]"},{start:2,name:"paddings",type:"number[]"}]},{tfOpName:"BatchToSpaceND",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"blockShape",type:"number[]"},{start:2,name:"crops",type:"number[]"}]},{tfOpName:"DepthToSpace",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"}],attrs:[{tfName:"block_size",name:"blockSize",type:"number"},{tfName:"data_format",name:"dataFormat",type:"string"}]},{tfOpName:"BroadcastTo",category:"transformation",inputs:[{start:0,name:"x",type:"tensor"},{start:1,name:"shape",type:"number[]"}],attrs:[]}];var transformation=Object.freeze({__proto__:null,json:json});
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class OperationMapper{static get Instance(){return this._instance||(this._instance=new this)}constructor(){const e=[arithmetic,basicMath,control,convolution,creation,dynamic,evaluation,graph,hashTable,image,logical,matrices,normalization,reduction,sliceJoin,sparse,spectral,string,transformation];const t=[].concat(...e.map((e=>e.json)));this.opMappers=t.reduce(((e,t)=>{e[t.tfOpName]=t;return e}),{});}transformGraph(e,t={}){const n=e.node;const r=[];const s=[];const a=[];const o=n.reduce(((e,t)=>{e[t.name]=this.mapNode(t);if(t.op.startsWith("Placeholder")){r.push(e[t.name]);}else if(t.op==="Const"){s.push(e[t.name]);}else if(t.input==null||t.input.length===0){a.push(e[t.name]);}return e}),{});let i=[];const u=[];let c={};let l={};if(t!=null){c=this.mapSignatureEntries(t.inputs);l=this.mapSignatureEntries(t.outputs);}const p=Object.keys(o);p.forEach((e=>{const t=o[e];t.inputNames.forEach(((e,n)=>{const[r,,s]=getNodeNameAndIndex(e);const a=o[r];if(a.outputs!=null){const e=a.outputs.indexOf(s);if(e!==-1){const s=`${r}:${e}`;t.inputNames[n]=s;}}t.inputs.push(a);a.children.push(t);}));}));if(Object.keys(l).length===0){p.forEach((e=>{const t=o[e];if(t.children.length===0){u.push(t);}}));}else {Object.keys(l).forEach((e=>{const[t]=getNodeNameAndIndex(e);const n=o[t];if(n!=null){n.signatureKey=l[e];u.push(n);}}));}if(Object.keys(c).length>0){Object.keys(c).forEach((e=>{const[t]=getNodeNameAndIndex(e);const n=o[t];if(n){n.signatureKey=c[e];i.push(n);}}));}else {i=r;}let d={};if(e.library!=null&&e.library.function!=null){d=e.library.function.reduce(((e,t)=>{e[t.signature.name]=this.mapFunction(t);return e}),{});}const h={nodes:o,inputs:i,outputs:u,weights:s,placeholders:r,signature:t,functions:d};if(a.length>0){h.initNodes=a;}return h}mapSignatureEntries(e){return Object.keys(e||{}).reduce(((t,n)=>{t[e[n].name]=n;return t}),{})}mapNode(e){const t=getRegisteredOp(e.op)||this.opMappers[e.op]||{};if(e.attr==null){e.attr={};}const n={name:e.name,op:e.op,category:t.category,inputNames:(e.input||[]).map((e=>e.startsWith("^")?e.substr(1):e)),inputs:[],children:[],inputParams:{},attrParams:{},rawAttrs:e.attr,outputs:t.outputs};if(t.inputs!=null){n.inputParams=t.inputs.reduce(((e,t)=>{e[t.name]={type:t.type,inputIndexStart:t.start,inputIndexEnd:t.end};return e}),{});}if(t.attrs!=null){n.attrParams=t.attrs.reduce(((t,n)=>{const r=n.type;let s=undefined;switch(n.type){case"string":s=getStringParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getStringParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"string[]":s=getStringArrayParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getStringArrayParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"number":s=getNumberParam(e.attr,n.tfName,n.defaultValue||0);if(s===undefined&&!!n.tfDeprecatedName){s=getNumberParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"number[]":s=getNumericArrayParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getNumericArrayParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"bool":s=getBoolParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getBoolParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"bool[]":s=getBoolArrayParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getBoolArrayParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"shape":s=getTensorShapeParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getTensorShapeParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"shape[]":s=getTensorShapeArrayParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getTensorShapeArrayParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"dtype":s=getDtypeParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getDtypeParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"dtype[]":s=getDtypeArrayParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getDtypeArrayParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"func":s=getFuncParam(e.attr,n.tfName,n.defaultValue);if(s===undefined&&!!n.tfDeprecatedName){s=getFuncParam(e.attr,n.tfDeprecatedName,n.defaultValue);}break;case"tensor":case"tensors":break;default:throw new Error(`Unsupported param type: ${n.type} for op: ${e.op}`)}t[n.name]={value:s,type:r};return t}),{});}return n}mapFunction(e){const t=e.nodeDef;const n=[];const r=[];let s={};if(t!=null){s=t.reduce(((e,t)=>{e[t.name]=this.mapNode(t);if(t.op==="Const"){r.push(e[t.name]);}return e}),{});}const a=[];const o=[];e.signature.inputArg.forEach((e=>{const[t]=getNodeNameAndIndex(e.name);const n={name:t,op:"Placeholder",inputs:[],inputNames:[],category:"graph",inputParams:{},attrParams:{dtype:{value:parseDtypeParam(e.type),type:"dtype"}},children:[]};n.signatureKey=e.name;a.push(n);s[t]=n;}));const i=Object.keys(s);i.forEach((e=>{const t=s[e];t.inputNames.forEach(((e,n)=>{const[r,,a]=getNodeNameAndIndex(e);const o=s[r];if(o.outputs!=null){const e=o.outputs.indexOf(a);if(e!==-1){const s=`${r}:${e}`;t.inputNames[n]=s;}}t.inputs.push(o);o.children.push(t);}));}));const u=e.ret;e.signature.outputArg.forEach((e=>{const[t,n]=getNodeNameAndIndex(u[e.name]);const r=s[t];if(r!=null){r.defaultOutput=n;o.push(r);}}));const c=this.mapArgsToSignature(e);return {nodes:s,inputs:a,outputs:o,weights:r,placeholders:n,signature:c}}mapArgsToSignature(e){return {methodName:e.signature.name,inputs:e.signature.inputArg.reduce(((e,t)=>{e[t.name]=this.mapArgToTensorInfo(t);return e}),{}),outputs:e.signature.outputArg.reduce(((t,n)=>{t[n.name]=this.mapArgToTensorInfo(n,e.ret);return t}),{})}}mapArgToTensorInfo(e,t){let n=e.name;if(t!=null){n=t[n];}return {name:n,dtype:e.type}}}function decodeBase64(e){const t=env().global;if(typeof t.atob!=="undefined"){return t.atob(e)}else if(typeof Buffer!=="undefined"){return new Buffer(e,"base64").toString()}else {throw new Error("Unable to decode base64 in this environment. "+"Missing built-in atob() or Buffer()")}}function parseStringParam(e,t){const n=Array.isArray(e)?String.fromCharCode.apply(null,e):decodeBase64(e);return t?n:n.toLowerCase()}function getStringParam(e,t,n,r=false){const s=e[t];if(s!=null){return parseStringParam(s.s,r)}return n}function getBoolParam(e,t,n){const r=e[t];return r?r.b:n}function getNumberParam(e,t,n){const r=e[t]||{};const s=r["i"]!=null?r["i"]:r["f"]!=null?r["f"]:n;return typeof s==="number"?s:parseInt(s,10)}function parseDtypeParam(e){if(typeof e==="string"){e=DataType[e];}switch(e){case DataType.DT_FLOAT:return "float32";case DataType.DT_INT32:case DataType.DT_INT64:case DataType.DT_INT8:case DataType.DT_UINT8:return "int32";case DataType.DT_BOOL:return "bool";case DataType.DT_DOUBLE:return "float32";case DataType.DT_STRING:return "string";default:return null}}function getFuncParam(e,t,n){const r=e[t];if(r&&r.func){return r.func.name}return n}function getDtypeParam(e,t,n){const r=e[t];if(r&&r.type){return parseDtypeParam(r.type)}return n}function getDtypeArrayParam(e,t,n){const r=e[t];if(r&&r.list&&r.list.type){return r.list.type.map((e=>parseDtypeParam(e)))}return n}function parseTensorShapeParam(e){if(e.unknownRank){return undefined}if(e.dim!=null){return e.dim.map((e=>typeof e.size==="number"?e.size:parseInt(e.size,10)))}return []}function getTensorShapeParam(e,t,n){const r=e[t];if(r&&r.shape){return parseTensorShapeParam(r.shape)}return n}function getNumericArrayParam(e,t,n){const r=e[t];if(r){return ((r.list.f&&r.list.f.length?r.list.f:r.list.i)||[]).map((e=>typeof e==="number"?e:parseInt(e,10)))}return n}function getStringArrayParam(e,t,n,r=false){const s=e[t];if(s&&s.list&&s.list.s){return s.list.s.map((e=>parseStringParam(e,r)))}return n}function getTensorShapeArrayParam(e,t,n){const r=e[t];if(r&&r.list&&r.list.shape){return r.list.shape.map((e=>parseTensorShapeParam(e)))}return n}function getBoolArrayParam(e,t,n){const r=e[t];if(r&&r.list&&r.list.b){return r.list.b}return n}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class NodeValueImpl{constructor(e,t,n){this.node=e;this.tensorMap=t;this.context=n;this.inputs=[];this.attrs={};this.inputs=e.inputNames.map((e=>this.getInput(e)));if(e.rawAttrs!=null){this.attrs=Object.keys(e.rawAttrs).reduce(((e,t)=>{e[t]=this.getAttr(t);return e}),{});}}getInput(e){return getTensor(e,this.tensorMap,this.context)}getAttr(e,t){const n=this.node.rawAttrs[e];if(n.tensor!=null){return getTensor(e,this.tensorMap,this.context)}if(n.i!=null||n.f!=null){return getNumberParam(this.node.rawAttrs,e,t)}if(n.s!=null){return getStringParam(this.node.rawAttrs,e,t)}if(n.b!=null){return getBoolParam(this.node.rawAttrs,e,t)}if(n.shape!=null){return getTensorShapeParam(this.node.rawAttrs,e,t)}if(n.type!=null){return getDtypeParam(this.node.rawAttrs,e,t)}if(n.list!=null){if(n.list.i!=null||n.list.f!=null){return getNumericArrayParam(this.node.rawAttrs,e,t)}if(n.list.s!=null){return getStringArrayParam(this.node.rawAttrs,e,t)}if(n.list.shape!=null){return getTensorShapeArrayParam(this.node.rawAttrs,e,t)}if(n.list.b!=null){return getBoolArrayParam(this.node.rawAttrs,e,t)}if(n.list.type!=null){return getDtypeArrayParam(this.node.rawAttrs,e,t)}}return t}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$j=(e,t,n)=>{switch(e.op){case"BiasAdd":case"AddV2":case"Add":{return [add(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"AddN":{return [addN(getParamValue("tensors",e,t,n))]}case"FloorMod":case"Mod":return [mod(getParamValue("a",e,t,n),getParamValue("b",e,t,n))];case"Mul":return [mul(getParamValue("a",e,t,n),getParamValue("b",e,t,n))];case"RealDiv":case"Div":{return [div(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"DivNoNan":{return [divNoNan(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"FloorDiv":{return [floorDiv(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"Sub":{return [sub(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"Minimum":{return [minimum(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"Maximum":{return [maximum(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"Pow":{return [pow$1(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"SquaredDifference":{return [squaredDifference(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$i=(e,t,n)=>{switch(e.op){case"Abs":case"ComplexAbs":return [abs(getParamValue("x",e,t,n))];case"Acos":return [acos(getParamValue("x",e,t,n))];case"Acosh":return [acosh(getParamValue("x",e,t,n))];case"Asin":return [asin(getParamValue("x",e,t,n))];case"Asinh":return [asinh(getParamValue("x",e,t,n))];case"Atan":return [atan(getParamValue("x",e,t,n))];case"Atan2":return [atan2(getParamValue("x",e,t,n),getParamValue("y",e,t,n))];case"Atanh":return [atanh(getParamValue("x",e,t,n))];case"Ceil":return [ceil(getParamValue("x",e,t,n))];case"Complex":return [complex$1(getParamValue("real",e,t,n),getParamValue("imag",e,t,n))];case"Cos":return [cos(getParamValue("x",e,t,n))];case"Cosh":return [cosh(getParamValue("x",e,t,n))];case"Elu":return [elu(getParamValue("x",e,t,n))];case"Erf":return [erf(getParamValue("x",e,t,n))];case"Exp":return [exp(getParamValue("x",e,t,n))];case"Expm1":{return [expm1(getParamValue("x",e,t,n))]}case"Floor":return [floor(getParamValue("x",e,t,n))];case"Log":return [log$1(getParamValue("x",e,t,n))];case"Log1p":{return [log1p(getParamValue("x",e,t,n))]}case"Imag":return [imag$1(getParamValue("x",e,t,n))];case"Neg":return [neg(getParamValue("x",e,t,n))];case"Reciprocal":{return [reciprocal(getParamValue("x",e,t,n))]}case"Real":return [real$1(getParamValue("x",e,t,n))];case"Relu":return [relu$1(getParamValue("x",e,t,n))];case"Round":{return [round(getParamValue("x",e,t,n))]}case"Selu":return [selu(getParamValue("x",e,t,n))];case"Sigmoid":return [sigmoid$1(getParamValue("x",e,t,n))];case"Sin":return [sin(getParamValue("x",e,t,n))];case"Sign":{return [sign(getParamValue("x",e,t,n))]}case"Sinh":{return [sinh(getParamValue("x",e,t,n))]}case"Softplus":{return [softplus(getParamValue("x",e,t,n))]}case"Sqrt":{return [sqrt(getParamValue("x",e,t,n))]}case"Square":{return [square(getParamValue("x",e,t,n))]}case"Tanh":{return [tanh(getParamValue("x",e,t,n))]}case"Tan":return [tan(getParamValue("x",e,t,n))];case"ClipByValue":return [clipByValue(getParamValue("x",e,t,n),getParamValue("clipValueMin",e,t,n),getParamValue("clipValueMax",e,t,n))];case"Relu6":return [relu6(getParamValue("x",e,t,n))];case"Rsqrt":return [rsqrt(getTensor(e.inputNames[0],t,n))];case"Prod":return [prod$1(getParamValue("x",e,t,n),getParamValue("axes",e,t,n))];case"LeakyRelu":return [leakyRelu(getParamValue("x",e,t,n),getParamValue("alpha",e,t,n))];case"Prelu":return [prelu(getParamValue("x",e,t,n),getParamValue("alpha",e,t,n))];case"IsNan":return [isNaN$1(getTensor(e.inputNames[0],t,n))];default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function assertShapesMatchAllowUndefinedSize(e,t,n=""){if(typeof e==="number"||typeof t==="number"){return}assert(e.length===t.length,(()=>n+` Shapes ${e} and ${t} must match`));for(let r=0;r<e.length;r++){const s=e[r];const a=t[r];assert(s<0||a<0||s===a,(()=>n+` Shapes ${e} and ${t} must match`));}}function fullDefinedShape(e){if(typeof e==="number"||e.some((e=>e<0))){return false}return true}function inferElementShape(e,t,n){let r=mergeElementShape(e,n);const s=!fullDefinedShape(r);if(s&&t.length===0){throw new Error(`Tried to calculate elements of an empty list`+` with non-fully-defined elementShape: ${r}`)}if(s){t.forEach((e=>{r=mergeElementShape(e.shape,r);}));}if(!fullDefinedShape(r)){throw new Error(`Non-fully-defined elementShape: ${r}`)}return r}function mergeElementShape(e,t){if(typeof e==="number"){return t}if(typeof t==="number"){return e}if(e.length!==t.length){throw new Error(`Incompatible ranks during merge: ${e} vs. ${t}`)}const n=[];for(let r=0;r<e.length;++r){const s=e[r];const a=t[r];if(s>=0&&a>=0&&s!==a){throw new Error(`Incompatible shape during merge: ${e} vs. ${t}`)}n[r]=s>=0?s:a;}return n}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class TensorArray{constructor(e,t,n,r,s,a,o){this.name=e;this.dtype=t;this.maxSize=n;this.elementShape=r;this.identicalElementShapes=s;this.dynamicSize=a;this.clearAfterRead=o;this.tensors=[];this.closed_=false;this.idTensor=scalar(0);keep(this.idTensor);}get id(){return this.idTensor.id}get closed(){return this.closed_}clearAndClose(e){this.tensors.forEach((t=>{if(e==null||!e.has(t.tensor.id)){t.tensor.dispose();}}));this.tensors=[];this.closed_=true;this.idTensor.dispose();}size(){return this.tensors.length}read(e){if(this.closed_){throw new Error(`TensorArray ${this.name} has already been closed.`)}if(e<0||e>=this.size()){throw new Error(`Tried to read from index ${e}, but array size is: ${this.size()}`)}const t=this.tensors[e];if(t.cleared){throw new Error(`TensorArray ${this.name}: Could not read index ${e} twice because it was cleared after a previous read `+`(perhaps try setting clear_after_read = false?).`)}if(this.clearAfterRead){t.cleared=true;}t.read=true;return t.tensor}readMany(e){return e.map((e=>this.read(e)))}write(e,t){if(this.closed_){throw new Error(`TensorArray ${this.name} has already been closed.`)}if(e<0||!this.dynamicSize&&e>=this.maxSize){throw new Error(`Tried to write to index ${e}, but array is not resizeable and size is: ${this.maxSize}`)}const n=this.tensors[e]||{};if(t.dtype!==this.dtype){throw new Error(`TensorArray ${this.name}: Could not write to TensorArray index ${e},\n          because the value dtype is ${t.dtype}, but TensorArray dtype is ${this.dtype}.`)}if(this.size()===0&&(this.elementShape==null||this.elementShape.length===0)){this.elementShape=t.shape;}assertShapesMatchAllowUndefinedSize(this.elementShape,t.shape,`TensorArray ${this.name}: Could not write to TensorArray index ${e}.`);if(n.read){throw new Error(`TensorArray ${this.name}: Could not write to TensorArray index ${e}, because it has already been read.`)}if(n.written){throw new Error(`TensorArray ${this.name}: Could not write to TensorArray index ${e}, because it has already been written.`)}n.tensor=t;keep(t);n.written=true;this.tensors[e]=n;}writeMany(e,t){if(e.length!==t.length){throw new Error(`TensorArray ${this.name}: could not write multiple tensors,`+`because the index size: ${e.length} is not the same as tensors size: ${t.length}.`)}e.forEach(((e,n)=>this.write(e,t[n])));}gather(e,t){if(!!t&&t!==this.dtype){throw new Error(`TensorArray dtype is ${this.dtype} but gather requested dtype ${t}`)}if(!e){e=[];for(let t=0;t<this.size();t++){e.push(t);}}else {e=e.slice(0,this.size());}if(e.length===0){return tensor([],[0].concat(this.elementShape))}const n=this.readMany(e);assertShapesMatchAllowUndefinedSize(this.elementShape,n[0].shape,"TensorArray shape mismatch: ");return stack(n,0)}concat(e){if(!!e&&e!==this.dtype){throw new Error(`TensorArray dtype is ${this.dtype} but concat requested dtype ${e}`)}if(this.size()===0){return tensor([],[0].concat(this.elementShape))}const t=[];for(let e=0;e<this.size();e++){t.push(e);}const n=this.readMany(t);assertShapesMatchAllowUndefinedSize(this.elementShape,n[0].shape,`TensorArray shape mismatch: tensor array shape (${this.elementShape}) vs first tensor shape (${n[0].shape})`);return concat$1(n,0)}scatter(e,t){if(t.dtype!==this.dtype){throw new Error(`TensorArray dtype is ${this.dtype} but tensor has dtype ${t.dtype}`)}if(e.length!==t.shape[0]){throw new Error(`Expected len(indices) == tensor.shape[0], but saw: ${e.length} vs. ${t.shape[0]}`)}const n=Math.max(...e);if(!this.dynamicSize&&n>=this.maxSize){throw new Error(`Max index must be < array size (${n}  vs. ${this.maxSize})`)}this.writeMany(e,unstack(t,0));}split(e,t){if(t.dtype!==this.dtype){throw new Error(`TensorArray dtype is ${this.dtype} but tensor has dtype ${t.dtype}`)}let n=0;const r=e.map((e=>{n+=e;return n}));if(n!==t.shape[0]){throw new Error(`Expected sum of lengths to be equal to\n          tensor.shape[0], but sum of lengths is\n        ${n}, and tensor's shape is: ${t.shape}`)}if(!this.dynamicSize&&e.length!==this.maxSize){throw new Error(`TensorArray's size is not equal to the size of lengths (${this.maxSize} vs. ${e.length}), `+"and the TensorArray is not marked as dynamically resizeable")}const s=n===0?0:t.size/n;const a=[];tidy((()=>{t=reshape$1(t,[1,n,s]);for(let n=0;n<e.length;++n){const o=n===0?0:r[n-1];const i=[0,o,0];const u=[1,e[n],s];a[n]=reshape$1(slice$1(t,i,u),this.elementShape);}return a}));const o=[];for(let t=0;t<e.length;t++){o[t]=t;}this.writeMany(o,a);}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class TensorList{constructor(e,t,n,r=-1){this.tensors=e;this.elementShape=t;this.elementDtype=n;if(e!=null){e.forEach((e=>{if(n!==e.dtype){throw new Error(`Invalid data types; op elements ${n}, but list elements ${e.dtype}`)}assertShapesMatchAllowUndefinedSize(t,e.shape,"TensorList shape mismatch: ");keep(e);}));}this.idTensor=scalar(0);this.maxNumElements=r;keep(this.idTensor);}get id(){return this.idTensor.id}copy(){return new TensorList([...this.tensors],this.elementShape,this.elementDtype)}clearAndClose(e){this.tensors.forEach((t=>{if(e==null||!e.has(t.id)){t.dispose();}}));this.tensors.length=0;this.idTensor.dispose();}size(){return this.tensors.length}stack(e,t,n=-1){if(t!==this.elementDtype){throw new Error(`Invalid data types; op elements ${t}, but list elements ${this.elementDtype}`)}if(n!==-1&&this.tensors.length!==n){throw new Error(`Operation expected a list with ${n} elements but got a list with ${this.tensors.length} elements.`)}assertShapesMatchAllowUndefinedSize(e,this.elementShape,"TensorList shape mismatch: ");const r=inferElementShape(this.elementShape,this.tensors,e);return tidy((()=>{const e=this.tensors.map((e=>reshape$1(e,r)));return stack(e,0)}))}popBack(e,t){if(t!==this.elementDtype){throw new Error(`Invalid data types; op elements ${t}, but list elements ${this.elementDtype}`)}if(this.size()===0){throw new Error("Trying to pop from an empty list.")}const n=inferElementShape(this.elementShape,this.tensors,e);const r=this.tensors.pop();assertShapesMatchAllowUndefinedSize(r.shape,e,"TensorList shape mismatch: ");return reshape$1(r,n)}pushBack(e){if(e.dtype!==this.elementDtype){throw new Error(`Invalid data types; op elements ${e.dtype}, but list elements ${this.elementDtype}`)}assertShapesMatchAllowUndefinedSize(e.shape,this.elementShape,"TensorList shape mismatch: ");if(this.maxNumElements===this.size()){throw new Error(`Trying to push element into a full list.`)}keep(e);this.tensors.push(e);}resize(e){if(e<0){throw new Error(`TensorListResize expects size to be non-negative. Got: ${e}`)}if(this.maxNumElements!==-1&&e>this.maxNumElements){throw new Error(`TensorListResize input size ${e} is greater maxNumElement ${this.maxNumElements}.`)}this.tensors.length=e;}getItem(e,t,n){if(n!==this.elementDtype){throw new Error(`Invalid data types; op elements ${n}, but list elements ${this.elementDtype}`)}if(e<0||e>this.tensors.length){throw new Error(`Trying to access element ${e} in a list with ${this.tensors.length} elements.`)}if(this.tensors[e]==null){throw new Error(`element at index ${e} is null.`)}assertShapesMatchAllowUndefinedSize(this.tensors[e].shape,t,"TensorList shape mismatch: ");const r=inferElementShape(this.elementShape,this.tensors,t);return reshape$1(this.tensors[e],r)}setItem(e,t){if(t.dtype!==this.elementDtype){throw new Error(`Invalid data types; op elements ${t.dtype}, but list elements ${this.elementDtype}`)}if(e<0||this.maxNumElements!==-1&&e>=this.maxNumElements){throw new Error(`Trying to set element ${e} in a list with max ${this.maxNumElements} elements.`)}assertShapesMatchAllowUndefinedSize(this.elementShape,t.shape,"TensorList shape mismatch: ");keep(t);this.tensors[e]=t;}gather(e,t,n){if(t!==this.elementDtype){throw new Error(`Invalid data types; op elements ${t}, but list elements ${this.elementDtype}`)}assertShapesMatchAllowUndefinedSize(this.elementShape,n,"TensorList shape mismatch: ");e=e.slice(0,this.size());const r=inferElementShape(this.elementShape,this.tensors,n);if(e.length===0){return tensor([],[0].concat(r))}return tidy((()=>{const t=e.map((e=>reshape$1(this.tensors[e],r)));return stack(t,0)}))}concat(e,t){if(!!e&&e!==this.elementDtype){throw new Error(`TensorList dtype is ${this.elementDtype} but concat requested dtype ${e}`)}assertShapesMatchAllowUndefinedSize(this.elementShape,t,"TensorList shape mismatch: ");const n=inferElementShape(this.elementShape,this.tensors,t);if(this.size()===0){return tensor([],[0].concat(n))}return tidy((()=>{const e=this.tensors.map((e=>reshape$1(e,n)));return concat$1(e,0)}))}}function fromTensor(e,t,n){const r=e.dtype;if(e.shape.length<1){throw new Error(`Tensor must be at least a vector, but saw shape: ${e.shape}`)}if(e.dtype!==n){throw new Error(`Invalid data types; op elements ${e.dtype}, but list elements ${n}`)}const s=e.shape.slice(1);assertShapesMatchAllowUndefinedSize(s,t,"TensorList shape mismatch: ");const a=unstack(e);return new TensorList(a,t,r)}function reserve(e,t,n){return new TensorList([],e,t,n)}function scatter(e,t,n,r){if(t.length!==e.shape[0]){throw new Error(`Expected len(indices) == tensor.shape[0], but saw: ${t.length} vs. ${e.shape[0]}`)}const s=Math.max(...t);if(r!=null&&r!==-1&&s>=r){throw new Error(`Max index must be < array size (${s}  vs. ${r})`)}const a=new TensorList([],n,e.dtype,r);const o=unstack(e,0);t.forEach(((e,t)=>{a.setItem(e,o[t]);}));return a}function split$1(e,t,n){let r=0;const s=t.map((e=>{r+=e;return r}));if(r!==e.shape[0]){throw new Error(`Expected sum of lengths to be equal to\n          tensor.shape[0], but sum of lengths is\n        ${r}, and tensor's shape is: ${e.shape}`)}const a=e.shape.slice(1);const o=mergeElementShape(a,n);const i=r===0?0:e.size/r;const u=tidy((()=>{const n=[];e=reshape$1(e,[1,r,i]);for(let r=0;r<t.length;++r){const a=r===0?0:s[r-1];const u=[0,a,0];const c=[1,t[r],i];n[r]=reshape$1(slice$1(e,u,c),o);}e.dispose();return n}));const c=new TensorList([],n,e.dtype,t.length);for(let e=0;e<u.length;e++){c.setItem(e,u[e]);}return c}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$h=async(e,t,n)=>{switch(e.op){case"If":case"StatelessIf":{const r=getParamValue("thenBranch",e,t,n);const s=getParamValue("elseBranch",e,t,n);const a=getParamValue("cond",e,t,n);const o=getParamValue("args",e,t,n);const i=await a.data();if(i[0]){return n.functionMap[r].executeFunctionAsync(o,n.tensorArrayMap,n.tensorListMap)}else {return n.functionMap[s].executeFunctionAsync(o,n.tensorArrayMap,n.tensorListMap)}}case"While":case"StatelessWhile":{const r=getParamValue("body",e,t,n);const s=getParamValue("cond",e,t,n);const a=getParamValue("args",e,t,n);const o=await n.functionMap[s].executeFunctionAsync(a,n.tensorArrayMap,n.tensorListMap);const i=a.map((e=>e.id));let u=await o[0].data();o.forEach((e=>{if(!e.kept&&i.indexOf(e.id)===-1){e.dispose();}}));let c=a;while(u[0]){const e=c;c=await n.functionMap[r].executeFunctionAsync(c,n.tensorArrayMap,n.tensorListMap);const t=c.map((e=>e.id));e.forEach((e=>{if(!e.kept&&i.indexOf(e.id)===-1&&t.indexOf(e.id)===-1){e.dispose();}}));const a=await n.functionMap[s].executeFunctionAsync(c,n.tensorArrayMap,n.tensorListMap);u=await a[0].data();a.forEach((e=>{if(!e.kept&&i.indexOf(e.id)===-1&&t.indexOf(e.id)===-1){e.dispose();}}));}return c}case"LoopCond":{const r=getParamValue("pred",e,t,n);return [cloneTensor(r)]}case"Switch":{const r=getParamValue("pred",e,t,n);let s=getParamValue("data",e,t,n);if(!s.kept){s=cloneTensor(s);}return (await r.data())[0]?[undefined,s]:[s,undefined]}case"Merge":{const r=e.inputNames.find((e=>getTensor(e,t,n)!==undefined));if(r){const e=getTensor(r,t,n);return [cloneTensor(e)]}return undefined}case"Enter":{const r=getParamValue("frameName",e,t,n);const s=getParamValue("tensor",e,t,n);n.enterFrame(r);return [cloneTensor(s)]}case"Exit":{const r=getParamValue("tensor",e,t,n);n.exitFrame();return [cloneTensor(r)]}case"NextIteration":{const r=getParamValue("tensor",e,t,n);n.nextIteration();return [cloneTensor(r)]}case"TensorArrayV3":{const r=getParamValue("size",e,t,n);const s=getParamValue("dtype",e,t,n);const a=getParamValue("elementShape",e,t,n);const o=getParamValue("dynamicSize",e,t,n);const i=getParamValue("clearAfterRead",e,t,n);const u=getParamValue("identicalElementShapes",e,t,n);const c=getParamValue("name",e,t,n);const l=new TensorArray(c,s,r,a,u,o,i);n.addTensorArray(l);return [l.idTensor,scalar(1)]}case"TensorArrayWriteV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=getParamValue("index",e,t,n);const a=getParamValue("tensor",e,t,n);const o=n.getTensorArray(r.id);o.write(s,a);return [o.idTensor]}case"TensorArrayReadV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=getParamValue("index",e,t,n);const a=n.getTensorArray(r.id);return [a.read(s)]}case"TensorArrayGatherV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=getParamValue("indices",e,t,n);const a=getParamValue("dtype",e,t,n);const o=n.getTensorArray(r.id);return [o.gather(s,a)]}case"TensorArrayScatterV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=getParamValue("indices",e,t,n);const a=getParamValue("tensor",e,t,n);const o=n.getTensorArray(r.id);o.scatter(s,a);return [o.idTensor]}case"TensorArrayConcatV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=n.getTensorArray(r.id);const a=getParamValue("dtype",e,t,n);return [s.concat(a)]}case"TensorArraySplitV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=getParamValue("tensor",e,t,n);const a=getParamValue("lengths",e,t,n);const o=n.getTensorArray(r.id);o.split(a,s);return [o.idTensor]}case"TensorArraySizeV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=n.getTensorArray(r.id);return [scalar(s.size(),"int32")]}case"TensorArrayCloseV3":{const r=getParamValue("tensorArrayId",e,t,n);const s=n.getTensorArray(r.id);s.clearAndClose();return [s.idTensor]}case"TensorListSetItem":{const r=getParamValue("tensorListId",e,t,n);const s=getParamValue("index",e,t,n);const a=getParamValue("tensor",e,t,n);const o=n.getTensorList(r.id);o.setItem(s,a);return [o.idTensor]}case"TensorListGetItem":{const r=getParamValue("tensorListId",e,t,n);const s=getParamValue("index",e,t,n);const a=getParamValue("elementShape",e,t,n);const o=getParamValue("elementDType",e,t,n);const i=n.getTensorList(r.id);return [i.getItem(s,a,o)]}case"TensorListScatterV2":case"TensorListScatter":{const r=getParamValue("indices",e,t,n);const s=getParamValue("tensor",e,t,n);const a=getParamValue("elementShape",e,t,n);const o=getParamValue("numElements",e,t,n);const i=scatter(s,r,a,o);n.addTensorList(i);return [i.idTensor]}case"TensorListReserve":case"EmptyTensorList":{const r=getParamValue("elementShape",e,t,n);const s=getParamValue("elementDType",e,t,n);let a;if(e.op==="TensorListReserve"){a="numElements";}else {a="maxNumElements";}const o=getParamValue(a,e,t,n);const i=reserve(r,s,o);n.addTensorList(i);return [i.idTensor]}case"TensorListGather":{const r=getParamValue("tensorListId",e,t,n);const s=getParamValue("indices",e,t,n);const a=getParamValue("elementShape",e,t,n);const o=getParamValue("elementDType",e,t,n);const i=n.getTensorList(r.id);return [i.gather(s,o,a)]}case"TensorListStack":{const r=getParamValue("tensorListId",e,t,n);const s=getParamValue("elementShape",e,t,n);const a=getParamValue("elementDType",e,t,n);const o=getParamValue("numElements",e,t,n);const i=n.getTensorList(r.id);return [i.stack(s,a,o)]}case"TensorListFromTensor":{const r=getParamValue("tensor",e,t,n);const s=getParamValue("elementShape",e,t,n);const a=getParamValue("elementDType",e,t,n);const o=fromTensor(r,s,a);n.addTensorList(o);return [o.idTensor]}case"TensorListConcat":{const r=getParamValue("tensorListId",e,t,n);const s=n.getTensorList(r.id);const a=getParamValue("dtype",e,t,n);const o=getParamValue("elementShape",e,t,n);return [s.concat(a,o)]}case"TensorListPushBack":{const r=getParamValue("tensorListId",e,t,n);const s=getParamValue("tensor",e,t,n);const a=n.getTensorList(r.id);a.pushBack(s);return [a.idTensor]}case"TensorListPopBack":{const r=getParamValue("tensorListId",e,t,n);const s=getParamValue("elementShape",e,t,n);const a=getParamValue("elementDType",e,t,n);const o=n.getTensorList(r.id);return [o.popBack(s,a)]}case"TensorListSplit":{const r=getParamValue("tensor",e,t,n);const s=getParamValue("elementShape",e,t,n);const a=getParamValue("lengths",e,t,n);const o=split$1(r,a,s);n.addTensorList(o);return [o.idTensor]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function fusedConvAndDepthWiseParams(e,t,n){const[r,s]=getParamValue("fusedOps",e,t,n);const a=r==="biasadd";const o=!a;const i=s==="prelu";const u=r==="fusedbatchnorm";const c=getParamValue("numArgs",e,t,n);if(a){if(i&&c!==2){throw new Error("FusedConv2d and DepthwiseConv2d with BiasAdd and Prelu "+"must have two extra arguments: bias and alpha.")}if(!i&&a&&c!==1){throw new Error("FusedConv2d and DepthwiseConv2d with BiasAdd must have "+"one extra argument: bias.")}}if(u){throw new Error("FusedConv2d and DepthwiseConv2d with FusedBatchNorm is not supported")}const l=getParamValue("strides",e,t,n);const p=getPadding(e,t,n);const d=getParamValue("dataFormat",e,t,n).toUpperCase();const h=getParamValue("dilations",e,t,n);let[m,f]=getParamValue("args",e,t,n);if(o){f=m;m=undefined;}const g=getParamValue("leakyreluAlpha",e,t,n);return {stride:l,pad:p,dataFormat:d,dilations:h,biasArg:m,preluArg:f,activationFunc:s,leakyreluAlpha:g}}const executeOp$g=(e,t,n)=>{switch(e.op){case"Conv1D":{const r=getParamValue("stride",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("dataFormat",e,t,n).toUpperCase();const o=getParamValue("dilation",e,t,n);return [conv1d(getParamValue("x",e,t,n),getParamValue("filter",e,t,n),r,s,a,o)]}case"Conv2D":{const r=getParamValue("strides",e,t,n);const s=getPadding(e,t,n);const a=getParamValue("dataFormat",e,t,n).toUpperCase();const o=getParamValue("dilations",e,t,n);return [conv2d$1(getParamValue("x",e,t,n),getParamValue("filter",e,t,n),[r[1],r[2]],s,a,[o[1],o[2]])]}case"_FusedConv2D":{const{stride:r,pad:s,dataFormat:a,dilations:o,biasArg:i,preluArg:u,activationFunc:c,leakyreluAlpha:l}=fusedConvAndDepthWiseParams(e,t,n);return [conv2d({x:getParamValue("x",e,t,n),filter:getParamValue("filter",e,t,n),strides:[r[1],r[2]],pad:s,dataFormat:a,dilations:[o[1],o[2]],bias:i,activation:c,preluActivationWeights:u,leakyreluAlpha:l})]}case"FusedDepthwiseConv2dNative":{const{stride:r,pad:s,dataFormat:a,dilations:o,biasArg:i,preluArg:u,activationFunc:c,leakyreluAlpha:l}=fusedConvAndDepthWiseParams(e,t,n);return [depthwiseConv2d({x:getParamValue("x",e,t,n),filter:getParamValue("filter",e,t,n),strides:[r[1],r[2]],pad:s,dataFormat:a,dilations:[o[1],o[2]],bias:i,activation:c,preluActivationWeights:u,leakyreluAlpha:l})]}case"Conv2DBackpropInput":case"Conv2dTranspose":{const r=getParamValue("outputShape",e,t,n);const s=getParamValue("strides",e,t,n);const a=getPadding(e,t,n);return [conv2dTranspose(getParamValue("x",e,t,n),getParamValue("filter",e,t,n),r,[s[1],s[2]],a)]}case"DepthwiseConv2dNative":case"DepthwiseConv2d":{const r=getParamValue("strides",e,t,n);const s=getPadding(e,t,n);const a=getParamValue("dilations",e,t,n);const o=getParamValue("dataFormat",e,t,n).toUpperCase();return [depthwiseConv2d$1(getParamValue("input",e,t,n),getParamValue("filter",e,t,n),[r[1],r[2]],s,o,[a[1],a[2]])]}case"Conv3D":{const r=getParamValue("strides",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("dataFormat",e,t,n).toUpperCase();const o=getParamValue("dilations",e,t,n);return [conv3d(getParamValue("x",e,t,n),getParamValue("filter",e,t,n),[r[1],r[2],r[3]],s,a,[o[1],o[2],o[3]])]}case"AvgPool":{const r=getParamValue("strides",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("kernelSize",e,t,n);return [avgPool(getParamValue("x",e,t,n),[a[1],a[2]],[r[1],r[2]],s)]}case"MaxPool":{const r=getParamValue("strides",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("kernelSize",e,t,n);return [maxPool(getParamValue("x",e,t,n),[a[1],a[2]],[r[1],r[2]],s)]}case"MaxPoolWithArgmax":{const r=getParamValue("strides",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("kernelSize",e,t,n);const o=getParamValue("includeBatchInIndex",e,t,n);const{result:i,indexes:u}=maxPoolWithArgmax(getParamValue("x",e,t,n),[a[1],a[2]],[r[1],r[2]],s,o);return [i,u]}case"AvgPool3D":{const r=getParamValue("strides",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("kernelSize",e,t,n);return [avgPool3d(getParamValue("x",e,t,n),[a[1],a[2],a[3]],[r[1],r[2],r[3]],s)]}case"MaxPool3D":{const r=getParamValue("strides",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("kernelSize",e,t,n);return [maxPool3d(getParamValue("x",e,t,n),[a[1],a[2],a[3]],[r[1],r[2],r[3]],s)]}case"Dilation2D":{const r=getParamValue("strides",e,t,n);const s=getParamValue("pad",e,t,n);const a=getParamValue("dilations",e,t,n);const o=r[1];const i=r[2];const u=a[1];const c=a[2];return [dilation2d(getParamValue("x",e,t,n),getParamValue("filter",e,t,n),[o,i],s,[u,c],"NHWC")]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$f=(e,t,n)=>{switch(e.op){case"Fill":{const r=getParamValue("shape",e,t,n);const s=getParamValue("dtype",e,t,n);const a=getParamValue("value",e,t,n);return [fill(r,a,s)]}case"LinSpace":{const r=getParamValue("start",e,t,n);const s=getParamValue("stop",e,t,n);const a=getParamValue("num",e,t,n);return [linspace(r,s,a)]}case"Multinomial":{const r=getParamValue("logits",e,t,n);const s=getParamValue("numSamples",e,t,n);const a=getParamValue("seed",e,t,n);return [multinomial(r,s,a)]}case"OneHot":{const r=getParamValue("indices",e,t,n);const s=getParamValue("depth",e,t,n);const a=getParamValue("onValue",e,t,n);const o=getParamValue("offValue",e,t,n);return [oneHot(r,s,a,o)]}case"Ones":{return [ones(getParamValue("shape",e,t,n),getParamValue("dtype",e,t,n))]}case"OnesLike":{return [onesLike(getParamValue("x",e,t,n))]}case"RandomUniform":{return [randomUniform(getParamValue("shape",e,t,n),getParamValue("minval",e,t,n),getParamValue("maxval",e,t,n),getParamValue("dtype",e,t,n))]}case"Range":{const r=getParamValue("start",e,t,n);const s=getParamValue("stop",e,t,n);const a=getParamValue("step",e,t,n);return [range(r,s,a,getParamValue("dtype",e,t,n))]}case"TruncatedNormal":{const r=getParamValue("shape",e,t,n);const s=getParamValue("mean",e,t,n);const a=getParamValue("stdDev",e,t,n);const o=getParamValue("seed",e,t,n);return [truncatedNormal(r,s,a,getParamValue("dtype",e,t,n),o)]}case"Zeros":{return [zeros(getParamValue("shape",e,t,n),getParamValue("dtype",e,t,n))]}case"ZerosLike":{return [zerosLike(getParamValue("x",e,t,n))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function nmsParams(e,t,n){const r=getParamValue("boxes",e,t,n);const s=getParamValue("scores",e,t,n);const a=getParamValue("maxOutputSize",e,t,n);const o=getParamValue("iouThreshold",e,t,n);const i=getParamValue("scoreThreshold",e,t,n);const u=getParamValue("softNmsSigma",e,t,n);return {boxes:r,scores:s,maxOutputSize:a,iouThreshold:o,scoreThreshold:i,softNmsSigma:u}}const executeOp$e=async(e,t,n)=>{switch(e.op){case"NonMaxSuppressionV5":{const{boxes:r,scores:s,maxOutputSize:a,iouThreshold:o,scoreThreshold:i,softNmsSigma:u}=nmsParams(e,t,n);const c=await image$1.nonMaxSuppressionWithScoreAsync(r,s,a,o,i,u);return [c.selectedIndices,c.selectedScores]}case"NonMaxSuppressionV4":{const{boxes:r,scores:s,maxOutputSize:a,iouThreshold:o,scoreThreshold:i}=nmsParams(e,t,n);const u=getParamValue("padToMaxOutputSize",e,t,n);const c=await image$1.nonMaxSuppressionPaddedAsync(r,s,a,o,i,u);return [c.selectedIndices,c.validOutputs]}case"NonMaxSuppressionV3":case"NonMaxSuppressionV2":{const{boxes:r,scores:s,maxOutputSize:a,iouThreshold:o,scoreThreshold:i}=nmsParams(e,t,n);return [await image$1.nonMaxSuppressionAsync(r,s,a,o,i)]}case"Where":{const r=cast$1(getParamValue("condition",e,t,n),"bool");const s=[await whereAsync(r)];r.dispose();return s}case"ListDiff":{return setdiff1dAsync(getParamValue("x",e,t,n),getParamValue("y",e,t,n))}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$d=(e,t,n)=>{switch(e.op){case"TopKV2":{const r=getParamValue("x",e,t,n);const s=getParamValue("k",e,t,n);const a=getParamValue("sorted",e,t,n);const o=topk(r,s,a);return [o.values,o.indices]}case"Unique":{const r=getParamValue("x",e,t,n);const s=unique(r);return [s.values,s.indices]}case"UniqueV2":{const r=getParamValue("x",e,t,n);const s=getParamValue("axis",e,t,n);const a=unique(r,s);return [a.values,a.indices]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$c=(e,t,n)=>{switch(e.op){case"Const":{return t[e.name]}case"PlaceholderWithDefault":const r=getParamValue("default",e,t,n);return [getTensor(e.name,t,n)||r];case"Placeholder":return [getTensor(e.name,t,n)];case"Identity":case"StopGradient":case"FakeQuantWithMinMaxVars":{const r=getParamValue("x",e,t,n);return [cloneTensor(r)]}case"IdentityN":return getParamValue("x",e,t,n).map((e=>cloneTensor(e)));case"Snapshot":const s=getParamValue("x",e,t,n);return [cloneTensor(s)];case"Shape":return [tensor1d(getParamValue("x",e,t,n).shape,"int32")];case"ShapeN":return getParamValue("x",e,t,n).map((e=>tensor1d(e.shape)));case"Size":return [scalar(getParamValue("x",e,t,n).size,"int32")];case"Rank":return [scalar(getParamValue("x",e,t,n).rank,"int32")];case"NoOp":return [scalar(1)];case"Print":const a=getParamValue("x",e,t,n);const o=getParamValue("data",e,t,n);const i=getParamValue("message",e,t,n);const u=getParamValue("summarize",e,t,n);console.warn("The graph has a tf.print() operation,"+"usually used for debugging, which slows down performance.");console.log(i);for(let e=0;e<o.length;e++){console.log(Array.prototype.slice.call(o[e].dataSync()).slice(0,u));}return [a];default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class HashTable{constructor(e,t){this.keyDType=e;this.valueDType=t;this.handle=scalar(0);this.tensorMap=new Map;keep(this.handle);}get id(){return this.handle.id}clearAndClose(){this.tensorMap.forEach((e=>e.dispose()));this.tensorMap.clear();this.handle.dispose();}size(){return this.tensorMap.size}tensorSize(){return scalar(this.size(),"int32")}async import(e,t){this.checkKeyAndValueTensor(e,t);const n=await e.data();this.tensorMap.forEach((e=>e.dispose()));this.tensorMap.clear();return tidy((()=>{const e=unstack(t);const r=n.length;const s=e.length;assert(r===s,(()=>`The number of elements doesn't match, keys has `+`${r} elements, the values has ${s} `+`elements.`));for(let t=0;t<r;t++){const r=n[t];const s=e[t];keep(s);this.tensorMap.set(r,s);}return this.handle}))}async find(e,t){this.checkKeyAndValueTensor(e,t);const n=await e.data();return tidy((()=>{const e=[];for(let r=0;r<n.length;r++){const s=n[r];const a=this.findWithDefault(s,t);e.push(a);}return stack(e)}))}findWithDefault(e,t){const n=this.tensorMap.get(e);return n!=null?n:t}checkKeyAndValueTensor(e,t){if(e.dtype!==this.keyDType){throw new Error(`Expect key dtype ${this.keyDType}, but got `+`${e.dtype}`)}if(t.dtype!==this.valueDType){throw new Error(`Expect value dtype ${this.valueDType}, but got `+`${t.dtype}`)}}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$b=async(e,t,n,r)=>{switch(e.op){case"HashTable":case"HashTableV2":{const s=getParamValue("keyDType",e,t,n);const a=getParamValue("valueDType",e,t,n);const o=new HashTable(s,a);r.addHashTable(e.name,o);return [o.handle]}case"LookupTableImport":case"LookupTableImportV2":{const s=getParamValue("tableHandle",e,t,n,r);const a=getParamValue("keys",e,t,n);const o=getParamValue("values",e,t,n);const i=r.getHashTableById(s.id);return [await i.import(a,o)]}case"LookupTableFind":case"LookupTableFindV2":{const s=getParamValue("tableHandle",e,t,n,r);const a=getParamValue("keys",e,t,n);const o=getParamValue("defaultValue",e,t,n);const i=r.getHashTableById(s.id);return [await i.find(a,o)]}case"LookupTableSize":case"LookupTableSizeV2":{const s=getParamValue("tableHandle",e,t,n,r);const a=r.getHashTableById(s.id);return [a.tensorSize()]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$a=(e,t,n)=>{switch(e.op){case"ResizeBilinear":{const r=getParamValue("images",e,t,n);const s=getParamValue("size",e,t,n);const a=getParamValue("alignCorners",e,t,n);const o=getParamValue("halfPixelCenters",e,t,n);return [image$1.resizeBilinear(r,[s[0],s[1]],a,o)]}case"ResizeNearestNeighbor":{const r=getParamValue("images",e,t,n);const s=getParamValue("size",e,t,n);const a=getParamValue("alignCorners",e,t,n);const o=getParamValue("halfPixelCenters",e,t,n);return [image$1.resizeNearestNeighbor(r,[s[0],s[1]],a,o)]}case"CropAndResize":{const r=getParamValue("image",e,t,n);const s=getParamValue("boxes",e,t,n);const a=getParamValue("boxInd",e,t,n);const o=getParamValue("cropSize",e,t,n);const i=getParamValue("method",e,t,n);const u=getParamValue("extrapolationValue",e,t,n);return [image$1.cropAndResize(r,s,a,o,i,u)]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$9=(e,t,n)=>{switch(e.op){case"Equal":{return [equal(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"NotEqual":{return [notEqual$1(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"Greater":{return [greater(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"GreaterEqual":{return [greaterEqual(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"Less":{return [less(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"LessEqual":{return [lessEqual(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"LogicalAnd":{return [logicalAnd(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"LogicalNot":{return [logicalNot(getParamValue("a",e,t,n))]}case"LogicalOr":{return [logicalOr(getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}case"Select":case"SelectV2":{return [where(getParamValue("condition",e,t,n),getParamValue("a",e,t,n),getParamValue("b",e,t,n))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$8=(e,t,n)=>{switch(e.op){case"BatchMatMul":case"BatchMatMulV2":case"MatMul":return [matMul$1(getParamValue("a",e,t,n),getParamValue("b",e,t,n),getParamValue("transposeA",e,t,n),getParamValue("transposeB",e,t,n))];case"Einsum":return [einsum(getParamValue("equation",e,t,n),...getParamValue("tensors",e,t,n))];case"Transpose":return [transpose$1(getParamValue("x",e,t,n),getParamValue("perm",e,t,n))];case"_FusedMatMul":const[r,s]=getParamValue("fusedOps",e,t,n);const a=r==="biasadd";const o=s==="prelu";const i=getParamValue("numArgs",e,t,n);const u=getParamValue("leakyreluAlpha",e,t,n);if(a){if(o&&i!==2){throw new Error("Fused MatMul with BiasAdd and Prelu must have two "+"extra arguments: bias and alpha.")}if(!o&&i!==1){throw new Error("Fused MatMul with BiasAdd must have one extra argument: bias.")}}const[c,l]=getParamValue("args",e,t,n);return [matMul({a:getParamValue("a",e,t,n),b:getParamValue("b",e,t,n),transposeA:getParamValue("transposeA",e,t,n),transposeB:getParamValue("transposeB",e,t,n),bias:c,activation:s,preluActivationWeights:l,leakyreluAlpha:u})];default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$7=(e,t,n)=>{switch(e.op){case"FusedBatchNorm":case"FusedBatchNormV2":{return [batchNorm(getParamValue("x",e,t,n),getParamValue("mean",e,t,n),getParamValue("variance",e,t,n),getParamValue("offset",e,t,n),getParamValue("scale",e,t,n),getParamValue("epsilon",e,t,n))]}case"FusedBatchNormV3":{return [batchNorm(getParamValue("x",e,t,n),getParamValue("mean",e,t,n),getParamValue("variance",e,t,n),getParamValue("offset",e,t,n),getParamValue("scale",e,t,n),getParamValue("epsilon",e,t,n))]}case"LRN":{return [localResponseNormalization(getParamValue("x",e,t,n),getParamValue("radius",e,t,n),getParamValue("bias",e,t,n),getParamValue("alpha",e,t,n),getParamValue("beta",e,t,n))]}case"Softmax":{return [softmax(getParamValue("x",e,t,n))]}case"LogSoftmax":{return [logSoftmax(getParamValue("x",e,t,n))]}case"SparseToDense":{return [sparseToDense(getParamValue("sparseIndices",e,t,n),getParamValue("outputShape",e,t,n),getParamValue("sparseValues",e,t,n),getParamValue("defaultValue",e,t,n))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$6=(e,t,n)=>{switch(e.op){case"Max":{const r=getParamValue("axis",e,t,n);const s=getParamValue("keepDims",e,t,n);return [max(getParamValue("x",e,t,n),r,s)]}case"Mean":{const r=getParamValue("axis",e,t,n);const s=getParamValue("keepDims",e,t,n);return [mean(getParamValue("x",e,t,n),r,s)]}case"Min":{const r=getParamValue("axis",e,t,n);const s=getParamValue("keepDims",e,t,n);return [min(getParamValue("x",e,t,n),r,s)]}case"Sum":{const r=getParamValue("axis",e,t,n);const s=getParamValue("keepDims",e,t,n);return [sum$1(getParamValue("x",e,t,n),r,s)]}case"All":{const r=getParamValue("axis",e,t,n);const s=getParamValue("keepDims",e,t,n);return [all(getParamValue("x",e,t,n),r,s)]}case"Any":{const r=getParamValue("axis",e,t,n);const s=getParamValue("keepDims",e,t,n);return [any(getParamValue("x",e,t,n),r,s)]}case"ArgMax":{const r=getParamValue("axis",e,t,n);return [argMax(getParamValue("x",e,t,n),r)]}case"ArgMin":{const r=getParamValue("axis",e,t,n);return [argMin(getParamValue("x",e,t,n),r)]}case"Prod":{const r=getParamValue("axis",e,t,n);const s=getParamValue("keepDims",e,t,n);return [prod$1(getParamValue("x",e,t,n),r,s)]}case"Cumsum":{const r=getParamValue("axis",e,t,n);const s=getParamValue("exclusive",e,t,n);const a=getParamValue("reverse",e,t,n);return [cumsum(getParamValue("x",e,t,n),r,s,a)]}case"Bincount":const r=getParamValue("x",e,t,n);const s=getParamValue("weights",e,t,n);const a=getParamValue("size",e,t,n);return [bincount(r,s,a)];case"DenseBincount":{const r=getParamValue("x",e,t,n);const s=getParamValue("weights",e,t,n);const a=getParamValue("size",e,t,n);const o=getParamValue("binaryOutput",e,t,n);return [denseBincount(r,s,a,o)]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$5=(e,t,n)=>{switch(e.op){case"ConcatV2":case"Concat":{const r=getParamValue("n",e,t,n);const s=getParamValue("axis",e,t,n);let a=getParamValue("tensors",e,t,n);a=a.slice(0,r);return [concat$1(a,s)]}case"Gather":{const r=getParamValue("x",e,t,n);const s=getParamValue("indices",e,t,n);return [gather(r,cast$1(s,"int32"),0)]}case"GatherV2":{const r=getParamValue("axis",e,t,n);const s=getParamValue("batchDims",e,t,n);const a=getParamValue("x",e,t,n);const o=getParamValue("indices",e,t,n);return [gather(a,cast$1(o,"int32"),r,s)]}case"Reverse":{const r=getParamValue("dims",e,t,n);const s=[];for(let e=0;e<r.length;e++){if(r[e]){s.push(e);}}const a=getParamValue("x",e,t,n);return [reverse(a,s)]}case"ReverseV2":{const r=getParamValue("axis",e,t,n);const s=getParamValue("x",e,t,n);return [reverse(s,r)]}case"Slice":{const r=getParamValue("begin",e,t,n);const s=getParamValue("size",e,t,n);return [slice$1(getParamValue("x",e,t,n),r,s)]}case"StridedSlice":{const r=getParamValue("begin",e,t,n);const s=getParamValue("end",e,t,n);const a=getParamValue("strides",e,t,n);const o=getParamValue("beginMask",e,t,n);const i=getParamValue("endMask",e,t,n);const u=getParamValue("ellipsisMask",e,t,n);const c=getParamValue("newAxisMask",e,t,n);const l=getParamValue("shrinkAxisMask",e,t,n);const p=getParamValue("x",e,t,n);return [stridedSlice(p,r,s,a,o,i,u,c,l)]}case"Pack":{return tidy((()=>{const r=getParamValue("axis",e,t,n);const s=getParamValue("tensors",e,t,n);const a=s[0].shape;const o=squeeze(s[0]).shape;const i=s.map((e=>{const t=arraysEqual(e.shape,a);if(!t&&!arraysEqual(squeeze(e).shape,o)){throw new Error("the input tensors shape does not match")}return t?e:reshape$1(e,a)}));return [stack(i,r)]}))}case"Unpack":{const r=getParamValue("axis",e,t,n);const s=getParamValue("tensor",e,t,n);return unstack(s,r)}case"Tile":{const r=getParamValue("reps",e,t,n);return [tile(getParamValue("x",e,t,n),r)]}case"Split":case"SplitV":{const r=getParamValue("axis",e,t,n);const s=getParamValue("numOrSizeSplits",e,t,n);const a=getParamValue("x",e,t,n);return split$2(a,s,r)}case"ScatterNd":{const r=getParamValue("indices",e,t,n);const s=getParamValue("values",e,t,n);const a=getParamValue("shape",e,t,n);return [scatterND(r,s,a)]}case"GatherNd":{const r=getParamValue("x",e,t,n);const s=getParamValue("indices",e,t,n);return [gatherND(r,s)]}case"SparseToDense":{const r=getParamValue("sparseIndices",e,t,n);const s=getParamValue("outputShape",e,t,n);const a=getParamValue("sparseValues",e,t,n);const o=getParamValue("defaultValue",e,t,n);return [sparseToDense(r,a,s,a.dtype===o.dtype?o:cast$1(o,a.dtype))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$4=(e,t,n)=>{switch(e.op){case"SparseFillEmptyRows":{const{outputIndices:r,outputValues:s,emptyRowIndicator:a,reverseIndexMap:o}=sparse$1.sparseFillEmptyRows(getParamValue("indices",e,t,n),getParamValue("values",e,t,n),getParamValue("denseShape",e,t,n),getParamValue("defaultValue",e,t,n));return [r,s,a,o]}case"SparseReshape":{const{outputIndices:r,outputShape:s}=sparse$1.sparseReshape(getParamValue("inputIndices",e,t,n),getParamValue("inputShape",e,t,n),getParamValue("newShape",e,t,n));return [r,s]}case"SparseSegmentMean":{const r=sparse$1.sparseSegmentMean(getParamValue("data",e,t,n),getParamValue("indices",e,t,n),getParamValue("segmentIds",e,t,n));return [r]}case"SparseSegmentSum":{const r=sparse$1.sparseSegmentSum(getParamValue("data",e,t,n),getParamValue("indices",e,t,n),getParamValue("segmentIds",e,t,n));return [r]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$3=(e,t,n)=>{switch(e.op){case"FFT":{return [fft(getParamValue("x",e,t,n))]}case"IFFT":{return [ifft(getParamValue("x",e,t,n))]}case"RFFT":{return [rfft(getParamValue("x",e,t,n))]}case"IRFFT":{return [irfft(getParamValue("x",e,t,n))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$2=(e,t,n)=>{switch(e.op){case"StringNGrams":{const{nGrams:r,nGramsSplits:s}=string$1.stringNGrams(getParamValue("data",e,t,n),getParamValue("dataSplits",e,t,n),getParamValue("separator",e,t,n),getParamValue("nGramWidths",e,t,n),getParamValue("leftPad",e,t,n),getParamValue("rightPad",e,t,n),getParamValue("padWidth",e,t,n),getParamValue("preserveShortSequences",e,t,n));return [r,s]}case"StringSplit":{const{indices:r,values:s,shape:a}=string$1.stringSplit(getParamValue("input",e,t,n),getParamValue("delimiter",e,t,n),getParamValue("skipEmpty",e,t,n));return [r,s,a]}case"StringToHashBucketFast":{const r=string$1.stringToHashBucketFast(getParamValue("input",e,t,n),getParamValue("numBuckets",e,t,n));return [r]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const executeOp$1=(e,t,n)=>{switch(e.op){case"Cast":{return [cast$1(getParamValue("x",e,t,n),getParamValue("dtype",e,t,n))]}case"ExpandDims":{const r=getParamValue("axis",e,t,n);return [expandDims$1(getParamValue("x",e,t,n),r)]}case"Squeeze":{const r=getParamValue("axis",e,t,n);return [squeeze(getParamValue("x",e,t,n),r)]}case"Reshape":{return [reshape$1(getParamValue("x",e,t,n),getParamValue("shape",e,t,n))]}case"MirrorPad":{return [mirrorPad(getParamValue("x",e,t,n),getParamValue("padding",e,t,n),getParamValue("mode",e,t,n))]}case"PadV2":case"Pad":{return [pad(getParamValue("x",e,t,n),getParamValue("padding",e,t,n),getParamValue("constantValue",e,t,n))]}case"SpaceToBatchND":{const r=getParamValue("blockShape",e,t,n);const s=getParamValue("paddings",e,t,n);return [spaceToBatchND(getParamValue("x",e,t,n),r,s)]}case"BatchToSpaceND":{const r=getParamValue("blockShape",e,t,n);const s=getParamValue("crops",e,t,n);return [batchToSpaceND(getParamValue("x",e,t,n),r,s)]}case"DepthToSpace":{const r=getParamValue("blockSize",e,t,n);const s=getParamValue("dataFormat",e,t,n).toUpperCase();return [depthToSpace(getParamValue("x",e,t,n),r,s)]}case"BroadcastTo":{return [broadcastTo(getParamValue("x",e,t,n),getParamValue("shape",e,t,n))]}default:throw TypeError(`Node type ${e.op} is not implemented`)}};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function executeOp(e,t,n,r){const s=((e,t,n)=>{switch(e.category){case"arithmetic":return tidy((()=>executeOp$j(e,t,n)));case"basic_math":return tidy((()=>executeOp$i(e,t,n)));case"control":return executeOp$h(e,t,n);case"convolution":return tidy((()=>executeOp$g(e,t,n)));case"creation":return tidy((()=>executeOp$f(e,t,n)));case"dynamic":return executeOp$e(e,t,n);case"evaluation":return tidy((()=>executeOp$d(e,t,n)));case"image":return tidy((()=>executeOp$a(e,t,n)));case"graph":return tidy((()=>executeOp$c(e,t,n)));case"logical":return tidy((()=>executeOp$9(e,t,n)));case"matrices":return tidy((()=>executeOp$8(e,t,n)));case"normalization":return tidy((()=>executeOp$7(e,t,n)));case"reduction":return tidy((()=>executeOp$6(e,t,n)));case"slice_join":return tidy((()=>executeOp$5(e,t,n)));case"sparse":return tidy((()=>executeOp$4(e,t,n)));case"spectral":return tidy((()=>executeOp$3(e,t,n)));case"string":return tidy((()=>executeOp$2(e,t,n)));case"transformation":return tidy((()=>executeOp$1(e,t,n)));case"hash_table":return executeOp$b(e,t,n,r);case"custom":const s=getRegisteredOp(e.op);if(s&&s.customExecutor){return s.customExecutor(new NodeValueImpl(e,t,n))}else {throw TypeError(`Custom op ${e.op} is not registered.`)}default:throw TypeError(`Unknown op '${e.op}'. File an issue at `+`https://github.com/tensorflow/tfjs/issues so we can add it`+`, or register a custom execution with tf.registerOp()`)}})(e,t,n);if(isPromise(s)){return s.then((e=>[].concat(e)))}return [].concat(s)}class ExecutionContext{constructor(e={},t={},n={},r={}){this.weightMap=e;this.tensorArrayMap=t;this.tensorListMap=n;this.functionMap=r;this.rootContext={id:0,frameName:"",iterationId:0};this.contexts=[this.rootContext];this.lastId=0;this.generateCurrentContextIds();}newFrame(e,t){return {id:e,frameName:t,iterationId:0}}set currentContext(e){if(this.contexts!==e){this.contexts=e;this.generateCurrentContextIds();}}get currentContext(){return this.contexts}get currentContextId(){return this._currentContextIds[0]}get currentContextIds(){return this._currentContextIds}generateCurrentContextIds(){const e=[];for(let t=0;t<this.contexts.length-1;t++){const n=this.contexts.slice(0,this.contexts.length-t);e.push(this.contextIdforContexts(n));}e.push("");this._currentContextIds=e;}contextIdforContexts(e){return e?e.map((e=>e.id===0&&e.iterationId===0?"":`${e.frameName}-${e.iterationId}`)).join("/"):""}enterFrame(e){if(this.contexts){this.lastId++;this.contexts=this.contexts.slice();this.contexts.push(this.newFrame(this.lastId,e));this._currentContextIds.unshift(this.contextIdforContexts(this.contexts));}}exitFrame(){if(this.contexts&&this.contexts.length>1){this.contexts=this.contexts.slice();this.contexts.splice(-1);this.currentContextIds.shift();}else {throw new Error("Cannot exit frame, the context is empty")}}nextIteration(){if(this.contexts&&this.contexts.length>0){this.contexts=this.contexts.slice();this.lastId++;const e=Object.assign({},this.contexts[this.contexts.length-1]);e.iterationId+=1;e.id=this.lastId;this.contexts.splice(-1,1,e);this._currentContextIds.splice(0,1,this.contextIdforContexts(this.contexts));}else {throw new Error("Cannot increase frame iteration, the context is empty")}}getWeight(e){return this.weightMap[e]}addTensorArray(e){this.tensorArrayMap[e.id]=e;}getTensorArray(e){return this.tensorArrayMap[e]}addTensorList(e){this.tensorListMap[e.id]=e;}getTensorList(e){return this.tensorListMap[e]}dispose(e){for(const t in this.tensorArrayMap){this.tensorArrayMap[t].clearAndClose(e);}for(const t in this.tensorListMap){this.tensorListMap[t].clearAndClose(e);}}}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getExecutionSubgraph(e,t,n,r){const s=new Set;const a=[];let o=null;let i=null;const u=new Set;const c=Object.keys(e).map((e=>parseNodeName(e)[0]));let l=[];if(r!=null){l=r.map((e=>parseNodeName(e.name)[0]));}const p=[...t];while(p.length>0){const e=p.pop();if(isControlFlow(e)||isDynamicShape(e)||isHashTable(e)){if(o==null){o=e;i=o.children.map((e=>e.name)).filter((e=>s.has(e)));}}s.add(e.name);if(n[e.name]!=null){continue}if(c.indexOf(e.name)!==-1){continue}if(l.indexOf(e.name)!==-1){continue}if(e.inputs.length===0){a.push(e.name);continue}e.inputs.forEach((e=>{if(u.has(e.name)){return}u.add(e.name);p.push(e);}));}return {inputs:e,outputs:t,usedNodes:s,missingInputs:a,dynamicNode:o,syncInputs:i}}function getNodesInTopologicalOrder(e,t,n){const{usedNodes:r,inputs:s}=n;const a=[];const o=Object.keys(s).map((e=>parseNodeName(e)[0])).map((t=>e.nodes[t]));const i=e.initNodes;o.forEach((e=>{if(r.has(e.name)){a.push(e);}}));e.weights.forEach((e=>{if(r.has(e.name)){a.push(e);}}));if(i!=null){i.forEach((e=>{if(r.has(e.name)){a.push(e);}}));}const u=new Set;const c=[];while(a.length>0){const e=a.pop();u.add(e.name);if(!t[e.name]){c.push(e);}e.children.forEach((e=>{if(!u.has(e.name)&&r.has(e.name)&&e.inputs.every((e=>u.has(e.name)))){a.push(e);}}));}return c}const CONTROL_FLOW_OPS=["Switch","Merge","Enter","Exit","NextIteration","StatelessIf","StatelessWhile","if","While"];const DYNAMIC_SHAPE_OPS=["NonMaxSuppressionV2","NonMaxSuppressionV3","NonMaxSuppressionV5","Where"];const HASH_TABLE_OPS=["HashTable","HashTableV2","LookupTableImport","LookupTableImportV2","LookupTableFind","LookupTableFindV2","LookupTableSize","LookupTableSizeV2"];function isControlFlow(e){return CONTROL_FLOW_OPS.indexOf(e.op)>=0}function isDynamicShape(e){return DYNAMIC_SHAPE_OPS.indexOf(e.op)>=0}function isHashTable(e){return HASH_TABLE_OPS.indexOf(e.op)>=0}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class GraphExecutor{constructor(e,t){this.graph=e;this.parent=t;this.compiledMap=new Map;this._weightMap={};this.SEPERATOR=",";this._functions={};this._functionExecutorMap={};this._outputs=e.outputs;this._inputs=e.inputs;this._initNodes=e.initNodes;this._signature=e.signature;this._functions=e.functions;if(e.functions!=null){Object.keys(e.functions).forEach((t=>{this._functionExecutorMap[t]=new GraphExecutor(e.functions[t],this);}));}}get weightIds(){return this.parent?this.parent.weightIds:this._weightIds}get functionExecutorMap(){return this.parent?this.parent.functionExecutorMap:this._functionExecutorMap}get weightMap(){return this.parent?this.parent.weightMap:this._weightMap}set weightMap(e){const t=Object.keys(e).map((t=>e[t].map((e=>e.id))));this._weightIds=[].concat(...t);this._weightMap=e;}set resourceManager(e){this._resourceManager=e;}get inputs(){return this._inputs.map((e=>({name:e.name,shape:e.attrParams["shape"]?e.attrParams["shape"].value:undefined,dtype:e.attrParams["dtype"]?e.attrParams["dtype"].value:undefined})))}get outputs(){return this._outputs.map((e=>({name:e.name,shape:e.attrParams["shape"]?e.attrParams["shape"].value:undefined,dtype:e.attrParams["dtype"]?e.attrParams["dtype"].value:undefined})))}get inputNodes(){return this._inputs.map((e=>e.signatureKey||e.name))}get outputNodes(){return this._outputs.map((e=>{const t=e.signatureKey||e.name;return e.defaultOutput?`${t}:${e.defaultOutput}`:t}))}get functions(){return Object.keys(this._functions).reduce(((e,t)=>{e[t]=this._functions[t].signature;return e}),{})}getCompilationKey(e,t){const n=e.map((e=>e.name)).sort();const r=t.map((e=>e.name)).sort();return n.join(this.SEPERATOR)+"--"+r.join(this.SEPERATOR)}compile(e,t){const n=getExecutionSubgraph(e,t,this.weightMap,this._initNodes);const{missingInputs:r,dynamicNode:s,syncInputs:a}=n;if(s!=null){throw new Error(`This execution contains the node '${s.name}', which has `+`the dynamic op '${s.op}'. Please use `+`model.executeAsync() instead. Alternatively, to avoid the `+`dynamic ops, specify the inputs [${a}]`)}if(r.length>0){const n=t.map((e=>e.name));const s=Object.keys(e);throw new Error(`Cannot compute the outputs [${n}] from the provided inputs `+`[${s}]. Missing the following inputs: [${r}]`)}return getNodesInTopologicalOrder(this.graph,this.weightMap,n)}execute(e,t){e=this.mapInputs(e);const n=Object.keys(e).sort();this.checkInputs(e);this.checkInputShapeAndType(e);t=this.mapOutputs(t);this.checkOutputs(t);const r=n.map((e=>this.graph.nodes[parseNodeName(e)[0]]));const s=t.map((e=>parseNodeName(e)[0]));let a=s.map((e=>this.graph.nodes[e]));if(a.length===0){a=this._outputs;}const o=this.getCompilationKey(r,a);let i=this.compiledMap.get(o);if(i==null){i=this.compile(e,a);this.compiledMap.set(o,i);}const u={};const c={};return tidy((()=>{const n=new ExecutionContext(this.weightMap,u,c,this.functionExecutorMap);const r=Object.assign({},this.weightMap);Object.keys(e).forEach((t=>{const[n,s]=parseNodeName(t);const a=[];a[s]=e[t];r[n]=a;}));const a=this.getFrozenTensorIds(r);const o={};for(let e=0;e<i.length;e++){const t=i[e];if(!r[t.name]){const e=executeOp(t,r,n,this._resourceManager);if(isPromise(e)){throw new Error(`The execution of the op '${t.op}' returned a promise. `+`Please use model.executeAsync() instead.`)}r[t.name]=e;this.checkTensorForDisposal(t.name,t,r,n,a,s,o);}}if(this.parent==null){n.dispose(a);}return t.map((e=>getTensor(e,r,n)))}))}getFrozenTensorIds(e){const t=[].concat.apply([],Object.keys(e).map((t=>e[t])).map((e=>e.map((e=>e.id)))));return new Set(t)}checkTensorForDisposal(e,t,n,r,s,a,o){if(t.category==="control"||a.indexOf(e)!==-1){return}n[e].forEach((e=>{if(e!=null){o[e.id]=(o[e.id]||0)+t.children.length;}}));t.inputs.forEach((e=>{if(e.category!=="control"){const t=getTensorsForCurrentContenxt(e.name,n,r);if(t!=null){t.forEach((e=>{if(e&&!e.kept&&!s.has(e.id)){const t=o[e.id];if(t===1){e.dispose();delete o[e.id];}else if(t!=null){o[e.id]--;}}}));}}}));}async executeAsync(e,t){return this._executeAsync(e,t)}async _executeAsync(e,t,n=false,r={},s={}){if(!n){e=this.mapInputs(e);this.checkInputs(e);this.checkInputShapeAndType(e);t=this.mapOutputs(t);this.checkOutputs(t);}const a=new ExecutionContext(this.weightMap,r,s,this.functionExecutorMap);const o=await this.executeWithControlFlow(e,a,t,n);const i=t.map((e=>getTensor(e,o,a)));const u=i.map((e=>e.id));const c=Object.keys(e).map((t=>e[t].id));const l=new Set([...u,...c,...this.weightIds]);Object.keys(o).forEach((e=>{const t=o[e];t.forEach((e=>{if(e&&!e.kept&&!e.isDisposed&&!l.has(e.id)){e.dispose();}}));}));if(this.parent==null){a.dispose(l);}return i}async executeFunctionAsync(e,t,n){const r=e.reduce(((e,t,n)=>{e[this.inputs[n].name]=t;return e}),{});return this._executeAsync(r,this.outputNodes,true,t,n)}async executeWithControlFlow(e,t,n,r){const s=Object.keys(e);const a=s.map((e=>this.graph.nodes[parseNodeName(e)[0]]));const o=n.map((e=>parseNodeName(e)[0]));let i=o.map((e=>this.graph.nodes[e]));if(i.length===0){i=this._outputs;}const{usedNodes:u,missingInputs:c,dynamicNode:l,syncInputs:p}=getExecutionSubgraph(e,i,this.weightMap,this._initNodes);const d=[...a,...this.graph.weights,...this._initNodes||[]].map((e=>({node:e,contexts:t.currentContext})));const h=Object.assign({},this.weightMap);Object.keys(e).forEach((t=>{const[n,r]=parseNodeName(t);const s=[];s[r]=e[t];h[n]=s;}));const m={};const f=this.getFrozenTensorIds(h);const g={};while(d.length>0){const e=this.processStack(a,d,t,h,g,f,o,m,u);await Promise.all(e);}if(l==null&&!r){console.warn(`This model execution did not contain any nodes with control flow `+`or dynamic output shapes. You can use model.execute() instead.`);}const y=i.filter((e=>!isControlFlow(e)&&!getTensor(e.name,h,t))).map((e=>e.name));if(y.length>0){let e="";if(l!=null){e=`Alternatively, to avoid the dynamic ops, use model.execute() `+`and specify the inputs [${p}]`;}throw new Error(`Cannot compute the outputs [${y}] from the provided `+`inputs [${s}]. Consider providing the following inputs: `+`[${c}]. ${e}`)}return h}processStack(e,t,n,r,s,a,o,i,u){const c=[];while(t.length>0){const e=t.pop();n.currentContext=e.contexts;let l="";if(e.node.op==="Enter"&&getParamValue("isConstant",e.node,r,n)){[l]=getNodeNameAndIndex(e.node.name,n);}if(r[e.node.name]==null){const p=executeOp(e.node,r,n,this._resourceManager);if(!l){[l]=getNodeNameAndIndex(e.node.name,n);}const d=n.currentContext;if(isPromise(p)){c.push(p.then((c=>{r[l]=c;n.currentContext=d;this.checkTensorForDisposal(l,e.node,r,n,a,o,i);this.processChildNodes(e.node,t,n,r,s,u);return c})));}else {r[l]=p;this.checkTensorForDisposal(l,e.node,r,n,a,o,i);this.processChildNodes(e.node,t,n,r,s,u);}}else {this.processChildNodes(e.node,t,n,r,s,u);}}return c}processChildNodes(e,t,n,r,s,a){e.children.forEach((e=>{const[o]=getNodeNameAndIndex(e.name,n);if(s[o]||!a.has(e.name)){return}if(e.op==="Merge"){if(e.inputNames.some((e=>!!getTensor(e,r,n)))){s[o]=true;t.push({contexts:n.currentContext,node:e});}}else if(e.inputNames.every((e=>!!getTensor(e,r,n)))){s[o]=true;t.push({contexts:n.currentContext,node:e});}}));}dispose(){Object.keys(this.weightMap).forEach((e=>this.weightMap[e].forEach((e=>e.dispose()))));}checkInputShapeAndType(e){Object.keys(e).forEach((t=>{const n=e[t];const[r]=parseNodeName(t);const s=this.graph.nodes[r];if(s.attrParams["shape"]&&s.attrParams["shape"].value){const e=s.attrParams["shape"].value;const t=e.length===n.shape.length&&n.shape.every(((t,n)=>e[n]===-1||e[n]===t));assert(t,(()=>`The shape of dict['${s.name}'] provided in `+`model.execute(dict) must be [${e}], but was `+`[${n.shape}]`));}if(s.attrParams["dtype"]&&s.attrParams["dtype"].value){assert(n.dtype===s.attrParams["dtype"].value,(()=>`The dtype of dict['${s.name}'] provided in `+`model.execute(dict) must be `+`${s.attrParams["dtype"].value}, but was ${n.dtype}`));}}));}mapInputs(e){const t={};for(const n in e){if(this._signature!=null&&this._signature.inputs!=null&&this._signature.inputs[n]!=null){const r=this._signature.inputs[n];t[r.name]=e[n];}else {t[n]=e[n];}}return t}checkInputs(e){const t=Object.keys(e).filter((e=>{const[t]=parseNodeName(e);return this.graph.nodes[t]==null}));if(t.length>0){throw new Error(`The dict provided in model.execute(dict) has `+`keys: [${t}] that are not part of graph`)}}mapOutputs(e){return e.map((e=>{if(this._signature!=null&&this._signature.outputs!=null&&this._signature.outputs[e]!=null){const t=this._signature.outputs[e];return t.name}return e}),{})}checkOutputs(e){e.forEach((e=>{const[t]=parseNodeName(e);if(!this.graph.nodes[t]){throw new Error(`The output '${e}' is not found in the graph`)}}));}}class ResourceManager{constructor(e={},t={}){this.hashTableNameToHandle=e;this.hashTableMap=t;}addHashTable(e,t){this.hashTableNameToHandle[e]=t.handle;this.hashTableMap[t.id]=t;}getHashTableHandleByName(e){return this.hashTableNameToHandle[e]}getHashTableById(e){return this.hashTableMap[e]}dispose(){for(const e in this.hashTableMap){this.hashTableMap[e].clearAndClose();delete this.hashTableMap[e];}for(const e in this.hashTableNameToHandle){this.hashTableNameToHandle[e].dispose();delete this.hashTableNameToHandle[e];}}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const TFHUB_SEARCH_PARAM="?tfjs-format=file";const DEFAULT_MODEL_NAME="model.json";class GraphModel{constructor(e,t={}){this.modelUrl=e;this.loadOptions=t;this.version="n/a";if(t==null){this.loadOptions={};}this.resourceManager=new ResourceManager;}get modelVersion(){return this.version}get inputNodes(){return this.executor.inputNodes}get outputNodes(){return this.executor.outputNodes}get inputs(){return this.executor.inputs}get outputs(){return this.executor.outputs}get weights(){return this.executor.weightMap}get metadata(){return this.artifacts.userDefinedMetadata}get modelSignature(){return this.signature}findIOHandler(){const e=this.modelUrl;if(e.load!=null){this.handler=e;}else if(this.loadOptions.requestInit!=null){this.handler=browserHTTPRequest(e,this.loadOptions);}else {const t=getLoadHandlers(e,this.loadOptions);if(t.length===0){t.push(browserHTTPRequest(e,this.loadOptions));}else if(t.length>1){throw new Error(`Found more than one (${t.length}) load handlers for `+`URL '${[e]}'`)}this.handler=t[0];}}async load(){this.findIOHandler();if(this.handler.load==null){throw new Error("Cannot proceed with model loading because the IOHandler provided "+"does not have the `load` method implemented.")}const e=await this.handler.load();return this.loadSync(e)}loadSync(e){this.artifacts=e;const t=this.artifacts.modelTopology;let n;if(this.artifacts.userDefinedMetadata!=null&&this.artifacts.userDefinedMetadata.signature!=null){n=this.artifacts.userDefinedMetadata.signature;}else {n=this.artifacts.signature;}this.signature=n;this.version=`${t.versions.producer}.${t.versions.minConsumer}`;const r=decodeWeights(this.artifacts.weightData,this.artifacts.weightSpecs);this.executor=new GraphExecutor(OperationMapper.Instance.transformGraph(t,this.signature));this.executor.weightMap=this.convertTensorMapToTensorsMap(r);this.executor.resourceManager=this.resourceManager;if(e.modelInitializer!=null&&e.modelInitializer.node!=null){const t=OperationMapper.Instance.transformGraph(e.modelInitializer);this.initializer=new GraphExecutor(t);this.initializer.weightMap=this.executor.weightMap;this.initializer.resourceManager=this.resourceManager;this.initializer.executeAsync({},[]);}return true}async save(e,t){if(typeof e==="string"){const t=getSaveHandlers(e);if(t.length===0){throw new Error(`Cannot find any save handlers for URL '${e}'`)}else if(t.length>1){throw new Error(`Found more than one (${t.length}) save handlers for `+`URL '${e}'`)}e=t[0];}if(e.save==null){throw new Error("GraphModel.save() cannot proceed because the IOHandler "+"provided does not have the `save` attribute defined.")}return e.save(this.artifacts)}predict(e,t){return this.execute(e,this.outputNodes)}normalizeInputs(e){if(!(e instanceof Tensor)&&!Array.isArray(e)){return e}e=Array.isArray(e)?e:[e];if(e.length!==this.inputNodes.length){throw new Error("Input tensor count mismatch,"+`the graph model has ${this.inputNodes.length} placeholders, `+`while there are ${e.length} input tensors.`)}return this.inputNodes.reduce(((t,n,r)=>{t[n]=e[r];return t}),{})}normalizeOutputs(e){e=e||this.outputNodes;return !Array.isArray(e)?[e]:e}execute(e,t){e=this.normalizeInputs(e);t=this.normalizeOutputs(t);const n=this.executor.execute(e,t);return n.length>1?n:n[0]}async executeAsync(e,t){e=this.normalizeInputs(e);t=this.normalizeOutputs(t);const n=await this.executor.executeAsync(e,t);return n.length>1?n:n[0]}convertTensorMapToTensorsMap(e){return Object.keys(e).reduce(((t,n)=>{t[n]=[e[n]];return t}),{})}dispose(){this.executor.dispose();if(this.initializer){this.initializer.dispose();}this.resourceManager.dispose();}}async function loadGraphModel(e,t={}){if(e==null){throw new Error("modelUrl in loadGraphModel() cannot be null. Please provide a url "+"or an IOHandler that loads the model")}if(t==null){t={};}if(t.fromTFHub){if(e.load==null){if(!e.endsWith("/")){e=e+"/";}e=`${e}${DEFAULT_MODEL_NAME}${TFHUB_SEARCH_PARAM}`;}}const n=new GraphModel(e,t);await n.load();return n}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */getGlobalTensorClass().prototype.pad=function(e,t){this.throwIfDisposed();return pad(this,e,t)};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */getGlobalTensorClass().prototype.where=function(e,t){this.throwIfDisposed();return where(e,this,t)};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */getGlobalTensorClass().prototype.mul=function(e){this.throwIfDisposed();return mul(this,e)};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */getGlobalTensorClass().prototype.dot=function(e){this.throwIfDisposed();return dot(this,e)};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */getGlobalTensorClass().prototype.add=function(e){this.throwIfDisposed();return add(this,e)};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const contexts={};const WEBGL_ATTRIBUTES={alpha:false,antialias:false,premultipliedAlpha:false,preserveDrawingBuffer:false,depth:false,stencil:false,failIfMajorPerformanceCaveat:true};function setWebGLContext(e,t){contexts[e]=t;}function getWebGLContext(e){if(!(e in contexts)){const t=getWebGLRenderingContext(e);if(t!==null){contexts[e]=t;}else {console.log("Could not get context for WebGL version",e);return null}}const t=contexts[e];if(t.isContextLost()){delete contexts[e];return getWebGLContext(e)}t.disable(t.DEPTH_TEST);t.disable(t.STENCIL_TEST);t.disable(t.BLEND);t.disable(t.DITHER);t.disable(t.POLYGON_OFFSET_FILL);t.disable(t.SAMPLE_COVERAGE);t.enable(t.SCISSOR_TEST);t.enable(t.CULL_FACE);t.cullFace(t.BACK);return contexts[e]}function createCanvas(e){if(typeof OffscreenCanvas!=="undefined"&&e===2){return new OffscreenCanvas(300,150)}else if(typeof document!=="undefined"){return document.createElement("canvas")}else {throw new Error("Cannot create a canvas in this context")}}function getWebGLRenderingContext(e){if(e!==1&&e!==2){throw new Error("Cannot get WebGL rendering context, WebGL is disabled.")}const t=createCanvas(e);t.addEventListener("webglcontextlost",(t=>{t.preventDefault();delete contexts[e];}),false);if(e===1){return t.getContext("webgl",WEBGL_ATTRIBUTES)||t.getContext("experimental-webgl",WEBGL_ATTRIBUTES)}return t.getContext("webgl2",WEBGL_ATTRIBUTES)}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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 PackingScheme;(function(e){e[e["DENSE"]=0]="DENSE";e[e["SHARED_BATCH"]=1]="SHARED_BATCH";})(PackingScheme||(PackingScheme={}));var TextureUsage;(function(e){e[e["RENDER"]=0]="RENDER";e[e["UPLOAD"]=1]="UPLOAD";e[e["PIXELS"]=2]="PIXELS";e[e["DOWNLOAD"]=3]="DOWNLOAD";})(TextureUsage||(TextureUsage={}));var PhysicalTextureType;(function(e){e[e["UNPACKED_FLOAT16"]=0]="UNPACKED_FLOAT16";e[e["UNPACKED_FLOAT32"]=1]="UNPACKED_FLOAT32";e[e["PACKED_4X1_UNSIGNED_BYTE"]=2]="PACKED_4X1_UNSIGNED_BYTE";e[e["PACKED_2X2_FLOAT32"]=3]="PACKED_2X2_FLOAT32";e[e["PACKED_2X2_FLOAT16"]=4]="PACKED_2X2_FLOAT16";})(PhysicalTextureType||(PhysicalTextureType={}));function getUnpackedMatrixTextureShapeWidthHeight(e,t){return [t,e]}function getUnpackedArraySizeFromMatrixSize(e,t){return e*t}function getDenseTexShape(e){const t=sizeFromShape(e);const n=Math.ceil(t/4);return sizeToSquarishShape(n)}function getPackedMatrixTextureShapeWidthHeight(e,t){return [Math.max(1,Math.ceil(t/2)),Math.max(1,Math.ceil(e/2))]}function getPackedRGBAArraySizeFromMatrixShape(e,t){const[n,r]=getPackedMatrixTextureShapeWidthHeight(e,t);return n*r*4}function getTextureConfig(e,t){const n=e;let r;let s;let a;let o;let i;let u;let c;let l;let p;let d;if(env().getNumber("WEBGL_VERSION")===2){r=n.R32F;s=n.R16F;a=n.RGBA16F;o=n.RGBA32F;i=n.RED;c=4;l=1;p=n.HALF_FLOAT;d=n.FLOAT;}else {r=e.RGBA;s=e.RGBA;a=e.RGBA;o=n.RGBA;i=e.RGBA;c=4;l=4;p=t!=null?t.HALF_FLOAT_OES:null;d=e.FLOAT;}u=e.RGBA;return {internalFormatFloat:r,internalFormatHalfFloat:s,internalFormatPackedHalfFloat:a,internalFormatPackedFloat:o,textureFormatFloat:i,downloadTextureFormat:u,downloadUnpackNumChannels:c,defaultNumChannels:l,textureTypeHalfFloat:p,textureTypeFloat:d}}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function callAndCheck(e,t){const n=t();if(env().getBool("DEBUG")){checkWebGLError(e);}return n}function checkWebGLError(e){const t=e.getError();if(t!==e.NO_ERROR){throw new Error("WebGL Error: "+getWebGLErrorMessage(e,t))}}const MIN_FLOAT16=5.96e-8;const MAX_FLOAT16=65504;function canBeRepresented(e){if(env().getBool("WEBGL_RENDER_FLOAT32_ENABLED")||e===0||MIN_FLOAT16<Math.abs(e)&&Math.abs(e)<MAX_FLOAT16){return true}return false}function getWebGLErrorMessage(e,t){switch(t){case e.NO_ERROR:return "NO_ERROR";case e.INVALID_ENUM:return "INVALID_ENUM";case e.INVALID_VALUE:return "INVALID_VALUE";case e.INVALID_OPERATION:return "INVALID_OPERATION";case e.INVALID_FRAMEBUFFER_OPERATION:return "INVALID_FRAMEBUFFER_OPERATION";case e.OUT_OF_MEMORY:return "OUT_OF_MEMORY";case e.CONTEXT_LOST_WEBGL:return "CONTEXT_LOST_WEBGL";default:return `Unknown error code ${t}`}}function getExtensionOrThrow(e,t){return throwIfNull(e,(()=>e.getExtension(t)),'Extension "'+t+'" not supported on this browser.')}function createVertexShader$1(e,t){const n=throwIfNull(e,(()=>e.createShader(e.VERTEX_SHADER)),"Unable to create vertex WebGLShader.");callAndCheck(e,(()=>e.shaderSource(n,t)));callAndCheck(e,(()=>e.compileShader(n)));if(e.getShaderParameter(n,e.COMPILE_STATUS)===false){console.log(e.getShaderInfoLog(n));throw new Error("Failed to compile vertex shader.")}return n}function createFragmentShader(e,t){const n=throwIfNull(e,(()=>e.createShader(e.FRAGMENT_SHADER)),"Unable to create fragment WebGLShader.");callAndCheck(e,(()=>e.shaderSource(n,t)));callAndCheck(e,(()=>e.compileShader(n)));if(e.getShaderParameter(n,e.COMPILE_STATUS)===false){logShaderSourceAndInfoLog(t,e.getShaderInfoLog(n));throw new Error("Failed to compile fragment shader.")}return n}const lineNumberRegex=/ERROR: [0-9]+:([0-9]+):/g;function logShaderSourceAndInfoLog(e,t){const n=lineNumberRegex.exec(t);if(n==null){console.log(`Couldn't parse line number in error: ${t}`);console.log(e);return}const r=+n[1];const s=e.split("\n");const a=s.length.toString().length+2;const o=s.map(((e,t)=>rightPad((t+1).toString(),a)+e));let i=0;for(let e=0;e<o.length;e++){i=Math.max(o[e].length,i);}const u=o.slice(0,r-1);const c=o.slice(r-1,r);const l=o.slice(r);console.log(u.join("\n"));console.log(t.split("\n")[0]);console.log(`%c ${rightPad(c[0],i)}`,"border:1px solid red; background-color:#e3d2d2; color:#a61717");console.log(l.join("\n"));}function createProgram(e){return throwIfNull(e,(()=>e.createProgram()),"Unable to create WebGLProgram.")}function linkProgram(e,t){callAndCheck(e,(()=>e.linkProgram(t)));if(e.getProgramParameter(t,e.LINK_STATUS)===false){console.log(e.getProgramInfoLog(t));throw new Error("Failed to link vertex and fragment shaders.")}}function validateProgram(e,t){callAndCheck(e,(()=>e.validateProgram(t)));if(e.getProgramParameter(t,e.VALIDATE_STATUS)===false){console.log(e.getProgramInfoLog(t));throw new Error("Shader program validation failed.")}}function createStaticVertexBuffer(e,t){const n=throwIfNull(e,(()=>e.createBuffer()),"Unable to create WebGLBuffer");callAndCheck(e,(()=>e.bindBuffer(e.ARRAY_BUFFER,n)));callAndCheck(e,(()=>e.bufferData(e.ARRAY_BUFFER,t,e.STATIC_DRAW)));return n}function createStaticIndexBuffer(e,t){const n=throwIfNull(e,(()=>e.createBuffer()),"Unable to create WebGLBuffer");callAndCheck(e,(()=>e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,n)));callAndCheck(e,(()=>e.bufferData(e.ELEMENT_ARRAY_BUFFER,t,e.STATIC_DRAW)));return n}function createTexture(e){return throwIfNull(e,(()=>e.createTexture()),"Unable to create WebGLTexture.")}function validateTextureSize(e,t){const n=env().getNumber("WEBGL_MAX_TEXTURE_SIZE");if(e<=0||t<=0){const n=`[${e}x${t}]`;throw new Error("Requested texture size "+n+" is invalid.")}if(e>n||t>n){const r=`[${e}x${t}]`;const s=`[${n}x${n}]`;throw new Error("Requested texture size "+r+" greater than WebGL maximum on this browser / GPU "+s+".")}}function createFramebuffer(e){return throwIfNull(e,(()=>e.createFramebuffer()),"Unable to create WebGLFramebuffer.")}function bindVertexBufferToProgramAttribute(e,t,n,r,s,a,o){const i=e.getAttribLocation(t,n);if(i===-1){return false}callAndCheck(e,(()=>e.bindBuffer(e.ARRAY_BUFFER,r)));callAndCheck(e,(()=>e.vertexAttribPointer(i,s,e.FLOAT,false,a,o)));callAndCheck(e,(()=>e.enableVertexAttribArray(i)));return true}function bindTextureUnit(e,t,n){validateTextureUnit(e,n);callAndCheck(e,(()=>e.activeTexture(e.TEXTURE0+n)));callAndCheck(e,(()=>e.bindTexture(e.TEXTURE_2D,t)));}function getProgramUniformLocationOrThrow(e,t,n){return throwIfNull(e,(()=>e.getUniformLocation(t,n)),'uniform "'+n+'" not present in program.')}function getProgramUniformLocation(e,t,n){return e.getUniformLocation(t,n)}function bindTextureToProgramUniformSampler(e,t,n,r){callAndCheck(e,(()=>bindTextureUnit(e,t,r)));callAndCheck(e,(()=>e.uniform1i(n,r)));}function bindColorTextureToFramebuffer(e,t,n){callAndCheck(e,(()=>e.bindFramebuffer(e.FRAMEBUFFER,n)));callAndCheck(e,(()=>e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0)));}function unbindColorTextureFromFramebuffer(e,t){callAndCheck(e,(()=>e.bindFramebuffer(e.FRAMEBUFFER,t)));callAndCheck(e,(()=>e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,null,0)));}function validateFramebuffer(e){const t=e.checkFramebufferStatus(e.FRAMEBUFFER);if(t!==e.FRAMEBUFFER_COMPLETE){throw new Error("Error binding framebuffer: "+getFramebufferErrorMessage(e,t))}}function getFramebufferErrorMessage(e,t){switch(t){case e.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:return "FRAMEBUFFER_INCOMPLETE_ATTACHMENT";case e.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:return "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";case e.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:return "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";case e.FRAMEBUFFER_UNSUPPORTED:return "FRAMEBUFFER_UNSUPPORTED";default:return `unknown error ${t}`}}function throwIfNull(e,t,n){const r=callAndCheck(e,(()=>t()));if(r==null){throw new Error(n)}return r}function validateTextureUnit(e,t){const n=e.MAX_COMBINED_TEXTURE_IMAGE_UNITS-1;const r=t+e.TEXTURE0;if(r<e.TEXTURE0||r>n){const e=`[gl.TEXTURE0, gl.TEXTURE${n}]`;throw new Error(`textureUnit must be in ${e}.`)}}function getBatchDim(e,t=2){return sizeFromShape(e.slice(0,e.length-t))}function getRowsCols(e){if(e.length===0){throw Error("Cannot get rows and columns of an empty shape array.")}return [e.length>1?e[e.length-2]:1,e[e.length-1]]}function getShapeAs3D(e){let t=[1,1,1];const n=e.length===0||e.length===1&&e[0]===1;if(!n){t=[getBatchDim(e),...getRowsCols(e)];}return t}function getTextureShapeFromLogicalShape(e,t=false){let n=env().getNumber("WEBGL_MAX_TEXTURE_SIZE");if(t){n=n*2;e=e.map(((t,n)=>n>=e.length-2?nearestLargerEven(e[n]):e[n]));if(e.length===1){e=[2,e[0]];}}if(e.length!==2){const t=squeezeShape(e);e=t.newShape;}let r=sizeFromShape(e);if(e.length<=1&&r<=n){return [1,r]}else if(e.length===2&&e[0]<=n&&e[1]<=n){return e}else if(e.length===3&&e[0]*e[1]<=n&&e[2]<=n){return [e[0]*e[1],e[2]]}else if(e.length===3&&e[0]<=n&&e[1]*e[2]<=n){return [e[0],e[1]*e[2]]}else if(e.length===4&&e[0]*e[1]*e[2]<=n&&e[3]<=n){return [e[0]*e[1]*e[2],e[3]]}else if(e.length===4&&e[0]<=n&&e[1]*e[2]*e[3]<=n){return [e[0],e[1]*e[2]*e[3]]}else {if(t){const t=getBatchDim(e);let n=2,s=2;if(e.length){[n,s]=getRowsCols(e);}r=t*(n/2)*(s/2);return sizeToSquarishShape(r).map((e=>e*2))}return sizeToSquarishShape(r)}}function isEven(e){return e%2===0}function isReshapeFree(e,t){e=e.slice(-2);t=t.slice(-2);if(arraysEqual(e,t)){return true}if(!e.length||!t.length){return true}if(e[0]===0||e[1]===0||t[0]===0||t[1]===0){return true}if(e.length!==t.length){const n=e.slice(-1)[0];const r=t.slice(-1)[0];if(n===r){return true}if(isEven(n)&&isEven(r)&&(e[0]===1||t[0]===1)){return true}}return e[1]===t[1]&&isEven(e[0])&&isEven(t[0])}let MAX_TEXTURE_SIZE;let MAX_TEXTURES_IN_SHADER;function getWebGLMaxTextureSize(e){if(MAX_TEXTURE_SIZE==null){const t=getWebGLContext(e);MAX_TEXTURE_SIZE=t.getParameter(t.MAX_TEXTURE_SIZE);}return MAX_TEXTURE_SIZE}function getMaxTexturesInShader(e){if(MAX_TEXTURES_IN_SHADER==null){const t=getWebGLContext(e);MAX_TEXTURES_IN_SHADER=t.getParameter(t.MAX_TEXTURE_IMAGE_UNITS);}return Math.min(16,MAX_TEXTURES_IN_SHADER)}function getWebGLDisjointQueryTimerVersion(e){if(e===0){return 0}let t;const n=getWebGLContext(e);if(hasExtension(n,"EXT_disjoint_timer_query_webgl2")&&e===2){t=2;}else if(hasExtension(n,"EXT_disjoint_timer_query")){t=1;}else {t=0;}return t}function hasExtension(e,t){const n=e.getExtension(t);return n!=null}function isWebGLVersionEnabled(e){try{const t=getWebGLContext(e);if(t!=null){return true}}catch(e){console.log("Error when getting WebGL context: ",e);return false}return false}function isCapableOfRenderingToFloatTexture(e){if(e===0){return false}const t=getWebGLContext(e);if(e===1){if(!hasExtension(t,"OES_texture_float")){return false}}else {if(!hasExtension(t,"EXT_color_buffer_float")){return false}}const n=createFloatTextureAndBindToFramebuffer(t);return n}function isDownloadFloatTextureEnabled(e){if(e===0){return false}const t=getWebGLContext(e);if(e===1){if(!hasExtension(t,"OES_texture_float")){return false}if(!hasExtension(t,"WEBGL_color_buffer_float")){return false}}else {if(hasExtension(t,"EXT_color_buffer_float")){return createFloatTextureAndBindToFramebuffer(t)}const e="EXT_color_buffer_half_float";if(hasExtension(t,e)){const n=t.getExtension(e);return createHalfFloatTextureAndBindToFramebuffer(t,n)}return false}const n=createFloatTextureAndBindToFramebuffer(t);return n}function createFloatTextureAndBindToFramebuffer(e){const t=getTextureConfig(e);const n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n);const r=1;const s=1;e.texImage2D(e.TEXTURE_2D,0,t.internalFormatFloat,r,s,0,t.textureFormatFloat,t.textureTypeFloat,null);const a=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,a);e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,n,0);const o=e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE;e.bindTexture(e.TEXTURE_2D,null);e.bindFramebuffer(e.FRAMEBUFFER,null);e.deleteTexture(n);e.deleteFramebuffer(a);return o}function createHalfFloatTextureAndBindToFramebuffer(e,t){const n=getTextureConfig(e,t);const r=e.createTexture();e.bindTexture(e.TEXTURE_2D,r);const s=1;const a=1;e.texImage2D(e.TEXTURE_2D,0,n.internalFormatHalfFloat,s,a,0,n.textureFormatFloat,n.textureTypeHalfFloat,null);const o=e.createFramebuffer();e.bindFramebuffer(e.FRAMEBUFFER,o);e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0);const i=e.checkFramebufferStatus(e.FRAMEBUFFER)===e.FRAMEBUFFER_COMPLETE;e.bindTexture(e.TEXTURE_2D,null);e.bindFramebuffer(e.FRAMEBUFFER,null);e.deleteTexture(r);e.deleteFramebuffer(o);return i}function isWebGLFenceEnabled(e){if(e!==2){return false}const t=getWebGLContext(e);const n=t.fenceSync!=null;return n}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const ENV=env();ENV.registerFlag("HAS_WEBGL",(()=>ENV.getNumber("WEBGL_VERSION")>0));ENV.registerFlag("WEBGL_VERSION",(()=>{if(isWebGLVersionEnabled(2)){return 2}else if(isWebGLVersionEnabled(1)){return 1}return 0}));ENV.registerFlag("WEBGL_CHECK_NUMERICAL_PROBLEMS",(()=>false));ENV.registerFlag("WEBGL_BUFFER_SUPPORTED",(()=>ENV.get("WEBGL_VERSION")===2));ENV.registerFlag("WEBGL_CPU_FORWARD",(()=>true));ENV.registerFlag("WEBGL_FORCE_F16_TEXTURES",(()=>false));ENV.registerFlag("WEBGL_PACK",(()=>ENV.getBool("HAS_WEBGL")));ENV.registerFlag("WEBGL_PACK_NORMALIZATION",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_PACK_CLIP",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_PACK_DEPTHWISECONV",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_PACK_BINARY_OPERATIONS",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_PACK_UNARY_OPERATIONS",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_PACK_ARRAY_OPERATIONS",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_PACK_IMAGE_OPERATIONS",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_PACK_REDUCE",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_LAZILY_UNPACK",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_CONV_IM2COL",(()=>ENV.getBool("WEBGL_PACK")));ENV.registerFlag("WEBGL_MAX_TEXTURE_SIZE",(()=>getWebGLMaxTextureSize(ENV.getNumber("WEBGL_VERSION"))));ENV.registerFlag("WEBGL_MAX_TEXTURES_IN_SHADER",(()=>getMaxTexturesInShader(ENV.getNumber("WEBGL_VERSION"))));ENV.registerFlag("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION",(()=>{const e=ENV.getNumber("WEBGL_VERSION");if(e===0){return 0}return getWebGLDisjointQueryTimerVersion(e)}));ENV.registerFlag("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE",(()=>ENV.getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")>0&&!isMobile()));ENV.registerFlag("WEBGL_RENDER_FLOAT32_CAPABLE",(()=>isCapableOfRenderingToFloatTexture(ENV.getNumber("WEBGL_VERSION"))));ENV.registerFlag("WEBGL_RENDER_FLOAT32_ENABLED",(()=>ENV.getBool("WEBGL_FORCE_F16_TEXTURES")?false:ENV.getBool("WEBGL_RENDER_FLOAT32_CAPABLE")));ENV.registerFlag("WEBGL_DOWNLOAD_FLOAT_ENABLED",(()=>isDownloadFloatTextureEnabled(ENV.getNumber("WEBGL_VERSION"))));ENV.registerFlag("WEBGL_FENCE_API_ENABLED",(()=>isWebGLFenceEnabled(ENV.getNumber("WEBGL_VERSION"))));ENV.registerFlag("WEBGL_SIZE_UPLOAD_UNIFORM",(()=>{const e=ENV.getBool("WEBGL_RENDER_FLOAT32_ENABLED");return e?4:0}));ENV.registerFlag("WEBGL_DELETE_TEXTURE_THRESHOLD",(()=>-1),(e=>{if(e<0&&e!==-1){throw new Error(`WEBGL_DELETE_TEXTURE_THRESHOLD must be -1 (indicating never `+`delete) or at least 0, but got ${e}.`)}}));ENV.registerFlag("WEBGL_FLUSH_THRESHOLD",(()=>isMobile()&&ENV.getBool("IS_CHROME")?1:-1),(e=>{if(e<0&&e!==-1){throw new Error(`WEBGL_FLUSH_THRESHOLD must be -1 (indicating never `+`manual flush) or at least 0, but got ${e}.`)}}));ENV.registerFlag("CPU_HANDOFF_SIZE_THRESHOLD",(()=>128));
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getGlslDifferences(){let e;let t;let n;let r;let s;let a;let o;let i;let u;let c;if(env().getNumber("WEBGL_VERSION")===2){e="#version 300 es";t="in";n="out";r="in";s="texture";a="outputColor";o="out vec4 outputColor;";i=`\n      bool isnan_custom(float val) {\n        return (val > 0.0 || val < 0.0) ? false : val != 0.0;\n      }\n\n      bvec4 isnan_custom(vec4 val) {\n        return bvec4(isnan_custom(val.x),\n          isnan_custom(val.y), isnan_custom(val.z), isnan_custom(val.w));\n      }\n\n      #define isnan(value) isnan_custom(value)\n    `;u=``;c=`\n      #define round(value) newRound(value)\n      int newRound(float value) {\n        return int(floor(value + 0.5));\n      }\n\n      ivec4 newRound(vec4 value) {\n        return ivec4(floor(value + vec4(0.5)));\n      }\n    `;}else {e="";t="attribute";n="varying";r="varying";s="texture2D";a="gl_FragColor";o="";i=`\n      #define isnan(value) isnan_custom(value)\n      bool isnan_custom(float val) {\n        return (val > 0. || val < 1. || val == 0.) ? false : true;\n      }\n      bvec4 isnan_custom(vec4 val) {\n        return bvec4(isnan(val.x), isnan(val.y), isnan(val.z), isnan(val.w));\n      }\n    `;u=`\n      uniform float INFINITY;\n\n      bool isinf(float val) {\n        return abs(val) == INFINITY;\n      }\n      bvec4 isinf(vec4 val) {\n        return equal(abs(val), vec4(INFINITY));\n      }\n    `;c=`\n      int round(float value) {\n        return int(floor(value + 0.5));\n      }\n\n      ivec4 round(vec4 value) {\n        return ivec4(floor(value + vec4(0.5)));\n      }\n    `;}return {version:e,attribute:t,varyingVs:n,varyingFs:r,texture2D:s,output:a,defineOutput:o,defineSpecialNaN:i,defineSpecialInf:u,defineRound:c}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getLogicalCoordinatesFromFlatIndex(e,t,n="index"){const r=computeStrides(t);return r.map(((t,s)=>{const a=`int ${e[s]} = ${n} / ${t}`;const o=s===r.length-1?`int ${e[s+1]} = ${n} - ${e[s]} * ${t}`:`index -= ${e[s]} * ${t}`;return `${a}; ${o};`})).join("")}function getFlatIndexFrom3D(e){const t=computeStrides(e).map((e=>e.toString()));return `\n  int getFlatIndex(ivec3 coords) {\n    return coords.x * ${t[0]} + coords.y * ${t[1]} + coords.z;\n  }\n`}const ENCODE_FLOAT_SNIPPET=`\n  const float FLOAT_MAX = 1.70141184e38;\n  const float FLOAT_MIN = 1.17549435e-38;\n\n  lowp vec4 encode_float(highp float v) {\n    if (isnan(v)) {\n      return vec4(255, 255, 255, 255);\n    }\n\n    highp float av = abs(v);\n\n    if(av < FLOAT_MIN) {\n      return vec4(0.0, 0.0, 0.0, 0.0);\n    } else if(v > FLOAT_MAX) {\n      return vec4(0.0, 0.0, 128.0, 127.0) / 255.0;\n    } else if(v < -FLOAT_MAX) {\n      return vec4(0.0, 0.0,  128.0, 255.0) / 255.0;\n    }\n\n    highp vec4 c = vec4(0,0,0,0);\n\n    highp float e = floor(log2(av));\n    highp float m = exp2(fract(log2(av))) - 1.0;\n\n    c[2] = floor(128.0 * m);\n    m -= c[2] / 128.0;\n    c[1] = floor(32768.0 * m);\n    m -= c[1] / 32768.0;\n    c[0] = floor(8388608.0 * m);\n\n    highp float ebias = e + 127.0;\n    c[3] = floor(ebias / 2.0);\n    ebias -= c[3] * 2.0;\n    c[2] += floor(ebias) * 128.0;\n\n    c[3] += 128.0 * step(0.0, -v);\n\n    return c / 255.0;\n  }\n`
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */;class DecodeMatrixProgram{constructor(e){this.variableNames=["A"];this.packedInputs=false;this.packedOutput=true;this.outPackingScheme=PackingScheme.DENSE;const t=getDenseTexShape(e);const n=getGlslDifferences();this.outputShape=e;this.userCode=`\n      ivec3 outCoordsFromFlatIndex(int index) {\n        ${getLogicalCoordinatesFromFlatIndex(["r","c","d"],e)}\n        return ivec3(r, c, d);\n      }\n\n      void main() {\n        ivec2 resTexRC = ivec2(resultUV.yx *\n          vec2(${t[0]}, ${t[1]}));\n        int index = 4 * (resTexRC.x * ${t[1]} + resTexRC.y);\n\n        vec4 result = vec4(0.);\n\n        for (int i=0; i<4; i++) {\n          int flatIndex = index + i;\n          ivec3 rc = outCoordsFromFlatIndex(flatIndex);\n          result[i] = getA(rc.x, rc.y, rc.z);\n        }\n\n        ${n.output} = result;\n      }\n    `;}}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class DecodeMatrixPackedProgram{constructor(e){this.variableNames=["A"];this.packedInputs=true;this.packedOutput=true;this.outPackingScheme=PackingScheme.DENSE;const t=getDenseTexShape(e);const n=getGlslDifferences();this.outputShape=e;this.userCode=`\n      ivec3 outCoordsFromFlatIndex(int index) {\n        ${getLogicalCoordinatesFromFlatIndex(["r","c","d"],e)}\n        return ivec3(r, c, d);\n      }\n\n      void main() {\n        ivec2 resTexRC = ivec2(resultUV.yx *\n          vec2(${t[0]}, ${t[1]}));\n        int index = 4 * (resTexRC.x * ${t[1]} + resTexRC.y);\n\n        vec4 result = vec4(0.);\n\n        for (int i=0; i<4; i++) {\n          int flatIndex = index + i;\n          ivec3 rc = outCoordsFromFlatIndex(flatIndex);\n          result[i] = getChannel(getA(rc.x, rc.y, rc.z), vec2(rc.y, rc.z));\n        }\n\n        ${n.output} = result;\n      }\n    `;}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class EncodeFloatProgram{constructor(e){this.variableNames=["A"];this.outTexUsage=TextureUsage.DOWNLOAD;const t=getGlslDifferences();this.outputShape=e;this.userCode=`\n      ${ENCODE_FLOAT_SNIPPET}\n\n      void main() {\n        float x = getAAtOutCoords();\n        ${t.output} = encode_float(x);\n      }\n    `;}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class EncodeFloatPackedProgram{constructor(e){this.variableNames=["A"];this.packedInputs=true;this.packedOutput=false;this.outTexUsage=TextureUsage.DOWNLOAD;const t=getGlslDifferences();this.outputShape=e;this.userCode=`\n      ${ENCODE_FLOAT_SNIPPET}\n\n      void main() {\n        ivec3 coords = getOutputCoords();\n        float x = getChannel(getAAtOutCoords(), vec2(coords.y, coords.z));\n        ${t.output} = encode_float(x);\n      }\n    `;}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class EncodeMatrixProgram{constructor(e,t,n=false){this.variableNames=["A"];const r=getGlslDifferences();const[s,a]=t;this.outputShape=e;let o=`result`;if(n){o=`floor(result * 255. + 0.5)`;}this.userCode=`\n      ${getFlatIndexFrom3D(e)}\n\n      void main() {\n        ivec3 coords = getOutputCoords();\n\n        int flatIndex = getFlatIndex(coords);\n        int offset = imod(flatIndex, 4);\n\n        flatIndex = idiv(flatIndex, 4, 1.);\n\n        int r = flatIndex / ${a};\n        int c = imod(flatIndex, ${a});\n        vec2 uv = (vec2(c, r) + halfCR) / vec2(${a}.0, ${s}.0);\n        vec4 values = ${r.texture2D}(A, uv);\n\n        float result;\n\n        if(offset == 0) {\n          result = values[0];\n        } else if(offset == 1) {\n          result = values[1];\n        } else if(offset == 2) {\n          result = values[2];\n        } else {\n          result = values[3];\n        }\n\n        ${r.output} = vec4(${o}, 0., 0., 0.);\n      }\n    `;}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class EncodeMatrixPackedProgram{constructor(e,t,n=false){this.variableNames=["A"];this.packedInputs=false;this.packedOutput=true;const r=getGlslDifferences();const[s,a]=t;this.outputShape=e;let o="";let i="result";if(n){i="floor(result * 255. + 0.5)";}for(let t=0;t<=1;t++){for(let n=0;n<=1;n++){const i=t*2+n;o+=`\n          localCoords = coords;\n          if(localCoords[2] + ${n} < ${e[2]}) {\n            localCoords[2] += ${n};\n            if(localCoords[1] + ${t} < ${e[1]}) {\n              localCoords[1] += ${t};\n\n              flatIndex = getFlatIndex(localCoords);\n              offset = imod(flatIndex, 4);\n\n              flatIndex = idiv(flatIndex, 4, 1.);\n\n              r = flatIndex / ${a};\n              c = imod(flatIndex, ${a});\n              uv = (vec2(c, r) + halfCR) / vec2(${a}.0, ${s}.0);\n              values = ${r.texture2D}(A, uv);\n\n              if(offset == 0) {\n                result[${i}] = values[0];\n              } else if(offset == 1) {\n                result[${i}] = values[1];\n              } else if(offset == 2) {\n                result[${i}] = values[2];\n              } else {\n                result[${i}] = values[3];\n              }\n            }\n          }\n        `;}}this.userCode=`\n      ${getFlatIndexFrom3D(e)}\n\n      void main() {\n        ivec3 coords = getOutputCoords();\n\n        vec4 result = vec4(0.);\n        int flatIndex, r, c, offset;\n        ivec3 localCoords;\n        vec2 uv;\n        vec4 values;\n\n        ${o}\n\n        ${r.output} = ${i};\n      }\n    `;}}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function createVertexShader(e){const t=getGlslDifferences();const n=`${t.version}\n    precision highp float;\n    ${t.attribute} vec3 clipSpacePos;\n    ${t.attribute} vec2 uv;\n    ${t.varyingVs} vec2 resultUV;\n\n    void main() {\n      gl_Position = vec4(clipSpacePos, 1);\n      resultUV = uv;\n    }`;return createVertexShader$1(e,n)}function createVertexBuffer(e){const t=new Float32Array([-1,1,0,0,1,-1,-1,0,0,0,1,1,0,1,1,1,-1,0,1,0]);return createStaticVertexBuffer(e,t)}function createIndexBuffer(e){const t=new Uint16Array([0,1,2,2,1,3]);return createStaticIndexBuffer(e,t)}function createAndConfigureTexture(e,t,n,r,s,a){validateTextureSize(t,n);const o=createTexture(e);const i=e.TEXTURE_2D;callAndCheck(e,(()=>e.bindTexture(i,o)));callAndCheck(e,(()=>e.texParameteri(i,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE)));callAndCheck(e,(()=>e.texParameteri(i,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE)));callAndCheck(e,(()=>e.texParameteri(i,e.TEXTURE_MIN_FILTER,e.NEAREST)));callAndCheck(e,(()=>e.texParameteri(i,e.TEXTURE_MAG_FILTER,e.NEAREST)));callAndCheck(e,(()=>e.texImage2D(i,0,r,t,n,0,s,a,null)));callAndCheck(e,(()=>e.bindTexture(e.TEXTURE_2D,null)));return o}function getInternalFormatForFloat32MatrixTexture(e){return e.internalFormatFloat}function createFloat32MatrixTexture(e,t,n,r){const[s,a]=getUnpackedMatrixTextureShapeWidthHeight(t,n);return createAndConfigureTexture(e,s,a,getInternalFormatForFloat32MatrixTexture(r),r.textureFormatFloat,e.FLOAT)}function getInternalFormatForFloat16MatrixTexture(e){return e.internalFormatHalfFloat}function createFloat16MatrixTexture(e,t,n,r){const[s,a]=getUnpackedMatrixTextureShapeWidthHeight(t,n);return createAndConfigureTexture(e,s,a,getInternalFormatForFloat16MatrixTexture(r),r.textureFormatFloat,r.textureTypeHalfFloat)}function getInternalFormatForUnsignedBytesMatrixTexture(e){return e.downloadTextureFormat}function createUnsignedBytesMatrixTexture(e,t,n,r){const[s,a]=getUnpackedMatrixTextureShapeWidthHeight(t,n);return createAndConfigureTexture(e,s,a,getInternalFormatForUnsignedBytesMatrixTexture(r),e.RGBA,e.UNSIGNED_BYTE)}function getInternalFormatForPackedMatrixTexture(e){return e.internalFormatPackedFloat}function createPackedMatrixTexture(e,t,n,r){const[s,a]=getPackedMatrixTextureShapeWidthHeight(t,n);return createAndConfigureTexture(e,s,a,getInternalFormatForPackedMatrixTexture(r),e.RGBA,e.FLOAT)}function getInternalFormatForFloat16PackedMatrixTexture(e){return e.internalFormatPackedHalfFloat}function createFloat16PackedMatrixTexture(e,t,n,r){const[s,a]=getPackedMatrixTextureShapeWidthHeight(t,n);return createAndConfigureTexture(e,s,a,getInternalFormatForFloat16PackedMatrixTexture(r),e.RGBA,r.textureTypeHalfFloat)}function bindVertexProgramAttributeStreams(e,t,n){const r=0;const s=3*4;const a=3*4+2*4;callAndCheck(e,(()=>e.bindBuffer(e.ARRAY_BUFFER,n)));const o=bindVertexBufferToProgramAttribute(e,t,"clipSpacePos",n,3,a,r);return o&&bindVertexBufferToProgramAttribute(e,t,"uv",n,2,a,s)}function uploadDenseMatrixToTexture(e,t,n,r,s,a){callAndCheck(e,(()=>e.bindTexture(e.TEXTURE_2D,t)));let o,i,u;if(s instanceof Uint8Array){o=new Uint8Array(n*r*4);i=e.UNSIGNED_BYTE;u=e.RGBA;}else {o=new Float32Array(n*r*4);i=e.FLOAT;u=a.internalFormatPackedFloat;}o.set(s);callAndCheck(e,(()=>e.texImage2D(e.TEXTURE_2D,0,u,n,r,0,e.RGBA,i,o)));callAndCheck(e,(()=>e.bindTexture(e.TEXTURE_2D,null)));}function uploadPixelDataToTexture(e,t,n){callAndCheck(e,(()=>e.bindTexture(e.TEXTURE_2D,t)));if(n.data instanceof Uint8Array){callAndCheck(e,(()=>e.texImage2D(e.TEXTURE_2D,0,e.RGBA,n.width,n.height,0,e.RGBA,e.UNSIGNED_BYTE,n.data)));}else {callAndCheck(e,(()=>e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,n)));}callAndCheck(e,(()=>e.bindTexture(e.TEXTURE_2D,null)));}function createBufferFromOutputTexture(e,t,n,r){const s=e.createBuffer();callAndCheck(e,(()=>e.bindBuffer(e.PIXEL_PACK_BUFFER,s)));const a=4;const o=4;const i=a*o*t*n;callAndCheck(e,(()=>e.bufferData(e.PIXEL_PACK_BUFFER,i,e.STREAM_READ)));callAndCheck(e,(()=>e.readPixels(0,0,n,t,e.RGBA,e.FLOAT,0)));callAndCheck(e,(()=>e.bindBuffer(e.PIXEL_PACK_BUFFER,null)));return s}function downloadFloat32MatrixFromBuffer(e,t,n){const r=e;const s=new Float32Array(n);r.bindBuffer(r.PIXEL_PACK_BUFFER,t);r.getBufferSubData(r.PIXEL_PACK_BUFFER,0,s);r.bindBuffer(r.PIXEL_PACK_BUFFER,null);return s}function downloadByteEncodedFloatMatrixFromOutputTexture(e,t,n,r){const[s,a]=getUnpackedMatrixTextureShapeWidthHeight(t,n);const o=4;const i=new Uint8Array(getUnpackedArraySizeFromMatrixSize(t*n,o));callAndCheck(e,(()=>e.readPixels(0,0,s,a,r.downloadTextureFormat,e.UNSIGNED_BYTE,i)));return new Float32Array(i.buffer)}function downloadPackedMatrixFromBuffer(e,t,n,r,s,a,o,i){const u=e;const c=new Float32Array(getPackedRGBAArraySizeFromMatrixShape(a,o));u.bindBuffer(u.PIXEL_PACK_BUFFER,t);u.getBufferSubData(u.PIXEL_PACK_BUFFER,0,c);u.bindBuffer(u.PIXEL_PACK_BUFFER,null);return c}function downloadMatrixFromPackedOutputTexture(e,t,n){const r=new Float32Array(t*n*4);callAndCheck(e,(()=>e.readPixels(0,0,n,t,e.RGBA,e.FLOAT,r)));return r}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class GPGPUContext{constructor(e){this.outputTexture=null;this.program=null;this.disposed=false;this.vertexAttrsAreBound=false;this.itemsToPoll=[];const t=env().getNumber("WEBGL_VERSION");if(e!=null){this.gl=e;setWebGLContext(t,e);}else {this.gl=getWebGLContext(t);}let n="WEBGL_color_buffer_float";const r="EXT_color_buffer_half_float";if(env().getNumber("WEBGL_VERSION")===1){const e="OES_texture_float";const t="OES_texture_half_float";this.textureFloatExtension=getExtensionOrThrow(this.gl,e);if(hasExtension(this.gl,t)){this.textureHalfFloatExtension=getExtensionOrThrow(this.gl,t);}else if(env().get("WEBGL_FORCE_F16_TEXTURES")){throw new Error("GL context does not support half float textures, yet the "+"environment flag WEBGL_FORCE_F16_TEXTURES is set to true.")}this.colorBufferFloatExtension=this.gl.getExtension(n);if(hasExtension(this.gl,r)){this.colorBufferHalfFloatExtension=getExtensionOrThrow(this.gl,r);}else if(env().get("WEBGL_FORCE_F16_TEXTURES")){throw new Error("GL context does not support color renderable half floats, yet "+"the environment flag WEBGL_FORCE_F16_TEXTURES is set to true.")}}else {n="EXT_color_buffer_float";if(hasExtension(this.gl,n)){this.colorBufferFloatExtension=this.gl.getExtension(n);}else if(hasExtension(this.gl,r)){this.colorBufferHalfFloatExtension=this.gl.getExtension(r);}else {throw new Error("GL context does not support color renderable floats")}}this.vertexBuffer=createVertexBuffer(this.gl);this.indexBuffer=createIndexBuffer(this.gl);this.framebuffer=createFramebuffer(this.gl);this.textureConfig=getTextureConfig(this.gl,this.textureHalfFloatExtension);}get debug(){return env().getBool("DEBUG")}dispose(){if(this.disposed){return}if(this.program!=null){console.warn("Disposing a GPGPUContext that still has a bound WebGLProgram."+" This is probably a resource leak, delete the program with "+"GPGPUContext.deleteProgram before disposing.");}if(this.outputTexture!=null){console.warn("Disposing a GPGPUContext that still has a bound output matrix "+"texture.  This is probably a resource leak, delete the output "+"matrix texture with GPGPUContext.deleteMatrixTexture before "+"disposing.");}const e=this.gl;callAndCheck(e,(()=>e.finish()));callAndCheck(e,(()=>e.bindFramebuffer(e.FRAMEBUFFER,null)));callAndCheck(e,(()=>e.deleteFramebuffer(this.framebuffer)));callAndCheck(e,(()=>e.bindBuffer(e.ARRAY_BUFFER,null)));callAndCheck(e,(()=>e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,null)));callAndCheck(e,(()=>e.deleteBuffer(this.indexBuffer)));this.disposed=true;}createFloat32MatrixTexture(e,t){this.throwIfDisposed();return createFloat32MatrixTexture(this.gl,e,t,this.textureConfig)}createFloat16MatrixTexture(e,t){this.throwIfDisposed();return createFloat16MatrixTexture(this.gl,e,t,this.textureConfig)}createUnsignedBytesMatrixTexture(e,t){this.throwIfDisposed();return createUnsignedBytesMatrixTexture(this.gl,e,t,this.textureConfig)}uploadPixelDataToTexture(e,t){this.throwIfDisposed();uploadPixelDataToTexture(this.gl,e,t);}uploadDenseMatrixToTexture(e,t,n,r){this.throwIfDisposed();uploadDenseMatrixToTexture(this.gl,e,t,n,r,this.textureConfig);}createFloat16PackedMatrixTexture(e,t){this.throwIfDisposed();return createFloat16PackedMatrixTexture(this.gl,e,t,this.textureConfig)}createPackedMatrixTexture(e,t){this.throwIfDisposed();return createPackedMatrixTexture(this.gl,e,t,this.textureConfig)}deleteMatrixTexture(e){this.throwIfDisposed();if(this.outputTexture===e){unbindColorTextureFromFramebuffer(this.gl,this.framebuffer);this.outputTexture=null;}callAndCheck(this.gl,(()=>this.gl.deleteTexture(e)));}downloadByteEncodedFloatMatrixFromOutputTexture(e,t,n){return this.downloadMatrixDriver(e,(()=>downloadByteEncodedFloatMatrixFromOutputTexture(this.gl,t,n,this.textureConfig)))}downloadPackedMatrixFromBuffer(e,t,n,r,s,a){return downloadPackedMatrixFromBuffer(this.gl,e,t,n,r,s,a,this.textureConfig)}downloadFloat32MatrixFromBuffer(e,t){return downloadFloat32MatrixFromBuffer(this.gl,e,t)}createBufferFromTexture(e,t,n){this.bindTextureToFrameBuffer(e);const r=createBufferFromOutputTexture(this.gl,t,n,this.textureConfig);this.unbindTextureToFrameBuffer();return r}createAndWaitForFence(){const e=this.createFence(this.gl);return this.pollFence(e)}createFence(e){let t;let n;if(env().getBool("WEBGL_FENCE_API_ENABLED")){const r=e;const s=r.fenceSync(r.SYNC_GPU_COMMANDS_COMPLETE,0);e.flush();n=()=>{const e=r.clientWaitSync(s,0,0);return e===r.ALREADY_SIGNALED||e===r.CONDITION_SATISFIED};t=s;}else if(env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")>0){t=this.beginQuery();this.endQuery();n=()=>this.isQueryAvailable(t,env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION"));}else {n=()=>true;}return {query:t,isFencePassed:n}}downloadMatrixFromPackedTexture(e,t,n){return this.downloadMatrixDriver(e,(()=>downloadMatrixFromPackedOutputTexture(this.gl,t,n)))}createProgram(e){this.throwIfDisposed();const t=this.gl;const n=createFragmentShader(t,e);if(this.vertexShader==null){this.vertexShader=createVertexShader(t);}const r=createProgram(t);callAndCheck(t,(()=>t.attachShader(r,this.vertexShader)));callAndCheck(t,(()=>t.attachShader(r,n)));linkProgram(t,r);if(this.debug){validateProgram(t,r);}if(!this.vertexAttrsAreBound){this.setProgram(r);this.vertexAttrsAreBound=bindVertexProgramAttributeStreams(t,this.program,this.vertexBuffer);}return r}deleteProgram(e){this.throwIfDisposed();if(e===this.program){this.program=null;}if(e!=null){callAndCheck(this.gl,(()=>this.gl.deleteProgram(e)));}}setProgram(e){this.throwIfDisposed();this.program=e;if(this.program!=null&&this.debug){validateProgram(this.gl,this.program);}callAndCheck(this.gl,(()=>this.gl.useProgram(e)));}getUniformLocation(e,t,n=true){this.throwIfDisposed();if(n){return getProgramUniformLocationOrThrow(this.gl,e,t)}else {return getProgramUniformLocation(this.gl,e,t)}}getAttributeLocation(e,t){this.throwIfDisposed();return callAndCheck(this.gl,(()=>this.gl.getAttribLocation(e,t)))}getUniformLocationNoThrow(e,t){this.throwIfDisposed();return this.gl.getUniformLocation(e,t)}setInputMatrixTexture(e,t,n){this.throwIfDisposed();this.throwIfNoProgram();bindTextureToProgramUniformSampler(this.gl,e,t,n);}setOutputMatrixTexture(e,t,n){this.setOutputMatrixTextureDriver(e,n,t);}setOutputPackedMatrixTexture(e,t,n){this.throwIfDisposed();const[r,s]=getPackedMatrixTextureShapeWidthHeight(t,n);this.setOutputMatrixTextureDriver(e,r,s);}setOutputMatrixWriteRegion(e,t,n,r){this.setOutputMatrixWriteRegionDriver(n,e,r,t);}setOutputPackedMatrixWriteRegion(e,t,n,r){throw new Error("setOutputPackedMatrixWriteRegion not implemented.")}debugValidate(){if(this.program!=null){validateProgram(this.gl,this.program);}validateFramebuffer(this.gl);}executeProgram(){this.throwIfDisposed();this.throwIfNoProgram();const e=this.gl;if(this.debug){this.debugValidate();}callAndCheck(e,(()=>e.drawElements(e.TRIANGLES,6,e.UNSIGNED_SHORT,0)));}blockUntilAllProgramsCompleted(){this.throwIfDisposed();callAndCheck(this.gl,(()=>this.gl.finish()));}getQueryTimerExtension(){if(this.disjointQueryTimerExtension==null){this.disjointQueryTimerExtension=getExtensionOrThrow(this.gl,env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")===2?"EXT_disjoint_timer_query_webgl2":"EXT_disjoint_timer_query");}return this.disjointQueryTimerExtension}getQueryTimerExtensionWebGL2(){return this.getQueryTimerExtension()}getQueryTimerExtensionWebGL1(){return this.getQueryTimerExtension()}beginQuery(){if(env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")===2){const e=this.gl;const t=this.getQueryTimerExtensionWebGL2();const n=e.createQuery();e.beginQuery(t.TIME_ELAPSED_EXT,n);return n}const e=this.getQueryTimerExtensionWebGL1();const t=e.createQueryEXT();e.beginQueryEXT(e.TIME_ELAPSED_EXT,t);return t}endQuery(){if(env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION")===2){const e=this.gl;const t=this.getQueryTimerExtensionWebGL2();e.endQuery(t.TIME_ELAPSED_EXT);return}const e=this.getQueryTimerExtensionWebGL1();e.endQueryEXT(e.TIME_ELAPSED_EXT);}async waitForQueryAndGetTime(e){await repeatedTry((()=>this.disposed||this.isQueryAvailable(e,env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION"))));return this.getQueryTime(e,env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION"))}getQueryTime(e,t){if(t===0){return null}if(t===2){const t=this.gl;const n=t.getQueryParameter(e,t.QUERY_RESULT);return n/1e6}else {const t=this.getQueryTimerExtensionWebGL1();const n=t.getQueryObjectEXT(e,t.QUERY_RESULT_EXT);return n/1e6}}isQueryAvailable(e,t){if(t===0){return true}if(t===2){const t=this.gl;const n=this.getQueryTimerExtensionWebGL2();const r=t.getQueryParameter(e,t.QUERY_RESULT_AVAILABLE);if(this.disjoint==null){this.disjoint=this.gl.getParameter(n.GPU_DISJOINT_EXT);}return r&&!this.disjoint}else {const t=this.getQueryTimerExtensionWebGL1();const n=t.getQueryObjectEXT(e,t.QUERY_RESULT_AVAILABLE_EXT);if(this.disjoint==null){this.disjoint=this.gl.getParameter(t.GPU_DISJOINT_EXT);}return n&&!this.disjoint}}pollFence(e){return new Promise((t=>{this.addItemToPoll((()=>e.isFencePassed()),(()=>t()));}))}pollItems(){const e=linearSearchLastTrue(this.itemsToPoll.map((e=>e.isDoneFn)));for(let t=0;t<=e;++t){const{resolveFn:e}=this.itemsToPoll[t];e();}this.itemsToPoll=this.itemsToPoll.slice(e+1);}addItemToPoll(e,t){this.itemsToPoll.push({isDoneFn:e,resolveFn:t});if(this.itemsToPoll.length>1){return}repeatedTry((()=>{this.pollItems();return this.itemsToPoll.length===0}));}bindTextureToFrameBuffer(e){this.throwIfDisposed();bindColorTextureToFramebuffer(this.gl,e,this.framebuffer);if(this.debug){validateFramebuffer(this.gl);}}unbindTextureToFrameBuffer(){if(this.outputTexture!=null){bindColorTextureToFramebuffer(this.gl,this.outputTexture,this.framebuffer);if(this.debug){validateFramebuffer(this.gl);}}else {unbindColorTextureFromFramebuffer(this.gl,this.framebuffer);}}downloadMatrixDriver(e,t){this.bindTextureToFrameBuffer(e);const n=t();this.unbindTextureToFrameBuffer();return n}setOutputMatrixTextureDriver(e,t,n){this.throwIfDisposed();const r=this.gl;bindColorTextureToFramebuffer(r,e,this.framebuffer);if(this.debug){validateFramebuffer(r);}this.outputTexture=e;callAndCheck(r,(()=>r.viewport(0,0,t,n)));callAndCheck(r,(()=>r.scissor(0,0,t,n)));}setOutputMatrixWriteRegionDriver(e,t,n,r){this.throwIfDisposed();callAndCheck(this.gl,(()=>this.gl.scissor(e,t,n,r)));}throwIfDisposed(){if(this.disposed){throw new Error("Attempted to use disposed GPGPUContext.")}}throwIfNoProgram(){if(this.program==null){throw new Error("No GPU program is currently set.")}}}function linearSearchLastTrue(e){let t=0;for(;t<e.length;++t){const n=e[t]();if(!n){break}}return t-1}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const{getBroadcastDims:getBroadcastDims}=backend_util;function makeShader(e,t,n,r){const s=[];e.forEach((e=>{const t=sizeFromShape(e.shapeInfo.logicalShape);if(e.shapeInfo.isUniform){s.push(`uniform float ${e.name}${t>1?`[${t}]`:""};`);}else {s.push(`uniform sampler2D ${e.name};`);s.push(`uniform int offset${e.name};`);}}));const a=s.join("\n");const o=e.map((e=>getInputSamplingSnippet(e,t,r))).join("\n");const i=t.texShape;const u=getGlslDifferences();const c=getFloatTextureSampleSnippet(u);let l;let p;let d=getShaderPrefix(u);if(t.isPacked){l=getPackedOutputSamplingSnippet(t.logicalShape,i);p=getFloatTextureSetRGBASnippet(u);}else {l=getOutputSamplingSnippet(t.logicalShape,i);p=getFloatTextureSetRSnippet(u);}if(r){d+=SHADER_PACKED_PREFIX;}const h=[d,c,p,a,l,o,n].join("\n");return h}function getSamplerFromInInfo(e){const t=e.shapeInfo.logicalShape;switch(t.length){case 0:return getSamplerScalar(e);case 1:return getSampler1D(e);case 2:return getSampler2D(e);case 3:return getSampler3D(e);case 4:return getSampler4D(e);case 5:return getSampler5D(e);case 6:return getSampler6D(e);default:throw new Error(`${t.length}-D input sampling`+` is not yet supported`)}}function getPackedSamplerFromInInfo(e){const t=e.shapeInfo.logicalShape;switch(t.length){case 0:return getPackedSamplerScalar(e);case 1:return getPackedSampler1D(e);case 2:return getPackedSampler2D(e);case 3:return getPackedSampler3D(e);default:return getPackedSamplerND(e)}}function getInputSamplingSnippet(e,t,n=false){let r="";if(n){r+=getPackedSamplerFromInInfo(e);}else {r+=getSamplerFromInInfo(e);}const s=e.shapeInfo.logicalShape;const a=t.logicalShape;if(s.length<=a.length){if(n){r+=getPackedSamplerAtOutputCoords(e,t);}else {r+=getSamplerAtOutputCoords(e,t);}}return r}function getPackedOutputSamplingSnippet(e,t){switch(e.length){case 0:return getOutputScalarCoords();case 1:return getOutputPacked1DCoords(e,t);case 2:return getOutputPacked2DCoords(e,t);case 3:return getOutputPacked3DCoords(e,t);default:return getOutputPackedNDCoords(e,t)}}function getOutputSamplingSnippet(e,t){switch(e.length){case 0:return getOutputScalarCoords();case 1:return getOutput1DCoords(e,t);case 2:return getOutput2DCoords(e,t);case 3:return getOutput3DCoords(e,t);case 4:return getOutput4DCoords(e,t);case 5:return getOutput5DCoords(e,t);case 6:return getOutput6DCoords(e,t);default:throw new Error(`${e.length}-D output sampling is not yet supported`)}}function getFloatTextureSampleSnippet(e){return `\n    float sampleTexture(sampler2D textureSampler, vec2 uv) {\n      return ${e.texture2D}(textureSampler, uv).r;\n    }\n  `}function getFloatTextureSetRSnippet(e){return `\n    void setOutput(float val) {\n      ${e.output} = vec4(val, 0, 0, 0);\n    }\n  `}function getFloatTextureSetRGBASnippet(e){return `\n    void setOutput(vec4 val) {\n      ${e.output} = val;\n    }\n  `}function getShaderPrefix(e){const t=`${e.version}\n    precision highp float;\n    precision highp int;\n    precision highp sampler2D;\n    ${e.varyingFs} vec2 resultUV;\n    ${e.defineOutput}\n    const vec2 halfCR = vec2(0.5, 0.5);\n\n    struct ivec5\n    {\n      int x;\n      int y;\n      int z;\n      int w;\n      int u;\n    };\n\n    struct ivec6\n    {\n      int x;\n      int y;\n      int z;\n      int w;\n      int u;\n      int v;\n    };\n\n    uniform float NAN;\n    ${e.defineSpecialNaN}\n    ${e.defineSpecialInf}\n    ${e.defineRound}\n\n    int imod(int x, int y) {\n      return x - y * (x / y);\n    }\n\n    int idiv(int a, int b, float sign) {\n      int res = a / b;\n      int mod = imod(a, b);\n      if (sign < 0. && mod != 0) {\n        res -= 1;\n      }\n      return res;\n    }\n\n    //Based on the work of Dave Hoskins\n    //https://www.shadertoy.com/view/4djSRW\n    #define HASHSCALE1 443.8975\n    float random(float seed){\n      vec2 p = resultUV * seed;\n      vec3 p3  = fract(vec3(p.xyx) * HASHSCALE1);\n      p3 += dot(p3, p3.yzx + 19.19);\n      return fract((p3.x + p3.y) * p3.z);\n    }\n\n    ${SAMPLE_1D_SNIPPET}\n    ${SAMPLE_2D_SNIPPET}\n    ${SAMPLE_3D_SNIPPET}\n  `;return t}const SAMPLE_1D_SNIPPET=`\nvec2 uvFromFlat(int texNumR, int texNumC, int index) {\n  int texR = index / texNumC;\n  int texC = index - texR * texNumC;\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\n}\nvec2 packedUVfrom1D(int texNumR, int texNumC, int index) {\n  int texelIndex = index / 2;\n  int texR = texelIndex / texNumC;\n  int texC = texelIndex - texR * texNumC;\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\n}\n`;const SAMPLE_2D_SNIPPET=`\nvec2 packedUVfrom2D(int texelsInLogicalRow, int texNumR,\n  int texNumC, int row, int col) {\n  int texelIndex = (row / 2) * texelsInLogicalRow + (col / 2);\n  int texR = texelIndex / texNumC;\n  int texC = texelIndex - texR * texNumC;\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\n}\n`;const SAMPLE_3D_SNIPPET=`\nvec2 packedUVfrom3D(int texNumR, int texNumC,\n    int texelsInBatch, int texelsInLogicalRow, int b,\n    int row, int col) {\n  int index = b * texelsInBatch + (row / 2) * texelsInLogicalRow + (col / 2);\n  int texR = index / texNumC;\n  int texC = index - texR * texNumC;\n  return (vec2(texC, texR) + halfCR) / vec2(texNumC, texNumR);\n}\n`;const SHADER_PACKED_PREFIX=`\n  float getChannel(vec4 frag, vec2 innerDims) {\n    vec2 modCoord = mod(innerDims, 2.);\n    return modCoord.x == 0. ?\n      (modCoord.y == 0. ? frag.r : frag.g) :\n      (modCoord.y == 0. ? frag.b : frag.a);\n  }\n  float getChannel(vec4 frag, int dim) {\n    float modCoord = mod(float(dim), 2.);\n    return modCoord == 0. ? frag.r : frag.g;\n  }\n`;function getOutputScalarCoords(){return `\n    int getOutputCoords() {\n      return 0;\n    }\n  `}function getOutputPacked1DCoords(e,t){const n=[Math.ceil(t[0]/2),Math.ceil(t[1]/2)];if(n[0]===1){return `\n      int getOutputCoords() {\n        return 2 * int(resultUV.x * ${n[1]}.0);\n      }\n    `}if(n[1]===1){return `\n      int getOutputCoords() {\n        return 2 * int(resultUV.y * ${n[0]}.0);\n      }\n    `}return `\n    int getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n                             vec2(${n[0]}, ${n[1]}));\n      return 2 * (resTexRC.x * ${n[1]} + resTexRC.y);\n    }\n  `}function getOutput1DCoords(e,t){if(t[0]===1){return `\n      int getOutputCoords() {\n        return int(resultUV.x * ${t[1]}.0);\n      }\n    `}if(t[1]===1){return `\n      int getOutputCoords() {\n        return int(resultUV.y * ${t[0]}.0);\n      }\n    `}return `\n    int getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n                             vec2(${t[0]}, ${t[1]}));\n      return resTexRC.x * ${t[1]} + resTexRC.y;\n    }\n  `}function getOutputPacked3DCoords(e,t){const n=[Math.ceil(t[0]/2),Math.ceil(t[1]/2)];const r=Math.ceil(e[2]/2);const s=r*Math.ceil(e[1]/2);return `\n    ivec3 getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n                             vec2(${n[0]}, ${n[1]}));\n      int index = resTexRC.x * ${n[1]} + resTexRC.y;\n\n      int b = index / ${s};\n      index -= b * ${s};\n\n      int r = 2 * (index / ${r});\n      int c = imod(index, ${r}) * 2;\n\n      return ivec3(b, r, c);\n    }\n  `}function getOutput3DCoords(e,t){const n=getLogicalCoordinatesFromFlatIndex(["r","c","d"],e);return `\n    ivec3 getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n                             vec2(${t[0]}, ${t[1]}));\n      int index = resTexRC.x * ${t[1]} + resTexRC.y;\n      ${n}\n      return ivec3(r, c, d);\n    }\n  `}function getOutputPackedNDCoords(e,t){const n=[Math.ceil(t[0]/2),Math.ceil(t[1]/2)];const r=Math.ceil(e[e.length-1]/2);const s=r*Math.ceil(e[e.length-2]/2);let a=s;let o=``;let i="b, r, c";for(let t=2;t<e.length-1;t++){a*=e[e.length-t-1];o=`\n      int b${t} = index / ${a};\n      index -= b${t} * ${a};\n    `+o;i=`b${t}, `+i;}return `\n    ivec${e.length} getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n                             vec2(${n[0]}, ${n[1]}));\n      int index = resTexRC.x * ${n[1]} + resTexRC.y;\n\n      ${o}\n\n      int b = index / ${s};\n      index -= b * ${s};\n\n      int r = 2 * (index / ${r});\n      int c = imod(index, ${r}) * 2;\n\n      return ivec${e.length}(${i});\n    }\n  `}function getOutput4DCoords(e,t){const n=getLogicalCoordinatesFromFlatIndex(["r","c","d","d2"],e);return `\n    ivec4 getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n        vec2(${t[0]}, ${t[1]}));\n      int index = resTexRC.x * ${t[1]} + resTexRC.y;\n      ${n}\n      return ivec4(r, c, d, d2);\n    }\n  `}function getOutput5DCoords(e,t){const n=getLogicalCoordinatesFromFlatIndex(["r","c","d","d2","d3"],e);return `\n    ivec5 getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx * vec2(${t[0]},\n                             ${t[1]}));\n\n      int index = resTexRC.x * ${t[1]} + resTexRC.y;\n\n      ${n}\n\n      ivec5 outShape = ivec5(r, c, d, d2, d3);\n      return outShape;\n    }\n  `}function getOutput6DCoords(e,t){const n=getLogicalCoordinatesFromFlatIndex(["r","c","d","d2","d3","d4"],e);return `\n    ivec6 getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n        vec2(${t[0]}, ${t[1]}));\n      int index = resTexRC.x * ${t[1]} + resTexRC.y;\n\n      ${n}\n\n      ivec6 result = ivec6(r, c, d, d2, d3, d4);\n      return result;\n    }\n  `}function getOutputPacked2DCoords(e,t){const n=[Math.ceil(t[0]/2),Math.ceil(t[1]/2)];if(arraysEqual(e,t)){return `\n      ivec2 getOutputCoords() {\n        return 2 * ivec2(resultUV.yx * vec2(${n[0]}, ${n[1]}));\n      }\n    `}const r=Math.ceil(e[1]/2);return `\n    ivec2 getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n                             vec2(${n[0]}, ${n[1]}));\n\n      int index = resTexRC.x * ${n[1]} + resTexRC.y;\n      int r = 2 * (index / ${r});\n      int c = imod(index, ${r}) * 2;\n\n      return ivec2(r, c);\n    }\n  `}function getOutput2DCoords(e,t){if(arraysEqual(e,t)){return `\n      ivec2 getOutputCoords() {\n        return ivec2(resultUV.yx * vec2(${t[0]}, ${t[1]}));\n      }\n    `}if(e[1]===1){return `\n      ivec2 getOutputCoords() {\n        ivec2 resTexRC = ivec2(resultUV.yx *\n                               vec2(${t[0]}, ${t[1]}));\n        int index = resTexRC.x * ${t[1]} + resTexRC.y;\n        return ivec2(index, 0);\n      }\n    `}if(e[0]===1){return `\n      ivec2 getOutputCoords() {\n        ivec2 resTexRC = ivec2(resultUV.yx *\n                               vec2(${t[0]}, ${t[1]}));\n        int index = resTexRC.x * ${t[1]} + resTexRC.y;\n        return ivec2(0, index);\n      }\n    `}return `\n    ivec2 getOutputCoords() {\n      ivec2 resTexRC = ivec2(resultUV.yx *\n                             vec2(${t[0]}, ${t[1]}));\n      int index = resTexRC.x * ${t[1]} + resTexRC.y;\n      int r = index / ${e[1]};\n      int c = index - r * ${e[1]};\n      return ivec2(r, c);\n    }\n  `}function getFlatOffsetUniformName(e){return `offset${e}`}function getPackedSamplerScalar(e){const t=e.name;const n="get"+t.charAt(0).toUpperCase()+t.slice(1);const r=getGlslDifferences();return `\n    vec4 ${n}() {\n      return ${r.texture2D}(${t}, halfCR);\n    }\n  `}function getSamplerScalar(e){const t=e.name;const n="get"+t.charAt(0).toUpperCase()+t.slice(1);if(e.shapeInfo.isUniform){return `float ${n}() {return ${t};}`}const[r,s]=e.shapeInfo.texShape;if(r===1&&s===1){return `\n      float ${n}() {\n        return sampleTexture(${t}, halfCR);\n      }\n    `}const[a,o]=e.shapeInfo.texShape;const i=getFlatOffsetUniformName(t);return `\n    float ${n}() {\n      vec2 uv = uvFromFlat(${a}, ${o}, ${i});\n      return sampleTexture(${t}, uv);\n    }\n  `}function getPackedSampler1D(e){const t=e.name;const n="get"+t.charAt(0).toUpperCase()+t.slice(1);const r=e.shapeInfo.texShape;const s=[Math.ceil(r[0]/2),Math.ceil(r[1]/2)];const a=getGlslDifferences();return `\n    vec4 ${n}(int index) {\n      vec2 uv = packedUVfrom1D(\n        ${s[0]}, ${s[1]}, index);\n      return ${a.texture2D}(${t}, uv);\n    }\n  `}function getSampler1D(e){const t=e.name;const n="get"+t.charAt(0).toUpperCase()+t.slice(1);if(e.shapeInfo.isUniform){return `\n      float ${n}(int index) {\n        ${getUniformSampler(e)}\n      }\n    `}const r=e.shapeInfo.texShape;const s=r[0];const a=r[1];if(a===1&&s===1){return `\n      float ${n}(int index) {\n        return sampleTexture(${t}, halfCR);\n      }\n    `}const o=getFlatOffsetUniformName(t);if(a===1){return `\n      float ${n}(int index) {\n        vec2 uv = vec2(0.5, (float(index + ${o}) + 0.5) / ${s}.0);\n        return sampleTexture(${t}, uv);\n      }\n    `}if(s===1){return `\n      float ${n}(int index) {\n        vec2 uv = vec2((float(index + ${o}) + 0.5) / ${a}.0, 0.5);\n        return sampleTexture(${t}, uv);\n      }\n    `}return `\n    float ${n}(int index) {\n      vec2 uv = uvFromFlat(${s}, ${a}, index + ${o});\n      return sampleTexture(${t}, uv);\n    }\n  `}function getPackedSampler2D(e){const t=e.shapeInfo.logicalShape;const n=e.name;const r="get"+n.charAt(0).toUpperCase()+n.slice(1);const s=e.shapeInfo.texShape;const a=s[0];const o=s[1];const i=getGlslDifferences();if(s!=null&&arraysEqual(t,s)){return `\n      vec4 ${r}(int row, int col) {\n        vec2 uv = (vec2(col, row) + halfCR) / vec2(${o}.0, ${a}.0);\n\n        return ${i.texture2D}(${n}, uv);\n      }\n    `}const u=[Math.ceil(s[0]/2),Math.ceil(s[1]/2)];const c=Math.ceil(t[1]/2);return `\n    vec4 ${r}(int row, int col) {\n      vec2 uv = packedUVfrom2D(${c}, ${u[0]}, ${u[1]}, row, col);\n      return ${i.texture2D}(${n}, uv);\n    }\n  `}function getSampler2D(e){const t=e.shapeInfo.logicalShape;const n=e.name;const r="get"+n.charAt(0).toUpperCase()+n.slice(1);const s=e.shapeInfo.texShape;if(s!=null&&arraysEqual(t,s)){const e=s[0];const t=s[1];return `\n    float ${r}(int row, int col) {\n      vec2 uv = (vec2(col, row) + halfCR) / vec2(${t}.0, ${e}.0);\n      return sampleTexture(${n}, uv);\n    }\n  `}const{newShape:a,keptDims:o}=squeezeShape(t);const i=a;if(i.length<t.length){const t=squeezeInputInfo(e,i);const n=["row","col"];return `\n      ${getSamplerFromInInfo(t)}\n      float ${r}(int row, int col) {\n        return ${r}(${getSqueezedParams(n,o)});\n      }\n    `}if(e.shapeInfo.isUniform){return `\n      float ${r}(int row, int col) {\n        int index = round(dot(vec2(row, col), vec2(${t[1]}, 1)));\n        ${getUniformSampler(e)}\n      }\n    `}const u=s[0];const c=s[1];const l=getFlatOffsetUniformName(n);if(c===1){return `\n    float ${r}(int row, int col) {\n      float index = dot(vec3(row, col, ${l}), vec3(${t[1]}, 1, 1));\n      vec2 uv = vec2(0.5, (index + 0.5) / ${u}.0);\n      return sampleTexture(${n}, uv);\n    }\n  `}if(u===1){return `\n    float ${r}(int row, int col) {\n      float index = dot(vec3(row, col, ${l}), vec3(${t[1]}, 1, 1));\n      vec2 uv = vec2((index + 0.5) / ${c}.0, 0.5);\n      return sampleTexture(${n}, uv);\n    }\n  `}return `\n  float ${r}(int row, int col) {\n    // Explicitly use integer operations as dot() only works on floats.\n    int index = row * ${t[1]} + col + ${l};\n    vec2 uv = uvFromFlat(${u}, ${c}, index);\n    return sampleTexture(${n}, uv);\n  }\n`}function getPackedSampler3D(e){const t=e.shapeInfo.logicalShape;const n=e.name;const r="get"+n.charAt(0).toUpperCase()+n.slice(1);const s=e.shapeInfo.texShape;const a=[Math.ceil(s[0]/2),Math.ceil(s[1]/2)];if(t[0]===1){const n=t.slice(1);const s=[1,2];const a=squeezeInputInfo(e,n);const o=["b","row","col"];return `\n        ${getPackedSamplerFromInInfo(a)}\n        vec4 ${r}(int b, int row, int col) {\n          return ${r}(${getSqueezedParams(o,s)});\n        }\n      `}const o=a[0];const i=a[1];const u=Math.ceil(t[2]/2);const c=u*Math.ceil(t[1]/2);const l=getGlslDifferences();return `\n    vec4 ${r}(int b, int row, int col) {\n      vec2 uv = packedUVfrom3D(\n        ${o}, ${i}, ${c}, ${u}, b, row, col);\n      return ${l.texture2D}(${n}, uv);\n    }\n  `}function getSampler3D(e){const t=e.shapeInfo.logicalShape;const n=e.name;const r="get"+n.charAt(0).toUpperCase()+n.slice(1);const s=t[1]*t[2];const a=t[2];const{newShape:o,keptDims:i}=squeezeShape(t);const u=o;if(u.length<t.length){const t=squeezeInputInfo(e,u);const n=["row","col","depth"];return `\n        ${getSamplerFromInInfo(t)}\n        float ${r}(int row, int col, int depth) {\n          return ${r}(${getSqueezedParams(n,i)});\n        }\n      `}if(e.shapeInfo.isUniform){return `\n      float ${r}(int row, int col, int depth) {\n        int index = round(dot(vec3(row, col, depth),\n                          vec3(${s}, ${a}, 1)));\n        ${getUniformSampler(e)}\n      }\n    `}const c=e.shapeInfo.texShape;const l=c[0];const p=c[1];const d=e.shapeInfo.flatOffset;if(p===s&&d==null){return `\n        float ${r}(int row, int col, int depth) {\n          float texR = float(row);\n          float texC = dot(vec2(col, depth), vec2(${a}, 1));\n          vec2 uv = (vec2(texC, texR) + halfCR) /\n                     vec2(${p}.0, ${l}.0);\n          return sampleTexture(${n}, uv);\n        }\n      `}if(p===a&&d==null){return `\n    float ${r}(int row, int col, int depth) {\n      float texR = dot(vec2(row, col), vec2(${t[1]}, 1));\n      float texC = float(depth);\n      vec2 uv = (vec2(texC, texR) + halfCR) / vec2(${p}.0, ${l}.0);\n      return sampleTexture(${n}, uv);\n    }\n  `}const h=getFlatOffsetUniformName(n);return `\n      float ${r}(int row, int col, int depth) {\n        // Explicitly use integer operations as dot() only works on floats.\n        int index = row * ${s} + col * ${a} + depth + ${h};\n        vec2 uv = uvFromFlat(${l}, ${p}, index);\n        return sampleTexture(${n}, uv);\n      }\n  `}function getPackedSamplerND(e){const t=e.shapeInfo.logicalShape;const n=t.length;const r=e.name;const s="get"+r.charAt(0).toUpperCase()+r.slice(1);const a=e.shapeInfo.texShape;const o=[Math.ceil(a[0]/2),Math.ceil(a[1]/2)];const i=o[0];const u=o[1];const c=Math.ceil(t[n-1]/2);let l=c*Math.ceil(t[n-2]/2);let p=`int b, int row, int col`;let d=`b * ${l} + (row / 2) * ${c} + (col / 2)`;for(let e=2;e<n-1;e++){p=`int b${e}, `+p;l*=t[n-e-1];d=`b${e} * ${l} + `+d;}const h=getGlslDifferences();return `\n    vec4 ${s}(${p}) {\n      int index = ${d};\n      int texR = index / ${u};\n      int texC = index - texR * ${u};\n      vec2 uv = (vec2(texC, texR) + halfCR) / vec2(${u}, ${i});\n      return ${h.texture2D}(${r}, uv);\n    }\n  `}function getSampler4D(e){const t=e.shapeInfo.logicalShape;const n=e.name;const r="get"+n.charAt(0).toUpperCase()+n.slice(1);const s=t[3];const a=t[2]*s;const o=t[1]*a;const{newShape:i,keptDims:u}=squeezeShape(t);if(i.length<t.length){const t=squeezeInputInfo(e,i);const n=["row","col","depth","depth2"];return `\n      ${getSamplerFromInInfo(t)}\n      float ${r}(int row, int col, int depth, int depth2) {\n        return ${r}(${getSqueezedParams(n,u)});\n      }\n    `}if(e.shapeInfo.isUniform){return `\n      float ${r}(int row, int col, int depth, int depth2) {\n        int index = round(dot(vec4(row, col, depth, depth2),\n                          vec4(${o}, ${a}, ${s}, 1)));\n        ${getUniformSampler(e)}\n      }\n    `}const c=e.shapeInfo.flatOffset;const l=e.shapeInfo.texShape;const p=l[0];const d=l[1];if(d===o&&c==null){return `\n      float ${r}(int row, int col, int depth, int depth2) {\n        float texR = float(row);\n        float texC =\n            dot(vec3(col, depth, depth2),\n                vec3(${a}, ${s}, 1));\n        vec2 uv = (vec2(texC, texR) + halfCR) /\n                   vec2(${d}.0, ${p}.0);\n        return sampleTexture(${n}, uv);\n      }\n    `}if(d===s&&c==null){return `\n      float ${r}(int row, int col, int depth, int depth2) {\n        float texR = dot(vec3(row, col, depth),\n                         vec3(${t[1]*t[2]}, ${t[2]}, 1));\n        float texC = float(depth2);\n        vec2 uv = (vec2(texC, texR) + halfCR) /\n                  vec2(${d}.0, ${p}.0);\n        return sampleTexture(${n}, uv);\n      }\n    `}const h=getFlatOffsetUniformName(n);return `\n    float ${r}(int row, int col, int depth, int depth2) {\n      // Explicitly use integer operations as dot() only works on floats.\n      int index = row * ${o} + col * ${a} +\n          depth * ${s} + depth2;\n      vec2 uv = uvFromFlat(${p}, ${d}, index + ${h});\n      return sampleTexture(${n}, uv);\n    }\n  `}function getSampler5D(e){const t=e.shapeInfo.logicalShape;const n=e.name;const r="get"+n.charAt(0).toUpperCase()+n.slice(1);const s=t[4];const a=t[3]*s;const o=t[2]*a;const i=t[1]*o;const{newShape:u,keptDims:c}=squeezeShape(t);if(u.length<t.length){const t=squeezeInputInfo(e,u);const n=["row","col","depth","depth2","depth3"];return `\n      ${getSamplerFromInInfo(t)}\n      float ${r}(int row, int col, int depth, int depth2, int depth3) {\n        return ${r}(${getSqueezedParams(n,c)});\n      }\n    `}if(e.shapeInfo.isUniform){return `\n      float ${r}(int row, int col, int depth, int depth2, int depth3) {\n        float index = dot(\n          vec4(row, col, depth, depth2),\n          vec4(${i}, ${o}, ${a}, ${s})) +\n          depth3;\n        ${getUniformSampler(e)}\n      }\n    `}const l=e.shapeInfo.flatOffset;const p=e.shapeInfo.texShape;const d=p[0];const h=p[1];if(h===i&&l==null){return `\n      float ${r}(int row, int col, int depth, int depth2, int depth3) {\n        int texR = row;\n        float texC = dot(vec4(col, depth, depth2, depth3),\n                         vec4(${o}, ${a}, ${s}, 1));\n        vec2 uv = (vec2(texC, texR) + halfCR) /\n                   vec2(${h}.0, ${d}.0);\n        return sampleTexture(${n}, uv);\n      }\n    `}if(h===s&&l==null){return `\n      float ${r}(int row, int col, int depth, int depth2, int depth3) {\n        float texR = dot(\n          vec4(row, col, depth, depth2),\n          vec4(${t[1]*t[2]*t[3]},\n               ${t[2]*t[3]}, ${t[3]}, 1));\n        int texC = depth3;\n        vec2 uv = (vec2(texC, texR) + halfCR) /\n                  vec2(${h}.0, ${d}.0);\n        return sampleTexture(${n}, uv);\n      }\n    `}const m=getFlatOffsetUniformName(n);return `\n    float ${r}(int row, int col, int depth, int depth2, int depth3) {\n      // Explicitly use integer operations as dot() only works on floats.\n      int index = row * ${i} + col * ${o} + depth * ${a} +\n          depth2 * ${s} + depth3 + ${m};\n      vec2 uv = uvFromFlat(${d}, ${h}, index);\n      return sampleTexture(${n}, uv);\n    }\n  `}function getSampler6D(e){const t=e.shapeInfo.logicalShape;const n=e.name;const r="get"+n.charAt(0).toUpperCase()+n.slice(1);const{newShape:s,keptDims:a}=squeezeShape(t);if(s.length<t.length){const t=squeezeInputInfo(e,s);const n=["row","col","depth","depth2","depth3","depth4"];return `\n      ${getSamplerFromInInfo(t)}\n      float ${r}(int row, int col, int depth,\n                    int depth2, int depth3, int depth4) {\n        return ${r}(${getSqueezedParams(n,a)});\n      }\n    `}const o=t[5];const i=t[4]*o;const u=t[3]*i;const c=t[2]*u;const l=t[1]*c;if(e.shapeInfo.isUniform){return `\n      float ${r}(int row, int col, int depth,\n                  int depth2, int depth3, int depth4) {\n        int index = round(dot(\n          vec4(row, col, depth, depth2),\n          vec4(${l}, ${c}, ${u}, ${i})) +\n          dot(\n            vec2(depth3, depth4),\n            vec2(${o}, 1)));\n        ${getUniformSampler(e)}\n      }\n    `}const p=e.shapeInfo.flatOffset;const d=e.shapeInfo.texShape;const h=d[0];const m=d[1];if(m===l&&p==null){return `\n      float ${r}(int row, int col, int depth,\n                    int depth2, int depth3, int depth4) {\n        int texR = row;\n        float texC = dot(vec4(col, depth, depth2, depth3),\n          vec4(${c}, ${u}, ${i}, ${o})) +\n               float(depth4);\n        vec2 uv = (vec2(texC, texR) + halfCR) /\n                   vec2(${m}.0, ${h}.0);\n        return sampleTexture(${n}, uv);\n      }\n    `}if(m===o&&p==null){return `\n      float ${r}(int row, int col, int depth,\n                    int depth2, int depth3, int depth4) {\n        float texR = dot(vec4(row, col, depth, depth2),\n          vec4(${t[1]*t[2]*t[3]*t[4]},\n               ${t[2]*t[3]*t[4]},\n               ${t[3]*t[4]},\n               ${t[4]})) + float(depth3);\n        int texC = depth4;\n        vec2 uv = (vec2(texC, texR) + halfCR) /\n                  vec2(${m}.0, ${h}.0);\n        return sampleTexture(${n}, uv);\n      }\n    `}const f=getFlatOffsetUniformName(n);return `\n    float ${r}(int row, int col, int depth,\n                  int depth2, int depth3, int depth4) {\n      // Explicitly use integer operations as dot() only works on floats.\n      int index = row * ${l} + col * ${c} + depth * ${u} +\n          depth2 * ${i} + depth3 * ${o} + depth4 + ${f};\n      vec2 uv = uvFromFlat(${h}, ${m}, index);\n      return sampleTexture(${n}, uv);\n    }\n  `}function getUniformSampler(e){const t=e.name;const n=sizeFromShape(e.shapeInfo.logicalShape);if(n<2){return `return ${t};`}return `\n    for (int i = 0; i < ${n}; i++) {\n      if (i == index) {\n        return ${t}[i];\n      }\n    }\n  `}function getPackedSamplerAtOutputCoords(e,t){const n=e.name;const r=n.charAt(0).toUpperCase()+n.slice(1);const s="get"+r+"AtOutCoords";const a=e.shapeInfo.logicalShape.length;const o=t.logicalShape.length;const i=getBroadcastDims(e.shapeInfo.logicalShape,t.logicalShape);const u=getCoordsDataType(o);const c=o-a;let l;const p=["x","y","z","w","u","v"];if(a===0){l="";}else if(o<2&&i.length>=1){l="coords = 0;";}else {l=i.map((e=>`coords.${p[e+c]} = 0;`)).join("\n");}let d="";if(o<2&&a>0){d="coords";}else {d=e.shapeInfo.logicalShape.map(((e,t)=>`coords.${p[t+c]}`)).join(", ");}let h=`return outputValue;`;const m=sizeFromShape(e.shapeInfo.logicalShape);const f=m===1;const g=sizeFromShape(t.logicalShape);const y=g===1;if(a===1&&!f&&!y){h=`\n      return vec4(outputValue.xy, outputValue.xy);\n    `;}else if(f&&!y){if(o===1){h=`\n        return vec4(outputValue.x, outputValue.x, 0., 0.);\n      `;}else {h=`\n        return vec4(outputValue.x);\n      `;}}else if(i.length){const e=a-2;const t=a-1;if(i.indexOf(e)>-1&&i.indexOf(t)>-1){h=`return vec4(outputValue.x);`;}else if(i.indexOf(e)>-1){h=`return vec4(outputValue.x, outputValue.y, `+`outputValue.x, outputValue.y);`;}else if(i.indexOf(t)>-1){h=`return vec4(outputValue.xx, outputValue.zz);`;}}return `\n    vec4 ${s}() {\n      ${u} coords = getOutputCoords();\n      ${l}\n      vec4 outputValue = get${r}(${d});\n      ${h}\n    }\n  `}function getSamplerAtOutputCoords(e,t){const n=e.name;const r=n.charAt(0).toUpperCase()+n.slice(1);const s="get"+r+"AtOutCoords";const a=t.texShape;const o=e.shapeInfo.texShape;const i=e.shapeInfo.logicalShape.length;const u=t.logicalShape.length;if(!e.shapeInfo.isUniform&&i===u&&e.shapeInfo.flatOffset==null&&arraysEqual(o,a)){return `\n      float ${s}() {\n        return sampleTexture(${n}, resultUV);\n      }\n    `}const c=getCoordsDataType(u);const l=getBroadcastDims(e.shapeInfo.logicalShape,t.logicalShape);const p=u-i;let d;const h=["x","y","z","w","u","v"];if(i===0){d="";}else if(u<2&&l.length>=1){d="coords = 0;";}else {d=l.map((e=>`coords.${h[e+p]} = 0;`)).join("\n");}let m="";if(u<2&&i>0){m="coords";}else {m=e.shapeInfo.logicalShape.map(((e,t)=>`coords.${h[t+p]}`)).join(", ");}return `\n    float ${s}() {\n      ${c} coords = getOutputCoords();\n      ${d}\n      return get${r}(${m});\n    }\n  `}function getCoordsDataType(e){if(e<=1){return "int"}else if(e===2){return "ivec2"}else if(e===3){return "ivec3"}else if(e===4){return "ivec4"}else if(e===5){return "ivec5"}else if(e===6){return "ivec6"}else {throw Error(`GPU for rank ${e} is not yet supported`)}}function squeezeInputInfo(e,t){const n=JSON.parse(JSON.stringify(e));n.shapeInfo.logicalShape=t;return n}function getSqueezedParams(e,t){return t.map((t=>e[t])).join(", ")}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function compileProgram(e,t,n,r){const s=t.userCode;const a=n.map(((e,n)=>{const r={logicalShape:e.shape,texShape:e.isUniform?null:e.texData.texShape,isUniform:e.isUniform,isPacked:e.isUniform?false:e.texData.isPacked,flatOffset:null};if(e.texData!=null&&e.texData.slice!=null&&e.texData.slice.flatOffset>0){r.flatOffset=e.texData.slice.flatOffset;}return {name:t.variableNames[n],shapeInfo:r}}));const o=a.map((e=>e.shapeInfo));const i={logicalShape:r.shape,texShape:r.texData.texShape,isUniform:false,isPacked:r.texData.isPacked,flatOffset:null};const u=makeShader(a,i,s,t.packedInputs);const c=e.createProgram(u);let l=null;const p=e.getUniformLocation(c,"NAN",false);if(env().getNumber("WEBGL_VERSION")===1){l=e.getUniformLocation(c,"INFINITY",false);}const d={};for(let n=0;n<t.variableNames.length;n++){const r=t.variableNames[n];const s=false;d[r]=e.getUniformLocation(c,r,s);d[`offset${r}`]=e.getUniformLocation(c,`offset${r}`,s);}return {program:t,source:u,webGLProgram:c,uniformLocations:d,inShapeInfos:o,outShapeInfo:i,infLoc:l,nanLoc:p}}function validateBinaryAndProgram(e,t){if(e.length!==t.length){throw Error(`Binary was compiled with ${e.length} inputs, but `+`was executed with ${t.length} inputs`)}e.forEach(((e,n)=>{const r=e.logicalShape;const s=t[n];const a=s.shape;if(!arraysEqual(r,a)){throw Error(`Binary was compiled with different shapes than `+`the current args. Shapes ${r} and ${a} must match`)}if(e.isUniform&&s.isUniform){return}const o=e.texShape;const i=s.isUniform?null:s.texData.texShape;if(!arraysEqual(o,i)){throw Error(`Binary was compiled with different texture shapes than the`+` current args. Shape ${o} and ${i} must match`)}}));}function runProgram(e,t,n,r,s){validateBinaryAndProgram(t.inShapeInfos,n);validateBinaryAndProgram([t.outShapeInfo],[r]);const a=r.texData.texture;const o=r.texData.texShape;if(r.texData.isPacked){e.setOutputPackedMatrixTexture(a,o[0],o[1]);}else {e.setOutputMatrixTexture(a,o[0],o[1]);}e.setProgram(t.webGLProgram);if(env().getNumber("WEBGL_VERSION")===1){if(t.infLoc!==null){e.gl.uniform1f(t.infLoc,Infinity);}}if(t.nanLoc!==null){e.gl.uniform1f(t.nanLoc,NaN);}n.forEach(((n,r)=>{const s=t.program.variableNames[r];const a=t.uniformLocations[s];const o=t.uniformLocations[`offset${s}`];if(a==null){return}if(n.isUniform){if(sizeFromShape(n.shape)<2){e.gl.uniform1f(a,n.uniformValues[0]);}else {let t=n.uniformValues;if(!(t instanceof Float32Array)){t=new Float32Array(t);}e.gl.uniform1fv(a,t);}return}if(n.texData.slice!=null&&o!=null){e.gl.uniform1i(o,n.texData.slice.flatOffset);}e.setInputMatrixTexture(n.texData.texture,a,r);}));if(s!=null){s(e,t.webGLProgram);}e.executeProgram();}function makeShaderKey(e,t,n){let r="";t.concat(n).forEach((e=>{const t=e.texData!=null&&e.texData.slice!=null&&e.texData.slice.flatOffset>0;const n=e.isUniform?"uniform":e.texData.texShape;r+=`${e.shape}_${n}_${t}`;}));const s=e.userCode;let a=e.constructor.name;a+="_"+r+"_"+s;return a}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function simpleAbsImpl(e){const t=new Float32Array(e.length);for(let n=0;n<e.length;++n){t[n]=Math.abs(e[n]);}return t}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function createSimpleBinaryKernelImpl(e){return (t,n,r,s,a)=>{const o=assertAndGetBroadcastShape(t,n);const i=o.length;const u=computeStrides(o);const c=sizeFromShape(o);const l=getTypedArrayFromDType(a,c);const p=t.length;const d=n.length;const h=computeStrides(t);const m=computeStrides(n);const f=getBroadcastDims$1(t,o);const g=getBroadcastDims$1(n,o);if(f.length+g.length===0){for(let t=0;t<l.length;++t){l[t]=e(r[t%r.length],s[t%s.length]);}}else {for(let t=0;t<l.length;++t){const n=indexToLoc(t,i,u);const a=n.slice(-p);f.forEach((e=>a[e]=0));const o=locToIndex(a,p,h);const c=n.slice(-d);g.forEach((e=>c[e]=0));const y=locToIndex(c,d,m);l[t]=e(r[o],s[y]);}}return [l,o]}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const addImpl=createSimpleBinaryKernelImpl(((e,t)=>e+t));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function bincountImpl(e,t,n,r,s){const a=sizeFromShape(r);const o=makeZerosTypedArray(s,n);for(let n=0;n<e.length;n++){const r=e[n];if(r<0){throw new Error("Input x must be non-negative!")}if(r>=s){continue}if(a>0){o[r]+=t[n];}else {o[r]+=1;}}return o}function bincountReduceImpl(e,t,n,r=false){const s=e.shape[0];const a=e.shape[1];const o=buffer([s,n],t.dtype);for(let i=0;i<s;i++){for(let s=0;s<a;s++){const a=e.get(i,s);if(a<0){throw new Error("Input x must be non-negative!")}if(a>=n){continue}if(r){o.set(1,i,a);}else {if(t.size>0){o.set(o.get(i,a)+t.get(i,s),i,a);}else {o.set(o.get(i,a)+1,i,a);}}}}return o}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function createSimpleUnaryImpl(e){return (t,n,r)=>{const s=getTypedArrayFromDType(n,t.length);for(let n=0;n<t.length;++n){s[n]=e(t[n],r);}return s}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const ceilImpl=createSimpleUnaryImpl((e=>Math.ceil(e)));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function concatImpl$1(e,t,n,r){const s=getArrayFromDType(n,sizeFromShape(t));if(r&&n!=="string"){let t=0;e.forEach((e=>{const n=sizeFromShape(e.shape);s.set(e.vals,t);t+=n;}));}else {let r=0;e.forEach((e=>{const a=n==="string"?fromUint8ToStringArray(e.vals):e.vals;let o=0;for(let n=0;n<e.shape[0];++n){const i=n*t[1]+r;for(let t=0;t<e.shape[1];++t){s[i+t]=a[o++];}}r+=e.shape[1];}));}return s}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const equalImpl=createSimpleBinaryKernelImpl(((e,t)=>e===t?1:0));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const expImpl=createSimpleUnaryImpl((e=>Math.exp(e)));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const expm1Impl=createSimpleUnaryImpl((e=>Math.expm1(e)));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const floorImpl=createSimpleUnaryImpl((e=>Math.floor(e)));
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function gatherNdImpl(e,t,n,r,s,a,o,i,u){const c=buffer([r,a],n);for(let n=0;n<r;n++){const r=[];let l=0;for(let t=0;t<s;t++){const a=e[n*s+t];l+=a*o[t];r.push(a);}if(l<0||l>=u/a){throw new Error(`Invalid indices: ${r} does not index into ${i}`)}for(let e=0;e<a;e++){c.values[n*a+e]=t.get(...t.indexToLoc(l*a+e));}}return c}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function gatherV2Impl(e,t,n){const r=buffer(n,e.dtype);for(let n=0;n<r.size;++n){const s=r.indexToLoc(n);const a=s.slice();const o=a[0];const i=a[2];const u=t.locToIndex([o,i]);a[2]=t.values[u];const c=e.locToIndex(a);r.values[n]=e.values[c];}return r}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const greaterImpl=createSimpleBinaryKernelImpl(((e,t)=>e>t?1:0));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const greaterEqualImpl=createSimpleBinaryKernelImpl(((e,t)=>e>=t?1:0));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const lessImpl=createSimpleBinaryKernelImpl(((e,t)=>e<t?1:0));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const lessEqualImpl=createSimpleBinaryKernelImpl(((e,t)=>e<=t?1:0));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function linSpaceImpl(e,t,n){const r=(t-e)/(n-1);const s=makeZerosTypedArray(n,"float32");s[0]=e;for(let e=1;e<s.length;e++){s[e]=s[e-1]+r;}return s}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const logImpl=createSimpleUnaryImpl((e=>Math.log(e)));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function maxImpl(e,t,n,r){const s=getTypedArrayFromDType(r,sizeFromShape(n));for(let n=0;n<s.length;++n){const r=n*t;let a=e[r];for(let n=0;n<t;++n){const t=e[r+n];if(Number.isNaN(t)||t>a){a=t;}}s[n]=a;}return s}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const maximumImpl=createSimpleBinaryKernelImpl(((e,t)=>Math.max(e,t)));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const minimumImpl=createSimpleBinaryKernelImpl(((e,t)=>Math.min(e,t)));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const multiplyImpl=createSimpleBinaryKernelImpl(((e,t)=>e*t));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function negImpl(e,t,n){const r=createScalarValue(-1,n);return multiplyImpl([],t,r,e,n)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const notEqualImpl=createSimpleBinaryKernelImpl(((e,t)=>e!==t?1:0));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function transposeImpl$1(e,t,n,r,s){const a=t.length;const o=sizeFromShape(t);const i=computeStrides(t);const u=computeStrides(s);const c=getTypedArrayFromDType(n,sizeFromShape(s));for(let t=0;t<o;++t){const n=indexToLoc(t,a,i);const s=new Array(n.length);for(let e=0;e<s.length;e++){s[e]=n[r[e]];}const o=locToIndex(s,a,u);c[o]=e[t];}return c}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function prodImpl(e,t,n,r){const[s,a]=computeOutAndReduceShapes(e,r);const o=upcastType(t,"int32");const i=makeZerosTypedArray(sizeFromShape(s),o);const u=sizeFromShape(a);for(let e=0;e<i.length;++e){const t=e*u;let r=1;for(let e=0;e<u;++e){r*=n[t+e];}i[e]=r;}return {outVals:i,outShape:s,outDtype:o}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function rangeImpl(e,t,n,r){const s=e===t;const a=e<t&&n<0;const o=t<e&&n>1;if(s||a||o){return makeZerosTypedArray(0,r)}const i=Math.abs(Math.ceil((t-e)/n));const u=makeZerosTypedArray(i,r);if(t<e&&n===1){n=-1;}u[0]=e;for(let e=1;e<u.length;e++){u[e]=u[e-1]+n;}return u}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const rsqrtImpl=createSimpleUnaryImpl((e=>1/Math.sqrt(e)));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sliceImpl(e,t,n,r,s){const a=isSliceContinous(r,t,n);const o=sizeFromShape(n);const i=computeStrides(r);if(a){const n=computeFlatOffset(t,i);if(s==="string"){return e.slice(n,n+o)}return e.subarray(n,n+o)}const u=s==="string"?fromUint8ToStringArray(e):e;const c=buffer(r,s,u);const l=buffer(n,s);for(let e=0;e<l.size;++e){const n=l.indexToLoc(e);const r=n.map(((e,n)=>e+t[n]));l.set(c.get(...r),...n);}if(s==="string"){return fromStringArrayToUint8(l.values)}return l.values}
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseFillEmptyRowsImpl(e,t,n,r,s,a,o){const i=t[0];const u=a[0];const c=new Array(u);const l=new Array(i);const p=t[1];if(u===0){if(i!==0){throw new Error(`Received SparseTensor with denseShape[0] = 0 but\n         indices.shape[0] = ${i}`)}const e=getArrayFromDType(n,0);const t=getArrayFromDType(s,0);return [e,[0,p],t,c,l]}let d=true;let h=0;const m=new Array(u).fill(0);for(let t=0;t<i;++t){const n=e[t*p];if(n<0){throw new Error(`indices(${t}, 0) is invalid: ${n} < 0`)}if(n>=u){throw new Error(`indices(${t}, 0) is invalid: ${n} >= ${u}`)}++m[n];d=d&&n>=h;h=n;}let f=true;for(let e=0;e<u;++e){const t=m[e]===0;c[e]=t;f=f&&!t;m[e]=Math.max(m[e],1);if(e>0){m[e]+=m[e-1];}}if(f&&d){const t=e;const n=r;for(let e=0;e<i;++e){l[e]=e;}return [t,[i,p],n,c,l]}else {const t=m[u-1];const a=getArrayFromDType(n,t*p);const d=getArrayFromDType(s,t);const h=new Array(u).fill(0);for(let t=0;t<i;++t){const n=e[t*p];const s=h[n];const o=(n===0?0:m[n-1])+s;h[n]++;for(let n=0;n<p;++n){a[o*p+n]=e[t*p+n];}d[o]=r[t];l[t]=o;}for(let e=0;e<u;++e){const t=h[e];if(t===0){const t=e===0?0:m[e-1];a[t*p+0]=e;for(let e=1;e<p;++e){a[t*p+e]=0;}d[t]=o;}}return [a,[t,p],d,c,l]}}
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseReshapeImpl(e,t,n,r,s){const a=sizeFromShape(r);const o=t[0];const i=s.length;const u=[];let c=1;let l=-1;for(let e=0;e<i;++e){const t=s[e];if(t===-1){if(l!==-1){throw new Error(`only one output dimension may be -1, not both ${l} and ${e}`)}l=e;u.push(1);}else {if(t<0){throw new Error(`size ${e} must be non-negative, not ${t}`)}c*=t;u.push(t);}}if(l!==-1){if(c<=0){throw new Error("reshape cannot infer the missing "+"input size for an empty tensor unless all "+"specified input sizes are non-zero")}const e=Math.trunc(a/c);if(c*e!==a){throw new Error(`Input to reshape is a SparseTensor with ${a}\n          dense values, but the requested shape requires a multiple of ${c}. inputShape=${r} outputShape= ${u}`)}u[l]=e;}const p=sizeFromShape(u);if(p!==a){throw new Error(`Input to reshape is a tensor with ${a} dense values, but the requested shape has ${p}. inputShape=${r} outputShape=${u}`)}const d=r.length;const h=[];if(d>0){h[d-1]=1;for(let e=d-2;e>=0;--e){h[e]=h[e+1]*r[e+1];}}const m=[];if(i>0){m[i-1]=1;for(let e=i-2;e>=0;--e){m[e]=m[e+1]*u[e+1];}}const f=getArrayFromDType(n,o*i);for(let t=0;t<o;++t){let n=0;for(let r=0;r<d;++r){n+=e[t*d+r]*h[r];}for(let e=0;e<i;++e){f[t*i+e]=Math.trunc(n/m[e]);n%=m[e];}}return [f,[o,i],u]}
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sparseSegmentReductionImpl(e,t,n,r,s,a=false,o=0){const i=r.length;if(i!==s.length){throw new Error(`segmentIds and indices should have same size.`)}const u=[t[0],e.length/t[0]];const c=u[1];const l=i>0?s[i-1]+1:0;const p=l;if(p<0){throw new Error(`segment ids must be >= 0`)}const d=t.slice();d[0]=p;const h=d.reduce(((e,t)=>e*t),1);const m=getArrayFromDType(n,h);if(i===0){if(p>0){m.fill(o);}return [m,d]}if(p<=0){throw new Error(`segment ids must be >= 0`)}let f=0,g=1;let y=0;let x=s[f];while(true){let t=0;if(g<i){t=s[g];if(x===t){++g;continue}if(x>=t){throw new Error(`segment ids are not increasing`)}}if(x<0||x>=p){throw new Error(`Segment id ${x} out of range [0, ${p}), possibly because segmentIds input is not sorted.`)}if(x>y){m.fill(o,y*c,x*c);}for(let t=f;t<g;++t){const n=r[t];if(n<0||n>=u[0]){throw new Error(`Bad: indices[${t}] == ${r[t]} out of range [0, ${u[0]})`)}for(let t=0;t<c;t++){m[x*c+t]+=e[n*c+t];}}if(a){for(let e=0;e<c;e++){m[x*c+e]/=g-f;}}f=g;++g;y=x+1;x=t;if(g>i){break}}if(y<p){m.fill(o,y*c,p*c);}return [m,d]}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const squaredDifferenceImpl=createSimpleBinaryKernelImpl(((e,t)=>{const n=e-t;return n*n}));
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stridedSliceImpl(e,t,n,r){const s=buffer(e,t.dtype);for(let e=0;e<s.size;e++){const a=s.indexToLoc(e);const o=new Array(a.length);for(let e=0;e<o.length;e++){o[e]=a[e]*n[e]+r[e];}s.set(t.get(...o),...a);}return s}
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class StringNGramsOp{constructor(e,t,n,r,s,a){this.separator=encodeString(e);this.nGramWidths=t;this.leftPad=encodeString(n);this.rightPad=encodeString(r);this.padWidth=s;this.preserveShort=a;}getPadWidth(e){return Math.min(this.padWidth<0?e-1:this.padWidth,e-1)}getNumNGrams(e,t){const n=this.getPadWidth(t);return Math.max(0,e+2*n-t+1)}createNGrams(e,t,n,r,s,a){for(let o=0;o<s;++o){const i=this.getPadWidth(a);const u=Math.max(0,i-o);const c=Math.max(0,i-(s-(o+1)));const l=a-(u+c);const p=t+(u>0?0:o-i);let d=0;d+=u*this.leftPad.length;for(let t=0;t<l;++t){d+=e[p+t].length;}d+=c*this.rightPad.length;const h=u+c+l-1;d+=h*this.separator.length;n[r+o]=new Uint8Array(d);const m=n[r+o];let f=0;const g=e=>e.forEach((e=>m[f++]=e));for(let e=0;e<u;++e){g(this.leftPad);g(this.separator);}for(let t=0;t<l-1;++t){g(e[p+t]);g(this.separator);}if(l>0){g(e[p+l-1]);for(let e=0;e<c;++e){g(this.separator);g(this.rightPad);}}else {for(let e=0;e<c-1;++e){g(this.rightPad);g(this.separator);}g(this.rightPad);}}}compute(e,t){const n=e.length;const r=t.length;if(r>0){let e=t[0];if(e!==0){throw new Error(`First split value must be 0, got ${e}`)}for(let s=1;s<r;++s){let r=t[s]>=e;r=r&&t[s]<=n;if(!r){throw new Error(`Invalid split value ${t[s]}, must be in [${e}, ${n}]`)}e=t[s];}if(e!==n){throw new Error(`Last split value must be data size. Expected ${n}, got ${e}`)}}const s=r-1;const a=getArrayFromDType("int32",r);if(n===0||r===0){const e=new Array(n);for(let e=0;e<=s;++e){a[e]=0;}return [e,a]}a[0]=0;for(let e=1;e<=s;++e){const n=t[e]-t[e-1];let r=0;this.nGramWidths.forEach((e=>{r+=this.getNumNGrams(n,e);}));if(this.preserveShort&&n>0&&r===0){r=1;}a[e]=a[e-1]+r;}const o=new Array(a[s]);for(let n=0;n<s;++n){const r=t[n];let s=a[n];this.nGramWidths.forEach((a=>{const i=t[n+1]-t[n];const u=this.getNumNGrams(i,a);this.createNGrams(e,r,o,s,u,a);s+=u;}));if(this.preserveShort&&s===a[n]){const a=t[n+1]-t[n];if(a===0){continue}const i=a+2*this.padWidth;const u=1;this.createNGrams(e,r,o,s,u,i);}}return [o,a]}}function stringNGramsImpl(e,t,n,r,s,a,o,i){return new StringNGramsOp(n,r,s,a,o,i).compute(e,t)}
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function split(e,t,n){if(!e.length){return []}if(t.length===0){const t=new Array(e.length);for(let n=0;n<e.length;++n){t[n]=e.subarray(n,n+1);}return t}if(t.length===1){const r=t[0];const s=[];let a=e.indexOf(r);while(a!==-1){const t=e.subarray(0,a);if(!n||t.length!==0){s.push(t);}e=e.subarray(a+1);a=e.indexOf(r);}if(!n||e.length!==0){s.push(e);}return s}const r=[];let s=0;for(let a=0;a<e.length+1;a++){if(a===e.length||t.indexOf(e[a])!==-1){const t=e.subarray(s,a);if(!n||t.length!==0){r.push(t);}s=a+1;}}return r}function stringSplitImpl(e,t,n){const r=e.length;const s=[];let a=0;let o=0;const i=new Array(r);for(let u=0;u<r;++u){const r=split(e[u],t,n);const c=r.length;i[u]=c;a+=c;o=Math.max(o,c);s.push(...r);}const u=getArrayFromDType("int32",a*2);const c=new Array(a);const l=[r,o];let p=0;for(let e=0;e<r;++e){for(let t=0;t<i[e];++t){u[p*2]=e;u[p*2+1]=t;c[p]=s[p];++p;}}return [u,c,l]}
/**
 * @license
 * Copyright 2021 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function stringToHashBucketFastImpl(e,t){const n=getArrayFromDType("int32",e.length);for(let r=0;r<e.length;++r){n[r]=fingerPrint64(e[r]).modulo(t).getLowBitsUnsigned();}return n}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const subImpl=createSimpleBinaryKernelImpl(((e,t)=>e-t));
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function tileImpl(e,t){const n=new Array(e.rank);for(let r=0;r<n.length;r++){n[r]=e.shape[r]*t[r];}const r=buffer(n,e.dtype);for(let t=0;t<r.values.length;++t){const n=r.indexToLoc(t);const s=new Array(e.rank);for(let t=0;t<s.length;t++){s[t]=n[t]%e.shape[t];}const a=e.locToIndex(s);r.values[t]=e.values[a];}return r}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function topKImpl(e,t,n,r,s){const a=t[t.length-1];const[o,i]=[e.length/a,a];const u=getTypedArrayFromDType(n,o*r);const c=getTypedArrayFromDType("int32",o*r);for(let t=0;t<o;t++){const n=t*i;const s=e.subarray(n,n+i);const a=[];for(let e=0;e<s.length;e++){a.push({value:s[e],index:e});}a.sort(((e,t)=>t.value-e.value));const o=t*r;const l=u.subarray(o,o+r);const p=c.subarray(o,o+r);for(let e=0;e<r;e++){l[e]=a[e].value;p[e]=a[e].index;}}const l=t.slice();l[l.length-1]=r;return [buffer(l,n,u),buffer(l,"int32",c)]}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function uniqueImpl(e,t,n,r){const s=parseAxisParam(t,n)[0];const a=[1,n[0],1];for(let e=0;e<s;e++){a[0]*=n[e];}a[1]=n[s];for(let e=s+1;e<n.length;e++){a[2]*=n[e];}const o={};const i=new Int32Array(n[s]);const u=new TensorBuffer(a,r,e);const c=[];const l=a[0]===1&&a[2]===1;for(let t=0;t<n[s];t++){let n;if(l){n=e[t].toString();}else {const e=[];for(let n=0;n<a[0];n++){for(let r=0;r<a[2];r++){e.push(u.get(n,t,r));}}n=e.join(",");}if(o[n]!==undefined){i[t]=o[n];}else {const e=Object.keys(o).length;o[n]=e;i[t]=e;c.push(t);}}const p=a.slice();p[1]=Object.keys(o).length;const d=new TensorBuffer(p,r);c.forEach(((e,t)=>{for(let n=0;n<a[0];n++){for(let r=0;r<a[2];r++){d.set(u.get(n,e,r),n,t,r);}}}));const h=n.slice();h[s]=p[1];return {outputValues:d.values,outputShape:h,indices:i}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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 shared=Object.freeze({__proto__:null,simpleAbsImpl:simpleAbsImpl,addImpl:addImpl,bincountImpl:bincountImpl,bincountReduceImpl:bincountReduceImpl,ceilImpl:ceilImpl,concatImpl:concatImpl$1,equalImpl:equalImpl,expImpl:expImpl,expm1Impl:expm1Impl,floorImpl:floorImpl,gatherNdImpl:gatherNdImpl,gatherV2Impl:gatherV2Impl,greaterImpl:greaterImpl,greaterEqualImpl:greaterEqualImpl,lessImpl:lessImpl,lessEqualImpl:lessEqualImpl,linSpaceImpl:linSpaceImpl,logImpl:logImpl,maxImpl:maxImpl,maximumImpl:maximumImpl,minimumImpl:minimumImpl,multiplyImpl:multiplyImpl,negImpl:negImpl,notEqualImpl:notEqualImpl,prodImpl:prodImpl,rangeImpl:rangeImpl,rsqrtImpl:rsqrtImpl,sliceImpl:sliceImpl,sparseFillEmptyRowsImpl:sparseFillEmptyRowsImpl,sparseReshapeImpl:sparseReshapeImpl,sparseSegmentReductionImpl:sparseSegmentReductionImpl,squaredDifferenceImpl:squaredDifferenceImpl,stridedSliceImpl:stridedSliceImpl,stringNGramsImpl:stringNGramsImpl,stringSplitImpl:stringSplitImpl,stringToHashBucketFastImpl:stringToHashBucketFastImpl,subImpl:subImpl,tileImpl:tileImpl,topKImpl:topKImpl,transposeImpl:transposeImpl$1,uniqueImpl:uniqueImpl});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const{addImpl:addImplCPU,bincountImpl:bincountImplCPU,bincountReduceImpl:bincountReduceImplCPU,ceilImpl:ceilImplCPU,concatImpl:concatImplCPU,equalImpl:equalImplCPU,expImpl:expImplCPU,expm1Impl:expm1ImplCPU,floorImpl:floorImplCPU,gatherNdImpl:gatherNdImplCPU,gatherV2Impl:gatherV2ImplCPU,greaterImpl:greaterImplCPU,greaterEqualImpl:greaterEqualImplCPU,lessImpl:lessImplCPU,lessEqualImpl:lessEqualImplCPU,linSpaceImpl:linSpaceImplCPU,logImpl:logImplCPU,maxImpl:maxImplCPU,maximumImpl:maximumImplCPU,minimumImpl:minimumImplCPU,multiplyImpl:multiplyImplCPU,negImpl:negImplCPU,notEqualImpl:notEqualImplCPU,prodImpl:prodImplCPU,rangeImpl:rangeImplCPU,rsqrtImpl:rsqrtImplCPU,simpleAbsImpl:simpleAbsImplCPU,sliceImpl:sliceImplCPU,sparseFillEmptyRowsImpl:sparseFillEmptyRowsImplCPU,sparseReshapeImpl:sparseReshapeImplCPU,sparseSegmentReductionImpl:sparseSegmentReductionImplCPU,stridedSliceImpl:stridedSliceImplCPU,stringNGramsImpl:stringNGramsImplCPU,stringSplitImpl:stringSplitImplCPU,stringToHashBucketFastImpl:stringToHashBucketFastImplCPU,subImpl:subImplCPU,tileImpl:tileImplCPU,topKImpl:topKImplCPU,transposeImpl:transposeImplCPU,uniqueImpl:uniqueImplCPU}=shared;
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getVecChannels(e,t){return ["x","y","z","w","u","v"].slice(0,t).map((t=>`${e}.${t}`))}function getChannels(e,t){if(t===1){return [e]}return getVecChannels(e,t)}function getSourceCoords$1(e,t){if(e===1){return "rc"}let n="";for(let r=0;r<e;r++){n+=t[r];if(r<e-1){n+=",";}}return n}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class PackProgram{constructor(e){this.variableNames=["A"];this.packedInputs=false;this.packedOutput=true;this.outputShape=e;const t=e.length;if(t===0){this.userCode=`\n        void main() {\n          setOutput(vec4(getA(), 0., 0., 0.));\n        }\n      `;}else {const n=getChannels("rc",t);const r=getCoordsDataType(t);const s=getOutOfBoundsCondition(t,e,n);const a=getSetup(t,e[e.length-1],e[e.length-2],n);const o=getOutput(e,n);this.userCode=`\n        void main() {\n          ${r} rc = getOutputCoords();\n\n          if(${s}) {\n            setOutput(vec4(0));\n          } else {\n            ${a}\n\n            setOutput(vec4(${o}));\n          }\n        }\n      `;}}}function getSourceCoordsArr(e,t){const n=[];for(let r=0;r<=1;r++){for(let s=0;s<=1;s++){let a=`${r===0?"r":"rp1"}, ${s===0?"c":"cp1"}`;for(let n=2;n<e;n++){a=`${t[t.length-1-n]},`+a;}n.push(a);}}return n}function getOutOfBoundsCondition(e,t,n){if(e===1){return `rc > ${t[0]}`}let r="";for(let s=e-2;s<e;s++){r+=`${n[s]} >= ${t[s]}`;if(s<e-1){r+="||";}}return r}function getSetup(e,t,n,r){if(e===1){return ""}const s=r.slice(-2);return `\n    int r = ${s[0]};\n    int c = ${s[1]};\n    int rp1 = r + 1;\n    int cp1 = c + 1;\n\n    bool cEdge = cp1 >= ${t};\n    bool rEdge = rp1 >= ${n};\n  `}function getOutput(e,t){const n=e.length;const r=getSourceCoordsArr(n,t);if(n===1){return `getA(rc),\n            rc + 1 >= ${e[0]} ? 0. : getA(rc + 1),\n            0, 0`}return `getA(${r[0]}),\n          cEdge ? 0. : getA(${r[1]}),\n          rEdge ? 0. : getA(${r[2]}),\n          rEdge || cEdge ? 0. : getA(${r[3]})`}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class ReshapePackedProgram{constructor(e,t){this.variableNames=["A"];this.packedInputs=true;this.packedOutput=true;this.outputShape=e;let n=``;for(let e=0;e<4;e++){let t=`thisRC = rc;`;if(e%2===1){t+=`thisRC.z += 1;`;}if(e>1){t+=`thisRC.y += 1;`;}n+=`\n        ${t}\n        ${e>0?`if(thisRC.y < rows && thisRC.z < cols){`:""}\n          int flatIndex = getFlatIndex(thisRC);\n\n          ivec3 inputRC = inputCoordsFromReshapedOutCoords(flatIndex);\n          vec2 inputRCInnerDims = vec2(float(inputRC.y),float(inputRC.z));\n\n          result[${e}] =\n            getChannel(getA(inputRC.x, inputRC.y, inputRC.z), inputRCInnerDims);\n        ${e>0?"}":""}\n      `;}this.userCode=`\n      ${getReshapedInputCoords(t)}\n      ${getFlatIndexFrom3D(e)}\n\n      void main() {\n        ivec3 rc = getOutputCoords();\n\n        vec4 result = vec4(0.);\n\n        ivec3 thisRC;\n        int rows = ${e[1]};\n        int cols = ${e[2]};\n\n        ${n}\n\n        setOutput(result);\n      }\n    `;}}function getReshapedInputCoords(e){const t=getLogicalCoordinatesFromFlatIndex(["r","c","d"],e);return `\n    ivec3 inputCoordsFromReshapedOutCoords(int index) {\n      ${t}\n      return ivec3(r, c, d);\n    }\n  `}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class TextureManager{constructor(e){this.gpgpu=e;this.numUsedTextures=0;this.numFreeTextures=0;this._numBytesAllocated=0;this._numBytesFree=0;this.freeTextures={};this.logEnabled=false;this.usedTextures={};}acquireTexture(e,t,n){const r=getPhysicalFromLogicalTextureType(t,n);const s=getKeyFromTextureShape(e,r,n);if(!(s in this.freeTextures)){this.freeTextures[s]=[];}if(!(s in this.usedTextures)){this.usedTextures[s]=[];}const a=computeBytes(e,r,this.gpgpu.gl,this.gpgpu.textureConfig,n);if(this.freeTextures[s].length>0){this.numFreeTextures--;this.numUsedTextures++;this._numBytesFree-=a;this.log();const e=this.freeTextures[s].shift();this.usedTextures[s].push(e);return e}let o;if(r===PhysicalTextureType.PACKED_2X2_FLOAT32){o=this.gpgpu.createPackedMatrixTexture(e[0],e[1]);}else if(r===PhysicalTextureType.PACKED_2X2_FLOAT16){o=this.gpgpu.createFloat16PackedMatrixTexture(e[0],e[1]);}else if(r===PhysicalTextureType.UNPACKED_FLOAT32){o=this.gpgpu.createFloat32MatrixTexture(e[0],e[1]);}else if(r===PhysicalTextureType.UNPACKED_FLOAT16){o=this.gpgpu.createFloat16MatrixTexture(e[0],e[1]);}else if(r===PhysicalTextureType.PACKED_4X1_UNSIGNED_BYTE){o=this.gpgpu.createUnsignedBytesMatrixTexture(e[0],e[1]);}this.usedTextures[s].push(o);this.numUsedTextures++;this._numBytesAllocated+=a;this.log();return o}releaseTexture(e,t,n,r){if(this.freeTextures==null){return}const s=getPhysicalFromLogicalTextureType(n,r);const a=getKeyFromTextureShape(t,s,r);if(!(a in this.freeTextures)){this.freeTextures[a]=[];}const o=computeBytes(t,s,this.gpgpu.gl,this.gpgpu.textureConfig,r);const i=env().get("WEBGL_DELETE_TEXTURE_THRESHOLD");if(i!==-1&&this._numBytesAllocated>i){this.gpgpu.deleteMatrixTexture(e);this._numBytesAllocated-=o;}else {this.freeTextures[a].push(e);this.numFreeTextures++;this._numBytesFree+=o;}this.numUsedTextures--;const u=this.usedTextures[a];const c=u.indexOf(e);if(c<0){throw new Error("Cannot release a texture that was never provided by this "+"texture manager")}u.splice(c,1);this.log();}log(){if(!this.logEnabled){return}const e=this.numFreeTextures+this.numUsedTextures;console.log("Free/Used",`${this.numFreeTextures} / ${this.numUsedTextures}`,`(${e})`);const t=this._numBytesFree/this._numBytesAllocated;console.log(`Bytes allocated: ${this._numBytesAllocated}`);console.log(`Bytes unused: ${this._numBytesFree} (${Math.round(100*t)}%)`);}get numBytesAllocated(){return this._numBytesAllocated}get numBytesFree(){return this._numBytesFree}getNumUsedTextures(){return this.numUsedTextures}getNumFreeTextures(){return this.numFreeTextures}dispose(){if(this.freeTextures==null){return}for(const e in this.freeTextures){this.freeTextures[e].forEach((e=>{this.gpgpu.deleteMatrixTexture(e);}));}for(const e in this.usedTextures){this.usedTextures[e].forEach((e=>{this.gpgpu.deleteMatrixTexture(e);}));}this.freeTextures=null;this.usedTextures=null;this.numUsedTextures=0;this.numFreeTextures=0;this._numBytesAllocated=0;this._numBytesFree=0;}}function numBytesForInternalFormat(e,t){const n=e;if(t===n.R32F){return 4}else if(t===n.R16F){return 2}else if(t===n.RGBA32F){return 16}else if(t===e.RGBA){return 16}else if(t===n.RGBA16F){return 8}throw new Error(`Unknown internal format ${t}`)}function computeBytes(e,t,n,r,s){const a=internalFormatForPhysicalTexType(t,r);let o;if(s){const[t,n]=getPackedMatrixTextureShapeWidthHeight(e[0],e[1]);o=t*n;}else {const[t,n]=getUnpackedMatrixTextureShapeWidthHeight(e[0],e[1]);o=t*n;}const i=numBytesForInternalFormat(n,a);return o*i}function internalFormatForPhysicalTexType(e,t){switch(e){case PhysicalTextureType.PACKED_2X2_FLOAT32:return getInternalFormatForPackedMatrixTexture(t);case PhysicalTextureType.PACKED_2X2_FLOAT16:return getInternalFormatForFloat16PackedMatrixTexture(t);case PhysicalTextureType.UNPACKED_FLOAT32:return getInternalFormatForFloat32MatrixTexture(t);case PhysicalTextureType.UNPACKED_FLOAT16:return getInternalFormatForFloat16MatrixTexture(t);case PhysicalTextureType.PACKED_4X1_UNSIGNED_BYTE:return getInternalFormatForUnsignedBytesMatrixTexture(t);default:throw new Error(`Unknown physical texture type ${e}`)}}function getPhysicalTextureForRendering(e){if(env().getBool("WEBGL_RENDER_FLOAT32_ENABLED")){if(e){return PhysicalTextureType.PACKED_2X2_FLOAT32}return PhysicalTextureType.UNPACKED_FLOAT32}if(e){return PhysicalTextureType.PACKED_2X2_FLOAT16}return PhysicalTextureType.UNPACKED_FLOAT16}function getPhysicalFromLogicalTextureType(e,t){if(e===TextureUsage.UPLOAD){return PhysicalTextureType.PACKED_2X2_FLOAT32}else if(e===TextureUsage.RENDER||e==null){return getPhysicalTextureForRendering(t)}else if(e===TextureUsage.DOWNLOAD||e===TextureUsage.PIXELS){return PhysicalTextureType.PACKED_4X1_UNSIGNED_BYTE}throw new Error(`Unknown logical texture type ${e}`)}function getKeyFromTextureShape(e,t,n){return `${e[0]}_${e[1]}_${t}_${n}`}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class UnaryOpProgram{constructor(e,t){this.variableNames=["A"];this.outputShape=e;this.userCode=`\n      float unaryOperation(float x) {\n        ${t}\n      }\n\n      void main() {\n        float x = getAAtOutCoords();\n        float y = unaryOperation(x);\n\n        setOutput(y);\n      }\n    `;}}const CHECK_NAN_SNIPPET$1=`if (isnan(x)) return x;`;const LINEAR$1=`return x;`;const ABS=`return abs(x);`;const ELU$1=`return (x >= 0.0) ? x : (exp(x) - 1.0);`;const RELU$2=CHECK_NAN_SNIPPET$1+`\n  return (x < 0.0) ? 0.0 : x;\n`;const RELU6$1=CHECK_NAN_SNIPPET$1+`\n  return (x < 0.0) ? 0.0 : min(6.0, x);\n`;const CLONE="return x;";const SIGMOID$2=`return 1.0 / (1.0 + exp(-1.0 * x));`
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */;const LINEAR=`return x;`;const ELU=`\n  vec4 result;\n\n  result.r = (x.r >= 0.0) ? x.r : (exp(x.r) - 1.0);\n  result.g = (x.g >= 0.0) ? x.g : (exp(x.g) - 1.0);\n  result.b = (x.b >= 0.0) ? x.b : (exp(x.b) - 1.0);\n  result.a = (x.a >= 0.0) ? x.a : (exp(x.a) - 1.0);\n\n  return result;\n`;const RELU$1=`\n  vec4 result = x * vec4(greaterThanEqual(x, vec4(0.0)));\n  bvec4 isNaN = isnan(x);\n\n  result.r = isNaN.r ? x.r : result.r;\n  result.g = isNaN.g ? x.g : result.g;\n  result.b = isNaN.b ? x.b : result.b;\n  result.a = isNaN.a ? x.a : result.a;\n\n  return result;\n`;const RELU6=`\n  vec4 result = min(x, vec4(6.)) * vec4(greaterThanEqual(x, vec4(0.0)));\n  bvec4 isNaN = isnan(x);\n\n  result.r = isNaN.r ? x.r : result.r;\n  result.g = isNaN.g ? x.g : result.g;\n  result.b = isNaN.b ? x.b : result.b;\n  result.a = isNaN.a ? x.a : result.a;\n\n  return result;\n`;const SIGMOID$1=`return 1.0 / (1.0 + exp(-1.0 * x));`;class UnaryOpPackedProgram{constructor(e,t){this.variableNames=["A"];this.packedInputs=true;this.packedOutput=true;this.outputShape=e;this.userCode=`\n      vec4 unaryOperation(vec4 x) {\n        ${t}\n      }\n\n      void main() {\n        vec4 x = getAAtOutCoords();\n        vec4 y = unaryOperation(x);\n\n        setOutput(y);\n      }\n    `;}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class UnpackProgram{constructor(e){this.variableNames=["A"];this.packedInputs=true;this.packedOutput=false;this.outputShape=e;const t=e.length;const n=getChannels("rc",t);const r=getCoordsDataType(t);const s=getSourceCoords$1(t,n);const a=n.slice(-2);const o=t<=1?"rc":`vec2(${a.join(",")})`;this.userCode=`\n      void main() {\n        ${r} rc = getOutputCoords();\n        vec4 packedInput = getA(${s});\n\n        setOutput(getChannel(packedInput, ${o}));\n      }\n    `;}}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const whereImpl=whereImpl$1;const EPSILON_FLOAT32=1e-7;const EPSILON_FLOAT16=1e-4;const binaryCaches={};function getBinaryCache(e){if(e in binaryCaches){return binaryCaches[e]}binaryCaches[e]={};return binaryCaches[e]}const CPU_HANDOFF_SIZE_THRESHOLD=env().getNumber("CPU_HANDOFF_SIZE_THRESHOLD");const BEFORE_PAGING_CONSTANT=600;function numMBBeforeWarning(){if(env().global.screen==null){return 1024}return env().global.screen.height*env().global.screen.width*window.devicePixelRatio*BEFORE_PAGING_CONSTANT/1024/1024}class MathBackendWebGL extends KernelBackend{constructor(e){super();this.pendingRead=new WeakMap;this.pendingDisposal=new WeakSet;this.dataRefCount=new WeakMap;this.numBytesInGPU=0;this.uploadWaitMs=0;this.downloadWaitMs=0;this.lastGlFlushTime=0;this.warnedAboutMemory=false;this.pendingDeletes=0;this.disposed=false;if(!env().getBool("HAS_WEBGL")){throw new Error("WebGL is not supported on this device")}if(e==null){const e=getWebGLContext(env().getNumber("WEBGL_VERSION"));this.binaryCache=getBinaryCache(env().getNumber("WEBGL_VERSION"));this.gpgpu=new GPGPUContext(e);this.canvas=e.canvas;this.gpgpuCreatedLocally=true;}else {this.gpgpu=e;this.binaryCache={};this.gpgpuCreatedLocally=false;this.canvas=e.gl.canvas;}this.textureManager=new TextureManager(this.gpgpu);this.numMBBeforeWarning=numMBBeforeWarning();this.texData=new DataStorage(this,engine());}nextDataId(){return MathBackendWebGL.nextDataId++}numDataIds(){return this.texData.numDataIds()-this.pendingDeletes}write(e,t,n){if(env().getBool("WEBGL_CHECK_NUMERICAL_PROBLEMS")||env().getBool("DEBUG")){this.checkNumericalProblems(e);}if(n==="complex64"&&e!=null){throw new Error(`Cannot write to a complex64 dtype. `+`Please use tf.complex(real, imag).`)}const r={id:this.nextDataId()};this.texData.set(r,{shape:t,dtype:n,values:e,usage:TextureUsage.UPLOAD,refCount:1});return r}refCount(e){if(this.texData.has(e)){const t=this.texData.get(e);return t.refCount}return 0}incRef(e){const t=this.texData.get(e);t.refCount++;}decRef(e){if(this.texData.has(e)){const t=this.texData.get(e);t.refCount--;}}move(e,t,n,r,s){if(env().getBool("DEBUG")){this.checkNumericalProblems(t);}if(r==="complex64"){throw new Error(`Cannot write to a complex64 dtype. `+`Please use tf.complex(real, imag).`)}this.texData.set(e,{shape:n,dtype:r,values:t,usage:TextureUsage.UPLOAD,refCount:s});}disposeIntermediateTensorInfo(e){this.disposeData(e.dataId);}readSync(e){const t=this.texData.get(e);const{values:n,dtype:r,complexTensorInfos:s,slice:a,shape:o,isPacked:i}=t;if(a!=null){let t;if(i){t=new UnaryOpPackedProgram(o,CLONE);}else {t=new UnaryOpProgram(o,CLONE);}const n=this.runWebGLProgram(t,[{dataId:e,shape:o,dtype:r}],r);const s=this.readSync(n.dataId);this.disposeIntermediateTensorInfo(n);return s}if(n!=null){return this.convertAndCacheOnCPU(e)}if(r==="string"){return n}const u=this.activeTimers!=null;let c;if(u){c=now();}let l;if(r==="complex64"){const e=this.readSync(s.real.dataId);const t=this.readSync(s.imag.dataId);l=mergeRealAndImagArrays(e,t);}else {l=this.getValuesFromTexture(e);}if(u){this.downloadWaitMs+=now()-c;}return this.convertAndCacheOnCPU(e,l)}async read(e){if(this.pendingRead.has(e)){const t=this.pendingRead.get(e);return new Promise((e=>t.push(e)))}const t=this.texData.get(e);const{values:n,shape:r,slice:s,dtype:a,complexTensorInfos:o,isPacked:i}=t;if(s!=null){let t;if(i){t=new UnaryOpPackedProgram(r,CLONE);}else {t=new UnaryOpProgram(r,CLONE);}const n=this.runWebGLProgram(t,[{dataId:e,shape:r,dtype:a}],a);const s=this.read(n.dataId);this.disposeIntermediateTensorInfo(n);return s}if(n!=null){return this.convertAndCacheOnCPU(e)}if(!env().getBool("WEBGL_DOWNLOAD_FLOAT_ENABLED")&&env().getNumber("WEBGL_VERSION")===2){throw new Error(`tensor.data() with WEBGL_DOWNLOAD_FLOAT_ENABLED=false and `+`WEBGL_VERSION=2 not yet supported.`)}let u=null;let c;if(a!=="complex64"&&env().get("WEBGL_BUFFER_SUPPORTED")){c=this.decode(e);const t=this.texData.get(c.dataId);u=this.gpgpu.createBufferFromTexture(t.texture,...getDenseTexShape(r));}this.pendingRead.set(e,[]);if(a!=="complex64"){await this.gpgpu.createAndWaitForFence();}let l;if(a==="complex64"){const e=await Promise.all([this.read(o.real.dataId),this.read(o.imag.dataId)]);const t=e[0];const n=e[1];l=mergeRealAndImagArrays(t,n);}else if(u==null){l=this.getValuesFromTexture(e);}else {const e=sizeFromShape(r);l=this.gpgpu.downloadFloat32MatrixFromBuffer(u,e);}if(c!=null){this.disposeIntermediateTensorInfo(c);}const p=this.convertAndCacheOnCPU(e,l);const d=this.pendingRead.get(e);this.pendingRead.delete(e);d.forEach((e=>e(p)));if(this.pendingDisposal.has(e)){this.pendingDisposal.delete(e);if(this.disposeData(e)){engine().removeDataId(e,this);}this.pendingDeletes--;}return p}bufferSync(e){const t=this.readSync(e.dataId);let n=t;if(e.dtype==="string"){try{n=t.map((e=>decodeString(e)));}catch(e){throw new Error("Failed to decode encoded string bytes into utf-8")}}return buffer(e.shape,e.dtype,n)}checkNumericalProblems(e){if(e==null){return}for(let t=0;t<e.length;t++){const n=e[t];if(!canBeRepresented(n)){if(env().getBool("WEBGL_RENDER_FLOAT32_CAPABLE")){throw Error(`The value ${n} cannot be represented with your `+`current settings. Consider enabling float32 rendering: `+`'tf.env().set('WEBGL_RENDER_FLOAT32_ENABLED', true);'`)}throw Error(`The value ${n} cannot be represented on this device.`)}}}getValuesFromTexture(e){const{shape:t,dtype:n,isPacked:r}=this.texData.get(e);const s=sizeFromShape(t);if(env().getBool("WEBGL_DOWNLOAD_FLOAT_ENABLED")){const n=this.decode(e);const r=this.texData.get(n.dataId);const a=this.gpgpu.downloadMatrixFromPackedTexture(r.texture,...getDenseTexShape(t)).subarray(0,s);this.disposeIntermediateTensorInfo(n);return a}const a=env().getBool("WEBGL_PACK")&&r===true;const o=a?getShapeAs3D(t):t;const i=a?new EncodeFloatPackedProgram(o):new EncodeFloatProgram(o);const u=this.runWebGLProgram(i,[{shape:o,dtype:n,dataId:e}],"float32");const c=this.texData.get(u.dataId);const l=this.gpgpu.downloadByteEncodedFloatMatrixFromOutputTexture(c.texture,c.texShape[0],c.texShape[1]).subarray(0,s);this.disposeIntermediateTensorInfo(u);return l}timerAvailable(){return env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0}async time(e){const t=this.activeTimers;const n=[];let r=false;if(this.programTimersStack==null){this.programTimersStack=n;r=true;}else {this.activeTimers.push(n);}this.activeTimers=n;e();const s=flatten(this.activeTimers.map((e=>e.query))).filter((e=>e!=null));const a=flatten(this.activeTimers.map((e=>e.name))).filter((e=>e!=null));this.activeTimers=t;if(r){this.programTimersStack=null;}const o={uploadWaitMs:this.uploadWaitMs,downloadWaitMs:this.downloadWaitMs,kernelMs:null,wallMs:null};if(env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0){const e=await Promise.all(s);o["kernelMs"]=sum$2(e);o["getExtraProfileInfo"]=()=>e.map(((e,t)=>({name:a[t],ms:e}))).map((e=>`${e.name}: ${e.ms}`)).join(", ");}else {o["kernelMs"]={error:"WebGL query timers are not supported in this environment."};}this.uploadWaitMs=0;this.downloadWaitMs=0;return o}memory(){return {unreliable:false,numBytesInGPU:this.numBytesInGPU,numBytesInGPUAllocated:this.textureManager.numBytesAllocated,numBytesInGPUFree:this.textureManager.numBytesFree}}startTimer(){if(env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0){return this.gpgpu.beginQuery()}return {startMs:now(),endMs:null}}endTimer(e){if(env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0){this.gpgpu.endQuery();return e}e.endMs=now();return e}async getQueryTime(e){if(env().getNumber("WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE")>0){return this.gpgpu.waitForQueryAndGetTime(e)}const t=e;return t.endMs-t.startMs}disposeData(e,t=false){if(this.pendingDisposal.has(e)){return false}if(!this.texData.has(e)){return true}if(t){this.texData.get(e).refCount=0;}else {this.texData.get(e).refCount--;}if(!t&&this.texData.get(e).refCount>0){return false}if(this.pendingRead.has(e)){this.pendingDisposal.add(e);this.pendingDeletes++;return false}this.releaseGPUData(e);const{complexTensorInfos:n}=this.texData.get(e);if(n!=null){this.disposeData(n.real.dataId,t);this.disposeData(n.imag.dataId,t);}this.texData.delete(e);return true}releaseGPUData(e){const{texture:t,dtype:n,texShape:r,usage:s,isPacked:a,slice:o}=this.texData.get(e);const i=o&&o.origDataId||e;const u=this.dataRefCount.get(i);if(u>1){this.dataRefCount.set(i,u-1);}else {this.dataRefCount.delete(i);if(t!=null){this.numBytesInGPU-=this.computeBytes(r,n);this.textureManager.releaseTexture(t,r,s,a);}}const c=this.texData.get(e);c.texture=null;c.texShape=null;c.isPacked=false;c.slice=null;}getTexture(e){this.uploadToGPU(e);return this.texData.get(e).texture}getDataInfo(e){return this.texData.get(e)}shouldExecuteOnCPU(e,t=CPU_HANDOFF_SIZE_THRESHOLD){return env().getBool("WEBGL_CPU_FORWARD")&&e.every((e=>this.texData.get(e.dataId).texture==null&&sizeFromShape(e.shape)<t))}getGPGPUContext(){return this.gpgpu}where(e){warn("tf.where() in webgl locks the UI thread. "+"Call tf.whereAsync() instead");const t=e.dataSync();return whereImpl(e.shape,t)}packedUnaryOp(e,t,n){const r=new UnaryOpPackedProgram(e.shape,t);const s=this.compileAndRun(r,[e],n);return engine().makeTensorFromDataId(s.dataId,s.shape,s.dtype)}abs(e){if(this.shouldExecuteOnCPU([e])&&e.dtype!=="complex64"){const t=simpleAbsImplCPU(this.texData.get(e.dataId).values);return this.makeOutput(e.shape,e.dtype,t)}if(env().getBool("WEBGL_PACK_UNARY_OPERATIONS")){return this.packedUnaryOp(e,ABS,e.dtype)}const t=new UnaryOpProgram(e.shape,ABS);const n=this.compileAndRun(t,[e]);return engine().makeTensorFromDataId(n.dataId,n.shape,n.dtype)}makeTensorInfo(e,t,n){let r;if(t==="string"&&n!=null&&n.length>0&&isString(n[0])){const s=n.map((e=>encodeString(e)));r=this.write(s,e,t);}else {r=this.write(n,e,t);}this.texData.get(r).usage=null;return {dataId:r,shape:e,dtype:t}}makeOutput(e,t,n){const{dataId:r}=this.makeTensorInfo(e,t,n);return engine().makeTensorFromDataId(r,e,t,this)}unpackTensor(e){const t=new UnpackProgram(e.shape);return this.runWebGLProgram(t,[e],e.dtype)}packTensor(e){const t=new PackProgram(e.shape);const n=true;return this.runWebGLProgram(t,[e],e.dtype,null,n)}packedReshape(e,t){const n=[getBatchDim(e.shape),...getRowsCols(e.shape)];const r={dtype:e.dtype,shape:n,dataId:e.dataId};const s=[getBatchDim(t),...getRowsCols(t)];const a=new ReshapePackedProgram(s,n);const o=true;const i=this.runWebGLProgram(a,[r],e.dtype,null,o);return {dataId:i.dataId,shape:t,dtype:i.dtype}}decode(e){const t=this.texData.get(e);const{isPacked:n,shape:r,dtype:s}=t;const a=getShapeAs3D(r);let o;if(n){o=new DecodeMatrixPackedProgram(a);}else {o=new DecodeMatrixProgram(a);}const i=true;const u=this.runWebGLProgram(o,[{shape:a,dtype:s,dataId:e}],s,null,i);return {dtype:s,shape:r,dataId:u.dataId}}runWebGLProgram(e,t,n,r,s=false){const a=this.makeTensorInfo(e.outputShape,n);const o=this.texData.get(a.dataId);if(e.packedOutput){o.isPacked=true;}if(e.outPackingScheme===PackingScheme.DENSE){const t=getDenseTexShape(e.outputShape);o.texShape=t.map((e=>e*2));}if(e.outTexUsage!=null){o.usage=e.outTexUsage;}if(sizeFromShape(a.shape)===0){o.values=getTypedArrayFromDType(a.dtype,0);return a}const i=[];const u=t.map((t=>{if(t.dtype==="complex64"){throw new Error(`GPGPUProgram does not support complex64 input. For complex64 `+`dtypes, please separate the program into real and imaginary `+`parts.`)}let n=this.texData.get(t.dataId);if(n.texture==null){if(!e.packedInputs&&sizeFromShape(t.shape)<=env().getNumber("WEBGL_SIZE_UPLOAD_UNIFORM")){return {shape:t.shape,texData:null,isUniform:true,uniformValues:n.values}}if(e.packedInputs){n.isPacked=true;n.shape=t.shape;}}else if(!!n.isPacked!==!!e.packedInputs){t=n.isPacked?this.unpackTensor(t):this.packTensor(t);i.push(t);n=this.texData.get(t.dataId);}else if(n.isPacked&&!isReshapeFree(n.shape,t.shape)){const e=t;const r=t.shape;t.shape=n.shape;t=this.packedReshape(t,r);i.push(t);n=this.texData.get(t.dataId);e.shape=r;}this.uploadToGPU(t.dataId);return {shape:t.shape,texData:n,isUniform:false}}));this.uploadToGPU(a.dataId);const c={shape:a.shape,texData:o,isUniform:false};const l=makeShaderKey(e,u,c);const p=this.getAndSaveBinary(l,(()=>compileProgram(this.gpgpu,e,u,c)));const d=this.activeTimers!=null;let h;if(d){h=this.startTimer();}runProgram(this.gpgpu,p,u,c,r);i.forEach((e=>this.disposeIntermediateTensorInfo(e)));if(d){h=this.endTimer(h);this.activeTimers.push({name:e.constructor.name,query:this.getQueryTime(h)});}const m=env().get("WEBGL_FLUSH_THRESHOLD");if(m>0){const e=now();if(e-this.lastGlFlushTime>m){this.gpgpu.gl.flush();this.lastGlFlushTime=e;}}if(!env().getBool("WEBGL_LAZILY_UNPACK")&&o.isPacked&&s===false){const e=this.unpackTensor(a);this.disposeIntermediateTensorInfo(a);return e}return a}compileAndRun(e,t,n,r,s=false){n=n||t[0].dtype;const a=this.runWebGLProgram(e,t,n,r,s);return a}getAndSaveBinary(e,t){if(!(e in this.binaryCache)){this.binaryCache[e]=t();}return this.binaryCache[e]}getTextureManager(){return this.textureManager}dispose(){if(this.disposed){return}if(!env().getBool("IS_TEST")){const e=Object.keys(this.binaryCache);e.forEach((e=>{this.gpgpu.deleteProgram(this.binaryCache[e].webGLProgram);delete this.binaryCache[e];}));}this.textureManager.dispose();if(this.canvas!=null&&(typeof HTMLCanvasElement!=="undefined"&&this.canvas instanceof HTMLCanvasElement)){this.canvas.remove();}else {this.canvas=null;}if(this.gpgpuCreatedLocally){this.gpgpu.program=null;this.gpgpu.dispose();}this.disposed=true;}floatPrecision(){if(this.floatPrecisionValue==null){this.floatPrecisionValue=tidy((()=>{if(!env().get("WEBGL_RENDER_FLOAT32_ENABLED")){const e=env().getBool("DEBUG");env().set("DEBUG",false);const t=this.abs(scalar(1e-8)).dataSync()[0];env().set("DEBUG",e);if(t>0){return 32}}return 16}));}return this.floatPrecisionValue}epsilon(){return this.floatPrecision()===32?EPSILON_FLOAT32:EPSILON_FLOAT16}uploadToGPU(e){const t=this.texData.get(e);const{shape:n,dtype:r,values:s,texture:a,usage:o,isPacked:i}=t;if(a!=null){return}const u=this.activeTimers!=null;let c;if(u){c=now();}let l=t.texShape;if(l==null){l=getTextureShapeFromLogicalShape(n,i);t.texShape=l;}if(s!=null){const e=getShapeAs3D(n);let a;let o=l[1],p=l[0];const d=s instanceof Uint8Array;if(i){[o,p]=getPackedMatrixTextureShapeWidthHeight(l[0],l[1]);a=new EncodeMatrixPackedProgram(e,[p,o],d);}else {a=new EncodeMatrixProgram(e,[p,o],d);}const h=this.makeTensorInfo([p,o],r);if(d){this.texData.get(h.dataId).usage=TextureUsage.PIXELS;}else {this.texData.get(h.dataId).usage=TextureUsage.UPLOAD;}this.gpgpu.uploadDenseMatrixToTexture(this.getTexture(h.dataId),o,p,s);const m=true;const f=this.runWebGLProgram(a,[h],r,null,m);const g=this.texData.get(f.dataId);t.texture=g.texture;t.texShape=g.texShape;t.isPacked=g.isPacked;t.usage=g.usage;this.disposeIntermediateTensorInfo(h);this.texData.delete(f.dataId);t.values=null;if(u){this.uploadWaitMs+=now()-c;}}else {const e=this.acquireTexture(l,o,r,i);t.texture=e;}}convertAndCacheOnCPU(e,t){const n=this.texData.get(e);const{dtype:r}=n;this.releaseGPUData(e);if(t!=null){n.values=float32ToTypedArray(t,r);}return n.values}acquireTexture(e,t,n,r){this.numBytesInGPU+=this.computeBytes(e,n);if(!this.warnedAboutMemory&&this.numBytesInGPU>this.numMBBeforeWarning*1024*1024){const e=(this.numBytesInGPU/1024/1024).toFixed(2);this.warnedAboutMemory=true;console.warn(`High memory usage in GPU: ${e} MB, `+`most likely due to a memory leak`);}return this.textureManager.acquireTexture(e,t,r)}computeBytes(e,t){return e[0]*e[1]*bytesPerElement(t)}}MathBackendWebGL.nextDataId=0;function float32ToTypedArray(e,t){if(t==="float32"||t==="complex64"){return e}else if(t==="int32"||t==="bool"){const n=t==="int32"?new Int32Array(e.length):new Uint8Array(e.length);for(let t=0;t<n.length;++t){n[t]=Math.round(e[t]);}return n}else {throw new Error(`Unknown dtype ${t}`)}}
/**
 * @license
 * Copyright 2020 Google Inc. All Rights Reserved.
 * 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.
 * =============================================================================
 */if(isBrowser()){registerBackend("webgl",(()=>new MathBackendWebGL),2);}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class BinaryOpProgram{constructor(e,t,n){this.variableNames=["A","B"];this.outputShape=assertAndGetBroadcastShape(t,n);this.userCode=`\n      float binaryOperation(float a, float b) {\n        ${e}\n      }\n\n      void main() {\n        float a = getAAtOutCoords();\n        float b = getBAtOutCoords();\n        setOutput(binaryOperation(a, b));\n      }\n    `;}}
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const CHECK_NAN_SNIPPET=`\n  result.r = isNaN.r > 0. ? NAN : result.r;\n  result.g = isNaN.g > 0. ? NAN : result.g;\n  result.b = isNaN.b > 0. ? NAN : result.b;\n  result.a = isNaN.a > 0. ? NAN : result.a;\n`;class BinaryOpPackedProgram{constructor(e,t,n,r=false){this.variableNames=["A","B"];this.supportsBroadcasting=true;this.packedInputs=true;this.packedOutput=true;this.outputShape=assertAndGetBroadcastShape(t,n);const s=this.outputShape.length;let a="";if(r){if(s===0||sizeFromShape(this.outputShape)===1){a=`\n          result.y = 0.;\n          result.z = 0.;\n          result.w = 0.;\n        `;}else {const e=getCoordsDataType(s);a=`\n          ${e} coords = getOutputCoords();\n        `;if(s===1){a+=`\n            result.y = (coords + 1) >= ${this.outputShape[0]} ? 0. : result.y;\n            result.z = 0.;\n            result.w = 0.;\n          `;}else {const e=getChannels("coords",s);a+=`\n            bool nextRowOutOfBounds =\n              (${e[s-2]} + 1) >= ${this.outputShape[s-2]};\n            bool nextColOutOfBounds =\n              (${e[s-1]} + 1) >= ${this.outputShape[s-1]};\n            result.y = nextColOutOfBounds ? 0. : result.y;\n            result.z = nextRowOutOfBounds ? 0. : result.z;\n            result.w = nextColOutOfBounds || nextRowOutOfBounds ? 0. : result.w;\n          `;}}}this.userCode=`\n      vec4 binaryOperation(vec4 a, vec4 b) {\n        ${e}\n      }\n\n      void main() {\n        vec4 a = getAAtOutCoords();\n        vec4 b = getBAtOutCoords();\n\n        vec4 result = binaryOperation(a, b);\n        ${a}\n\n        setOutput(result);\n      }\n    `;}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function identity(e){const{inputs:t,backend:n}=e;const{x:r}=t;n.incRef(r.dataId);return {dataId:r.dataId,shape:r.shape,dtype:r.dtype}}const identityConfig={kernelName:Identity,backendName:"webgl",kernelFunc:identity};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function complex(e){const{inputs:t,backend:n}=e;const{real:r,imag:s}=t;const a=n.makeTensorInfo(r.shape,"complex64");const o=n.texData.get(a.dataId);const i=identity({inputs:{x:r},backend:n});const u=identity({inputs:{x:s},backend:n});o.complexTensorInfos={real:i,imag:u};return a}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const LEAKYRELU=`return (a < 0.) ? b * a : a;`;const LEAKYRELU_PACKED=`\n  vec4 aLessThanZero = vec4(lessThan(a, vec4(0.)));\n  return (aLessThanZero * (b * a)) + ((vec4(1.0) - aLessThanZero) * a);\n`
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */;const PRELU=`return (a < 0.) ? b * a : a;`;const PRELU_PACKED=`\n  vec4 aLessThanZero = vec4(lessThan(a, vec4(0.)));\n  return (aLessThanZero * (b * a)) + ((vec4(1.0) - aLessThanZero) * a);\n`
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */;function unaryKernelFunc({opSnippet:e,packedOpSnippet:t,cpuKernelImpl:n,dtype:r}){return ({inputs:s,backend:a})=>{const{x:o}=s;const i=a;const u=r||o.dtype;if(i.shouldExecuteOnCPU([o])&&n!=null){const e=i.texData.get(o.dataId);const t=n(e.values,u);return i.makeTensorInfo(o.shape,u,t)}const c=env().getBool("WEBGL_PACK_UNARY_OPERATIONS")&&t!=null;let l;if(c){l=new UnaryOpPackedProgram(o.shape,t);}else {l=new UnaryOpProgram(o.shape,e);}return i.runWebGLProgram(l,[o],u)}}function binaryKernelFunc({opSnippet:e,packedOpSnippet:t,checkOutOfBounds:n=false,supportsComplex:r=false,cpuKernelImpl:s,dtype:a}){return ({inputs:o,backend:i})=>{const{a:u,b:c}=o;const l=i;if(r&&u.dtype==="complex64"){const t=l.texData.get(u.dataId);const n=l.texData.get(c.dataId);const[r,s]=[[t.complexTensorInfos.real,n.complexTensorInfos.real],[t.complexTensorInfos.imag,n.complexTensorInfos.imag]].map((t=>{const[n,r]=t;const s={dataId:n.dataId,dtype:n.dtype,shape:u.shape};const a={dataId:r.dataId,dtype:r.dtype,shape:c.shape};const o=new BinaryOpProgram(e,u.shape,c.shape);return l.runWebGLProgram(o,[s,a],upcastType(n.dtype,r.dtype))}));const a=complex({inputs:{real:r,imag:s},backend:l});l.disposeIntermediateTensorInfo(r);l.disposeIntermediateTensorInfo(s);return a}const p=a||upcastType(u.dtype,c.dtype);if((u.dtype==="string"||c.dtype==="string"||l.shouldExecuteOnCPU([u,c]))&&s!=null){const e=l.texData.get(u.dataId).values;const t=l.texData.get(c.dataId).values;const n=u.dtype==="string"?fromUint8ToStringArray(e):e;const r=u.dtype==="string"?fromUint8ToStringArray(t):t;const[a,o]=s(u.shape,c.shape,n,r,p);const i=l.makeTensorInfo(o,p);const d=l.texData.get(i.dataId);d.values=a;return i}const d=env().getBool("WEBGL_PACK_BINARY_OPERATIONS")&&t!=null;let h;if(d){h=new BinaryOpPackedProgram(t,u.shape,c.shape,n);}else {h=new BinaryOpProgram(e,u.shape,c.shape);}return l.runWebGLProgram(h,[u,c],p)}}function mapActivationToShaderProgram(e,t=false){if(e==="linear"){if(t){return LINEAR}return LINEAR$1}else if(e==="relu"){if(t){return RELU$1}return RELU$2}else if(e==="elu"){if(t){return ELU}return ELU$1}else if(e==="relu6"){if(t){return RELU6}return RELU6$1}else if(e==="prelu"){if(t){return PRELU_PACKED}return PRELU}else if(e==="leakyrelu"){if(t){return LEAKYRELU_PACKED}return LEAKYRELU}else if(e==="sigmoid"){if(t){return SIGMOID$1}return SIGMOID$2}throw new Error(`Activation ${e} has not been implemented for the WebGL backend.`)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const ADD="return a + b;";const addKernelFunc=binaryKernelFunc({opSnippet:ADD,packedOpSnippet:ADD,supportsComplex:true,cpuKernelImpl:addImplCPU});const addConfig={kernelName:Add,backendName:"webgl",kernelFunc:addKernelFunc};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class MeanProgram{constructor(e,t){this.variableNames=["x"];const{windowSize:n,batchSize:r,inSize:s,outSize:a}=e;this.outputShape=[r,a];const o=Math.floor(n/4)*4;const i=n%4;let u=`sumValue += dot(values, ones);`;if(t!=null){const e=1/t;u=`sumValue += dot(values * ${isInt(e)?e.toPrecision(2):e}, ones);`;}let c="";if(s%n>0){c=`\n        if (inIdx < 0 || inIdx >= ${s}) {\n          return 0.0;\n        }\n      `;}this.userCode=`\n      const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0);\n\n      float getValue(int batch, int inIdx) {\n        ${c}\n        return getX(batch, inIdx);\n      }\n\n      void main() {\n        ivec2 coords = getOutputCoords();\n        int batch = coords[0];\n        int outIdx = coords[1];\n        int inOffset = outIdx * ${n};\n\n        float sumValue = 0.0;\n\n        for (int i = 0; i < ${o}; i += 4) {\n          int inIdx = inOffset + i;\n          vec4 values = vec4(\n            getValue(batch, inIdx),\n            getValue(batch, inIdx + 1),\n            getValue(batch, inIdx + 2),\n            getValue(batch, inIdx + 3)\n          );\n\n          ${u}\n        }\n\n        int inIdx = inOffset + ${o};\n        if (${i===1}) {\n          vec4 values = vec4(getValue(batch, inIdx), 0.0, 0.0, 0.0);\n\n          ${u}\n        } else if (${i===2}) {\n          vec4 values = vec4(\n            getValue(batch, inIdx),\n            getValue(batch, inIdx + 1), 0.0, 0.0);\n\n          ${u}\n        } else if (${i===3}) {\n          vec4 values = vec4(\n            getValue(batch, inIdx),\n            getValue(batch, inIdx + 1),\n            getValue(batch, inIdx + 2), 0.0);\n\n          ${u}\n        }\n        setOutput(sumValue);\n      }\n    `;}}
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class ReduceProgram{constructor(e,t){this.variableNames=["x"];const{windowSize:n,batchSize:r,inSize:s,outSize:a}=e;this.outputShape=[r,a];let o="0.0";let i=``;if(t==="prod"){o="1.0";}else if(t==="min"){o="1.0 / 1e-20";i=`min`;}else if(t==="max"){o="-1.0 / 1e-20";i=`max`;}let u=`${t}(${t}(${t}(`+"minMaxValue[0], minMaxValue[1]), minMaxValue[2]), minMaxValue[3])";if(t==="sum"){u=`sumValue`;}else if(t==="prod"){u=`prodValue`;}else if(t==="all"){u=`allValue`;}else if(t==="any"){u=`anyValue`;}const c=Math.floor(n/4)*4;const l=n%4;let p=`\n      if (${t==="sum"}) {\n        sumValue += dot(values, ones);\n      } else if (${t==="prod"}) {\n        vec2 tmp = vec2(values[0], values[1]) * vec2(values[2], values[3]);\n        prodValue *= tmp[0] * tmp[1];\n      } else {\n        minMaxValue = ${i}(values, minMaxValue);\n        if (${t==="min"} || ${t==="max"}) {\n          minMaxValue = ${i}(values, minMaxValue);\n          bvec4 isNaN = isnan(values);\n          if (isNaN.r || isNaN.g || isNaN.b || isNaN.a) {\n            minMaxValue = vec4(NAN);\n          }\n        }\n      }\n    `;let d=`vec4`;if(t==="all"){o="1.0";p=`\n        bool reducedAllValue = all(values);\n        float floatedReducedAllValue = float(reducedAllValue);\n        allValue = float(allValue >= 1.0 && floatedReducedAllValue >= 1.0);\n      `;d=`bvec4`;}else if(t==="any"){o="0.0";p=`\n        bool reducedAnyValue = any(values);\n        float floatedReducedAnyValue = float(reducedAnyValue);\n        anyValue = float(anyValue >= 1.0 || floatedReducedAnyValue >= 1.0);\n      `;d=`bvec4`;}let h="";if(s%n>0){h=`\n        if (inIdx < 0 || inIdx >= ${s}) {\n          return initializationValue;\n        }\n      `;}this.userCode=`\n      const float initializationValue = ${o};\n      const vec4 ones = vec4(1.0, 1.0, 1.0, 1.0);\n\n      float getValue(int batch, int inIdx) {\n        ${h}\n        return getX(batch, inIdx);\n      }\n\n      void main() {\n        ivec2 coords = getOutputCoords();\n        int batch = coords[0];\n        int outIdx = coords[1];\n        int inOffset = outIdx * ${n};\n\n        vec4 minMaxValue = vec4(${o});\n        float prodValue = 1.0;\n        float sumValue = 0.0;\n        float allValue = 1.0;\n        float anyValue = 0.0;\n\n        for (int i = 0; i < ${c}; i += 4) {\n          int inIdx = inOffset + i;\n          ${d} values = ${d}(\n            getValue(batch, inIdx),\n            getValue(batch, inIdx + 1),\n            getValue(batch, inIdx + 2),\n            getValue(batch, inIdx + 3)\n          );\n\n          ${p}\n        }\n\n        int inIdx = inOffset + ${c};\n        if (${l===1}) {\n          ${d} values = ${d}(\n            getValue(batch, inIdx),\n            initializationValue,\n            initializationValue,\n            initializationValue\n          );\n\n          ${p}\n        } else if (${l===2}) {\n          ${d} values = ${d}(\n            getValue(batch, inIdx),\n            getValue(batch, inIdx + 1),\n            initializationValue,\n            initializationValue\n          );\n\n          ${p}\n        } else if (${l===3}) {\n          ${d} values = ${d}(\n            getValue(batch, inIdx),\n            getValue(batch, inIdx + 1),\n            getValue(batch, inIdx + 2),\n            initializationValue\n          );\n\n          ${p}\n        }\n        setOutput(${u});\n      }\n    `;}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function getReductionStages(e){const t=[];while(t.length===0||t[t.length-1].outSize!==1){const n=t.length?t[t.length-1].outSize:e[1];const r=computeOptimalWindowSize(n);t.push({inSize:n,windowSize:r,outSize:Math.ceil(n/r)});}return t}function reduce(e,t,n,r){const s=getReductionStages(e.shape);let a=e;for(let o=0;o<s.length;o++){const{inSize:i,windowSize:u,outSize:c}=s[o];let l;let p;if(n==="mean"){l=o===0?new MeanProgram({windowSize:u,inSize:i,batchSize:e.shape[0],outSize:c},i):new MeanProgram({windowSize:u,inSize:i,batchSize:e.shape[0],outSize:c});}else {l=new ReduceProgram({windowSize:u,inSize:i,batchSize:e.shape[0],outSize:c},n);}p=a;a=r.runWebGLProgram(l,[a],t);if(p.dataId!==e.dataId){r.disposeIntermediateTensorInfo(p);}}return a}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function packedReshape(e,t,n){const r=[getBatchDim(e.shape),...getRowsCols(e.shape)];const s={dtype:e.dtype,shape:r,dataId:e.dataId};const a=[getBatchDim(t),...getRowsCols(t)];const o=new ReshapePackedProgram(a,r);const i=true;const u=n.runWebGLProgram(o,[s],e.dtype,null,i);return {dataId:u.dataId,shape:t,dtype:u.dtype}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function reshape(e){const{inputs:t,backend:n,attrs:r}=e;const{x:s}=t;const{shape:a}=r;const o=n;const i=sizeFromShape(s.shape);const u=inferFromImplicitShape(a,i);const c=sizeFromShape(u);assert(i===c,(()=>`The new shape (${u}) has ${c} elements and the old `+`shape (${s.shape}) has ${i} elements. The new shape and old `+`shape must have the same number of elements.`));const l=o.texData.get(s.dataId);if(l.isPacked&&!isReshapeFree(s.shape,u)&&!(l.texture!==null&&isReshapeFree(l.shape,u))){return packedReshape(s,u,o)}o.incRef(s.dataId);return {dataId:s.dataId,shape:u,dtype:s.dtype}}const reshapeConfig={kernelName:Reshape,backendName:"webgl",kernelFunc:reshape};
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class TransposeProgram{constructor(e,t){this.variableNames=["A"];const n=new Array(e.length);for(let r=0;r<n.length;r++){n[r]=e[t[r]];}this.outputShape=n;this.rank=n.length;const r=getCoordsDataType(this.rank);const s=getSwitchedCoords(t);this.userCode=`\n    void main() {\n      ${r} resRC = getOutputCoords();\n      setOutput(getA(${s}));\n    }\n    `;}}function getSwitchedCoords(e){const t=e.length;if(t>6){throw Error(`Transpose for rank ${t} is not yet supported`)}const n=["resRC.x","resRC.y","resRC.z","resRC.w","resRC.u","resRC.v"];const r=new Array(t);for(let t=0;t<e.length;t++){r[e[t]]=n[t];}return r.join()}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class TransposePackedProgram{constructor(e,t){this.variableNames=["A"];this.packedInputs=true;this.packedOutput=true;const n=new Array(e.length);for(let r=0;r<n.length;r++){n[r]=e[t[r]];}this.outputShape=n;this.rank=n.length;if(this.rank>6){throw Error(`Packed transpose for rank ${this.rank} is not yet supported.`)}const r=getCoordsDataType(this.rank);const s=getVecChannels("rc",this.rank);const a=new Array(this.rank);for(let e=0;e<t.length;e++){a[t[e]]=s[e];}const o=`vec2(${a.slice(-2).join()})`;const i=`++${s[this.rank-1]} < ${n[this.rank-1]}`;const u=`getChannel(getA(${a.join()}), ${o})`;this.userCode=`\n    void main() {\n      ${r} rc = getOutputCoords();\n      vec4 result = vec4(0.);\n      result[0] = ${u};\n      if(${i}) {\n        result[1] = ${u};\n      }\n      --${s[this.rank-1]};\n      if(++${s[this.rank-2]} < ${n[this.rank-2]}) {\n        result[2] = ${u};\n        if(${i}) {\n          result[3] = ${u};\n        }\n      }\n      setOutput(result);\n    }\n    `;}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function transposeImpl(e,t,n){const r=env().getBool("WEBGL_PACK_ARRAY_OPERATIONS")?new TransposePackedProgram(e.shape,t):new TransposeProgram(e.shape,t);return n.runWebGLProgram(r,[e],e.dtype)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sumImpl(e,t,n,r){const s=t;const a=e.shape.length;const o=parseAxisParam(s,e.shape);let i=o;const u=getAxesPermutation(i,a);const c=u!=null;let l=e;if(c){l=transposeImpl(e,u,r);i=getInnerMostAxes(i.length,a);}assertAxesAreInnerMostDims("sum",i,a);const[p,d]=computeOutAndReduceShapes(l.shape,i);let h=p;if(n){h=expandShapeToKeepDim(p,o);}const m=sizeFromShape(d);const f=sizeFromShape(e.shape);const g=f/m;const y=reshape({inputs:{x:l},attrs:{shape:[g,m]},backend:r});const x=sumOutType(e.dtype);const T=reduce(y,x,"sum",r);const E=reshape({inputs:{x:T},attrs:{shape:h},backend:r});r.disposeIntermediateTensorInfo(y);r.disposeIntermediateTensorInfo(T);if(c){r.disposeIntermediateTensorInfo(l);}return E}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function sum(e){const{inputs:t,backend:n,attrs:r}=e;const{x:s}=t;const{axis:a,keepDims:o}=r;return sumImpl(s,a,o,n)}const sumConfig={kernelName:Sum,backendName:"webgl",kernelFunc:sum};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const POW=`\n  if(a < 0.0 && floor(b) < b){\n    return NAN;\n  }\n  if (b == 0.0) {\n    return 1.0;\n  }\n  return (round(mod(b, 2.0)) != 1) ?\n      pow(abs(a), b) : sign(a) * pow(abs(a), b);\n`;const POW_PACKED=`\n  // isModRound1 has 1 for components with round(mod(b, 2.0)) == 1, 0 otherwise.\n  vec4 isModRound1 = vec4(equal(round(mod(b, 2.0)), ivec4(1)));\n  vec4 multiplier = sign(a) * isModRound1 + (vec4(1.0) - isModRound1);\n  vec4 result = multiplier * pow(abs(a), b);\n\n  // Ensure that a^0 = 1, including 0^0 = 1 as this correspond to TF and JS\n  bvec4 isExpZero = equal(b, vec4(0.0));\n  result.r = isExpZero.r ? 1.0 : result.r;\n  result.g = isExpZero.g ? 1.0 : result.g;\n  result.b = isExpZero.b ? 1.0 : result.b;\n  result.a = isExpZero.a ? 1.0 : result.a;\n\n  vec4 isNaN = vec4(lessThan(a, vec4(0.0))) * vec4(lessThan(floor(b), b));\n  `+CHECK_NAN_SNIPPET+`\n  return result;\n`;const pow=binaryKernelFunc({opSnippet:POW,packedOpSnippet:POW_PACKED});const powConfig={kernelName:Pow,backendName:"webgl",kernelFunc:pow};
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class ConcatProgram{constructor(e){this.outputShape=[];this.outputShape=computeOutShape$1(e,1);this.variableNames=e.map(((e,t)=>`T${t}`));const t=new Array(e.length-1);t[0]=e[0][1];for(let n=1;n<t.length;n++){t[n]=t[n-1]+e[n][1];}const n=[`if (yC < ${t[0]}) setOutput(getT0(yR, yC));`];for(let e=1;e<t.length;e++){const r=t[e-1];n.push(`else if (yC < ${t[e]}) `+`setOutput(getT${e}(yR, yC-${r}));`);}const r=t.length;const s=t[t.length-1];n.push(`else setOutput(getT${r}(yR, yC-${s}));`);this.userCode=`\n      void main() {\n        ivec2 coords = getOutputCoords();\n        int yR = coords.x;\n        int yC = coords.y;\n\n        ${n.join("\n        ")}\n      }\n    `;}}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class ConcatPackedProgram{constructor(e,t){this.packedInputs=true;this.packedOutput=true;this.outputShape=[];this.outputShape=computeOutShape$1(e,t);const n=this.outputShape;const r=n.length;const s=getCoordsDataType(r);const a=getChannels("coords",r);const o=["x","y","z","w","u","v"].slice(0,r);this.variableNames=e.map(((e,t)=>`T${t}`));const i=new Array(e.length-1);i[0]=e[0][t];for(let n=1;n<i.length;n++){i[n]=i[n-1]+e[n][t];}const u=o[t];const c=o.slice(-2);const l=o.join();let p=`if (${u} < ${i[0]}) {\n        return getChannel(\n            getT0(${l}), vec2(${c.join()}));\n        }`;for(let e=1;e<i.length;e++){const t=i[e-1];p+=`\n        if (${u} < ${i[e]}  && ${u} >= ${i[e-1]}) {\n          return getChannel(\n            getT${e}(${shiftedChannels(o,u,t)}),\n            vec2(${shiftedChannels(c,u,t)}));\n        }`;}const d=i.length;const h=i[i.length-1];p+=`\n        return getChannel(\n          getT${d}(${shiftedChannels(o,u,h)}),\n          vec2(${shiftedChannels(c,u,h)}));`;this.userCode=`\n      float getValue(${o.map((e=>"int "+e))}) {\n        ${p}\n      }\n\n      void main() {\n        ${s} coords = getOutputCoords();\n        vec4 result = vec4(getValue(${a}), 0., 0., 0.);\n\n        ${a[r-1]} = ${a[r-1]} + 1;\n        if (${a[r-1]} < ${n[r-1]}) {\n          result.g = getValue(${a});\n        }\n\n        ${a[r-2]} = ${a[r-2]} + 1;\n        if (${a[r-2]} < ${n[r-2]}) {\n          result.a = getValue(${a});\n        }\n\n        ${a[r-1]} = ${a[r-1]} - 1;\n        if (${a[r-2]} < ${n[r-2]} &&\n            ${a[r-1]} < ${n[r-1]}) {\n          result.b = getValue(${a});\n        }\n        setOutput(result);\n      }\n    `;}}function shiftedChannels(e,t,n){const r=e.indexOf(t);const s=e.map(((e,t)=>{if(t===r){return `${e} - ${n}`}else {return e}}));return s.join()}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function imag(e){const{inputs:t,backend:n}=e;const{input:r}=t;const s=n.texData.get(r.dataId);return identity({inputs:{x:s.complexTensorInfos.imag},backend:n})}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function real(e){const{inputs:t,backend:n}=e;const{input:r}=t;const s=n.texData.get(r.dataId);return identity({inputs:{x:s.complexTensorInfos.real},backend:n})}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function concatImpl(e,t,n){const r=e[0].dtype;if(r==="complex64"){const r=e.map((e=>real({inputs:{input:e},backend:n})));const s=e.map((e=>imag({inputs:{input:e},backend:n})));const a=concatImpl(r,t,n);const o=concatImpl(s,t,n);const i=complex({inputs:{real:a,imag:o},backend:n});r.forEach((e=>n.disposeIntermediateTensorInfo(e)));s.forEach((e=>n.disposeIntermediateTensorInfo(e)));n.disposeIntermediateTensorInfo(a);n.disposeIntermediateTensorInfo(o);return i}let s=n.shouldExecuteOnCPU(e);if(r==="string"){s=true;}if(s){const s=e.map((e=>{const r=sizeFromShape(e.shape.slice(t));const s=[-1,r];return reshape({inputs:{x:e},backend:n,attrs:{shape:s}})}));const a=s.map((e=>({vals:n.readSync(e.dataId),shape:e.shape})));const o=computeOutShape$1(s.map((e=>e.shape)),1);const i=s[0].shape[0]===1;const u=concatImplCPU(a,o,r,i);const c=computeOutShape$1(e.map((e=>e.shape)),t);const l=n.makeTensorInfo(c,r,u);s.forEach((e=>n.disposeIntermediateTensorInfo(e)));return l}if(e.length>env().getNumber("WEBGL_MAX_TEXTURES_IN_SHADER")){const r=Math.floor(e.length/2);const s=concatImpl(e.slice(0,r),t,n);const a=concatImpl(e.slice(r),t,n);const o=concatImpl([s,a],t,n);n.disposeIntermediateTensorInfo(s);n.disposeIntermediateTensorInfo(a);return o}if(env().getBool("WEBGL_PACK_ARRAY_OPERATIONS")&&e[0].shape.length>1){const s=new ConcatPackedProgram(e.map((e=>e.shape)),t);return n.runWebGLProgram(s,e,r)}const{tensors2D:a,outShape:o}=computeTensors2D(e,t,n);const i=new ConcatProgram(a.map((e=>e.shape)));const u=n.runWebGLProgram(i,a,r);a.forEach((e=>n.disposeIntermediateTensorInfo(e)));const c=reshape({inputs:{x:u},attrs:{shape:o},backend:n});n.disposeIntermediateTensorInfo(u);return c}function computeTensors2D(e,t,n){const r=computeOutShape$1(e.map((e=>e.shape)),t);const s=e.map((e=>reshape({inputs:{x:e},attrs:{shape:[-1,sizeFromShape(e.shape.slice(t))]},backend:n})));return {tensors2D:s,outShape:r}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function concat(e){const{inputs:t,backend:n,attrs:r}=e;const{axis:s}=r;const a=parseAxisParam(s,t[0].shape)[0];const o=computeOutShape$1(t.map((e=>e.shape)),a);if(sizeFromShape(o)===0){return n.makeTensorInfo(o,t[0].dtype,[])}const i=t.filter((e=>sizeFromShape(e.shape)>0));if(i.length===1){return identity({inputs:{x:i[0]},backend:n})}const u=i.map((e=>e.shape));assertParamsConsistent(u,a);return concatImpl(i,a,n)}const concatConfig={kernelName:Concat,backendName:"webgl",kernelFunc:concat};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function expandDims(e){const{inputs:t,attrs:n,backend:r}=e;const{dim:s}=n;const{input:a}=t;const o=a.shape.length;const i=a.shape.slice();let u=s;if(s<0){assert(-(o+1)<=s,(()=>`Axis must be in the interval [${-(o+1)}, ${o}]`));u=o+s+1;}i.splice(u,0,1);return reshape({inputs:{x:a},backend:r,attrs:{shape:i}})}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function pack(e){const{inputs:t,backend:n,attrs:r}=e;const{axis:s}=r;if(t.length===1){return expandDims({inputs:{input:t[0]},backend:n,attrs:{dim:s}})}const a=t[0].shape;const o=t[0].dtype;t.forEach((e=>{assertShapesMatch(a,e.shape,"All tensors passed to stack must have matching shapes");assert(o===e.dtype,(()=>"All tensors passed to stack must have matching dtypes"));}));const i=[];const u=t.map((e=>{const t=expandDims({inputs:{input:e},backend:n,attrs:{dim:s}});i.push(t);return t}));const c=concat({inputs:u,backend:n,attrs:{axis:s}});i.forEach((e=>n.disposeIntermediateTensorInfo(e)));return c}const packConfig={kernelName:Pack,backendName:"webgl",kernelFunc:pack};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const NOT_EQUAL=`return float(a != b);`;const notEqual=binaryKernelFunc({opSnippet:NOT_EQUAL,cpuKernelImpl:notEqualImplCPU,dtype:"bool"});
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const TO_INT=`return float(int(x));`;function int(e,t){const n=new UnaryOpProgram(e.shape,TO_INT);const r=t.runWebGLProgram(n,[e],"int32");return {dataId:r.dataId,shape:r.shape,dtype:r.dtype}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function cast(e){const{inputs:t,backend:n,attrs:r}=e;const{x:s}=t;const{dtype:a}=r;if(a==="complex64"){if(s.dtype==="complex64"){return identity({inputs:{x:s},backend:n})}const e=zeros(s.shape);const t=cast({inputs:{x:s},backend:n,attrs:{dtype:"float32"}});const r=complex({inputs:{real:t,imag:e},backend:n});e.dispose();n.disposeIntermediateTensorInfo(t);return r}if(s.dtype==="complex64"){const e=real({inputs:{input:s},backend:n});const t=cast({inputs:{x:e},backend:n,attrs:{dtype:a}});n.disposeIntermediateTensorInfo(e);return t}if(!hasEncodingLoss(s.dtype,a)){const e=identity({inputs:{x:s},backend:n});return {dataId:e.dataId,shape:e.shape,dtype:a}}if(a==="int32"){return int(s,n)}if(a==="bool"){const e=n.makeTensorInfo([],"bool",getTypedArrayFromDType("bool",1));const t={a:s,b:e};const r=notEqual({inputs:t,backend:n});n.disposeIntermediateTensorInfo(e);return r}throw new Error(`Error in Cast: failed to cast ${s.dtype} to ${a}`)}const castConfig={kernelName:Cast,backendName:"webgl",kernelFunc:cast};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const RELU=CHECK_NAN_SNIPPET$1+`\n  return (x < 0.0) ? 0.0 : x;\n`;const RELU_PACKED=`\n  vec4 result = x * vec4(greaterThanEqual(x, vec4(0.0)));\n  bvec4 isNaN = isnan(x);\n\n  result.r = isNaN.r ? x.r : result.r;\n  result.g = isNaN.g ? x.g : result.g;\n  result.b = isNaN.b ? x.b : result.b;\n  result.a = isNaN.a ? x.a : result.a;\n\n  return result;\n`;const relu=unaryKernelFunc({opSnippet:RELU,packedOpSnippet:RELU_PACKED});const reluConfig={kernelName:Relu,backendName:"webgl",kernelFunc:relu};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function meanImpl(e,t,n,r){const s=sizeFromShape(t);const a=sizeFromShape(e.shape);const o=a/s;const i=reshape({inputs:{x:e},attrs:{shape:[o,s]},backend:r});const u=reduce(i,"float32","mean",r);const c=reshape({inputs:{x:u},attrs:{shape:n},backend:r});r.disposeIntermediateTensorInfo(i);r.disposeIntermediateTensorInfo(u);return c}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const meanConfig={kernelName:Mean,backendName:"webgl",kernelFunc:({inputs:e,attrs:t,backend:n})=>{const{x:r}=e;const{keepDims:s,axis:a}=t;const o=n;const i=r.shape.length;const u=parseAxisParam(a,r.shape);let c=u;const l=getAxesPermutation(c,i);const p=l!=null;const d=o.shouldExecuteOnCPU([r]);const h=[];let m=r;if(p){if(d){const e=o.texData.get(m.dataId);const t=e.values;const n=new Array(i);for(let e=0;e<n.length;e++){n[e]=r.shape[l[e]];}const s=transposeImplCPU(t,r.shape,r.dtype,l,n);m=o.makeTensorInfo(n,r.dtype);const a=o.texData.get(m.dataId);a.values=s;}else {m=transposeImpl(r,l,o);}h.push(m);c=getInnerMostAxes(c.length,i);}assertAxesAreInnerMostDims("sum",c,i);const[f,g]=computeOutAndReduceShapes(m.shape,c);let y=f;if(s){y=expandShapeToKeepDim(f,u);}const x=meanImpl(m,g,y,o);for(const e of h){o.disposeIntermediateTensorInfo(e);}return x}};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function transpose(e){const{inputs:t,backend:n,attrs:r}=e;const{x:s}=t;const{perm:a}=r;const o=n;const i=s.shape.length;const u=new Array(i);for(let e=0;e<u.length;e++){u[e]=s.shape[a[e]];}let c;if(o.shouldExecuteOnCPU([s])){const e=o.texData.get(s.dataId);const t=e.values;const n=transposeImplCPU(t,s.shape,s.dtype,a,u);c=o.makeTensorInfo(u,s.dtype);const r=o.texData.get(c.dataId);r.values=n;}else {c=transposeImpl(s,a,o);}return c}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function prod(e){const{inputs:t,backend:n,attrs:r}=e;const{x:s}=t;const{axis:a,keepDims:o}=r;const i=s.shape.length;const u=[];const c=parseAxisParam(a,s.shape);let l=c;const p=getAxesPermutation(l,i);let d=s;if(p!=null){d=transpose({inputs:{x:s},backend:n,attrs:{perm:p}});l=getInnerMostAxes(l.length,i);u.push(d);}assertAxesAreInnerMostDims("prod",l,i);let h;if(n.shouldExecuteOnCPU([d])){const e=n.texData.get(d.dataId).values;const{outVals:t,outShape:r,outDtype:s}=prodImplCPU(d.shape,d.dtype,e,l);h=n.makeTensorInfo(r,s,t);}else {const[e,t]=computeOutAndReduceShapes(d.shape,l);const r=sizeFromShape(t);const a=reshape({inputs:{x:d},backend:n,attrs:{shape:[-1,r]}});const o=sumOutType(s.dtype);const i=reduce(a,o,"prod",n);h=reshape({inputs:{x:i},backend:n,attrs:{shape:e}});u.push(a);u.push(i);}if(o){u.push(h);const e=expandShapeToKeepDim(h.shape,c);h=reshape({inputs:{x:h},backend:n,attrs:{shape:e}});}u.forEach((e=>n.disposeIntermediateTensorInfo(e)));return h}const prodConfig={kernelName:Prod,backendName:"webgl",kernelFunc:prod};
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class PadProgram{constructor(e,t,n){this.variableNames=["x"];this.outputShape=t.map(((t,n)=>t[0]+e[n]+t[1]));const r=e.length;const s=getCoordsDataType(r);const a=t.map((e=>e[0])).join(",");const o=t.map(((t,n)=>t[0]+e[n])).join(",");const i=["coords[0]","coords[1]","coords[2]","coords[3]"].slice(0,r);if(r===1){this.userCode=`\n        int start = ${a};\n        int end = ${o};\n        uniform float value;\n\n        void main() {\n          int outC = getOutputCoords();\n          if (outC < start || outC >= end) {\n            setOutput(value);\n          } else {\n            setOutput(getX(outC - start));\n          }\n        }\n      `;return}this.userCode=`\n      ${s} start = ${s}(${a});\n      ${s} end = ${s}(${o});\n      uniform float value;\n\n      void main() {\n        ${s} outC = getOutputCoords();\n        if (any(lessThan(outC, start)) || any(greaterThanEqual(outC, end))) {\n          setOutput(value);\n        } else {\n          ${s} coords = outC - start;\n          setOutput(getX(${i}));\n        }\n      }\n    `;}getCustomSetupFunc(e){return (t,n)=>{if(this.valueLoc==null){this.valueLoc=t.getUniformLocationNoThrow(n,"value");}t.gl.uniform1f(this.valueLoc,e);}}}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class PadPackedProgram{constructor(e,t,n){this.variableNames=["x"];this.packedInputs=true;this.packedOutput=true;this.outputShape=t.map(((t,n)=>t[0]+e[n]+t[1]));const r=e.length;const s=getCoordsDataType(r);const a=t.map((e=>e[0])).join(",");const o=t.map(((t,n)=>t[0]+e[n])).join(",");const i=getChannels("rc",r);const u=getChannels("source",r);const c=`${i[r-1]} < ${this.outputShape[r-1]}`;const l=r===1?"source":`vec2(${u.slice(-2).join()})`;const p=[`${s} rc = outputLoc;`,`${i[r-1]} += 1;\n       if(${c}) {\n      `,r===1?"":`}\n       rc = outputLoc;\n       ${i[r-2]} += 1;\n       if(${i[r-2]} < ${this.outputShape[r-2]}) {`,r===1?"":`  ${i[r-1]} += 1;\n         if(${c}) {`];const d=r===1?"rc < start || rc >= end":"any(lessThan(rc, start)) || any(greaterThanEqual(rc, end))";let h="";for(let e=0,t=r===1?2:4;e<t;e++){h+=`\n        ${p[e]}\n        if (${d}) {\n          result[${e}] = float(value);\n        } else {\n          ${s} source = rc - start;\n          result[${e}] = getChannel(getX(${u.join()}), ${l});\n        }\n      `;}h+=r===1?`} `:`}}`;this.userCode=`\n      const ${s} start = ${s}(${a});\n      const ${s} end = ${s}(${o});\n      uniform float value;\n\n      void main() {\n        ${s} outputLoc = getOutputCoords();\n        vec4 result = vec4(0.);\n        ${h}\n        setOutput(result);\n      }\n    `;}getCustomSetupFunc(e){return (t,n)=>{if(this.valueLoc==null){this.valueLoc=t.getUniformLocationNoThrow(n,"value");}t.gl.uniform1f(this.valueLoc,e);}}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const padV2=e=>{const{inputs:t,backend:n,attrs:r}=e;const{x:s}=t;const{paddings:a,constantValue:o}=r;const i=env().getBool("WEBGL_PACK_ARRAY_OPERATIONS")?new PadPackedProgram(s.shape,a,o):new PadProgram(s.shape,a,o);const u=i.getCustomSetupFunc(o);return n.runWebGLProgram(i,[s],s.dtype,u)};const padV2Config={kernelName:PadV2,backendName:"webgl",kernelFunc:padV2};
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class SliceProgram{constructor(e){this.variableNames=["source"];this.outputShape=e;this.rank=e.length;const t=getCoordsDataType(this.rank);const n=`uniform int start[${this.rank}];`;const r=getCoords(this.rank);let s;const a=e.map(((e,t)=>`sourceLoc.${coords[t]} = start[${t}] + coords.${coords[t]};`));s=`\n        ${t} sourceLoc;\n        ${t} coords = getOutputCoords();\n        ${a.join("\n")}\n      `;this.userCode=`\n      ${n}\n      void main() {\n        ${s}\n        setOutput(getSource(${r}));\n      }\n    `;}getCustomSetupFunc(e){if(e.length!==this.rank){throw Error(`The rank (${this.rank}) of the program must match the `+`length of start (${e.length})`)}return (t,n)=>{if(this.startLoc==null){this.startLoc=t.getUniformLocationNoThrow(n,"start");if(this.startLoc==null){return}}t.gl.uniform1iv(this.startLoc,e);}}}const coords=["x","y","z","w","u","v"];function getCoords(e){if(e===1){return "sourceLoc"}else if(e<=6){return coords.slice(0,e).map((e=>"sourceLoc."+e)).join(",")}else {throw Error(`Slicing for rank ${e} is not yet supported`)}}
/**
 * @license
 * Copyright 2019 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class SlicePackedProgram{constructor(e){this.variableNames=["source"];this.packedInputs=true;this.packedOutput=true;this.outputShape=e;this.rank=e.length;const t=getCoordsDataType(this.rank);const n=getChannels("coords",this.rank);const r=getChannels("sourceLoc",this.rank);const s=this.rank===1?"sourceLoc":`vec2(${r.slice(-2).join()})`;const a=`getChannel(getSource(${r.join()}), ${s})`;const o=`\n      result.x = ${a};\n      if (++${n[this.rank-1]} < ${e[this.rank-1]}) {\n        ++${r[this.rank-1]};\n        result.y = ${a};\n        --${r[this.rank-1]};\n      }\n    `;const i=this.rank===1?"":`\n      --${n[this.rank-1]};\n      if (++${n[this.rank-2]} < ${e[this.rank-2]}) {\n        ++${r[this.rank-2]};\n        result.z = ${a};\n        if (++${n[this.rank-1]} < ${e[this.rank-1]}) {\n          ++${r[this.rank-1]};\n          result.w = ${a};\n        }\n      }\n    `;const u=this.rank<=4?`sourceLoc = coords +\n            ${t}(${e.map(((e,t)=>`start[${t}]`)).join()});`:e.map(((e,t)=>`${r[t]} = ${n[t]} + start[${t}];`)).join("\n");this.userCode=`\n      uniform int start[${this.rank}];\n      void main() {\n        ${t} coords = getOutputCoords();\n        ${t} sourceLoc;\n        ${u}\n        vec4 result = vec4(0.);\n        ${o}\n        ${i}\n        setOutput(result);\n      }\n    `;}getCustomSetupFunc(e){if(e.length!==this.rank){throw Error(`The rank (${this.rank}) of the program must match the `+`length of start (${e.length})`)}return (t,n)=>{if(this.startLoc==null){this.startLoc=t.getUniformLocationNoThrow(n,"start");if(this.startLoc==null){return}}t.gl.uniform1iv(this.startLoc,e);}}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function shallowSlice(e,t,n,r){const s=r.texData.get(e.dataId);const a=r.makeTensorInfo(n,e.dtype);const o=r.texData.get(a.dataId);Object.assign(o,s);o.refCount=1;o.shape=n;o.dtype=e.dtype;let i=computeFlatOffset(t,computeStrides(e.shape));if(s.slice){i+=s.slice.flatOffset;}o.slice={flatOffset:i,origDataId:s.slice&&s.slice.origDataId||e.dataId};const u=r.dataRefCount.get(o.slice.origDataId)||1;r.dataRefCount.set(o.slice.origDataId,u+1);return a}function slice(e){const{inputs:t,backend:n,attrs:r}=e;const{x:s}=t;const{begin:a,size:o}=r;const[i,u]=parseSliceParams(s,a,o);assertParamsValid(s,i,u);if(sizeFromShape(u)===0){return n.makeTensorInfo(u,s.dtype,[])}if(n.shouldExecuteOnCPU([s])||s.dtype==="string"){const e=n.texData.get(s.dataId);const t=sliceImplCPU(e.values,i,u,s.shape,s.dtype);return n.makeTensorInfo(u,s.dtype,t)}const{isPacked:c}=n.texData.get(s.dataId);const l=isSliceContinous(s.shape,i,u);if(c||!l){const e=env().getBool("WEBGL_PACK_ARRAY_OPERATIONS")?new SlicePackedProgram(u):new SliceProgram(u);const t=e.getCustomSetupFunc(i);return n.runWebGLProgram(e,[s],s.dtype,t)}n.uploadToGPU(s.dataId);return shallowSlice(s,i,u,n)}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function unpack(e){const{inputs:t,backend:n,attrs:r}=e;const{value:s}=t;let{axis:a}=r;if(a<0){a+=s.shape.length;}const o=s;const i=o.shape.length;const u=s.shape[a];const c=new Array(i-1);let l=0;for(let e=0;e<i;e++){if(e!==a){c[l++]=o.shape[e];}}const p=[];const d=new Array(i).fill(0);const h=o.shape.slice();h[a]=1;const m=new Array(u);for(let e=0;e<m.length;e++){d[a]=e;const t=slice({inputs:{x:o},backend:n,attrs:{begin:d,size:h}});const r=reshape({inputs:{x:t},backend:n,attrs:{shape:c}});m[e]=r;p.push(t);}p.forEach((e=>n.disposeIntermediateTensorInfo(e)));return m}const unpackConfig={kernelName:Unpack,backendName:"webgl",kernelFunc:unpack};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const IS_FINITE=`return float(!isnan(x) && !isinf(x));`;const isFinite$1=unaryKernelFunc({opSnippet:IS_FINITE,dtype:"bool"});const isFiniteConfig={kernelName:IsFinite,backendName:"webgl",kernelFunc:isFinite$1};
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class SelectProgram{constructor(e,t,n){this.variableNames=["c","a","b"];this.outputShape=t;let r;let s;if(n>4){throw Error(`Where for rank ${n} is not yet supported`)}if(n===1){s=`resRC`;r=`resRC`;}else {const n=["resRC.x","resRC.y","resRC.z","resRC.w"];const a=[];const o=[];for(let r=0;r<t.length;r++){o.push(`${n[r]}`);if(r<e){a.push(`${n[r]}`);}}r=a.join();s=o.join();}const a=getCoordsDataType(n);this.userCode=`\n      void main() {\n        ${a} resRC = getOutputCoords();\n        float cVal = getC(${r});\n        if (cVal >= 1.0) {\n          setOutput(getA(${s}));\n        } else {\n          setOutput(getB(${s}));\n        }\n      }\n    `;}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function select(e){const{inputs:t,backend:n}=e;const{condition:r,t:s,e:a}=t;const o=new SelectProgram(r.shape.length,s.shape,s.shape.length);return n.runWebGLProgram(o,[r,s,a],upcastType(s.dtype,a.dtype))}const selectConfig={kernelName:Select,backendName:"webgl",kernelFunc:select};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const COMPLEX_MULTIPLY={REAL:"return areal * breal - aimag * bimag;",IMAG:"return areal * bimag + aimag * breal;"};class BinaryOpComplexProgram{constructor(e,t,n){this.variableNames=["AReal","AImag","BReal","BImag"];this.outputShape=assertAndGetBroadcastShape(t,n);this.userCode=`\n      float binaryOpComplex(\n          float areal, float aimag, float breal, float bimag) {\n        ${e}\n      }\n\n      void main() {\n        float areal = getARealAtOutCoords();\n        float aimag = getAImagAtOutCoords();\n        float breal = getBRealAtOutCoords();\n        float bimag = getBImagAtOutCoords();\n        setOutput(binaryOpComplex(areal, aimag, breal, bimag));\n      }\n    `;}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const MUL="return a * b;";function multiply(e){const{inputs:t,backend:n}=e;const{a:r,b:s}=t;const a=upcastType(r.dtype,s.dtype);if(r.dtype==="complex64"){const e=n.texData.get(r.dataId);const t=n.texData.get(s.dataId);const a=new BinaryOpComplexProgram(COMPLEX_MULTIPLY.REAL,r.shape,s.shape);const o=new BinaryOpComplexProgram(COMPLEX_MULTIPLY.IMAG,r.shape,s.shape);const i=[{dataId:e.complexTensorInfos.real.dataId,dtype:e.complexTensorInfos.real.dtype,shape:r.shape},{dataId:e.complexTensorInfos.imag.dataId,dtype:e.complexTensorInfos.imag.dtype,shape:r.shape},{dataId:t.complexTensorInfos.real.dataId,dtype:t.complexTensorInfos.real.dtype,shape:s.shape},{dataId:t.complexTensorInfos.imag.dataId,dtype:t.complexTensorInfos.imag.dtype,shape:s.shape}];const u=n.runWebGLProgram(a,i,"float32");const c=n.runWebGLProgram(o,i,"float32");const l=complex({inputs:{real:u,imag:c},backend:n});n.disposeIntermediateTensorInfo(u);n.disposeIntermediateTensorInfo(c);return l}if(n.shouldExecuteOnCPU([r,s])){const e=n.texData.get(r.dataId);const t=n.texData.get(s.dataId);const[o,i]=multiplyImplCPU(r.shape,s.shape,e.values,t.values,a);const u=n.makeTensorInfo(i,a);const c=n.texData.get(u.dataId);c.values=o;return u}let o;if(env().getBool("WEBGL_PACK_BINARY_OPERATIONS")){o=new BinaryOpPackedProgram(MUL,r.shape,s.shape);}else {o=new BinaryOpProgram(MUL,r.shape,s.shape);}return n.runWebGLProgram(o,[r,s],a)}const multiplyConfig={kernelName:Multiply,backendName:"webgl",kernelFunc:multiply};
/**
 * @license
 * Copyright 2018 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class MatMulPackedProgram{constructor(e,t,n,r=false,s=false,a=false,o=null,i=false,u=false){this.variableNames=["matrixA","matrixB"];this.packedInputs=true;this.packedOutput=true;this.outputShape=n;const c=r?e[1]:e[2];const l=Math.ceil(c/2);const p=r?"i * 2, rc.y":"rc.y, i * 2";const d=s?"rc.z, i * 2":"i * 2, rc.z";const h=r?["a.xxyy","a.zzww"]:["a.xxzz","a.yyww"];const m=s?["b.xzxz","b.ywyw"]:["b.xyxy","b.zwzw"];let f="",g="";if(o){if(i){f=`vec4 activation(vec4 a) {\n          vec4 b = getPreluActivationWeightsAtOutCoords();\n          ${o}\n        }`;}else if(u){f=`vec4 activation(vec4 a) {\n          vec4 b = getLeakyreluAlphaAtOutCoords();\n          ${o}\n        }`;}else {f=`vec4 activation(vec4 x) {\n          ${o}\n        }`;}g=`result = activation(result);`;}const y=a?"result += getBiasAtOutCoords();":"";if(a){this.variableNames.push("bias");}if(i){this.variableNames.push("preluActivationWeights");}if(u){this.variableNames.push("leakyreluAlpha");}let x="rc.x";let T="rc.x";if(e[0]<t[0]){x=`int(min(float(rc.x), ${e[0]-1}.))`;}else if(t[0]<e[0]){T=`int(min(float(rc.x), ${t[0]-1}.))`;}this.userCode=`\n      ${f}\n\n      const float sharedDimension = ${l}.0;\n\n      vec4 dot2x2ARowBCol(ivec3 rc) {\n        vec4 result = vec4(0);\n        for (int i = 0; i < ${l}; i++) {\n          int batchA = ${x};\n          int batchB = ${T};\n          vec4 a = getMatrixA(batchA, ${p});\n          vec4 b = getMatrixB(batchB, ${d});\n\n          // These swizzled products need to be separately added.\n          // See: https://github.com/tensorflow/tfjs/issues/1735\n          result += (${h[0]} * ${m[0]});\n          result += (${h[1]} * ${m[1]});\n        }\n        return result;\n      }\n\n      void main() {\n        ivec3 rc = getOutputCoords();\n        vec4 result = dot2x2ARowBCol(rc);\n\n        ${y}\n\n        ${g}\n\n        setOutput(result);\n      }\n    `;}}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const MATMUL_SHARED_DIM_THRESHOLD=1e3;function batchMatMulImpl({a:e,b:t,transposeA:n,transposeB:r,backend:s,bias:a=null,preluActivationWeights:o=null,leakyreluAlpha:i=0,activation:u=null}){const c=e.shape.length;const l=t.shape.length;const p=n?e.shape[c-2]:e.shape[c-1];const d=r?t.shape[l-1]:t.shape[l-2];const h=n?e.shape[c-1]:e.shape[c-2];const m=r?t.shape[l-2]:t.shape[l-1];const f=e.shape.slice(0,-2);const g=t.shape.slice(0,-2);const y=sizeFromShape(f);const x=sizeFromShape(g);const T=y===x||y===1||x===1;assert(c>=2&&l>=2&&T,(()=>`Error in matMul: the input batch dimensions must either be the `+`same or at least one input batch dimension must be 1. Got input `+`batch dimensions of (${f}) and (${g}).`));const E=y>x?e.shape.slice(0,-2):t.shape.slice(0,-2);const b=E.concat([h,m]);assert(p===d,(()=>`Error in matMul: inner shapes (${p}) and (`+`${d}) of Tensors with shapes ${e.shape} and `+`${t.shape} and transposeA=${n}`+` and transposeB=${r} must match.`));const N=n?[y,p,h]:[y,h,p];const S=r?[x,m,d]:[x,d,m];const I=reshape({inputs:{x:e},backend:s,attrs:{shape:N}});const v=reshape({inputs:{x:t},backend:s,attrs:{shape:S}});const _=[I,v];const w=Math.max(y,x);const A=n?I.shape[1]:I.shape[2];const $=a!=null;const P=o!=null;const k=u==="leakyrelu";const O=u!=null?mapActivationToShaderProgram(u,true):null;const D=$||P||k||O!=null;let F;if((h===1||m===1)&&A>MATMUL_SHARED_DIM_THRESHOLD&&D===false){let e=I;let t=v;if(n){e=transpose({inputs:{x:I},backend:s,attrs:{perm:[0,2,1]}});_.push(e);}if(r){t=transpose({inputs:{x:v},backend:s,attrs:{perm:[0,2,1]}});_.push(t);}const a=m!==1;const o=m===1;let i=e;if(a){i=reshape({inputs:{x:e},backend:s,attrs:{shape:[w,A,1]}});_.push(i);}const u=m===1?2:1;let c=t;if(o){c=reshape({inputs:{x:t},backend:s,attrs:{shape:[w,1,A]}});_.push(c);}const l=multiply({inputs:{a:i,b:c},backend:s});F=sum({inputs:{x:l},backend:s,attrs:{axis:u,keepDims:true}});_.push(l);}else {const u=upcastType(e.dtype,t.dtype);const c=new MatMulPackedProgram(N,S,[w,h,m],n,r,$,O,P,k);const l=[I,v];if(a!=null){l.push(a);}if(P){l.push(o);}if(k){const e=s.makeTensorInfo([],"float32",createScalarValue(i,"float32"));l.push(e);_.push(e);}F=s.runWebGLProgram(c,l,u);}const C=reshape({inputs:{x:F},backend:s,attrs:{shape:b}});_.push(F);for(const e of _){s.disposeIntermediateTensorInfo(e);}return C}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function batchMatMul(e){const{inputs:t,backend:n,attrs:r}=e;const{a:s,b:a}=t;const{transposeA:o,transposeB:i}=r;return batchMatMulImpl({a:s,b:a,transposeA:o,transposeB:i,backend:n})}const batchMatMulConfig={kernelName:BatchMatMul,backendName:"webgl",kernelFunc:batchMatMul};
/**
 * @license
 * Copyright 2017 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */class GatherProgram{constructor(e,t){this.variableNames=["A","indices"];this.outputShape=t;this.rank=t.length;const n=getCoordsDataType(this.rank);const r=getSourceCoords(e);this.userCode=`\n      void main() {\n        ${n} resRC = getOutputCoords();\n        setOutput(getA(${r}));\n      }\n    `;}}function getSourceCoords(e,t){const n=["resRC.x","resRC.y","resRC.z","resRC.w"];const r=[];for(let t=0;t<e.length;t++){if(t===2){r.push("int(getIndices(resRC.x, resRC.z))");}else {r.push(`${n[t]}`);}}return r.join()}
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function gatherV2(e){const{inputs:t,backend:n,attrs:r}=e;const{x:s,indices:a}=t;const{axis:o,batchDims:i}=r;const u=parseAxisParam(o,s.shape)[0];const c=collectGatherOpShapeInfo(s,a,u,i);const l=sizeFromShape(a.shape);const p=[];const d=reshape({inputs:{x:s},backend:n,attrs:{shape:[c.batchSize,c.outerSize,c.dimSize,c.sliceSize]}});const h=reshape({inputs:{x:a},backend:n,attrs:{shape:[c.batchSize,l/c.batchSize]}});p.push(d);p.push(h);const m=[c.batchSize,c.outerSize,l/c.batchSize,c.sliceSize];if(n.shouldExecuteOnCPU([s,a])||s.dtype==="string"){const e=n.bufferSync(h);const t=n.bufferSync(d);const r=gatherV2ImplCPU(t,e,m);p.forEach((e=>n.disposeIntermediateTensorInfo(e)));return n.makeTensorInfo(c.outputShape,r.dtype,r.values)}const f=new GatherProgram(d.shape,m);const g=n.runWebGLProgram(f,[d,h],d.dtype);p.push(g);const y=reshape({inputs:{x:g},backend:n,attrs:{shape:c.outputShape}});p.forEach((e=>n.disposeIntermediateTensorInfo(e)));return y}const gatherV2Config={kernelName:GatherV2,backendName:"webgl",kernelFunc:gatherV2};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */const SIGMOID=`return 1.0 / (1.0 + exp(-1.0 * x));`;const sigmoid=unaryKernelFunc({opSnippet:SIGMOID});const sigmoidConfig={kernelName:Sigmoid,backendName:"webgl",kernelFunc:sigmoid};
/**
 * @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * 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.
 * =============================================================================
 */function _fusedMatMul(e){const{inputs:t,backend:n,attrs:r}=e;const{a:s,b:a,bias:o,preluActivationWeights:i}=t;const{transposeA:u,transposeB:c,activation:l,leakyreluAlpha:p}=r;return batchMatMulImpl({a:s,b:a,transposeA:u,transposeB:c,backend:n,bias:o,preluActivationWeights:i,leakyreluAlpha:p,activation:l})}const _fusedMatMulConfig={kernelName:_FusedMatMul,backendName:"webgl",kernelFunc:_fusedMatMul};for(let e of [addConfig,sumConfig,powConfig,packConfig,castConfig,reluConfig,meanConfig,prodConfig,padV2Config,unpackConfig,reshapeConfig,isFiniteConfig,identityConfig,selectConfig,multiplyConfig,batchMatMulConfig,gatherV2Config,concatConfig,sigmoidConfig,_fusedMatMulConfig])registerKernel(e);var cast_1 = partial_bundle_ml.cast=cast$1;var enableProdMode_1 = partial_bundle_ml.enableProdMode=enableProdMode;var eye_1 = partial_bundle_ml.eye=eye;var _isFinite = partial_bundle_ml.isFinite=isFinite$2;var loadGraphModel_1 = partial_bundle_ml.loadGraphModel=loadGraphModel;var oneHot_1 = partial_bundle_ml.oneHot=oneHot;var pow_1 = partial_bundle_ml.pow=pow$1;var stack_1 = partial_bundle_ml.stack=stack;var sum_1 = partial_bundle_ml.sum=sum$1;var tensor_1 = partial_bundle_ml.tensor=tensor;var tidy_1 = partial_bundle_ml.tidy=tidy;var unstack_1 = partial_bundle_ml.unstack=unstack;var zeros_1 = partial_bundle_ml.zeros=zeros;

var tf = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.assign(/*#__PURE__*/Object.create(null), partial_bundle_ml, {
	cast: cast_1,
	enableProdMode: enableProdMode_1,
	eye: eye_1,
	isFinite: _isFinite,
	loadGraphModel: loadGraphModel_1,
	oneHot: oneHot_1,
	pow: pow_1,
	stack: stack_1,
	sum: sum_1,
	tensor: tensor_1,
	tidy: tidy_1,
	unstack: unstack_1,
	zeros: zeros_1,
	'default': partial_bundle_ml
}));

/** @module */

/**
 * @typedef {number|Array.<module:ml~InputData>} InputData
 */

/**
 * @typedef {object} InputObject
 * @property {Array.<module:ml~InputData>} data The data to feed into the model.
 * @property {Array.<module:ml~PreprocessingObject>} preprocess A list of
 * preprocessing steps in `{@link module:ml~PreprocessingObject}` format.
 */

/**
 * @typedef {object} PreprocessingObject
 * @property {string} funcName The name of a preprocessing function.
 * @property {?*} [args] Arguments for the preprocessing function.
 */

/**
 * An `ML` object implements machine learning based on
 * {@link https://www.tensorflow.org/js TensorFlow.js}.
 *
 * Currently these preprocessing functions are supported:
 *
 * - `cast` - cast tensor into a type provided as an argument
 * - `stack` - {@link https://js.tensorflow.org/api/latest/#stack tf.stack}
 * - `unstack` - {@link https://js.tensorflow.org/api/latest/#unstack tf.unstack}
 * - `localPooling` - run local pooling on each element in an array
 * - `pad` - {@link https://js.tensorflow.org/api/latest/#pad tf.pad}
 * - `oneHot` - {@link https://js.tensorflow.org/api/latest/#oneHot tf.oneHot}
 *
 * @example <caption>Simple usage</caption>
 * let tf = require("@tensorflow/tfjs");
 * let ml = new ML(tf);
 * // Assuming a pretrained model that predicts (y = 2x - 1)
 *
 * // See here: https://github.com/tensorflow/tfjs-examples/blob/master/getting-started/index.js
 * ml.modelURL = "https://example.com/model.json";
 * console.log(await ml.predict([{data: [[20]]}]));
 * // Outputs approximately 39
 *
 * @example <caption>Usage with preprocessing options</caption>
 * let tf = require("@tensorflow/tfjs");
 * let ml = new ML(tf);
 * // Assuming a graph classification model
 * ml.modelURL = "https://example.com/model.json";
 * let adjacencyMatrices = [[0, 1, 0],
 *                          [1, 0, 1],
 *                          [0, 1, 0]];
 * let numberOfFeatures = 100;
 * let graphSize = 10;
 * let preprocessAdjacency = [
 *   {funcName: "pad", args: graphSize}
 *   {funcName: "unstack"}
 *   {funcName: "localPooling"}
 *   {funcName: "stack"}
 * ];
 * let featureVectors = [[1], [2], [3]];
 * let preprocessFeatures = [
 *   {funcName: "cast", args: "int32"}
 *   {funcName: "pad", args: graphSize}
 *   {funcName: "oneHot", args: numberOfFeatures}
 *   {funcName: "cast", args: "float32"}
 * ];
 * console.log(await ml.predict([
 *   {data: adjacencyMatrices, preprocess: preprocessAdjacency},
 *   {data: featureVectors, preprocess: preprocessFeatures}
 * ]));
 */
var ML_1 = class ML
{
  /**
   * @param {object} lib TensorFlow.js library to use for ML operations.
   */
  constructor(lib)
  {
    this._modelURL = null;
    this._model = null;

    if (lib == null)
      throw new Error("lib must not be null.");

    this._tf = lib;

    this._preprocessingFunctions = new Map([
      ["cast", this._tf.cast],
      ["stack", this._tf.stack],
      ["unstack", this._tf.unstack],
      ["localPooling", this._localPoolingMap.bind(this)],
      ["padAdjacency", this._padTensorAdjacency.bind(this)],
      ["padFeatures", this._padTensorFeatures.bind(this)],
      ["oneHot", this._oneHotEncode.bind(this)]
    ]);
  }

  /**
   * A URL to the model manifest in `tfjs_graphmodel` format.
   * @type {string}
   */
  get modelURL()
  {
    return this._modelURL;
  }

  set modelURL(value)
  {
    if (this._modelURL != value)
    {
      if (this._model)
      {
        this._model.dispose();
        this._model = null;
      }
      this._modelURL = value;
    }
  }

  /**
   * Runs prediction based on provided inputs.
   * @param {Array.<module:ml~InputObject>} inputs
   *   `{@link module:ml~InputObject}` instances for prediction.
   * @returns {Promise.<Array.<number>>} A promise that fulfills with raw
   *   results from the model.
   */
  async predict(inputs)
  {
    if (!this._model)
    {
      await this._initModel();
      return this.predict(inputs);
    }

    let preprocessed = this._preprocess(inputs);

    try
    {
      let result = await this._model.execute(preprocessed);

      try
      {
        return result.dataSync();
      }
      finally
      {
        result.dispose();
      }
    }
    finally
    {
      for (let inputTensor of preprocessed)
        inputTensor.dispose();
    }
  }

  /**
   * Initializes the model from a provided URL.
   * @returns {Promise}
   * @private
   */
  async _initModel()
  {
    if (!this._modelURL)
      throw new Error("modelURL must be set to a URL.");

    this._tf.enableProdMode();
    this._model = await this._tf.loadGraphModel(this._modelURL);
  }

  /**
   * Prepares the inputs for running inference according to the preprocessing
   * rules defined for each.
   * @param {Array.<module:ml~InputObject>} inputs
   *   {@link module:ml~InputObject} instances for preprocessing.
   * @returns {Array.<tf.Tensor>}
   * @private
   */
  _preprocess(inputs)
  {
    return this._tf.tidy(() =>
    {
      return inputs.map(input =>
      {
        let preprocessed = this._tf.tensor(input.data);
        if (input.preprocess)
        {
          for (let params of input.preprocess)
          {
            preprocessed = this._preprocessingFunctions.get(params.funcName)(
              preprocessed, params.args
            );
          }
        }
        return preprocessed;
      });
    });
  }

  /**
   * Computes a pooling operation for a matrix `A: (D^(-0.5))*(A)*(D^(-0.5))`
   * where `D` is the diagonal node degree matrix.
   *
   * Based on Kipf & Welling (2017).
   *
   * See {@link https://github.com/danielegrattarola/spektral/blob/a3883117b16b958e2e24723afc6885fbc7df397a/spektral/utils/convolution.py#L88 Python implementation}
   * @param {tf.Tensor} adjacencyMatrix
   * @returns {tf.Tensor} The normalized adjacency matrix.
   * @private
   */
  _localPooling(adjacencyMatrix)
  {
    let tf = this._tf;
    let aTilde = adjacencyMatrix.add(tf.eye(adjacencyMatrix.shape[0]));
    let degreePow = tf.pow(tf.sum(aTilde, 1), -0.5);
    degreePow = degreePow.where(
      tf.isFinite(degreePow),
      tf.zeros(degreePow.shape)
    );
    let degreeMx = degreePow.mul(tf.eye(aTilde.shape[0]));
    let normalized = degreeMx.dot(aTilde).dot(degreeMx);
    return normalized;
  }

  /**
   * Runs `{@link module:ml.ML#_localPooling}` on an array of tensors.
   * @param {Array.<tf.Tensor>} adjacencyMatrices
   * @returns {Array.<tf.Tensor>}
   * @private
   */
  _localPoolingMap(adjacencyMatrices)
  {
    return adjacencyMatrices.map(x => this._localPooling(x));
  }

  /**
   * Pads adjacency matrix tensor in two dimensions with `0`s or according
   * to the padSize given.
   *
   * See {@link https://js.tensorflow.org/api/latest/#pad here} for details.
   * @param {tf.Tensor} tensor
   * @param {number} padSize
   * @returns {tf.Tensor}
   * @private
   *
   * @example
   * // returns [[[0, 1, 0, 0, 0],
   *              [1, 0, 1, 0, 0],
   *              [0, 1, 0, 0, 0],
   *              [0, 0, 0, 0, 0],
   *              [0, 0, 0, 0, 0]]]
   * _padTensorAdjacency([[[0, 1, 0],
   *                       [1, 0, 1],
   *                       [0, 1, 0]]]
   *                      5
   *                     );
   */
  _padTensorAdjacency(tensor, padSize)
  {
    return tensor.pad([
      [0, 0],
      [0, padSize - tensor.shape[1]],
      [0, padSize - tensor.shape[2]]
    ]);
  }

  /**
   * Pads feature matrix tensor in one dimension with `0`s according
   * to the padSize given.
   *
   * See {@link https://js.tensorflow.org/api/latest/#pad here} for details.
   * @param {tf.Tensor} tensor
   * @param {number} padSize
   * @returns {tf.Tensor}
   * @private
   *
   * @example
   * // returns [[[0, 0, 0],
   *              [1, 0, 0],
   *              [2, 1, 0],
   *              [0, 0, 0],
   *              [0, 0, 0]]]
   * _padTensorAdjacency([[[0, 0, 0],
   *                       [1, 0, 0],
   *                       [2, 1, 0]]]
   *                      5
   *                     );
   */
  _padTensorFeatures(tensor, padSize)
  {
    return tensor.pad([
      [0, 0],
      [0, padSize - tensor.shape[1]],
      [0, 0]
    ]);
  }

  /**
   * One-hot encodes tensor (place 1 on a relevant position in a vector).
   *
   * See {@link https://js.tensorflow.org/api/latest/#oneHot here} for details.
   * @param {tf.Tensor} tensor
   * @param {number} numOfClasses Number of output classes.
   * @returns {tf.Tensor}
   * @private
   *
   * @example
   * //  returns [
   * //    [1, 0, 0, 0],
   * //    [0, 1, 0, 0],
   * //    [0, 0, 1, 0]
   * //  ]
   * _oneHotEncode([0, 1, 2], 4);
   */
  _oneHotEncode(tensor, numOfClasses)
  {
    return this._tf.oneHot(tensor, numOfClasses);
  }
};

if (typeof browser === "object" && "runtime" in browser)
{
  let mlByModel = new Map([
    ["hideIfGraphMatches", new ML_1(tf)]
  ]);

  for (let [key, value] of mlByModel)
    value.modelURL = browser.runtime.getURL(`data/${key}/model.json`);

  /**
   * Returns the inference on a ML model.
   *
   * @event "ml.inference"
   * @property {string} model Name of the model to use
   * @returns {Array.<number>}
   */
  browser.runtime.onMessage.addListener(message =>
  {
    if (message.type === "ml.inference")
    {
      let ml = mlByModel.get(message.model);
      if (!ml)
        return Promise.reject(new Error("Model not found."));

      if (ml)
        return ml.predict(message.inputs);
    }
  });
}


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

function getAvailableFiles() {
return {
jquery: {
"jquery-1.10.2.min.js": 93107,
"jquery-1.11.0.min.js": 96381,
"jquery-1.11.1.min.js": 95786,
"jquery-1.11.2.min.js": 95931,
"jquery-1.11.3.min.js": 95957,
"jquery-1.12.4.min.js": 97163,
"jquery-1.3.2.min.js": 57254,
"jquery-1.4.2.min.js": 72174,
"jquery-1.7.1.min.js": 93868,
"jquery-1.7.2.min.js": 94840,
"jquery-1.8.2.min.js": 93435,
"jquery-1.8.3.min.js": 93636,
"jquery-1.9.1.min.js": 92629,
"jquery-2.1.1.min.js": 84245,
"jquery-2.1.3.min.js": 84320,
"jquery-2.1.4.min.js": 84345,
"jquery-2.2.4.min.js": 85578,
"jquery-3.1.1.min.js": 86709,
"jquery-3.2.1.min.js": 86659,
},
};
}
 
// Attach methods to window
Object.assign(window, {
  getAvailableFiles
});
const {LocalCDN} = __webpack_require__(105);
LocalCDN.setUp();
 


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

"use strict";


/* For ESLint: List any global identifiers used in this file below */
/* global browser, parseUri, exports, getAvailableFiles, adblockIsPaused
   getSettings, settings */

const LocalCDN = (function getLocalCDN() {
  const urlsMatchPattern = ['http://*/*', 'https://*/*'];
  const hostRegex = /ajax\.googleapis\.com|ajax\.aspnetcdn\.com|ajax\.microsoft\.com|cdnjs\.cloudflare\.com|code\.jquery\.com|cdn\.jsdelivr\.net|yastatic\.net|yandex\.st|libs\.baidu\.com|lib\.sinaapp\.com|upcdn\.b0\.upaiyun\.com/;
  const pathRegex = { jquery: /jquery[/-](\d*\.\d*\.\d*)/ };
  const libraryPaths = { jquery: { prefix: 'jquery-', postfix: '.min.js' } };
  const headersToRemove = ['Cookie', 'Origin', 'Referer'];
  const redirectCountKey = 'redirectCount';
  const dataCountKey = 'redirectDataCount';
  const missedVersionsKey = 'missedVersions';
  let localFiles = {};
  let libraries = [];
  let versionArray = {};

  // Gets a stored value from localStorage if available, and parses it. Otherwise,
  // if the value isn't currently stored or if the parse fails, returns a default
  // value.
  // Param: keyName: the key under which the value is stored
  //        defaultValue: the value to be returned if the stored value cannot be
  //                      retrieved
  const getStoredValue = function (keyName, defaultValue) {
    let storedValue = localStorage.getItem(keyName);
    try {
      storedValue = JSON.parse(storedValue);
    } catch (err) {
      storedValue = defaultValue;
    } finally {
      if (!storedValue) {
        storedValue = defaultValue;
      }
    }
    return storedValue;
  };

  // Populates the version array based on the files available locally
  // Pre: localFiles and libraries must be populated first
  const populateVersionArray = function () {
    const libraryVersions = {};
    // go through each libarary
    for (let i = 0; i < libraries.length; i++) {
      // check for path info
      if (libraryPaths[libraries[i]]) {
        // get the filenames
        const filenames = Object.getOwnPropertyNames(localFiles[libraries[i]]);
        libraryVersions[libraries[i]] = [];
        for (let j = 0; j < filenames.length; j++) {
          // extract the version from the filesname
          let version = filenames[j].replace(libraryPaths[libraries[i]].prefix, '');
          version = version.replace(libraryPaths[libraries[i]].postfix, '');
          libraryVersions[libraries[i]].push(version);
        }
      }
    }

    return libraryVersions;
  };

  // Completes necessary set up for the LocalCDN
  // Post:  localFiles, libraries, and versionArray are populated based on
  //        available local files
  const setUp = function () {
    localFiles = getAvailableFiles();
    libraries = Object.getOwnPropertyNames(localFiles);
    versionArray = populateVersionArray();
  };

  // Increments the redirect count by one.
  // The redirect count is loaded from and saved to localStorage.
  const incrementRedirectCount = function () {
    // get stored redirect count
    let storedRedirectCount = getStoredValue(redirectCountKey, 0);

    // increment
    storedRedirectCount += 1;

    // store updated count
    localStorage.setItem(redirectCountKey, JSON.stringify(storedRedirectCount));
  };

  // Adds the size of the specified file to the data count for that library.
  // The data count is loaded from and saved to localStorage.
  // Param: targetLibrary: the library that the file belongs to
  //        fileName: the file to be added to the data count
  const addToDataCount = function (targetLibrary, fileName) {
    // get stored redirect count
    let storedDataCount = getStoredValue(dataCountKey, 0);

    // add file size to data count
    storedDataCount += localFiles[targetLibrary][fileName];

    // store updated count
    localStorage.setItem(dataCountKey, JSON.stringify(storedDataCount));
  };

  // Adds the specified version of the specified library to the missed versions
  // object, if it hasn't already been added. Otherwise increments the count for
  // that version.
  // The missed versions object is loaded from and saved to localStorage.
  // Param: targetLibrary: the library that the missing version belongs to
  //        version: the missing version to be added
  const addMissedVersion = function (targetLibrary, version) {
    // get stored missed versions
    const storedMissedVersions = getStoredValue(missedVersionsKey, {});

    // add new missed version
    if (!storedMissedVersions[targetLibrary]) {
      storedMissedVersions[targetLibrary] = {};
    }
    if (storedMissedVersions[targetLibrary][version] > 0) {
      storedMissedVersions[targetLibrary][version] += 1;
    } else {
      storedMissedVersions[targetLibrary][version] = 1;
    }

    // store updated missed versions
    localStorage.setItem(missedVersionsKey, JSON.stringify(storedMissedVersions));
  };

  // Handles a webRequest.onBeforeRequest event.
  // Redirects any requests for locally available files from a matching host,
  // if AdBlock is not paused. Otherwise allows request to continue as normal.
  // Records any redirects, bytes of data redirected, and missing versions of
  // supported libararies.
  // Param: details: holds information about the request, including the URL.
  const libRequestHandler = function (details) {
    // respect pause
    if (!adblockIsPaused()) {
      let targetLibrary = null;
      const requestUrl = parseUri(details.url);

      // check if the url contains a library keyword
      for (let i = 0; i < libraries.length; i++) {
        if (requestUrl.pathname.indexOf(libraries[i]) !== -1) {
          targetLibrary = libraries[i];
        }
      }

      // check the request host
      if (targetLibrary !== null && hostRegex.test(requestUrl.host)) {
        // check the path
        const matches = pathRegex[targetLibrary].exec(requestUrl.pathname);
        if (matches) {
          const version = matches[1];

          // check if we have the version locally
          if (versionArray[targetLibrary].indexOf(version) !== -1) {
            const libraryPrefix = libraryPaths[targetLibrary].prefix;
            const libraryPostfix = libraryPaths[targetLibrary].postfix;
            const fileName = libraryPrefix + version + libraryPostfix;
            const localPath = `localLib/${targetLibrary}/${fileName}`;
            incrementRedirectCount();
            addToDataCount(targetLibrary, fileName);
            return { redirectUrl: browser.runtime.getURL(localPath) };
          }
          addMissedVersion(targetLibrary, version);
        }
      }
    }

    return { cancel: false };
  };

  // Handles a webrequest.onBeforeSendHeaders event.
  // Strips the cookie, origin, and referer headers (if present) from any requests for
  // a supported libarary from a matching host, if AdBlock is not paused. Otherwise
  // allows request to continue as normal.
  // Param: details: holds information about the request, including the URL and request
  //                 headers
  const stripMetadataHandler = function (details) {
    // respect pause
    if (!adblockIsPaused()) {
      const requestUrl = parseUri(details.url);
      let match = false;

      // check if the url contains a library keyword
      for (let k = 0; k < libraries.length; k++) {
        if (requestUrl.pathname.indexOf(libraries[k]) !== -1) {
          match = true;
        }
      }

      // check for a matching host
      if (match && hostRegex.test(requestUrl.host)) {
        // strip the headers to remove, if present
        for (let i = 0; i < details.requestHeaders.length; i++) {
          const aHeader = details.requestHeaders[i].name;
          if (headersToRemove.includes(aHeader)) {
            details.requestHeaders.splice(i -= 1, 1);
          }
        }
      }
    }

    return { requestHeaders: details.requestHeaders };
  };

  // Sets redirect count, data count, and missed versions back to default
  // (0 for redirect count and data count, and an empty object for missed
  // versions)
  const resetCollectedData = function () {
    localStorage.setItem(redirectCountKey, '0');
    localStorage.setItem(dataCountKey, '0');
    localStorage.setItem(missedVersionsKey, '{}');
  };

  return {
    setUp,
    // Starts the LocalCDN listeners
    start() {
      browser.webRequest.onBeforeRequest.addListener(libRequestHandler, { urls: urlsMatchPattern }, ['blocking']);
      browser.webRequest.onBeforeSendHeaders.addListener(stripMetadataHandler, { urls: urlsMatchPattern }, ['blocking', 'requestHeaders']);
    },
    // Stops the LocalCDN listeners and reset data
    end() {
      browser.webRequest.onBeforeRequest.removeListener(libRequestHandler);
      browser.webRequest.onBeforeSendHeaders.removeListener(stripMetadataHandler);
      resetCollectedData();
    },
    // Gets the redirect count as a number of redirects
    getRedirectCount() {
      return getStoredValue(redirectCountKey, 0);
    },
    // Gets the data count as a number of bytes
    getDataCount() {
      return getStoredValue(dataCountKey, 0);
    },
    // Gets the missed versions object, which includes a count of how many
    // times the missed version has been requested
    getMissedVersions() {
      return getStoredValue(missedVersionsKey, undefined);
    },
  };
}());

exports.LocalCDN = LocalCDN;

settings.onload().then(() => {
  if (getSettings().local_cdn) {
    LocalCDN.start();
  }
});

Object.assign(window, {
  LocalCDN,
});


/***/ }),
/* 106 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/lib/messaging.js
var messaging = __webpack_require__(1);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/lib/prefs.js
var prefs = __webpack_require__(5);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/lib/stats.js
var stats = __webpack_require__(16);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/filterStorage.js
var filterStorage = __webpack_require__(3);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/filterNotifier.js
var filterNotifier = __webpack_require__(4);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/matcher.js
var matcher = __webpack_require__(10);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/url.js
var url = __webpack_require__(9);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/lib/hitLogger.js
var hitLogger = __webpack_require__(11);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/filterClasses.js
var filterClasses = __webpack_require__(0);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/synchronizer.js
var synchronizer = __webpack_require__(18);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/subscriptionClasses.js
var subscriptionClasses = __webpack_require__(2);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/lib/allowlisting.js
var allowlisting = __webpack_require__(8);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/build/templates/info.chrome.js.tmpl
var info_chrome_js = __webpack_require__(7);

// CONCATENATED MODULE: ./adblockplusui/adblockpluschrome/lib/options.js
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */

/** @module options */





const optionsUrl = browser.runtime.getManifest().options_ui.page;

const openOptionsPageAPISupported = (
  // Some versions of Firefox for Android before version 57 do have a
  // runtime.openOptionsPage but it doesn't do anything.
  // https://bugzilla.mozilla.org/show_bug.cgi?id=1364945
  (info_chrome_js["application"] != "fennec" ||
   parseInt(info_chrome_js["applicationVersion"], 10) >= 57)
);

async function findOptionsPage()
{
  let tabs = await browser.tabs.query({});
  // Firefox won't let us query for moz-extension:// pages, though
  // starting with Firefox 56 an extension can query for its own URLs:
  // https://bugzilla.mozilla.org/show_bug.cgi?id=1271354
  let fullOptionsUrl = browser.runtime.getURL(optionsUrl);
  let optionsTab = tabs.find(tab => tab.url == fullOptionsUrl);
  if (optionsTab)
    return optionsTab;

  // Newly created tabs might have about:blank as their URL in Firefox or
  // an empty string on Chrome (80) rather than the final options page URL,
  // we need to wait for those to finish loading.
  let potentialOptionTabIds = new Set(
    tabs.filter(tab => (tab.url == "about:blank" || !tab.url) &&
                       tab.status == "loading").map(tab => tab.id)
  );
  if (potentialOptionTabIds.size == 0)
    return;

  let removeListener;
  let updateListener = (tabId, changeInfo, tab) =>
  {
    if (potentialOptionTabIds.has(tabId) &&
        changeInfo.status == "complete")
    {
      potentialOptionTabIds.delete(tabId);
      let urlMatch = tab.url == fullOptionsUrl;
      if (urlMatch || potentialOptionTabIds.size == 0)
      {
        browser.tabs.onUpdated.removeListener(updateListener);
        browser.tabs.onRemoved.removeListener(removeListener);
        return urlMatch ? tab : null;
      }
    }
  };
  browser.tabs.onUpdated.addListener(updateListener);
  removeListener = removedTabId =>
  {
    potentialOptionTabIds.delete(removedTabId);
    if (potentialOptionTabIds.size == 0)
    {
      browser.tabs.onUpdated.removeListener(updateListener);
      browser.tabs.onRemoved.removeListener(removeListener);
    }
  };
  browser.tabs.onRemoved.addListener(removeListener);
}

async function openOptionsPage()
{
  let opened = new Promise(resolve =>
  {
    function onMessage(message, optionsPort)
    {
      if (message.type != "app.listen")
        return;
      optionsPort.onMessage.removeListener(onMessage);
      resolve([optionsPort.sender.tab, optionsPort]);
    }

    function onConnect(optionsPort)
    {
      if (optionsPort.name != "ui")
        return;
      browser.runtime.onConnect.removeListener(onConnect);
      optionsPort.onMessage.addListener(onMessage);
    }

    browser.runtime.onConnect.addListener(onConnect);
  });

  if (openOptionsPageAPISupported)
    await browser.runtime.openOptionsPage();
  else
    await browser.tabs.create({url: optionsUrl});

  return opened;
}

async function focusOptionsPage(tab)
{
  if (openOptionsPageAPISupported)
    return browser.runtime.openOptionsPage();

  let focusTab = () => browser.tabs.update(tab.id, {active: true});

  if ("windows" in browser)
  {
    await browser.windows.update(tab.windowId, {focused: true});
    return focusTab();
  }

  // Firefox for Android before version 57 does not support
  // runtime.openOptionsPage, nor does it support the windows API.
  // Since there is effectively only one window on the mobile browser,
  // we can just bring the tab to focus instead.
  return focusTab();
}

/**
 * Opens the options page, or switches to its existing tab.
 * @returns {Promise.<Array>}
 *   Promise resolving to an Array containg the tab Object of the options page
 *   and sometimes (when the page was just opened) a messaging port.
 */
async function showOptions()
{
  let existingTab = await findOptionsPage();
  if (existingTab)
    return focusOptionsPage(existingTab);
  return openOptionsPage();
}

// We need to clear the popup URL on Firefox for Android in order for the
// options page to open instead of the bubble. Unfortunately there's a bug[1]
// which prevents us from doing that, so we must avoid setting the URL on
// Firefox from the manifest at all, instead setting it here only for
// non-mobile.
// [1] - https://bugzilla.mozilla.org/show_bug.cgi?id=1414613
Promise.all([browser.browserAction.getPopup({}),
             browser.runtime.getPlatformInfo()]).then(
  ([popup, platformInfo]) =>
  {
    if (!popup && platformInfo.os != "android")
      browser.browserAction.setPopup({popup: "popup.html"});
  }
);

// On Firefox for Android, open the options page directly when the browser
// action is clicked.
browser.browserAction.onClicked.addListener(async() =>
{
  let [tab] = await browser.tabs.query({active: true});
  let currentPage = new ext.Page(tab);

  let [, optionsPort] = await showOptions();
  if (!/^https?:$/.test(currentPage.url.protocol))
    return;

  optionsPort.postMessage({
    type: "app.respond",
    action: "showPageOptions",
    args: [
      {
        host: currentPage.url.hostname.replace(/^www\./, ""),
        whitelisted: !!Object(allowlisting["checkAllowlisted"])(currentPage)
      }
    ]
  });
});

/**
 * Opens the options page in a new tab and waits for it to load, or switches to
 * the existing tab if the options page is already open.
 *
 * @event "options.open"
 * @returns {object} optionsTab
 */
messaging["port"].on("options.open", async(message, sender) =>
{
  let [optionsTab] = await showOptions();
  return optionsTab;
});

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/recommendations.js
var recommendations = __webpack_require__(23);

// EXTERNAL MODULE: ./adblockplusui/adblockpluschrome/adblockpluscore/lib/filterState.js
var filterState = __webpack_require__(14);

// EXTERNAL MODULE: ./adblock-betafish/alias/requestBlocker.js
var requestBlocker = __webpack_require__(32);

// CONCATENATED MODULE: ./adblockplusui/adblockpluschrome/lib/filterConfiguration.js
/*
 * This file is part of Adblock Plus <https://adblockplus.org/>,
 * Copyright (C) 2006-present eyeo GmbH
 *
 * Adblock Plus is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Adblock Plus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
 */


















function convertObject(keys, obj)
{
  let result = {};
  for (let key of keys)
  {
    if (key in obj)
      result[key] = obj[key];
  }
  return result;
}

let convertRecommendation = convertObject.bind(null, [
  "languages", "title", "type", "url"
]);

function convertSubscriptionFilters(subscription)
{
  return Array.from(subscription.filterText(),
                    text => convertFilter(filterClasses["Filter"].fromText(text)));
}

function convertSubscription(subscription)
{
  let obj = convertObject(["disabled", "downloadStatus", "homepage",
                           "version", "lastDownload", "lastSuccess",
                           "softExpiration", "expires", "title",
                           "url"], subscription);
  if (subscription instanceof subscriptionClasses["SpecialSubscription"])
    obj.filters = convertSubscriptionFilters(subscription);

  obj.downloading = synchronizer["synchronizer"].isExecuting(subscription.url);
  obj.validURL = subscriptionClasses["Subscription"].isValidURL(subscription.url);
  return obj;
}

// pollute a converted filter object with `slow` detail
// there are 3 kind of slow filters
//  1. filter instanceof URLFilter && isSlowFilter(filter)
//  2. filter instanceof ElemHideEmulationFilter
//  3. filter instanceof SnippetFilter
// for the time being, we want to simply expose the first kind
// since there's nothing users can do to avoid others being slow
function convertFilter(filter)
{
  let obj = convertObject(["disabled", "text"], filter);
  obj.slow = filter instanceof filterClasses["URLFilter"] && Object(matcher["isSlowFilter"])(filter);
  return obj;
}

let uiPorts = new Map();
let listenedPreferences = new Set();
let listenedFilterChanges = new Set();
let listenedStats = new Set();
let messageTypes = new Map([
  ["app", "app.respond"],
  ["filter", "filters.respond"],
  ["pref", "prefs.respond"],
  ["requests", "requests.respond"],
  ["subscription", "subscriptions.respond"],
  ["stats", "stats.respond"]
]);

function sendMessage(type, action, ...args)
{
  if (uiPorts.size == 0)
    return;

  let convertedArgs = [];
  for (let arg of args)
  {
    if (arg instanceof subscriptionClasses["Subscription"])
      convertedArgs.push(convertSubscription(arg));
    else if (arg instanceof filterClasses["Filter"])
      convertedArgs.push(convertFilter(arg));
    else
      convertedArgs.push(arg);
  }

  for (let [uiPort, filters] of uiPorts)
  {
    let actions = filters.get(type);
    if (actions && actions.indexOf(action) != -1)
    {
      uiPort.postMessage({
        type: messageTypes.get(type),
        action,
        args: convertedArgs
      });
    }
  }
}

function includeActiveRemoteSubscriptions(s)
{
  if (s.disabled || !(s instanceof subscriptionClasses["RegularSubscription"]))
    return false;
  if (s instanceof subscriptionClasses["DownloadableSubscription"] &&
      !/^(http|https|ftp):/i.test(s.url))
    return false;
  return true;
}

function addRequestListeners(dataCollectionTabId, issueReporterTabId)
{
  let logRequest = (request, filter) =>
  {
    let subscriptions = [];
    if (filter)
    {
      for (let subscription of filterStorage["filterStorage"].subscriptions(filter.text))
      {
        if (includeActiveRemoteSubscriptions(subscription))
          subscriptions.push(subscription.url);
      }

      filter = convertFilter(filter);
    }
    request = convertObject(["url", "type", "docDomain", "thirdParty"],
                            request);
    sendMessage("requests", "hits", request, filter, subscriptions);
  };
  let removeTabListeners = tabId =>
  {
    if (tabId == dataCollectionTabId ||
        typeof issueReporterTabId == "number" && tabId == issueReporterTabId)
    {
      hitLogger["HitLogger"].removeListener(dataCollectionTabId, logRequest);
      browser.tabs.onRemoved.removeListener(removeTabListeners);
    }
  };
  hitLogger["HitLogger"].addListener(dataCollectionTabId, logRequest);
  browser.tabs.onRemoved.addListener(removeTabListeners);
}

function addFilterListeners(type, actions)
{
  for (let action of actions)
  {
    let name;
    if (type == "filter" && action == "loaded")
      name = "ready";
    else
      name = type + "." + action;

    if (!listenedFilterChanges.has(name))
    {
      listenedFilterChanges.add(name);
      filterNotifier["filterNotifier"].on(name, item =>
      {
        sendMessage(type, action, item);
      });
    }
  }
}

function addSubscription(subscription, properties)
{
  if (!subscriptionClasses["Subscription"].isValidURL(subscription.url))
    return false;

  subscription.disabled = false;
  if ("title" in properties)
    subscription.title = properties.title;
  if ("homepage" in properties)
    subscription.homepage = properties.homepage;

  filterStorage["filterStorage"].addSubscription(subscription);
  if (subscription instanceof subscriptionClasses["DownloadableSubscription"] &&
      !subscription.lastDownload)
    synchronizer["synchronizer"].execute(subscription);

  return true;
}

class FilterError
{
  constructor(type, reason = null)
  {
    this.lineno = null;
    this.reason = reason;
    this.selector = null;
    this.type = type;
  }

  toJSON()
  {
    return {
      lineno: this.lineno,
      reason: this.reason,
      selector: this.selector,
      type: this.type
    };
  }
}

function parseFilter(text)
{
  let filter = null;
  let error = null;

  text = filterClasses["Filter"].normalize(text);
  if (text)
  {
    if (text[0] == "[")
    {
      error = new FilterError("unexpected_filter_list_header");
    }
    else
    {
      filter = filterClasses["Filter"].fromText(text);
      if (filter instanceof filterClasses["InvalidFilter"])
      {
        error = new FilterError("invalid_filter", filter.reason);
      }
      else if (Object(filterClasses["isActiveFilter"])(filter) && filter.domains)
      {
        for (let domain of filter.domains.keys())
        {
          if (domain && !Object(url["isValidHostname"])(domain))
          {
            error = new FilterError("invalid_domain", domain);
            break;
          }
        }
      }
    }
  }

  return [filter, error];
}

/**
 * Attempts to add the given filter, or returns an error.
 *
 * @event "filters.add"
 * @property {string} text - The filter text to add
 * @returns {FilterError[]}
 */
messaging["port"].on("filters.add", (message, sender) => filtersAdd(message.text));

/**
 * Returns a serialised version of all the filters that a given subscription
 * contains.
 *
 * @event "filters.get"
 * @property {string} subscriptionUrl - The subscription's URL.
 * @returns {object[]}
 */
messaging["port"].on("filters.get", (message, sender) =>
{
  let subscription = subscriptionClasses["Subscription"].fromURL(message.subscriptionUrl);
  if (!subscription)
    return [];

  return convertSubscriptionFilters(subscription);
});

/**
 * Returns the available filter types, e.g. "FONT", "WEBSOCKET", etc.
 *
 * @event "filters.getTypes"
 * @returns {string[]}
 */
messaging["port"].on("filters.getTypes", (message, sender) =>
{
  let types = Array.from(requestBlocker["filterTypes"]);
  types.push(...types.splice(types.indexOf("OTHER"), 1));

  return types;
});

/**
 * Import the given block of filter text as custom user filters, optionally
 * removing any previously add custom user filters.
 *
 * @event "filters.importRaw"
 * @property {string} text
 *   The filters to add.
 * @property {boolean} removeExisting
 *   If true we remove any previously added custom user filters after adding
 *   the new ones.
 * @returns {string[]} errors
 */
messaging["port"].on("filters.importRaw", (message, sender) =>
{
  let [filters, errors] = filtersValidate(message.text);

  if (errors.length > 0)
    return errors;

  let addedFilters = new Set();
  for (let filter of filters)
  {
    if (Object(filterClasses["isActiveFilter"])(filter))
      filterState["filterState"].setEnabled(filter.text, true);

    filterStorage["filterStorage"].addFilter(filter);
    addedFilters.add(filter.text);
  }

  if (!message.removeExisting)
    return errors;

  for (let subscription of filterStorage["filterStorage"].subscriptions())
  {
    if (!(subscription instanceof subscriptionClasses["SpecialSubscription"]))
      continue;

    // We have to iterate backwards for now due to
    // https://issues.adblockplus.org/ticket/7152
    for (let i = subscription.filterCount; i--;)
    {
      let text = subscription.filterTextAt(i);
      if (!allowlisting["allowlistedDomainRegexp"].test(text) &&
          !addedFilters.has(text))
        filterStorage["filterStorage"].removeFilter(filterClasses["Filter"].fromText(text));
    }
  }

  return errors;
});

/**
 * Remove the given filter.
 *
 * @event "filters.remove"
 * @property {string} text
 *   The text of the filter to remove.
 * @property {string} [subscriptionUrl]
 *   The URL of the subscription to remove the filter from, defaults to all
 *   subscriptions.
 * @property {number} [index]
 *   The index of the filter in the given subscription to remove, defaults to
 *   all instances and ignored if subscriptionUrl isn't given.
 * @returns {string[]} errors
 */
messaging["port"].on("filters.remove", (message, sender) => filtersRemove(message));

/**
 * Replaces one custom user filter with another.
 *
 * @event "filters.replace"
 * @property {} new - The new filter text to add.
 * @property {} old - The old filter text to remove.
 * @returns {string[]} errors
 */
messaging["port"].on("filters.replace", (message, sender) =>
{
  let errors = filtersAdd(message.new);
  if (errors.length)
    return errors;
  filtersRemove({text: message.old});
  return [];
});

/**
 * Enabled or disables the given filter.
 *
 * @event "filters.toggle"
 * @property {string} text - The filter text.
 * @property {boolean} disabled - True to disable the filter, false to enable.
 */
messaging["port"].on("filters.toggle", (message, sender) =>
{
  filterState["filterState"].setEnabled(message.text, !message.disabled);
});

/**
 * Validates the filters inside the given block of filter text.
 *
 * @event "filters.validate"
 * @property {string} text - The filters to validate
 * @returns {string[]} errors
 */
messaging["port"].on("filters.validate", (message, sender) =>
{
  let [, errors] = filtersValidate(message.text);
  return errors;
});

/**
 * Adds a subscription, either in the background or with the user's
 * confirmation.
 *
 * @event "subscriptions.add"
 * @property {string} url
 *   The subscription's URL.
 * @property {boolean} confirm
 *   If true the user will first be asked to confirm the subscription's details
 *   before it is added.
 * @property {string} [title]
 *   The subscription's title.
 * @property {string} [homepage]
 *   The subscription's homepage.
 * @returns {?boolean}
 *   true if the subscription was added, false if the URL is invalid,
 *   null if the "confirm" property was set
 */
messaging["port"].on("subscriptions.add", async(message, sender) =>
{
  let subscription = subscriptionClasses["Subscription"].fromURL(message.url);

  if (message.confirm)
  {
    if ("title" in message)
      subscription.title = message.title;
    if ("homepage" in message)
      subscription.homepage = message.homepage;

    await showOptions();
    sendMessage("app", "addSubscription", subscription);

    return null;
  }

  return addSubscription(subscription, message);
});

/**
 * Returns a serialised version of all the subscriptions which meet the given
 * criteria. Optionally include the disabled filters for those subscriptions.
 *
 * @event "subscriptions.get"
 * @property {boolean} ignoreDisabled
 *   Skip disabled subscriptions if true.
 * @property {boolean} downloadable
 *   Skip all but downloadable subscriptions if true.
 * @property {boolean} special
 *   Skip all but special subscriptions if true.
 * @property {boolean} disabledFilters
 *   Include a subscription's disabled filters if true.
 * @returns {object[]} subscriptions
 */
messaging["port"].on("subscriptions.get", (message, sender) =>
{
  let subscriptions = [];
  for (let s of filterStorage["filterStorage"].subscriptions())
  {
    if (message.ignoreDisabled && s.disabled)
      continue;

    if (!(message.downloadable && s instanceof subscriptionClasses["DownloadableSubscription"] ||
          message.special && s instanceof subscriptionClasses["SpecialSubscription"]))
      continue;

    let subscription = convertSubscription(s);
    if (message.disabledFilters)
    {
      subscription.disabledFilters =
        Array.from(s.filterText(), filterClasses["Filter"].fromText)
        .filter(f => Object(filterClasses["isActiveFilter"])(f) && !filterState["filterState"].isEnabled(f.text))
        .map(f => f.text);
    }
    subscriptions.push(subscription);
  }
  return subscriptions;
});

/**
 * Returns a list of serialised recommended subscriptions for the user.
 *
 * @event "subscriptions.getRecommendations"
 * @returns {object[]} recommendedSubscriptions
 */
messaging["port"].on("subscriptions.getRecommendations",
        (message, sender) => Array.from(Object(recommendations["recommendations"])(),
                                        convertRecommendation));

/**
 * Remove the given subscription if it exists.
 *
 * @event "subscriptions.remove"
 * @property {string} url - The subscription's URL.
 */
messaging["port"].on("subscriptions.remove", (message, sender) =>
{
  let subscription = subscriptionClasses["Subscription"].fromURL(message.url);
  if (filterStorage["filterStorage"].hasSubscription(subscription))
    filterStorage["filterStorage"].removeSubscription(subscription);
});

/**
 * Toggles a subscription by either enabling/disabling, or by adding/removing
 * it.
 *
 * @event "subscriptions.toggle"
 * @property {string} url
 *   The subscription's URL.
 * @property {boolean} keepInstalled
 *   If true enable/disable the subscription, otherwise add/remove.
 * @returns {boolean}
 *   true if the subscription was toggled successfully,
 *   false if it's a new subscription with an invalid URL
 */
messaging["port"].on("subscriptions.toggle", (message, sender) =>
{
  let subscription = subscriptionClasses["Subscription"].fromURL(message.url);

  if (filterStorage["filterStorage"].hasSubscription(subscription))
  {
    if (subscription.disabled || message.keepInstalled)
      subscription.disabled = !subscription.disabled;
    else
      filterStorage["filterStorage"].removeSubscription(subscription);
    return true;
  }

  return addSubscription(subscription, message);
});

/**
 * Trigger either the given subscription, or all subscriptions, to update.
 *
 * @event "subscriptions.update"
 * @property {string} [url]
 *   The subscription to update, if not specified all subscriptions will be
 *   updated.
 */
messaging["port"].on("subscriptions.update", (message, sender) =>
{
  let subscriptions;
  if (message.url)
    subscriptions = [subscriptionClasses["Subscription"].fromURL(message.url)];
  else
    subscriptions = filterStorage["filterStorage"].subscriptions();

  for (let subscription of subscriptions)
  {
    if (subscription instanceof subscriptionClasses["DownloadableSubscription"])
      synchronizer["synchronizer"].execute(subscription, true);
  }
});

function filtersAdd(text)
{
  let [filter, error] = parseFilter(text);

  if (error)
    return [error];

  if (filter)
  {
    if (Object(filterClasses["isActiveFilter"])(filter))
      filterState["filterState"].setEnabled(text, true);
    filterStorage["filterStorage"].addFilter(filter);
  }

  return [];
}

function filtersValidate(text)
{
  let filters = [];
  let errors = [];

  let lines = text.split("\n");
  for (let i = 0; i < lines.length; i++)
  {
    let [filter, error] = parseFilter(lines[i]);

    if (error)
    {
      // We don't treat filter headers like invalid filters,
      // instead we simply ignore them and don't show any errors
      // in order to allow pasting complete filter lists.
      // If there are no filters, we do treat it as an invalid filter
      // to inform users about it and to give them a chance to edit it.
      if (error.type === "unexpected_filter_list_header" &&
          lines.length > 1)
        continue;

      if (lines.length > 1)
        error.lineno = i + 1;

      errors.push(error);
    }
    else if (filter)
    {
      filters.push(filter);
    }
  }

  return [filters, errors];
}

function filtersRemove(message)
{
  let filter = filterClasses["Filter"].fromText(message.text);
  let subscription = null;
  if (message.subscriptionUrl)
    subscription = subscriptionClasses["Subscription"].fromURL(message.subscriptionUrl);

  if (!subscription)
    filterStorage["filterStorage"].removeFilter(filter);
  else
    filterStorage["filterStorage"].removeFilter(filter, subscription, message.index);
  // in order to behave, from consumer perspective, like any other
  // method that could produce errors, return an Array, even if empty
  return [];
}

function listen(type, filters, newFilter, message, senderTabId)
{
  switch (type)
  {
    case "app":
      filters.set("app", newFilter);
      break;
    case "filters":
      filters.set("filter", newFilter);
      addFilterListeners("filter", newFilter);
      break;
    case "prefs":
      filters.set("pref", newFilter);
      for (let preference of newFilter)
      {
        if (!listenedPreferences.has(preference))
        {
          listenedPreferences.add(preference);
          prefs["Prefs"].on(preference, () =>
          {
            sendMessage("pref", preference, prefs["Prefs"][preference]);
          });
        }
      }
      break;
    case "subscriptions":
      filters.set("subscription", newFilter);
      addFilterListeners("subscription", newFilter);
      break;
    case "requests":
      filters.set("requests", newFilter);
      addRequestListeners(message.tabId, senderTabId);
      break;
    case "stats":
      filters.set("stats", newFilter);
      for (let stat of newFilter)
      {
        if (!listenedStats.has(stat))
        {
          listenedStats.add(stat);
          stats["Stats"].on(stat, info =>
          {
            sendMessage("stats", stat, info);
          });
        }
      }
      break;
  }
}

function onConnect(uiPort)
{
  if (uiPort.name != "ui")
    return;

  let filters = new Map();
  uiPorts.set(uiPort, filters);

  uiPort.onDisconnect.addListener(() =>
  {
    uiPorts.delete(uiPort);
  });

  uiPort.onMessage.addListener(message =>
  {
    let [type, action] = message.type.split(".", 2);

    // For now we're only using long-lived connections for handling
    // "*.listen" messages to tackle #6440
    if (action == "listen")
    {
      listen(type, filters, message.filter, message,
             uiPort.sender && uiPort.sender.tab && uiPort.sender.tab.id);
    }
  });
}

browser.runtime.onConnect.addListener(onConnect);


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